| // 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 |
| |
| import ( |
| "cmd/internal/obj" |
| "fmt" |
| ) |
| |
| // 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 in the opcode files in gen/*Ops.go. |
| // There is one file for generic (architecture-independent) ops and one file |
| // for each architecture. |
| type Op int32 |
| |
| type opInfo struct { |
| name string |
| reg regInfo |
| auxType auxType |
| argLen int32 // the number of arguments, -1 if variable length |
| asm obj.As |
| generic bool // this is a generic (arch-independent) opcode |
| rematerializeable bool // this op is rematerializeable |
| commutative bool // this operation is commutative (e.g. addition) |
| resultInArg0 bool // (first, if a tuple) output of v and v.Args[0] must be allocated to the same register |
| resultNotInArgs bool // outputs must not be allocated to the same registers as inputs |
| clobberFlags bool // this op clobbers flags register |
| call bool // is a function call |
| nilCheck bool // this op is a nil check on arg0 |
| faultOnNilArg0 bool // this op will fault if arg0 is nil (and aux encodes a small offset) |
| faultOnNilArg1 bool // this op will fault if arg1 is nil (and aux encodes a small offset) |
| usesScratch bool // this op requires scratch memory space |
| hasSideEffects bool // for "reasons", not to be eliminated. E.g., atomic store, #19182. |
| zeroWidth bool // op never translates into any machine code. example: copy, which may sometimes translate to machine code, is not zero-width. |
| symEffect SymEffect // effect this op has on symbol in aux |
| } |
| |
| type inputInfo struct { |
| idx int // index in Args array |
| regs regMask // allowed input registers |
| } |
| |
| type outputInfo struct { |
| idx int // index in output tuple |
| regs regMask // allowed output registers |
| } |
| |
| type regInfo struct { |
| // inputs encodes the register restrictions for an instruction's inputs. |
| // Each entry specifies an allowed register set for a particular input. |
| // They are listed in the order in which regalloc should pick a register |
| // from the register set (most constrained first). |
| // Inputs which do not need registers are not listed. |
| inputs []inputInfo |
| // clobbers encodes the set of registers that are overwritten by |
| // the instruction (other than the output registers). |
| clobbers regMask |
| // outputs is the same as inputs, but for the outputs of the instruction. |
| outputs []outputInfo |
| } |
| |
| type auxType int8 |
| |
| const ( |
| auxNone auxType = iota |
| auxBool // auxInt is 0/1 for false/true |
| auxInt8 // auxInt is an 8-bit integer |
| auxInt16 // auxInt is a 16-bit integer |
| auxInt32 // auxInt is a 32-bit integer |
| auxInt64 // auxInt is a 64-bit integer |
| auxInt128 // auxInt represents a 128-bit integer. Always 0. |
| auxFloat32 // auxInt is a float32 (encoded with math.Float64bits) |
| auxFloat64 // auxInt is a float64 (encoded with math.Float64bits) |
| auxString // aux is a string |
| auxSym // aux is a symbol (a *gc.Node for locals or an *obj.LSym for globals) |
| auxSymOff // aux is a symbol, auxInt is an offset |
| auxSymValAndOff // aux is a symbol, auxInt is a ValAndOff |
| auxTyp // aux is a type |
| auxTypSize // aux is a type, auxInt is a size, must have Aux.(Type).Size() == AuxInt |
| auxCCop // aux is a ssa.Op that represents a flags-to-bool conversion (e.g. LessThan) |
| |
| auxSymInt32 // aux is a symbol, auxInt is a 32-bit integer |
| ) |
| |
| // A SymEffect describes the effect that an SSA Value has on the variable |
| // identified by the symbol in its Aux field. |
| type SymEffect int8 |
| |
| const ( |
| SymRead SymEffect = 1 << iota |
| SymWrite |
| SymAddr |
| |
| SymRdWr = SymRead | SymWrite |
| |
| SymNone SymEffect = 0 |
| ) |
| |
| // A ValAndOff is used by the several opcodes. It holds |
| // both a value and a pointer offset. |
| // A ValAndOff is intended to be encoded into an AuxInt field. |
| // The zero ValAndOff encodes a value of 0 and an offset of 0. |
| // The high 32 bits hold a value. |
| // The low 32 bits hold a pointer offset. |
| type ValAndOff int64 |
| |
| func (x ValAndOff) Val() int64 { |
| return int64(x) >> 32 |
| } |
| func (x ValAndOff) Off() int64 { |
| return int64(int32(x)) |
| } |
| func (x ValAndOff) Int64() int64 { |
| return int64(x) |
| } |
| func (x ValAndOff) String() string { |
| return fmt.Sprintf("val=%d,off=%d", x.Val(), x.Off()) |
| } |
| |
| // validVal reports whether the value can be used |
| // as an argument to makeValAndOff. |
| func validVal(val int64) bool { |
| return val == int64(int32(val)) |
| } |
| |
| // validOff reports whether the offset can be used |
| // as an argument to makeValAndOff. |
| func validOff(off int64) bool { |
| return off == int64(int32(off)) |
| } |
| |
| // validValAndOff reports whether we can fit the value and offset into |
| // a ValAndOff value. |
| func validValAndOff(val, off int64) bool { |
| if !validVal(val) { |
| return false |
| } |
| if !validOff(off) { |
| return false |
| } |
| return true |
| } |
| |
| // makeValAndOff encodes a ValAndOff into an int64 suitable for storing in an AuxInt field. |
| func makeValAndOff(val, off int64) int64 { |
| if !validValAndOff(val, off) { |
| panic("invalid makeValAndOff") |
| } |
| return ValAndOff(val<<32 + int64(uint32(off))).Int64() |
| } |
| |
| func (x ValAndOff) canAdd(off int64) bool { |
| newoff := x.Off() + off |
| return newoff == int64(int32(newoff)) |
| } |
| |
| func (x ValAndOff) add(off int64) int64 { |
| if !x.canAdd(off) { |
| panic("invalid ValAndOff.add") |
| } |
| return makeValAndOff(x.Val(), x.Off()+off) |
| } |