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