1// Copyright 2020 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 ir
6
7import (
8	"cmd/compile/internal/base"
9	"cmd/compile/internal/types"
10	"cmd/internal/obj"
11	"cmd/internal/objabi"
12	"cmd/internal/src"
13	"fmt"
14
15	"go/constant"
16)
17
18// An Ident is an identifier, possibly qualified.
19type Ident struct {
20	miniExpr
21	sym *types.Sym
22}
23
24func NewIdent(pos src.XPos, sym *types.Sym) *Ident {
25	n := new(Ident)
26	n.op = ONONAME
27	n.pos = pos
28	n.sym = sym
29	return n
30}
31
32func (n *Ident) Sym() *types.Sym { return n.sym }
33
34// Name holds Node fields used only by named nodes (ONAME, OTYPE, some OLITERAL).
35type Name struct {
36	miniExpr
37	BuiltinOp Op         // uint8
38	Class     Class      // uint8
39	pragma    PragmaFlag // int16
40	flags     bitset16
41	DictIndex uint16 // index of the dictionary entry describing the type of this variable declaration plus 1
42	sym       *types.Sym
43	Func      *Func // TODO(austin): nil for I.M
44	Offset_   int64
45	val       constant.Value
46	Opt       interface{} // for use by escape analysis
47	Embed     *[]Embed    // list of embedded files, for ONAME var
48
49	// For a local variable (not param) or extern, the initializing assignment (OAS or OAS2).
50	// For a closure var, the ONAME node of the original (outermost) captured variable.
51	// For the case-local variables of a type switch, the type switch guard (OTYPESW).
52	// For a range variable, the range statement (ORANGE)
53	// For a recv variable in a case of a select statement, the receive assignment (OSELRECV2)
54	// For the name of a function, points to corresponding Func node.
55	Defn Node
56
57	// The function, method, or closure in which local variable or param is declared.
58	Curfn *Func
59
60	Heapaddr *Name // temp holding heap address of param
61
62	// Outer points to the immediately enclosing function's copy of this
63	// closure variable. If not a closure variable, then Outer is nil.
64	Outer *Name
65}
66
67func (n *Name) isExpr() {}
68
69func (n *Name) copy() Node                                  { panic(n.no("copy")) }
70func (n *Name) doChildren(do func(Node) bool) bool          { return false }
71func (n *Name) editChildren(edit func(Node) Node)           {}
72func (n *Name) editChildrenWithHidden(edit func(Node) Node) {}
73
74// RecordFrameOffset records the frame offset for the name.
75// It is used by package types when laying out function arguments.
76func (n *Name) RecordFrameOffset(offset int64) {
77	n.SetFrameOffset(offset)
78}
79
80// NewNameAt returns a new ONAME Node associated with symbol s at position pos.
81// The caller is responsible for setting Curfn.
82func NewNameAt(pos src.XPos, sym *types.Sym, typ *types.Type) *Name {
83	if sym == nil {
84		base.Fatalf("NewNameAt nil")
85	}
86	n := newNameAt(pos, ONAME, sym)
87	if typ != nil {
88		n.SetType(typ)
89		n.SetTypecheck(1)
90	}
91	return n
92}
93
94// NewBuiltin returns a new Name representing a builtin function,
95// either predeclared or from package unsafe.
96func NewBuiltin(sym *types.Sym, op Op) *Name {
97	n := newNameAt(src.NoXPos, ONAME, sym)
98	n.BuiltinOp = op
99	n.SetTypecheck(1)
100	sym.Def = n
101	return n
102}
103
104// NewLocal returns a new function-local variable with the given name and type.
105func (fn *Func) NewLocal(pos src.XPos, sym *types.Sym, typ *types.Type) *Name {
106	if fn.Dcl == nil {
107		base.FatalfAt(pos, "must call DeclParams on %v first", fn)
108	}
109
110	n := NewNameAt(pos, sym, typ)
111	n.Class = PAUTO
112	n.Curfn = fn
113	fn.Dcl = append(fn.Dcl, n)
114	return n
115}
116
117// NewDeclNameAt returns a new Name associated with symbol s at position pos.
118// The caller is responsible for setting Curfn.
119func NewDeclNameAt(pos src.XPos, op Op, sym *types.Sym) *Name {
120	if sym == nil {
121		base.Fatalf("NewDeclNameAt nil")
122	}
123	switch op {
124	case ONAME, OTYPE, OLITERAL:
125		// ok
126	default:
127		base.Fatalf("NewDeclNameAt op %v", op)
128	}
129	return newNameAt(pos, op, sym)
130}
131
132// NewConstAt returns a new OLITERAL Node associated with symbol s at position pos.
133func NewConstAt(pos src.XPos, sym *types.Sym, typ *types.Type, val constant.Value) *Name {
134	if sym == nil {
135		base.Fatalf("NewConstAt nil")
136	}
137	n := newNameAt(pos, OLITERAL, sym)
138	n.SetType(typ)
139	n.SetTypecheck(1)
140	n.SetVal(val)
141	return n
142}
143
144// newNameAt is like NewNameAt but allows sym == nil.
145func newNameAt(pos src.XPos, op Op, sym *types.Sym) *Name {
146	n := new(Name)
147	n.op = op
148	n.pos = pos
149	n.sym = sym
150	return n
151}
152
153func (n *Name) Name() *Name            { return n }
154func (n *Name) Sym() *types.Sym        { return n.sym }
155func (n *Name) SetSym(x *types.Sym)    { n.sym = x }
156func (n *Name) SubOp() Op              { return n.BuiltinOp }
157func (n *Name) SetSubOp(x Op)          { n.BuiltinOp = x }
158func (n *Name) SetFunc(x *Func)        { n.Func = x }
159func (n *Name) FrameOffset() int64     { return n.Offset_ }
160func (n *Name) SetFrameOffset(x int64) { n.Offset_ = x }
161
162func (n *Name) Linksym() *obj.LSym               { return n.sym.Linksym() }
163func (n *Name) LinksymABI(abi obj.ABI) *obj.LSym { return n.sym.LinksymABI(abi) }
164
165func (*Name) CanBeNtype()    {}
166func (*Name) CanBeAnSSASym() {}
167func (*Name) CanBeAnSSAAux() {}
168
169// Pragma returns the PragmaFlag for p, which must be for an OTYPE.
170func (n *Name) Pragma() PragmaFlag { return n.pragma }
171
172// SetPragma sets the PragmaFlag for p, which must be for an OTYPE.
173func (n *Name) SetPragma(flag PragmaFlag) { n.pragma = flag }
174
175// Alias reports whether p, which must be for an OTYPE, is a type alias.
176func (n *Name) Alias() bool { return n.flags&nameAlias != 0 }
177
178// SetAlias sets whether p, which must be for an OTYPE, is a type alias.
179func (n *Name) SetAlias(alias bool) { n.flags.set(nameAlias, alias) }
180
181const (
182	nameReadonly                 = 1 << iota
183	nameByval                    // is the variable captured by value or by reference
184	nameNeedzero                 // if it contains pointers, needs to be zeroed on function entry
185	nameAutoTemp                 // is the variable a temporary (implies no dwarf info. reset if escapes to heap)
186	nameUsed                     // for variable declared and not used error
187	nameIsClosureVar             // PAUTOHEAP closure pseudo-variable; original (if any) at n.Defn
188	nameIsOutputParamHeapAddr    // pointer to a result parameter's heap copy
189	nameIsOutputParamInRegisters // output parameter in registers spills as an auto
190	nameAddrtaken                // address taken, even if not moved to heap
191	nameInlFormal                // PAUTO created by inliner, derived from callee formal
192	nameInlLocal                 // PAUTO created by inliner, derived from callee local
193	nameOpenDeferSlot            // if temporary var storing info for open-coded defers
194	nameLibfuzzer8BitCounter     // if PEXTERN should be assigned to __sancov_cntrs section
195	nameCoverageAuxVar           // instrumentation counter var or pkg ID for cmd/cover
196	nameAlias                    // is type name an alias
197	nameNonMergeable             // not a candidate for stack slot merging
198)
199
200func (n *Name) Readonly() bool                 { return n.flags&nameReadonly != 0 }
201func (n *Name) Needzero() bool                 { return n.flags&nameNeedzero != 0 }
202func (n *Name) AutoTemp() bool                 { return n.flags&nameAutoTemp != 0 }
203func (n *Name) Used() bool                     { return n.flags&nameUsed != 0 }
204func (n *Name) IsClosureVar() bool             { return n.flags&nameIsClosureVar != 0 }
205func (n *Name) IsOutputParamHeapAddr() bool    { return n.flags&nameIsOutputParamHeapAddr != 0 }
206func (n *Name) IsOutputParamInRegisters() bool { return n.flags&nameIsOutputParamInRegisters != 0 }
207func (n *Name) Addrtaken() bool                { return n.flags&nameAddrtaken != 0 }
208func (n *Name) InlFormal() bool                { return n.flags&nameInlFormal != 0 }
209func (n *Name) InlLocal() bool                 { return n.flags&nameInlLocal != 0 }
210func (n *Name) OpenDeferSlot() bool            { return n.flags&nameOpenDeferSlot != 0 }
211func (n *Name) Libfuzzer8BitCounter() bool     { return n.flags&nameLibfuzzer8BitCounter != 0 }
212func (n *Name) CoverageAuxVar() bool           { return n.flags&nameCoverageAuxVar != 0 }
213func (n *Name) NonMergeable() bool             { return n.flags&nameNonMergeable != 0 }
214
215func (n *Name) setReadonly(b bool)                 { n.flags.set(nameReadonly, b) }
216func (n *Name) SetNeedzero(b bool)                 { n.flags.set(nameNeedzero, b) }
217func (n *Name) SetAutoTemp(b bool)                 { n.flags.set(nameAutoTemp, b) }
218func (n *Name) SetUsed(b bool)                     { n.flags.set(nameUsed, b) }
219func (n *Name) SetIsClosureVar(b bool)             { n.flags.set(nameIsClosureVar, b) }
220func (n *Name) SetIsOutputParamHeapAddr(b bool)    { n.flags.set(nameIsOutputParamHeapAddr, b) }
221func (n *Name) SetIsOutputParamInRegisters(b bool) { n.flags.set(nameIsOutputParamInRegisters, b) }
222func (n *Name) SetAddrtaken(b bool)                { n.flags.set(nameAddrtaken, b) }
223func (n *Name) SetInlFormal(b bool)                { n.flags.set(nameInlFormal, b) }
224func (n *Name) SetInlLocal(b bool)                 { n.flags.set(nameInlLocal, b) }
225func (n *Name) SetOpenDeferSlot(b bool)            { n.flags.set(nameOpenDeferSlot, b) }
226func (n *Name) SetLibfuzzer8BitCounter(b bool)     { n.flags.set(nameLibfuzzer8BitCounter, b) }
227func (n *Name) SetCoverageAuxVar(b bool)           { n.flags.set(nameCoverageAuxVar, b) }
228func (n *Name) SetNonMergeable(b bool)             { n.flags.set(nameNonMergeable, b) }
229
230// OnStack reports whether variable n may reside on the stack.
231func (n *Name) OnStack() bool {
232	if n.Op() == ONAME {
233		switch n.Class {
234		case PPARAM, PPARAMOUT, PAUTO:
235			return n.Esc() != EscHeap
236		case PEXTERN, PAUTOHEAP:
237			return false
238		}
239	}
240	// Note: fmt.go:dumpNodeHeader calls all "func() bool"-typed
241	// methods, but it can only recover from panics, not Fatalf.
242	panic(fmt.Sprintf("%v: not a variable: %v", base.FmtPos(n.Pos()), n))
243}
244
245// MarkReadonly indicates that n is an ONAME with readonly contents.
246func (n *Name) MarkReadonly() {
247	if n.Op() != ONAME {
248		base.Fatalf("Node.MarkReadonly %v", n.Op())
249	}
250	n.setReadonly(true)
251	// Mark the linksym as readonly immediately
252	// so that the SSA backend can use this information.
253	// It will be overridden later during dumpglobls.
254	n.Linksym().Type = objabi.SRODATA
255}
256
257// Val returns the constant.Value for the node.
258func (n *Name) Val() constant.Value {
259	if n.val == nil {
260		return constant.MakeUnknown()
261	}
262	return n.val
263}
264
265// SetVal sets the constant.Value for the node.
266func (n *Name) SetVal(v constant.Value) {
267	if n.op != OLITERAL {
268		panic(n.no("SetVal"))
269	}
270	AssertValidTypeForConst(n.Type(), v)
271	n.val = v
272}
273
274// Canonical returns the logical declaration that n represents. If n
275// is a closure variable, then Canonical returns the original Name as
276// it appears in the function that immediately contains the
277// declaration. Otherwise, Canonical simply returns n itself.
278func (n *Name) Canonical() *Name {
279	if n.IsClosureVar() && n.Defn != nil {
280		n = n.Defn.(*Name)
281	}
282	return n
283}
284
285func (n *Name) SetByval(b bool) {
286	if n.Canonical() != n {
287		base.Fatalf("SetByval called on non-canonical variable: %v", n)
288	}
289	n.flags.set(nameByval, b)
290}
291
292func (n *Name) Byval() bool {
293	// We require byval to be set on the canonical variable, but we
294	// allow it to be accessed from any instance.
295	return n.Canonical().flags&nameByval != 0
296}
297
298// NewClosureVar returns a new closure variable for fn to refer to
299// outer variable n.
300func NewClosureVar(pos src.XPos, fn *Func, n *Name) *Name {
301	switch n.Class {
302	case PAUTO, PPARAM, PPARAMOUT, PAUTOHEAP:
303		// ok
304	default:
305		// Prevent mistaken capture of global variables.
306		base.Fatalf("NewClosureVar: %+v", n)
307	}
308
309	c := NewNameAt(pos, n.Sym(), n.Type())
310	c.Curfn = fn
311	c.Class = PAUTOHEAP
312	c.SetIsClosureVar(true)
313	c.Defn = n.Canonical()
314	c.Outer = n
315
316	fn.ClosureVars = append(fn.ClosureVars, c)
317
318	return c
319}
320
321// NewHiddenParam returns a new hidden parameter for fn with the given
322// name and type.
323func NewHiddenParam(pos src.XPos, fn *Func, sym *types.Sym, typ *types.Type) *Name {
324	if fn.OClosure != nil {
325		base.FatalfAt(fn.Pos(), "cannot add hidden parameters to closures")
326	}
327
328	fn.SetNeedctxt(true)
329
330	// Create a fake parameter, disassociated from any real function, to
331	// pretend to capture.
332	fake := NewNameAt(pos, sym, typ)
333	fake.Class = PPARAM
334	fake.SetByval(true)
335
336	return NewClosureVar(pos, fn, fake)
337}
338
339// SameSource reports whether two nodes refer to the same source
340// element.
341//
342// It exists to help incrementally migrate the compiler towards
343// allowing the introduction of IdentExpr (#42990). Once we have
344// IdentExpr, it will no longer be safe to directly compare Node
345// values to tell if they refer to the same Name. Instead, code will
346// need to explicitly get references to the underlying Name object(s),
347// and compare those instead.
348//
349// It will still be safe to compare Nodes directly for checking if two
350// nodes are syntactically the same. The SameSource function exists to
351// indicate code that intentionally compares Nodes for syntactic
352// equality as opposed to code that has yet to be updated in
353// preparation for IdentExpr.
354func SameSource(n1, n2 Node) bool {
355	return n1 == n2
356}
357
358// Uses reports whether expression x is a (direct) use of the given
359// variable.
360func Uses(x Node, v *Name) bool {
361	if v == nil || v.Op() != ONAME {
362		base.Fatalf("RefersTo bad Name: %v", v)
363	}
364	return x.Op() == ONAME && x.Name() == v
365}
366
367// DeclaredBy reports whether expression x refers (directly) to a
368// variable that was declared by the given statement.
369func DeclaredBy(x, stmt Node) bool {
370	if stmt == nil {
371		base.Fatalf("DeclaredBy nil")
372	}
373	return x.Op() == ONAME && SameSource(x.Name().Defn, stmt)
374}
375
376// The Class of a variable/function describes the "storage class"
377// of a variable or function. During parsing, storage classes are
378// called declaration contexts.
379type Class uint8
380
381//go:generate stringer -type=Class name.go
382const (
383	Pxxx       Class = iota // no class; used during ssa conversion to indicate pseudo-variables
384	PEXTERN                 // global variables
385	PAUTO                   // local variables
386	PAUTOHEAP               // local variables or parameters moved to heap
387	PPARAM                  // input arguments
388	PPARAMOUT               // output results
389	PTYPEPARAM              // type params
390	PFUNC                   // global functions
391
392	// Careful: Class is stored in three bits in Node.flags.
393	_ = uint((1 << 3) - iota) // static assert for iota <= (1 << 3)
394)
395
396type Embed struct {
397	Pos      src.XPos
398	Patterns []string
399}
400