Keith Randall | f52b234 | 2015-03-03 13:38:14 -0800 | [diff] [blame] | 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 | |
Todd Neal | 19447a6 | 2015-09-04 06:33:56 -0500 | [diff] [blame] | 7 | import ( |
| 8 | "fmt" |
| 9 | "math" |
| 10 | ) |
Keith Randall | f52b234 | 2015-03-03 13:38:14 -0800 | [diff] [blame] | 11 | |
| 12 | // A Value represents a value in the SSA representation of the program. |
Brad Fitzpatrick | 5fea2cc | 2016-03-01 23:21:55 +0000 | [diff] [blame] | 13 | // The ID and Type fields must not be modified. The remainder may be modified |
Keith Randall | f52b234 | 2015-03-03 13:38:14 -0800 | [diff] [blame] | 14 | // if they preserve the value of the Value (e.g. changing a (mul 2 x) to an (add x x)). |
| 15 | type Value struct { |
Brad Fitzpatrick | 5fea2cc | 2016-03-01 23:21:55 +0000 | [diff] [blame] | 16 | // A unique identifier for the value. For performance we allocate these IDs |
Keith Randall | 0b46b42 | 2015-08-11 12:51:33 -0700 | [diff] [blame] | 17 | // densely starting at 1. There is no guarantee that there won't be occasional holes, though. |
Keith Randall | f52b234 | 2015-03-03 13:38:14 -0800 | [diff] [blame] | 18 | ID ID |
| 19 | |
Brad Fitzpatrick | 5fea2cc | 2016-03-01 23:21:55 +0000 | [diff] [blame] | 20 | // The operation that computes this value. See op.go. |
Keith Randall | f52b234 | 2015-03-03 13:38:14 -0800 | [diff] [blame] | 21 | Op Op |
| 22 | |
Brad Fitzpatrick | 5fea2cc | 2016-03-01 23:21:55 +0000 | [diff] [blame] | 23 | // The type of this value. Normally this will be a Go type, but there |
Keith Randall | f52b234 | 2015-03-03 13:38:14 -0800 | [diff] [blame] | 24 | // are a few other pseudo-types, see type.go. |
| 25 | Type Type |
| 26 | |
Brad Fitzpatrick | 5fea2cc | 2016-03-01 23:21:55 +0000 | [diff] [blame] | 27 | // Auxiliary info for this value. The type of this information depends on the opcode and type. |
Keith Randall | 8f22b52 | 2015-06-11 21:29:25 -0700 | [diff] [blame] | 28 | // AuxInt is used for integer values, Aux is used for other values. |
Kevin Burke | 8e24a98 | 2016-08-20 22:05:47 -0700 | [diff] [blame] | 29 | // Floats are stored in AuxInt using math.Float64bits(f). |
Keith Randall | 8f22b52 | 2015-06-11 21:29:25 -0700 | [diff] [blame] | 30 | AuxInt int64 |
| 31 | Aux interface{} |
Keith Randall | f52b234 | 2015-03-03 13:38:14 -0800 | [diff] [blame] | 32 | |
| 33 | // Arguments of this value |
| 34 | Args []*Value |
| 35 | |
| 36 | // Containing basic block |
| 37 | Block *Block |
| 38 | |
Michael Matloob | 81ccf50 | 2015-05-30 01:03:06 -0400 | [diff] [blame] | 39 | // Source line number |
| 40 | Line int32 |
| 41 | |
Keith Randall | 56e0ecc | 2016-03-15 20:45:50 -0700 | [diff] [blame] | 42 | // Use count. Each appearance in Value.Args and Block.Control counts once. |
| 43 | Uses int32 |
| 44 | |
Josh Bleecher Snyder | f3a29f1 | 2016-03-06 21:22:11 -0800 | [diff] [blame] | 45 | // Storage for the first three args |
| 46 | argstorage [3]*Value |
Keith Randall | f52b234 | 2015-03-03 13:38:14 -0800 | [diff] [blame] | 47 | } |
| 48 | |
| 49 | // Examples: |
| 50 | // Opcode aux args |
| 51 | // OpAdd nil 2 |
Keith Randall | 2c9b491 | 2015-03-26 10:49:03 -0700 | [diff] [blame] | 52 | // OpConst string 0 string constant |
| 53 | // OpConst int64 0 int64 constant |
Keith Randall | f52b234 | 2015-03-03 13:38:14 -0800 | [diff] [blame] | 54 | // OpAddcq int64 1 amd64 op: v = arg[0] + constant |
| 55 | |
Brad Fitzpatrick | 5fea2cc | 2016-03-01 23:21:55 +0000 | [diff] [blame] | 56 | // short form print. Just v#. |
Keith Randall | f52b234 | 2015-03-03 13:38:14 -0800 | [diff] [blame] | 57 | func (v *Value) String() string { |
Josh Bleecher Snyder | 220e705 | 2015-08-22 13:30:45 -0700 | [diff] [blame] | 58 | if v == nil { |
| 59 | return "nil" // should never happen, but not panicking helps with debugging |
| 60 | } |
Keith Randall | f52b234 | 2015-03-03 13:38:14 -0800 | [diff] [blame] | 61 | return fmt.Sprintf("v%d", v.ID) |
| 62 | } |
| 63 | |
Keith Randall | 16b1fce | 2016-01-31 11:39:39 -0800 | [diff] [blame] | 64 | func (v *Value) AuxInt8() int8 { |
| 65 | if opcodeTable[v.Op].auxType != auxInt8 { |
| 66 | v.Fatalf("op %s doesn't have an int8 aux field", v.Op) |
| 67 | } |
| 68 | return int8(v.AuxInt) |
| 69 | } |
| 70 | |
| 71 | func (v *Value) AuxInt16() int16 { |
| 72 | if opcodeTable[v.Op].auxType != auxInt16 { |
| 73 | v.Fatalf("op %s doesn't have an int16 aux field", v.Op) |
| 74 | } |
| 75 | return int16(v.AuxInt) |
| 76 | } |
| 77 | |
| 78 | func (v *Value) AuxInt32() int32 { |
| 79 | if opcodeTable[v.Op].auxType != auxInt32 { |
| 80 | v.Fatalf("op %s doesn't have an int32 aux field", v.Op) |
| 81 | } |
| 82 | return int32(v.AuxInt) |
| 83 | } |
Todd Neal | c17b6b4 | 2016-02-19 16:58:21 -0600 | [diff] [blame] | 84 | |
Keith Randall | 16b1fce | 2016-01-31 11:39:39 -0800 | [diff] [blame] | 85 | func (v *Value) AuxFloat() float64 { |
Todd Neal | f6ceed2 | 2016-03-11 19:36:54 -0600 | [diff] [blame] | 86 | if opcodeTable[v.Op].auxType != auxFloat32 && opcodeTable[v.Op].auxType != auxFloat64 { |
Keith Randall | 16b1fce | 2016-01-31 11:39:39 -0800 | [diff] [blame] | 87 | v.Fatalf("op %s doesn't have a float aux field", v.Op) |
| 88 | } |
| 89 | return math.Float64frombits(uint64(v.AuxInt)) |
| 90 | } |
| 91 | func (v *Value) AuxValAndOff() ValAndOff { |
| 92 | if opcodeTable[v.Op].auxType != auxSymValAndOff { |
| 93 | v.Fatalf("op %s doesn't have a ValAndOff aux field", v.Op) |
| 94 | } |
| 95 | return ValAndOff(v.AuxInt) |
| 96 | } |
| 97 | |
Keith Randall | f52b234 | 2015-03-03 13:38:14 -0800 | [diff] [blame] | 98 | // long form print. v# = opcode <type> [aux] args [: reg] |
| 99 | func (v *Value) LongString() string { |
Keith Randall | 0dca735 | 2015-06-06 16:03:33 -0700 | [diff] [blame] | 100 | s := fmt.Sprintf("v%d = %s", v.ID, v.Op.String()) |
Keith Randall | f52b234 | 2015-03-03 13:38:14 -0800 | [diff] [blame] | 101 | s += " <" + v.Type.String() + ">" |
Frits van Bommel | b13b249 | 2016-04-30 11:13:29 +0200 | [diff] [blame] | 102 | s += v.auxString() |
Keith Randall | f52b234 | 2015-03-03 13:38:14 -0800 | [diff] [blame] | 103 | for _, a := range v.Args { |
| 104 | s += fmt.Sprintf(" %v", a) |
| 105 | } |
| 106 | r := v.Block.Func.RegAlloc |
Keith Randall | 0b46b42 | 2015-08-11 12:51:33 -0700 | [diff] [blame] | 107 | if int(v.ID) < len(r) && r[v.ID] != nil { |
Keith Randall | f52b234 | 2015-03-03 13:38:14 -0800 | [diff] [blame] | 108 | s += " : " + r[v.ID].Name() |
| 109 | } |
| 110 | return s |
| 111 | } |
| 112 | |
Frits van Bommel | b13b249 | 2016-04-30 11:13:29 +0200 | [diff] [blame] | 113 | func (v *Value) auxString() string { |
| 114 | switch opcodeTable[v.Op].auxType { |
| 115 | case auxBool: |
| 116 | if v.AuxInt == 0 { |
| 117 | return " [false]" |
| 118 | } else { |
| 119 | return " [true]" |
| 120 | } |
| 121 | case auxInt8: |
| 122 | return fmt.Sprintf(" [%d]", v.AuxInt8()) |
| 123 | case auxInt16: |
| 124 | return fmt.Sprintf(" [%d]", v.AuxInt16()) |
| 125 | case auxInt32: |
| 126 | return fmt.Sprintf(" [%d]", v.AuxInt32()) |
| 127 | case auxInt64, auxInt128: |
| 128 | return fmt.Sprintf(" [%d]", v.AuxInt) |
Keith Randall | 33bb597 | 2016-08-31 12:30:46 -0700 | [diff] [blame] | 129 | case auxSizeAndAlign: |
| 130 | return fmt.Sprintf(" [%s]", SizeAndAlign(v.AuxInt)) |
Frits van Bommel | b13b249 | 2016-04-30 11:13:29 +0200 | [diff] [blame] | 131 | case auxFloat32, auxFloat64: |
| 132 | return fmt.Sprintf(" [%g]", v.AuxFloat()) |
| 133 | case auxString: |
| 134 | return fmt.Sprintf(" {%q}", v.Aux) |
| 135 | case auxSym: |
| 136 | if v.Aux != nil { |
| 137 | return fmt.Sprintf(" {%s}", v.Aux) |
| 138 | } |
| 139 | case auxSymOff, auxSymInt32: |
| 140 | s := "" |
| 141 | if v.Aux != nil { |
| 142 | s = fmt.Sprintf(" {%s}", v.Aux) |
| 143 | } |
| 144 | if v.AuxInt != 0 { |
| 145 | s += fmt.Sprintf(" [%v]", v.AuxInt) |
| 146 | } |
| 147 | return s |
| 148 | case auxSymValAndOff: |
| 149 | s := "" |
| 150 | if v.Aux != nil { |
| 151 | s = fmt.Sprintf(" {%s}", v.Aux) |
| 152 | } |
| 153 | return s + fmt.Sprintf(" [%s]", v.AuxValAndOff()) |
| 154 | } |
| 155 | return "" |
| 156 | } |
| 157 | |
Keith Randall | f52b234 | 2015-03-03 13:38:14 -0800 | [diff] [blame] | 158 | func (v *Value) AddArg(w *Value) { |
Josh Bleecher Snyder | 7c2c0b4 | 2015-03-16 16:31:13 -0700 | [diff] [blame] | 159 | if v.Args == nil { |
| 160 | v.resetArgs() // use argstorage |
| 161 | } |
Keith Randall | f52b234 | 2015-03-03 13:38:14 -0800 | [diff] [blame] | 162 | v.Args = append(v.Args, w) |
Keith Randall | 56e0ecc | 2016-03-15 20:45:50 -0700 | [diff] [blame] | 163 | w.Uses++ |
Keith Randall | f52b234 | 2015-03-03 13:38:14 -0800 | [diff] [blame] | 164 | } |
| 165 | func (v *Value) AddArgs(a ...*Value) { |
Josh Bleecher Snyder | 7c2c0b4 | 2015-03-16 16:31:13 -0700 | [diff] [blame] | 166 | if v.Args == nil { |
| 167 | v.resetArgs() // use argstorage |
| 168 | } |
Keith Randall | f52b234 | 2015-03-03 13:38:14 -0800 | [diff] [blame] | 169 | v.Args = append(v.Args, a...) |
Keith Randall | 56e0ecc | 2016-03-15 20:45:50 -0700 | [diff] [blame] | 170 | for _, x := range a { |
| 171 | x.Uses++ |
| 172 | } |
Keith Randall | f52b234 | 2015-03-03 13:38:14 -0800 | [diff] [blame] | 173 | } |
| 174 | func (v *Value) SetArg(i int, w *Value) { |
Keith Randall | 56e0ecc | 2016-03-15 20:45:50 -0700 | [diff] [blame] | 175 | v.Args[i].Uses-- |
Keith Randall | f52b234 | 2015-03-03 13:38:14 -0800 | [diff] [blame] | 176 | v.Args[i] = w |
Keith Randall | 56e0ecc | 2016-03-15 20:45:50 -0700 | [diff] [blame] | 177 | w.Uses++ |
Keith Randall | f52b234 | 2015-03-03 13:38:14 -0800 | [diff] [blame] | 178 | } |
| 179 | func (v *Value) RemoveArg(i int) { |
Keith Randall | 56e0ecc | 2016-03-15 20:45:50 -0700 | [diff] [blame] | 180 | v.Args[i].Uses-- |
Keith Randall | f52b234 | 2015-03-03 13:38:14 -0800 | [diff] [blame] | 181 | copy(v.Args[i:], v.Args[i+1:]) |
Josh Bleecher Snyder | 7c2c0b4 | 2015-03-16 16:31:13 -0700 | [diff] [blame] | 182 | v.Args[len(v.Args)-1] = nil // aid GC |
Keith Randall | f52b234 | 2015-03-03 13:38:14 -0800 | [diff] [blame] | 183 | v.Args = v.Args[:len(v.Args)-1] |
| 184 | } |
| 185 | func (v *Value) SetArgs1(a *Value) { |
| 186 | v.resetArgs() |
| 187 | v.AddArg(a) |
| 188 | } |
| 189 | func (v *Value) SetArgs2(a *Value, b *Value) { |
| 190 | v.resetArgs() |
| 191 | v.AddArg(a) |
| 192 | v.AddArg(b) |
| 193 | } |
| 194 | |
| 195 | func (v *Value) resetArgs() { |
Keith Randall | 56e0ecc | 2016-03-15 20:45:50 -0700 | [diff] [blame] | 196 | for _, a := range v.Args { |
| 197 | a.Uses-- |
| 198 | } |
Keith Randall | f52b234 | 2015-03-03 13:38:14 -0800 | [diff] [blame] | 199 | v.argstorage[0] = nil |
| 200 | v.argstorage[1] = nil |
Keith Randall | 7e40627 | 2016-04-11 13:17:52 -0700 | [diff] [blame] | 201 | v.argstorage[2] = nil |
Keith Randall | f52b234 | 2015-03-03 13:38:14 -0800 | [diff] [blame] | 202 | v.Args = v.argstorage[:0] |
| 203 | } |
Josh Bleecher Snyder | 8c6abfe | 2015-06-12 11:01:13 -0700 | [diff] [blame] | 204 | |
Alexandru Moșoi | 2df4b9c | 2016-02-04 17:21:57 +0100 | [diff] [blame] | 205 | func (v *Value) reset(op Op) { |
| 206 | v.Op = op |
| 207 | v.resetArgs() |
| 208 | v.AuxInt = 0 |
| 209 | v.Aux = nil |
| 210 | } |
| 211 | |
Keith Randall | c140df0 | 2015-12-09 15:58:18 -0800 | [diff] [blame] | 212 | // copyInto makes a new value identical to v and adds it to the end of b. |
| 213 | func (v *Value) copyInto(b *Block) *Value { |
| 214 | c := b.NewValue0(v.Line, v.Op, v.Type) |
| 215 | c.Aux = v.Aux |
| 216 | c.AuxInt = v.AuxInt |
| 217 | c.AddArgs(v.Args...) |
Keith Randall | f94e074 | 2016-01-26 15:47:08 -0800 | [diff] [blame] | 218 | for _, a := range v.Args { |
| 219 | if a.Type.IsMemory() { |
| 220 | v.Fatalf("can't move a value with a memory arg %s", v.LongString()) |
| 221 | } |
| 222 | } |
Keith Randall | c140df0 | 2015-12-09 15:58:18 -0800 | [diff] [blame] | 223 | return c |
| 224 | } |
| 225 | |
Keith Randall | da8af47 | 2016-01-13 11:14:57 -0800 | [diff] [blame] | 226 | func (v *Value) Logf(msg string, args ...interface{}) { v.Block.Logf(msg, args...) } |
David Chase | 88b230e | 2016-01-29 14:44:15 -0500 | [diff] [blame] | 227 | func (v *Value) Log() bool { return v.Block.Log() } |
Keith Randall | da8af47 | 2016-01-13 11:14:57 -0800 | [diff] [blame] | 228 | func (v *Value) Fatalf(msg string, args ...interface{}) { |
| 229 | v.Block.Func.Config.Fatalf(v.Line, msg, args...) |
| 230 | } |
Keith Randall | 8c46aa5 | 2015-06-19 21:02:28 -0700 | [diff] [blame] | 231 | |
Keith Randall | 47c9e13 | 2016-03-23 10:20:44 -0700 | [diff] [blame] | 232 | // isGenericIntConst returns whether v is a generic integer constant. |
| 233 | func (v *Value) isGenericIntConst() bool { |
| 234 | return v != nil && (v.Op == OpConst64 || v.Op == OpConst32 || v.Op == OpConst16 || v.Op == OpConst8) |
| 235 | } |
| 236 | |
Keith Randall | 8c46aa5 | 2015-06-19 21:02:28 -0700 | [diff] [blame] | 237 | // ExternSymbol is an aux value that encodes a variable's |
| 238 | // constant offset from the static base pointer. |
| 239 | type ExternSymbol struct { |
| 240 | Typ Type // Go type |
| 241 | Sym fmt.Stringer // A *gc.Sym referring to a global variable |
| 242 | // Note: the offset for an external symbol is not |
| 243 | // calculated until link time. |
| 244 | } |
| 245 | |
| 246 | // ArgSymbol is an aux value that encodes an argument or result |
| 247 | // variable's constant offset from FP (FP = SP + framesize). |
| 248 | type ArgSymbol struct { |
Keith Randall | c24681a | 2015-10-22 14:22:38 -0700 | [diff] [blame] | 249 | Typ Type // Go type |
| 250 | Node GCNode // A *gc.Node referring to the argument/result variable. |
Keith Randall | 8c46aa5 | 2015-06-19 21:02:28 -0700 | [diff] [blame] | 251 | } |
| 252 | |
| 253 | // AutoSymbol is an aux value that encodes a local variable's |
| 254 | // constant offset from SP. |
| 255 | type AutoSymbol struct { |
Keith Randall | c24681a | 2015-10-22 14:22:38 -0700 | [diff] [blame] | 256 | Typ Type // Go type |
| 257 | Node GCNode // A *gc.Node referring to a local (auto) variable. |
Keith Randall | 8c46aa5 | 2015-06-19 21:02:28 -0700 | [diff] [blame] | 258 | } |
| 259 | |
| 260 | func (s *ExternSymbol) String() string { |
| 261 | return s.Sym.String() |
| 262 | } |
| 263 | |
| 264 | func (s *ArgSymbol) String() string { |
Keith Randall | d2107fc | 2015-08-24 02:16:19 -0700 | [diff] [blame] | 265 | return s.Node.String() |
Keith Randall | 8c46aa5 | 2015-06-19 21:02:28 -0700 | [diff] [blame] | 266 | } |
| 267 | |
| 268 | func (s *AutoSymbol) String() string { |
Keith Randall | d2107fc | 2015-08-24 02:16:19 -0700 | [diff] [blame] | 269 | return s.Node.String() |
Keith Randall | 8c46aa5 | 2015-06-19 21:02:28 -0700 | [diff] [blame] | 270 | } |
Keith Randall | 833ed7c | 2016-09-16 09:36:00 -0700 | [diff] [blame] | 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 | } |