github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/compile/internal/ssa/op.go (about) 1 // Copyright 2015 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package ssa 6 7 import ( 8 "github.com/gagliardetto/golang-go/cmd/internal/obj" 9 "fmt" 10 ) 11 12 // An Op encodes the specific operation that a Value performs. 13 // Opcodes' semantics can be modified by the type and aux fields of the Value. 14 // For instance, OpAdd can be 32 or 64 bit, signed or unsigned, float or complex, depending on Value.Type. 15 // Semantics of each op are described in the opcode files in gen/*Ops.go. 16 // There is one file for generic (architecture-independent) ops and one file 17 // for each architecture. 18 type Op int32 19 20 type opInfo struct { 21 name string 22 reg regInfo 23 auxType auxType 24 argLen int32 // the number of arguments, -1 if variable length 25 asm obj.As 26 generic bool // this is a generic (arch-independent) opcode 27 rematerializeable bool // this op is rematerializeable 28 commutative bool // this operation is commutative (e.g. addition) 29 resultInArg0 bool // (first, if a tuple) output of v and v.Args[0] must be allocated to the same register 30 resultNotInArgs bool // outputs must not be allocated to the same registers as inputs 31 clobberFlags bool // this op clobbers flags register 32 call bool // is a function call 33 nilCheck bool // this op is a nil check on arg0 34 faultOnNilArg0 bool // this op will fault if arg0 is nil (and aux encodes a small offset) 35 faultOnNilArg1 bool // this op will fault if arg1 is nil (and aux encodes a small offset) 36 usesScratch bool // this op requires scratch memory space 37 hasSideEffects bool // for "reasons", not to be eliminated. E.g., atomic store, #19182. 38 zeroWidth bool // op never translates into any machine code. example: copy, which may sometimes translate to machine code, is not zero-width. 39 unsafePoint bool // this op is an unsafe point, i.e. not safe for async preemption 40 symEffect SymEffect // effect this op has on symbol in aux 41 scale uint8 // amd64/386 indexed load scale 42 } 43 44 type inputInfo struct { 45 idx int // index in Args array 46 regs regMask // allowed input registers 47 } 48 49 type outputInfo struct { 50 idx int // index in output tuple 51 regs regMask // allowed output registers 52 } 53 54 type regInfo struct { 55 // inputs encodes the register restrictions for an instruction's inputs. 56 // Each entry specifies an allowed register set for a particular input. 57 // They are listed in the order in which regalloc should pick a register 58 // from the register set (most constrained first). 59 // Inputs which do not need registers are not listed. 60 inputs []inputInfo 61 // clobbers encodes the set of registers that are overwritten by 62 // the instruction (other than the output registers). 63 clobbers regMask 64 // outputs is the same as inputs, but for the outputs of the instruction. 65 outputs []outputInfo 66 } 67 68 type auxType int8 69 70 const ( 71 auxNone auxType = iota 72 auxBool // auxInt is 0/1 for false/true 73 auxInt8 // auxInt is an 8-bit integer 74 auxInt16 // auxInt is a 16-bit integer 75 auxInt32 // auxInt is a 32-bit integer 76 auxInt64 // auxInt is a 64-bit integer 77 auxInt128 // auxInt represents a 128-bit integer. Always 0. 78 auxFloat32 // auxInt is a float32 (encoded with math.Float64bits) 79 auxFloat64 // auxInt is a float64 (encoded with math.Float64bits) 80 auxString // aux is a string 81 auxSym // aux is a symbol (a *gc.Node for locals or an *obj.LSym for globals) 82 auxSymOff // aux is a symbol, auxInt is an offset 83 auxSymValAndOff // aux is a symbol, auxInt is a ValAndOff 84 auxTyp // aux is a type 85 auxTypSize // aux is a type, auxInt is a size, must have Aux.(Type).Size() == AuxInt 86 auxCCop // aux is a ssa.Op that represents a flags-to-bool conversion (e.g. LessThan) 87 auxArchSpecific // aux type is specific to a particular backend (see the relevant op for the actual type) 88 ) 89 90 // A SymEffect describes the effect that an SSA Value has on the variable 91 // identified by the symbol in its Aux field. 92 type SymEffect int8 93 94 const ( 95 SymRead SymEffect = 1 << iota 96 SymWrite 97 SymAddr 98 99 SymRdWr = SymRead | SymWrite 100 101 SymNone SymEffect = 0 102 ) 103 104 // A ValAndOff is used by the several opcodes. It holds 105 // both a value and a pointer offset. 106 // A ValAndOff is intended to be encoded into an AuxInt field. 107 // The zero ValAndOff encodes a value of 0 and an offset of 0. 108 // The high 32 bits hold a value. 109 // The low 32 bits hold a pointer offset. 110 type ValAndOff int64 111 112 func (x ValAndOff) Val() int64 { 113 return int64(x) >> 32 114 } 115 func (x ValAndOff) Off() int64 { 116 return int64(int32(x)) 117 } 118 func (x ValAndOff) Int64() int64 { 119 return int64(x) 120 } 121 func (x ValAndOff) String() string { 122 return fmt.Sprintf("val=%d,off=%d", x.Val(), x.Off()) 123 } 124 125 // validVal reports whether the value can be used 126 // as an argument to makeValAndOff. 127 func validVal(val int64) bool { 128 return val == int64(int32(val)) 129 } 130 131 // validOff reports whether the offset can be used 132 // as an argument to makeValAndOff. 133 func validOff(off int64) bool { 134 return off == int64(int32(off)) 135 } 136 137 // validValAndOff reports whether we can fit the value and offset into 138 // a ValAndOff value. 139 func validValAndOff(val, off int64) bool { 140 if !validVal(val) { 141 return false 142 } 143 if !validOff(off) { 144 return false 145 } 146 return true 147 } 148 149 // makeValAndOff encodes a ValAndOff into an int64 suitable for storing in an AuxInt field. 150 func makeValAndOff(val, off int64) int64 { 151 if !validValAndOff(val, off) { 152 panic("invalid makeValAndOff") 153 } 154 return ValAndOff(val<<32 + int64(uint32(off))).Int64() 155 } 156 157 // offOnly returns the offset half of ValAndOff vo. 158 // It is intended for use in rewrite rules. 159 func offOnly(vo int64) int64 { 160 return ValAndOff(vo).Off() 161 } 162 163 // valOnly returns the value half of ValAndOff vo. 164 // It is intended for use in rewrite rules. 165 func valOnly(vo int64) int64 { 166 return ValAndOff(vo).Val() 167 } 168 169 func (x ValAndOff) canAdd(off int64) bool { 170 newoff := x.Off() + off 171 return newoff == int64(int32(newoff)) 172 } 173 174 func (x ValAndOff) add(off int64) int64 { 175 if !x.canAdd(off) { 176 panic("invalid ValAndOff.add") 177 } 178 return makeValAndOff(x.Val(), x.Off()+off) 179 } 180 181 type BoundsKind uint8 182 183 const ( 184 BoundsIndex BoundsKind = iota // indexing operation, 0 <= idx < len failed 185 BoundsIndexU // ... with unsigned idx 186 BoundsSliceAlen // 2-arg slicing operation, 0 <= high <= len failed 187 BoundsSliceAlenU // ... with unsigned high 188 BoundsSliceAcap // 2-arg slicing operation, 0 <= high <= cap failed 189 BoundsSliceAcapU // ... with unsigned high 190 BoundsSliceB // 2-arg slicing operation, 0 <= low <= high failed 191 BoundsSliceBU // ... with unsigned low 192 BoundsSlice3Alen // 3-arg slicing operation, 0 <= max <= len failed 193 BoundsSlice3AlenU // ... with unsigned max 194 BoundsSlice3Acap // 3-arg slicing operation, 0 <= max <= cap failed 195 BoundsSlice3AcapU // ... with unsigned max 196 BoundsSlice3B // 3-arg slicing operation, 0 <= high <= max failed 197 BoundsSlice3BU // ... with unsigned high 198 BoundsSlice3C // 3-arg slicing operation, 0 <= low <= high failed 199 BoundsSlice3CU // ... with unsigned low 200 BoundsKindCount 201 ) 202 203 // boundsAPI determines which register arguments a bounds check call should use. For an [a:b:c] slice, we do: 204 // CMPQ c, cap 205 // JA fail1 206 // CMPQ b, c 207 // JA fail2 208 // CMPQ a, b 209 // JA fail3 210 // 211 // fail1: CALL panicSlice3Acap (c, cap) 212 // fail2: CALL panicSlice3B (b, c) 213 // fail3: CALL panicSlice3C (a, b) 214 // 215 // When we register allocate that code, we want the same register to be used for 216 // the first arg of panicSlice3Acap and the second arg to panicSlice3B. That way, 217 // initializing that register once will satisfy both calls. 218 // That desire ends up dividing the set of bounds check calls into 3 sets. This function 219 // determines which set to use for a given panic call. 220 // The first arg for set 0 should be the second arg for set 1. 221 // The first arg for set 1 should be the second arg for set 2. 222 func boundsABI(b int64) int { 223 switch BoundsKind(b) { 224 case BoundsSlice3Alen, 225 BoundsSlice3AlenU, 226 BoundsSlice3Acap, 227 BoundsSlice3AcapU: 228 return 0 229 case BoundsSliceAlen, 230 BoundsSliceAlenU, 231 BoundsSliceAcap, 232 BoundsSliceAcapU, 233 BoundsSlice3B, 234 BoundsSlice3BU: 235 return 1 236 case BoundsIndex, 237 BoundsIndexU, 238 BoundsSliceB, 239 BoundsSliceBU, 240 BoundsSlice3C, 241 BoundsSlice3CU: 242 return 2 243 default: 244 panic("bad BoundsKind") 245 } 246 }