github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/compile/internal/ssa/value.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/compile/internal/types" 9 "github.com/gagliardetto/golang-go/cmd/internal/src" 10 "fmt" 11 "math" 12 "sort" 13 "strings" 14 ) 15 16 // A Value represents a value in the SSA representation of the program. 17 // The ID and Type fields must not be modified. The remainder may be modified 18 // if they preserve the value of the Value (e.g. changing a (mul 2 x) to an (add x x)). 19 type Value struct { 20 // A unique identifier for the value. For performance we allocate these IDs 21 // densely starting at 1. There is no guarantee that there won't be occasional holes, though. 22 ID ID 23 24 // The operation that computes this value. See op.go. 25 Op Op 26 27 // The type of this value. Normally this will be a Go type, but there 28 // are a few other pseudo-types, see ../types/type.go. 29 Type *types.Type 30 31 // Auxiliary info for this value. The type of this information depends on the opcode and type. 32 // AuxInt is used for integer values, Aux is used for other values. 33 // Floats are stored in AuxInt using math.Float64bits(f). 34 // Unused portions of AuxInt are filled by sign-extending the used portion, 35 // even if the represented value is unsigned. 36 // Users of AuxInt which interpret AuxInt as unsigned (e.g. shifts) must be careful. 37 // Use Value.AuxUnsigned to get the zero-extended value of AuxInt. 38 AuxInt int64 39 Aux interface{} 40 41 // Arguments of this value 42 Args []*Value 43 44 // Containing basic block 45 Block *Block 46 47 // Source position 48 Pos src.XPos 49 50 // Use count. Each appearance in Value.Args and Block.Controls counts once. 51 Uses int32 52 53 // wasm: Value stays on the WebAssembly stack. This value will not get a "register" (WebAssembly variable) 54 // nor a slot on Go stack, and the generation of this value is delayed to its use time. 55 OnWasmStack bool 56 57 // Storage for the first three args 58 argstorage [3]*Value 59 } 60 61 // Examples: 62 // Opcode aux args 63 // OpAdd nil 2 64 // OpConst string 0 string constant 65 // OpConst int64 0 int64 constant 66 // OpAddcq int64 1 amd64 op: v = arg[0] + constant 67 68 // short form print. Just v#. 69 func (v *Value) String() string { 70 if v == nil { 71 return "nil" // should never happen, but not panicking helps with debugging 72 } 73 return fmt.Sprintf("v%d", v.ID) 74 } 75 76 func (v *Value) AuxInt8() int8 { 77 if opcodeTable[v.Op].auxType != auxInt8 { 78 v.Fatalf("op %s doesn't have an int8 aux field", v.Op) 79 } 80 return int8(v.AuxInt) 81 } 82 83 func (v *Value) AuxInt16() int16 { 84 if opcodeTable[v.Op].auxType != auxInt16 { 85 v.Fatalf("op %s doesn't have an int16 aux field", v.Op) 86 } 87 return int16(v.AuxInt) 88 } 89 90 func (v *Value) AuxInt32() int32 { 91 if opcodeTable[v.Op].auxType != auxInt32 { 92 v.Fatalf("op %s doesn't have an int32 aux field", v.Op) 93 } 94 return int32(v.AuxInt) 95 } 96 97 // AuxUnsigned returns v.AuxInt as an unsigned value for OpConst*. 98 // v.AuxInt is always sign-extended to 64 bits, even if the 99 // represented value is unsigned. This undoes that sign extension. 100 func (v *Value) AuxUnsigned() uint64 { 101 c := v.AuxInt 102 switch v.Op { 103 case OpConst64: 104 return uint64(c) 105 case OpConst32: 106 return uint64(uint32(c)) 107 case OpConst16: 108 return uint64(uint16(c)) 109 case OpConst8: 110 return uint64(uint8(c)) 111 } 112 v.Fatalf("op %s isn't OpConst*", v.Op) 113 return 0 114 } 115 116 func (v *Value) AuxFloat() float64 { 117 if opcodeTable[v.Op].auxType != auxFloat32 && opcodeTable[v.Op].auxType != auxFloat64 { 118 v.Fatalf("op %s doesn't have a float aux field", v.Op) 119 } 120 return math.Float64frombits(uint64(v.AuxInt)) 121 } 122 func (v *Value) AuxValAndOff() ValAndOff { 123 if opcodeTable[v.Op].auxType != auxSymValAndOff { 124 v.Fatalf("op %s doesn't have a ValAndOff aux field", v.Op) 125 } 126 return ValAndOff(v.AuxInt) 127 } 128 129 // long form print. v# = opcode <type> [aux] args [: reg] (names) 130 func (v *Value) LongString() string { 131 s := fmt.Sprintf("v%d = %s", v.ID, v.Op) 132 s += " <" + v.Type.String() + ">" 133 s += v.auxString() 134 for _, a := range v.Args { 135 s += fmt.Sprintf(" %v", a) 136 } 137 var r []Location 138 if v.Block != nil { 139 r = v.Block.Func.RegAlloc 140 } 141 if int(v.ID) < len(r) && r[v.ID] != nil { 142 s += " : " + r[v.ID].String() 143 } 144 var names []string 145 if v.Block != nil { 146 for name, values := range v.Block.Func.NamedValues { 147 for _, value := range values { 148 if value == v { 149 names = append(names, name.String()) 150 break // drop duplicates. 151 } 152 } 153 } 154 } 155 if len(names) != 0 { 156 sort.Strings(names) // Otherwise a source of variation in debugging output. 157 s += " (" + strings.Join(names, ", ") + ")" 158 } 159 return s 160 } 161 162 func (v *Value) auxString() string { 163 switch opcodeTable[v.Op].auxType { 164 case auxBool: 165 if v.AuxInt == 0 { 166 return " [false]" 167 } else { 168 return " [true]" 169 } 170 case auxInt8: 171 return fmt.Sprintf(" [%d]", v.AuxInt8()) 172 case auxInt16: 173 return fmt.Sprintf(" [%d]", v.AuxInt16()) 174 case auxInt32: 175 return fmt.Sprintf(" [%d]", v.AuxInt32()) 176 case auxInt64, auxInt128: 177 return fmt.Sprintf(" [%d]", v.AuxInt) 178 case auxFloat32, auxFloat64: 179 return fmt.Sprintf(" [%g]", v.AuxFloat()) 180 case auxString: 181 return fmt.Sprintf(" {%q}", v.Aux) 182 case auxSym, auxTyp, auxArchSpecific: 183 if v.Aux != nil { 184 return fmt.Sprintf(" {%v}", v.Aux) 185 } 186 case auxSymOff, auxTypSize: 187 s := "" 188 if v.Aux != nil { 189 s = fmt.Sprintf(" {%v}", v.Aux) 190 } 191 if v.AuxInt != 0 { 192 s += fmt.Sprintf(" [%v]", v.AuxInt) 193 } 194 return s 195 case auxSymValAndOff: 196 s := "" 197 if v.Aux != nil { 198 s = fmt.Sprintf(" {%v}", v.Aux) 199 } 200 return s + fmt.Sprintf(" [%s]", v.AuxValAndOff()) 201 case auxCCop: 202 return fmt.Sprintf(" {%s}", v.Aux.(Op)) 203 } 204 return "" 205 } 206 207 // If/when midstack inlining is enabled (-l=4), the compiler gets both larger and slower. 208 // Not-inlining this method is a help (*Value.reset and *Block.NewValue0 are similar). 209 //go:noinline 210 func (v *Value) AddArg(w *Value) { 211 if v.Args == nil { 212 v.resetArgs() // use argstorage 213 } 214 v.Args = append(v.Args, w) 215 w.Uses++ 216 } 217 func (v *Value) AddArgs(a ...*Value) { 218 if v.Args == nil { 219 v.resetArgs() // use argstorage 220 } 221 v.Args = append(v.Args, a...) 222 for _, x := range a { 223 x.Uses++ 224 } 225 } 226 func (v *Value) SetArg(i int, w *Value) { 227 v.Args[i].Uses-- 228 v.Args[i] = w 229 w.Uses++ 230 } 231 func (v *Value) RemoveArg(i int) { 232 v.Args[i].Uses-- 233 copy(v.Args[i:], v.Args[i+1:]) 234 v.Args[len(v.Args)-1] = nil // aid GC 235 v.Args = v.Args[:len(v.Args)-1] 236 } 237 func (v *Value) SetArgs1(a *Value) { 238 v.resetArgs() 239 v.AddArg(a) 240 } 241 func (v *Value) SetArgs2(a *Value, b *Value) { 242 v.resetArgs() 243 v.AddArg(a) 244 v.AddArg(b) 245 } 246 247 func (v *Value) resetArgs() { 248 for _, a := range v.Args { 249 a.Uses-- 250 } 251 v.argstorage[0] = nil 252 v.argstorage[1] = nil 253 v.argstorage[2] = nil 254 v.Args = v.argstorage[:0] 255 } 256 257 func (v *Value) reset(op Op) { 258 v.Op = op 259 if op != OpCopy && notStmtBoundary(op) { 260 // Special case for OpCopy because of how it is used in rewrite 261 v.Pos = v.Pos.WithNotStmt() 262 } 263 v.resetArgs() 264 v.AuxInt = 0 265 v.Aux = nil 266 } 267 268 // copyInto makes a new value identical to v and adds it to the end of b. 269 // unlike copyIntoWithXPos this does not check for v.Pos being a statement. 270 func (v *Value) copyInto(b *Block) *Value { 271 c := b.NewValue0(v.Pos.WithNotStmt(), v.Op, v.Type) // Lose the position, this causes line number churn otherwise. 272 c.Aux = v.Aux 273 c.AuxInt = v.AuxInt 274 c.AddArgs(v.Args...) 275 for _, a := range v.Args { 276 if a.Type.IsMemory() { 277 v.Fatalf("can't move a value with a memory arg %s", v.LongString()) 278 } 279 } 280 return c 281 } 282 283 // copyIntoWithXPos makes a new value identical to v and adds it to the end of b. 284 // The supplied position is used as the position of the new value. 285 // Because this is used for rematerialization, check for case that (rematerialized) 286 // input to value with position 'pos' carried a statement mark, and that the supplied 287 // position (of the instruction using the rematerialized value) is not marked, and 288 // preserve that mark if its line matches the supplied position. 289 func (v *Value) copyIntoWithXPos(b *Block, pos src.XPos) *Value { 290 if v.Pos.IsStmt() == src.PosIsStmt && pos.IsStmt() != src.PosIsStmt && v.Pos.SameFileAndLine(pos) { 291 pos = pos.WithIsStmt() 292 } 293 c := b.NewValue0(pos, v.Op, v.Type) 294 c.Aux = v.Aux 295 c.AuxInt = v.AuxInt 296 c.AddArgs(v.Args...) 297 for _, a := range v.Args { 298 if a.Type.IsMemory() { 299 v.Fatalf("can't move a value with a memory arg %s", v.LongString()) 300 } 301 } 302 return c 303 } 304 305 func (v *Value) Logf(msg string, args ...interface{}) { v.Block.Logf(msg, args...) } 306 func (v *Value) Log() bool { return v.Block.Log() } 307 func (v *Value) Fatalf(msg string, args ...interface{}) { 308 v.Block.Func.fe.Fatalf(v.Pos, msg, args...) 309 } 310 311 // isGenericIntConst reports whether v is a generic integer constant. 312 func (v *Value) isGenericIntConst() bool { 313 return v != nil && (v.Op == OpConst64 || v.Op == OpConst32 || v.Op == OpConst16 || v.Op == OpConst8) 314 } 315 316 // Reg returns the register assigned to v, in cmd/internal/obj/$ARCH numbering. 317 func (v *Value) Reg() int16 { 318 reg := v.Block.Func.RegAlloc[v.ID] 319 if reg == nil { 320 v.Fatalf("nil register for value: %s\n%s\n", v.LongString(), v.Block.Func) 321 } 322 return reg.(*Register).objNum 323 } 324 325 // Reg0 returns the register assigned to the first output of v, in cmd/internal/obj/$ARCH numbering. 326 func (v *Value) Reg0() int16 { 327 reg := v.Block.Func.RegAlloc[v.ID].(LocPair)[0] 328 if reg == nil { 329 v.Fatalf("nil first register for value: %s\n%s\n", v.LongString(), v.Block.Func) 330 } 331 return reg.(*Register).objNum 332 } 333 334 // Reg1 returns the register assigned to the second output of v, in cmd/internal/obj/$ARCH numbering. 335 func (v *Value) Reg1() int16 { 336 reg := v.Block.Func.RegAlloc[v.ID].(LocPair)[1] 337 if reg == nil { 338 v.Fatalf("nil second register for value: %s\n%s\n", v.LongString(), v.Block.Func) 339 } 340 return reg.(*Register).objNum 341 } 342 343 func (v *Value) RegName() string { 344 reg := v.Block.Func.RegAlloc[v.ID] 345 if reg == nil { 346 v.Fatalf("nil register for value: %s\n%s\n", v.LongString(), v.Block.Func) 347 } 348 return reg.(*Register).name 349 } 350 351 // MemoryArg returns the memory argument for the Value. 352 // The returned value, if non-nil, will be memory-typed (or a tuple with a memory-typed second part). 353 // Otherwise, nil is returned. 354 func (v *Value) MemoryArg() *Value { 355 if v.Op == OpPhi { 356 v.Fatalf("MemoryArg on Phi") 357 } 358 na := len(v.Args) 359 if na == 0 { 360 return nil 361 } 362 if m := v.Args[na-1]; m.Type.IsMemory() { 363 return m 364 } 365 return nil 366 } 367 368 // LackingPos indicates whether v is a value that is unlikely to have a correct 369 // position assigned to it. Ignoring such values leads to more user-friendly positions 370 // assigned to nearby values and the blocks containing them. 371 func (v *Value) LackingPos() bool { 372 // The exact definition of LackingPos is somewhat heuristically defined and may change 373 // in the future, for example if some of these operations are generated more carefully 374 // with respect to their source position. 375 return v.Op == OpVarDef || v.Op == OpVarKill || v.Op == OpVarLive || v.Op == OpPhi || 376 (v.Op == OpFwdRef || v.Op == OpCopy) && v.Type == types.TypeMem 377 }