github.com/goproxy0/go@v0.0.0-20171111080102-49cc0c489d2c/src/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 "cmd/compile/internal/types" 9 "cmd/internal/src" 10 "fmt" 11 "math" 12 "strings" 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)). 18 type 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#. 60 func (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 67 func (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 74 func (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 81 func (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 88 func (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 } 94 func (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] (names) 102 func (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].String() 112 } 113 var names []string 114 for name, values := range v.Block.Func.NamedValues { 115 for _, value := range values { 116 if value == v { 117 names = append(names, name.String()) 118 break // drop duplicates. 119 } 120 } 121 } 122 if len(names) != 0 { 123 s += " (" + strings.Join(names, ", ") + ")" 124 } 125 return s 126 } 127 128 func (v *Value) auxString() string { 129 switch opcodeTable[v.Op].auxType { 130 case auxBool: 131 if v.AuxInt == 0 { 132 return " [false]" 133 } else { 134 return " [true]" 135 } 136 case auxInt8: 137 return fmt.Sprintf(" [%d]", v.AuxInt8()) 138 case auxInt16: 139 return fmt.Sprintf(" [%d]", v.AuxInt16()) 140 case auxInt32: 141 return fmt.Sprintf(" [%d]", v.AuxInt32()) 142 case auxInt64, auxInt128: 143 return fmt.Sprintf(" [%d]", v.AuxInt) 144 case auxFloat32, auxFloat64: 145 return fmt.Sprintf(" [%g]", v.AuxFloat()) 146 case auxString: 147 return fmt.Sprintf(" {%q}", v.Aux) 148 case auxSym, auxTyp: 149 if v.Aux != nil { 150 return fmt.Sprintf(" {%v}", v.Aux) 151 } 152 case auxSymOff, auxSymInt32, auxTypSize: 153 s := "" 154 if v.Aux != nil { 155 s = fmt.Sprintf(" {%v}", v.Aux) 156 } 157 if v.AuxInt != 0 { 158 s += fmt.Sprintf(" [%v]", v.AuxInt) 159 } 160 return s 161 case auxSymValAndOff: 162 s := "" 163 if v.Aux != nil { 164 s = fmt.Sprintf(" {%v}", v.Aux) 165 } 166 return s + fmt.Sprintf(" [%s]", v.AuxValAndOff()) 167 } 168 return "" 169 } 170 171 func (v *Value) AddArg(w *Value) { 172 if v.Args == nil { 173 v.resetArgs() // use argstorage 174 } 175 v.Args = append(v.Args, w) 176 w.Uses++ 177 } 178 func (v *Value) AddArgs(a ...*Value) { 179 if v.Args == nil { 180 v.resetArgs() // use argstorage 181 } 182 v.Args = append(v.Args, a...) 183 for _, x := range a { 184 x.Uses++ 185 } 186 } 187 func (v *Value) SetArg(i int, w *Value) { 188 v.Args[i].Uses-- 189 v.Args[i] = w 190 w.Uses++ 191 } 192 func (v *Value) RemoveArg(i int) { 193 v.Args[i].Uses-- 194 copy(v.Args[i:], v.Args[i+1:]) 195 v.Args[len(v.Args)-1] = nil // aid GC 196 v.Args = v.Args[:len(v.Args)-1] 197 } 198 func (v *Value) SetArgs1(a *Value) { 199 v.resetArgs() 200 v.AddArg(a) 201 } 202 func (v *Value) SetArgs2(a *Value, b *Value) { 203 v.resetArgs() 204 v.AddArg(a) 205 v.AddArg(b) 206 } 207 208 func (v *Value) resetArgs() { 209 for _, a := range v.Args { 210 a.Uses-- 211 } 212 v.argstorage[0] = nil 213 v.argstorage[1] = nil 214 v.argstorage[2] = nil 215 v.Args = v.argstorage[:0] 216 } 217 218 func (v *Value) reset(op Op) { 219 v.Op = op 220 v.resetArgs() 221 v.AuxInt = 0 222 v.Aux = nil 223 } 224 225 // copyInto makes a new value identical to v and adds it to the end of b. 226 func (v *Value) copyInto(b *Block) *Value { 227 c := b.NewValue0(v.Pos, v.Op, v.Type) // Lose the position, this causes line number churn otherwise. 228 c.Aux = v.Aux 229 c.AuxInt = v.AuxInt 230 c.AddArgs(v.Args...) 231 for _, a := range v.Args { 232 if a.Type.IsMemory() { 233 v.Fatalf("can't move a value with a memory arg %s", v.LongString()) 234 } 235 } 236 return c 237 } 238 239 // copyIntoNoXPos makes a new value identical to v and adds it to the end of b. 240 // The copied value receives no source code position to avoid confusing changes 241 // in debugger information (the intended user is the register allocator). 242 func (v *Value) copyIntoNoXPos(b *Block) *Value { 243 return v.copyIntoWithXPos(b, src.NoXPos) 244 } 245 246 // copyIntoWithXPos makes a new value identical to v and adds it to the end of b. 247 // The supplied position is used as the position of the new value. 248 func (v *Value) copyIntoWithXPos(b *Block, pos src.XPos) *Value { 249 c := b.NewValue0(pos, v.Op, v.Type) 250 c.Aux = v.Aux 251 c.AuxInt = v.AuxInt 252 c.AddArgs(v.Args...) 253 for _, a := range v.Args { 254 if a.Type.IsMemory() { 255 v.Fatalf("can't move a value with a memory arg %s", v.LongString()) 256 } 257 } 258 return c 259 } 260 261 func (v *Value) Logf(msg string, args ...interface{}) { v.Block.Logf(msg, args...) } 262 func (v *Value) Log() bool { return v.Block.Log() } 263 func (v *Value) Fatalf(msg string, args ...interface{}) { 264 v.Block.Func.fe.Fatalf(v.Pos, msg, args...) 265 } 266 267 // isGenericIntConst returns whether v is a generic integer constant. 268 func (v *Value) isGenericIntConst() bool { 269 return v != nil && (v.Op == OpConst64 || v.Op == OpConst32 || v.Op == OpConst16 || v.Op == OpConst8) 270 } 271 272 // Reg returns the register assigned to v, in cmd/internal/obj/$ARCH numbering. 273 func (v *Value) Reg() int16 { 274 reg := v.Block.Func.RegAlloc[v.ID] 275 if reg == nil { 276 v.Fatalf("nil register for value: %s\n%s\n", v.LongString(), v.Block.Func) 277 } 278 return reg.(*Register).objNum 279 } 280 281 // Reg0 returns the register assigned to the first output of v, in cmd/internal/obj/$ARCH numbering. 282 func (v *Value) Reg0() int16 { 283 reg := v.Block.Func.RegAlloc[v.ID].(LocPair)[0] 284 if reg == nil { 285 v.Fatalf("nil first register for value: %s\n%s\n", v.LongString(), v.Block.Func) 286 } 287 return reg.(*Register).objNum 288 } 289 290 // Reg1 returns the register assigned to the second output of v, in cmd/internal/obj/$ARCH numbering. 291 func (v *Value) Reg1() int16 { 292 reg := v.Block.Func.RegAlloc[v.ID].(LocPair)[1] 293 if reg == nil { 294 v.Fatalf("nil second register for value: %s\n%s\n", v.LongString(), v.Block.Func) 295 } 296 return reg.(*Register).objNum 297 } 298 299 func (v *Value) RegName() string { 300 reg := v.Block.Func.RegAlloc[v.ID] 301 if reg == nil { 302 v.Fatalf("nil register for value: %s\n%s\n", v.LongString(), v.Block.Func) 303 } 304 return reg.(*Register).name 305 } 306 307 // MemoryArg returns the memory argument for the Value. 308 // The returned value, if non-nil, will be memory-typed (or a tuple with a memory-typed second part). 309 // Otherwise, nil is returned. 310 func (v *Value) MemoryArg() *Value { 311 if v.Op == OpPhi { 312 v.Fatalf("MemoryArg on Phi") 313 } 314 na := len(v.Args) 315 if na == 0 { 316 return nil 317 } 318 if m := v.Args[na-1]; m.Type.IsMemory() { 319 return m 320 } 321 return nil 322 } 323 324 // LackingPos indicates whether v is a value that is unlikely to have a correct 325 // position assigned to it. Ignoring such values leads to more user-friendly positions 326 // assigned to nearby values and the blocks containing them. 327 func (v *Value) LackingPos() bool { 328 // The exact definition of LackingPos is somewhat heuristically defined and may change 329 // in the future, for example if some of these operations are generated more carefully 330 // with respect to their source position. 331 return v.Op == OpVarDef || v.Op == OpVarKill || v.Op == OpVarLive || v.Op == OpPhi || 332 (v.Op == OpFwdRef || v.Op == OpCopy) && v.Type == types.TypeMem 333 }