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/obj" 10 "cmd/internal/src" 11 "fmt" 12 "math" 13) 14 15// A Value represents a value in the SSA representation of the program. 16// The ID and Type fields must not be modified. The remainder may be modified 17// if they preserve the value of the Value (e.g. changing a (mul 2 x) to an (add x x)). 18type Value struct { 19 // A unique identifier for the value. For performance we allocate these IDs 20 // densely starting at 1. There is no guarantee that there won't be occasional holes, though. 21 ID ID 22 23 // The operation that computes this value. See op.go. 24 Op Op 25 26 // The type of this value. Normally this will be a Go type, but there 27 // are a few other pseudo-types, see type.go. 28 Type *types.Type 29 30 // Auxiliary info for this value. The type of this information depends on the opcode and type. 31 // AuxInt is used for integer values, Aux is used for other values. 32 // Floats are stored in AuxInt using math.Float64bits(f). 33 AuxInt int64 34 Aux interface{} 35 36 // Arguments of this value 37 Args []*Value 38 39 // Containing basic block 40 Block *Block 41 42 // Source position 43 Pos src.XPos 44 45 // Use count. Each appearance in Value.Args and Block.Control counts once. 46 Uses int32 47 48 // Storage for the first three args 49 argstorage [3]*Value 50} 51 52// Examples: 53// Opcode aux args 54// OpAdd nil 2 55// OpConst string 0 string constant 56// OpConst int64 0 int64 constant 57// OpAddcq int64 1 amd64 op: v = arg[0] + constant 58 59// short form print. Just v#. 60func (v *Value) String() string { 61 if v == nil { 62 return "nil" // should never happen, but not panicking helps with debugging 63 } 64 return fmt.Sprintf("v%d", v.ID) 65} 66 67func (v *Value) AuxInt8() int8 { 68 if opcodeTable[v.Op].auxType != auxInt8 { 69 v.Fatalf("op %s doesn't have an int8 aux field", v.Op) 70 } 71 return int8(v.AuxInt) 72} 73 74func (v *Value) AuxInt16() int16 { 75 if opcodeTable[v.Op].auxType != auxInt16 { 76 v.Fatalf("op %s doesn't have an int16 aux field", v.Op) 77 } 78 return int16(v.AuxInt) 79} 80 81func (v *Value) AuxInt32() int32 { 82 if opcodeTable[v.Op].auxType != auxInt32 { 83 v.Fatalf("op %s doesn't have an int32 aux field", v.Op) 84 } 85 return int32(v.AuxInt) 86} 87 88func (v *Value) AuxFloat() float64 { 89 if opcodeTable[v.Op].auxType != auxFloat32 && opcodeTable[v.Op].auxType != auxFloat64 { 90 v.Fatalf("op %s doesn't have a float aux field", v.Op) 91 } 92 return math.Float64frombits(uint64(v.AuxInt)) 93} 94func (v *Value) AuxValAndOff() ValAndOff { 95 if opcodeTable[v.Op].auxType != auxSymValAndOff { 96 v.Fatalf("op %s doesn't have a ValAndOff aux field", v.Op) 97 } 98 return ValAndOff(v.AuxInt) 99} 100 101// long form print. v# = opcode <type> [aux] args [: reg] 102func (v *Value) LongString() string { 103 s := fmt.Sprintf("v%d = %s", v.ID, v.Op) 104 s += " <" + v.Type.String() + ">" 105 s += v.auxString() 106 for _, a := range v.Args { 107 s += fmt.Sprintf(" %v", a) 108 } 109 r := v.Block.Func.RegAlloc 110 if int(v.ID) < len(r) && r[v.ID] != nil { 111 s += " : " + r[v.ID].Name() 112 } 113 return s 114} 115 116func (v *Value) auxString() string { 117 switch opcodeTable[v.Op].auxType { 118 case auxBool: 119 if v.AuxInt == 0 { 120 return " [false]" 121 } else { 122 return " [true]" 123 } 124 case auxInt8: 125 return fmt.Sprintf(" [%d]", v.AuxInt8()) 126 case auxInt16: 127 return fmt.Sprintf(" [%d]", v.AuxInt16()) 128 case auxInt32: 129 return fmt.Sprintf(" [%d]", v.AuxInt32()) 130 case auxInt64, auxInt128: 131 return fmt.Sprintf(" [%d]", v.AuxInt) 132 case auxFloat32, auxFloat64: 133 return fmt.Sprintf(" [%g]", v.AuxFloat()) 134 case auxString: 135 return fmt.Sprintf(" {%q}", v.Aux) 136 case auxSym, auxTyp: 137 if v.Aux != nil { 138 return fmt.Sprintf(" {%v}", v.Aux) 139 } 140 case auxSymOff, auxSymInt32, auxTypSize: 141 s := "" 142 if v.Aux != nil { 143 s = fmt.Sprintf(" {%v}", v.Aux) 144 } 145 if v.AuxInt != 0 { 146 s += fmt.Sprintf(" [%v]", v.AuxInt) 147 } 148 return s 149 case auxSymValAndOff: 150 s := "" 151 if v.Aux != nil { 152 s = fmt.Sprintf(" {%v}", v.Aux) 153 } 154 return s + fmt.Sprintf(" [%s]", v.AuxValAndOff()) 155 } 156 return "" 157} 158 159func (v *Value) AddArg(w *Value) { 160 if v.Args == nil { 161 v.resetArgs() // use argstorage 162 } 163 v.Args = append(v.Args, w) 164 w.Uses++ 165} 166func (v *Value) AddArgs(a ...*Value) { 167 if v.Args == nil { 168 v.resetArgs() // use argstorage 169 } 170 v.Args = append(v.Args, a...) 171 for _, x := range a { 172 x.Uses++ 173 } 174} 175func (v *Value) SetArg(i int, w *Value) { 176 v.Args[i].Uses-- 177 v.Args[i] = w 178 w.Uses++ 179} 180func (v *Value) RemoveArg(i int) { 181 v.Args[i].Uses-- 182 copy(v.Args[i:], v.Args[i+1:]) 183 v.Args[len(v.Args)-1] = nil // aid GC 184 v.Args = v.Args[:len(v.Args)-1] 185} 186func (v *Value) SetArgs1(a *Value) { 187 v.resetArgs() 188 v.AddArg(a) 189} 190func (v *Value) SetArgs2(a *Value, b *Value) { 191 v.resetArgs() 192 v.AddArg(a) 193 v.AddArg(b) 194} 195 196func (v *Value) resetArgs() { 197 for _, a := range v.Args { 198 a.Uses-- 199 } 200 v.argstorage[0] = nil 201 v.argstorage[1] = nil 202 v.argstorage[2] = nil 203 v.Args = v.argstorage[:0] 204} 205 206func (v *Value) reset(op Op) { 207 v.Op = op 208 v.resetArgs() 209 v.AuxInt = 0 210 v.Aux = nil 211} 212 213// copyInto makes a new value identical to v and adds it to the end of b. 214func (v *Value) copyInto(b *Block) *Value { 215 c := b.NewValue0(v.Pos, v.Op, v.Type) // Lose the position, this causes line number churn otherwise. 216 c.Aux = v.Aux 217 c.AuxInt = v.AuxInt 218 c.AddArgs(v.Args...) 219 for _, a := range v.Args { 220 if a.Type.IsMemory() { 221 v.Fatalf("can't move a value with a memory arg %s", v.LongString()) 222 } 223 } 224 return c 225} 226 227// copyIntoNoXPos makes a new value identical to v and adds it to the end of b. 228// The copied value receives no source code position to avoid confusing changes 229// in debugger information (the intended user is the register allocator). 230func (v *Value) copyIntoNoXPos(b *Block) *Value { 231 c := b.NewValue0(src.NoXPos, v.Op, v.Type) // Lose the position, this causes line number churn otherwise. 232 c.Aux = v.Aux 233 c.AuxInt = v.AuxInt 234 c.AddArgs(v.Args...) 235 for _, a := range v.Args { 236 if a.Type.IsMemory() { 237 v.Fatalf("can't move a value with a memory arg %s", v.LongString()) 238 } 239 } 240 return c 241} 242 243func (v *Value) Logf(msg string, args ...interface{}) { v.Block.Logf(msg, args...) } 244func (v *Value) Log() bool { return v.Block.Log() } 245func (v *Value) Fatalf(msg string, args ...interface{}) { 246 v.Block.Func.fe.Fatalf(v.Pos, msg, args...) 247} 248 249// isGenericIntConst returns whether v is a generic integer constant. 250func (v *Value) isGenericIntConst() bool { 251 return v != nil && (v.Op == OpConst64 || v.Op == OpConst32 || v.Op == OpConst16 || v.Op == OpConst8) 252} 253 254// ExternSymbol is an aux value that encodes a variable's 255// constant offset from the static base pointer. 256type ExternSymbol struct { 257 Sym *obj.LSym 258 // Note: the offset for an external symbol is not 259 // calculated until link time. 260} 261 262// ArgSymbol is an aux value that encodes an argument or result 263// variable's constant offset from FP (FP = SP + framesize). 264type ArgSymbol struct { 265 Node GCNode // A *gc.Node referring to the argument/result variable. 266} 267 268// AutoSymbol is an aux value that encodes a local variable's 269// constant offset from SP. 270type AutoSymbol struct { 271 Node GCNode // A *gc.Node referring to a local (auto) variable. 272} 273 274func (s *ExternSymbol) String() string { 275 return s.Sym.String() 276} 277 278func (s *ArgSymbol) String() string { 279 return s.Node.String() 280} 281 282func (s *AutoSymbol) String() string { 283 return s.Node.String() 284} 285 286// Reg returns the register assigned to v, in cmd/internal/obj/$ARCH numbering. 287func (v *Value) Reg() int16 { 288 reg := v.Block.Func.RegAlloc[v.ID] 289 if reg == nil { 290 v.Fatalf("nil register for value: %s\n%s\n", v.LongString(), v.Block.Func) 291 } 292 return reg.(*Register).objNum 293} 294 295// Reg0 returns the register assigned to the first output of v, in cmd/internal/obj/$ARCH numbering. 296func (v *Value) Reg0() int16 { 297 reg := v.Block.Func.RegAlloc[v.ID].(LocPair)[0] 298 if reg == nil { 299 v.Fatalf("nil first register for value: %s\n%s\n", v.LongString(), v.Block.Func) 300 } 301 return reg.(*Register).objNum 302} 303 304// Reg1 returns the register assigned to the second output of v, in cmd/internal/obj/$ARCH numbering. 305func (v *Value) Reg1() int16 { 306 reg := v.Block.Func.RegAlloc[v.ID].(LocPair)[1] 307 if reg == nil { 308 v.Fatalf("nil second register for value: %s\n%s\n", v.LongString(), v.Block.Func) 309 } 310 return reg.(*Register).objNum 311} 312 313func (v *Value) RegName() string { 314 reg := v.Block.Func.RegAlloc[v.ID] 315 if reg == nil { 316 v.Fatalf("nil register for value: %s\n%s\n", v.LongString(), v.Block.Func) 317 } 318 return reg.(*Register).name 319} 320 321// MemoryArg returns the memory argument for the Value. 322// The returned value, if non-nil, will be memory-typed (or a tuple with a memory-typed second part). 323// Otherwise, nil is returned. 324func (v *Value) MemoryArg() *Value { 325 if v.Op == OpPhi { 326 v.Fatalf("MemoryArg on Phi") 327 } 328 na := len(v.Args) 329 if na == 0 { 330 return nil 331 } 332 if m := v.Args[na-1]; m.Type.IsMemory() { 333 return m 334 } 335 return nil 336} 337