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 5package ssa 6 7import ( 8 "cmd/compile/internal/types" 9 "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)). 19type 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#. 69func (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 76func (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 83func (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 90func (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. 100func (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 116func (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} 122func (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) 130func (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 162func (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 210func (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} 217func (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} 226func (v *Value) SetArg(i int, w *Value) { 227 v.Args[i].Uses-- 228 v.Args[i] = w 229 w.Uses++ 230} 231func (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} 237func (v *Value) SetArgs1(a *Value) { 238 v.resetArgs() 239 v.AddArg(a) 240} 241func (v *Value) SetArgs2(a *Value, b *Value) { 242 v.resetArgs() 243 v.AddArg(a) 244 v.AddArg(b) 245} 246 247func (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 257func (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. 270func (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. 289func (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 305func (v *Value) Logf(msg string, args ...interface{}) { v.Block.Logf(msg, args...) } 306func (v *Value) Log() bool { return v.Block.Log() } 307func (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. 312func (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. 317func (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. 326func (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. 335func (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 343func (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. 354func (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. 371func (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} 378