| // Copyright 2015 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package ssa |
| |
| // An Op encodes the specific operation that a Value performs. |
| // Opcodes' semantics can be modified by the type and aux fields of the Value. |
| // For instance, OpAdd can be 32 or 64 bit, signed or unsigned, float or complex, depending on Value.Type. |
| // Semantics of each op are described below. |
| // |
| // Ops come in two flavors, architecture-independent and architecture-dependent. |
| // Architecture-independent opcodes appear in this file. |
| // Architecture-dependent opcodes appear in op{arch}.go files. |
| type Op int32 |
| |
| // Opcode ranges, a generic one and one for each architecture. |
| const ( |
| opInvalid Op = 0 |
| opGenericBase Op = 1 + 1000*iota |
| opAMD64Base |
| op386Base |
| |
| opMax // sentinel |
| ) |
| |
| // Generic opcodes |
| const ( |
| opGenericStart Op = opGenericBase + iota |
| |
| // 2-input arithmetic |
| OpAdd // arg0 + arg1 |
| OpSub // arg0 - arg1 |
| OpMul // arg0 * arg1 |
| |
| // 2-input comparisons |
| OpLess // arg0 < arg1 |
| |
| // constants. Constant values are stored in the aux field. |
| // booleans have a bool aux field, strings have a string aux |
| // field, and so on. All integer types store their value |
| // in the aux field as an int64 (including int, uint64, etc.). |
| // We could store int8 as an int8, but that won't work for int, |
| // as it may be different widths on the host and target. |
| OpConst |
| |
| OpArg // address of a function parameter/result. Memory input is an arg called ".mem". aux is a string (TODO: make it something other than a string?) |
| OpGlobal // the address of a global variable aux.(*gc.Sym) |
| OpFunc // entry address of a function |
| |
| OpCopy // output = arg0 |
| OpPhi // select an argument based on which predecessor block we came from |
| |
| OpSliceMake // arg0=ptr, arg1=len, arg2=cap |
| OpSlicePtr // ptr(arg0) |
| OpSliceLen // len(arg0) |
| OpSliceCap // cap(arg0) |
| |
| OpStringMake // arg0=ptr, arg1=len |
| OpStringPtr // ptr(arg0) |
| OpStringLen // len(arg0) |
| |
| OpLoad // Load from arg0+aux.(int64). arg1=memory |
| OpStore // Store arg1 to arg0+aux.(int64). arg2=memory. Returns memory. |
| OpSliceIndex // arg0=slice, arg1=index, arg2=memory |
| OpIsNonNil // arg0 != nil |
| OpIsInBounds // 0 <= arg0 < arg1 |
| |
| // function calls. Arguments to the call have already been written to the stack. |
| // Return values appear on the stack. The method receiver, if any, is treated |
| // as a phantom first argument. |
| OpCall // arg0=code pointer, arg1=context ptr, arg2=memory. Returns memory. |
| OpStaticCall // call function aux.(*gc.Sym), arg0=memory. Returns memory. |
| |
| OpConvert // convert arg0 to another type |
| OpConvNop // interpret arg0 as another type |
| |
| // These ops return a pointer to a location on the stack. |
| OpFPAddr // FP + aux.(int64) (+ == args from caller, - == locals) |
| OpSPAddr // SP + aux.(int64) |
| |
| // spill&restore ops for the register allocator. These are |
| // semantically identical to OpCopy; they do not take/return |
| // stores like regular memory ops do. We can get away without memory |
| // args because we know there is no aliasing of spill slots on the stack. |
| OpStoreReg8 |
| OpLoadReg8 |
| |
| // used during ssa construction. Like OpCopy, but the arg has not been specified yet. |
| OpFwdRef |
| ) |
| |
| // GlobalOffset represents a fixed offset within a global variable |
| type GlobalOffset struct { |
| Global interface{} // holds a *gc.Sym |
| Offset int64 |
| } |
| |
| //go:generate stringer -type=Op |
| |
| type opInfo struct { |
| flags int32 |
| |
| // assembly template |
| // %In: location of input n |
| // %On: location of output n |
| // %A: print aux with fmt.Print |
| asm string |
| |
| // returns a reg constraint for the instruction. [0] gives a reg constraint |
| // for each input, [1] gives a reg constraint for each output. (Values have |
| // exactly one output for now) |
| reg [2][]regMask |
| } |
| |
| const ( |
| // possible properties of opcodes |
| OpFlagCommutative int32 = 1 << iota |
| ) |
| |
| // Opcodes that represent the input Go program |
| var genericTable = map[Op]opInfo{ |
| // the unknown op is used only during building and should not appear in a |
| // fully formed ssa representation. |
| |
| OpAdd: {flags: OpFlagCommutative}, |
| OpSub: {}, |
| OpMul: {flags: OpFlagCommutative}, |
| OpLess: {}, |
| |
| OpConst: {}, // aux matches the type (e.g. bool, int64 float64) |
| OpArg: {}, // aux is the name of the input variable. Currently only ".mem" is used |
| OpGlobal: {}, // address of a global variable |
| OpFunc: {}, |
| OpCopy: {}, |
| OpPhi: {}, |
| |
| OpConvNop: {}, // aux is the type to convert to |
| |
| /* |
| // build and take apart slices |
| {name: "slicemake"}, // (ptr,len,cap) -> slice |
| {name: "sliceptr"}, // pointer part of slice |
| {name: "slicelen"}, // length part of slice |
| {name: "slicecap"}, // capacity part of slice |
| |
| // build and take apart strings |
| {name: "stringmake"}, // (ptr,len) -> string |
| {name: "stringptr"}, // pointer part of string |
| {name: "stringlen"}, // length part of string |
| |
| // operations on arrays/slices/strings |
| {name: "slice"}, // (s, i, j) -> s[i:j] |
| {name: "index"}, // (mem, ptr, idx) -> val |
| {name: "indexaddr"}, // (ptr, idx) -> ptr |
| |
| // loads & stores |
| {name: "load"}, // (mem, check, ptr) -> val |
| {name: "store"}, // (mem, check, ptr, val) -> mem |
| |
| // checks |
| {name: "checknil"}, // (mem, ptr) -> check |
| {name: "checkbound"}, // (mem, idx, len) -> check |
| |
| // functions |
| {name: "call"}, |
| |
| // builtins |
| {name: "len"}, |
| {name: "convert"}, |
| |
| // tuples |
| {name: "tuple"}, // build a tuple out of its arguments |
| {name: "extract"}, // aux is an int64. Extract that index out of a tuple |
| {name: "extractsuffix"}, // aux is an int64. Slice a tuple with [aux:] |
| |
| */ |
| } |
| |
| // table of opcodes, indexed by opcode ID |
| var opcodeTable [opMax]opInfo |
| |
| func init() { |
| for op, info := range genericTable { |
| opcodeTable[op] = info |
| } |
| } |