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