github.com/bir3/gocompiler@v0.9.2202/src/cmd/compile/internal/ir/name.go (about) 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 5 package ir 6 7 import ( 8 "github.com/bir3/gocompiler/src/cmd/compile/internal/base" 9 "github.com/bir3/gocompiler/src/cmd/compile/internal/types" 10 "github.com/bir3/gocompiler/src/cmd/internal/obj" 11 "github.com/bir3/gocompiler/src/cmd/internal/objabi" 12 "github.com/bir3/gocompiler/src/cmd/internal/src" 13 "fmt" 14 15 "github.com/bir3/gocompiler/src/go/constant" 16 ) 17 18 // An Ident is an identifier, possibly qualified. 19 type Ident struct { 20 miniExpr 21 sym *types.Sym 22 } 23 24 func 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 32 func (n *Ident) Sym() *types.Sym { return n.sym } 33 34 // Name holds Node fields used only by named nodes (ONAME, OTYPE, some OLITERAL). 35 type 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 67 func (n *Name) isExpr() {} 68 69 func (n *Name) copy() Node { panic(n.no("copy")) } 70 func (n *Name) doChildren(do func(Node) bool) bool { return false } 71 func (n *Name) editChildren(edit func(Node) Node) {} 72 func (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. 76 func (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. 82 func 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. 96 func 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. 105 func (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. 119 func 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. 133 func 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. 145 func 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 153 func (n *Name) Name() *Name { return n } 154 func (n *Name) Sym() *types.Sym { return n.sym } 155 func (n *Name) SetSym(x *types.Sym) { n.sym = x } 156 func (n *Name) SubOp() Op { return n.BuiltinOp } 157 func (n *Name) SetSubOp(x Op) { n.BuiltinOp = x } 158 func (n *Name) SetFunc(x *Func) { n.Func = x } 159 func (n *Name) FrameOffset() int64 { return n.Offset_ } 160 func (n *Name) SetFrameOffset(x int64) { n.Offset_ = x } 161 162 func (n *Name) Linksym() *obj.LSym { return n.sym.Linksym() } 163 func (n *Name) LinksymABI(abi obj.ABI) *obj.LSym { return n.sym.LinksymABI(abi) } 164 165 func (*Name) CanBeNtype() {} 166 func (*Name) CanBeAnSSASym() {} 167 func (*Name) CanBeAnSSAAux() {} 168 169 // Pragma returns the PragmaFlag for p, which must be for an OTYPE. 170 func (n *Name) Pragma() PragmaFlag { return n.pragma } 171 172 // SetPragma sets the PragmaFlag for p, which must be for an OTYPE. 173 func (n *Name) SetPragma(flag PragmaFlag) { n.pragma = flag } 174 175 // Alias reports whether p, which must be for an OTYPE, is a type alias. 176 func (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. 179 func (n *Name) SetAlias(alias bool) { n.flags.set(nameAlias, alias) } 180 181 const ( 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 nameCoverageCounter // instrumentation counter var for cmd/cover 196 nameCoverageAuxVar // instrumentation pkg ID variable cmd/cover 197 nameAlias // is type name an alias 198 ) 199 200 func (n *Name) Readonly() bool { return n.flags&nameReadonly != 0 } 201 func (n *Name) Needzero() bool { return n.flags&nameNeedzero != 0 } 202 func (n *Name) AutoTemp() bool { return n.flags&nameAutoTemp != 0 } 203 func (n *Name) Used() bool { return n.flags&nameUsed != 0 } 204 func (n *Name) IsClosureVar() bool { return n.flags&nameIsClosureVar != 0 } 205 func (n *Name) IsOutputParamHeapAddr() bool { return n.flags&nameIsOutputParamHeapAddr != 0 } 206 func (n *Name) IsOutputParamInRegisters() bool { return n.flags&nameIsOutputParamInRegisters != 0 } 207 func (n *Name) Addrtaken() bool { return n.flags&nameAddrtaken != 0 } 208 func (n *Name) InlFormal() bool { return n.flags&nameInlFormal != 0 } 209 func (n *Name) InlLocal() bool { return n.flags&nameInlLocal != 0 } 210 func (n *Name) OpenDeferSlot() bool { return n.flags&nameOpenDeferSlot != 0 } 211 func (n *Name) Libfuzzer8BitCounter() bool { return n.flags&nameLibfuzzer8BitCounter != 0 } 212 func (n *Name) CoverageCounter() bool { return n.flags&nameCoverageCounter != 0 } 213 func (n *Name) CoverageAuxVar() bool { return n.flags&nameCoverageAuxVar != 0 } 214 215 func (n *Name) setReadonly(b bool) { n.flags.set(nameReadonly, b) } 216 func (n *Name) SetNeedzero(b bool) { n.flags.set(nameNeedzero, b) } 217 func (n *Name) SetAutoTemp(b bool) { n.flags.set(nameAutoTemp, b) } 218 func (n *Name) SetUsed(b bool) { n.flags.set(nameUsed, b) } 219 func (n *Name) SetIsClosureVar(b bool) { n.flags.set(nameIsClosureVar, b) } 220 func (n *Name) SetIsOutputParamHeapAddr(b bool) { n.flags.set(nameIsOutputParamHeapAddr, b) } 221 func (n *Name) SetIsOutputParamInRegisters(b bool) { n.flags.set(nameIsOutputParamInRegisters, b) } 222 func (n *Name) SetAddrtaken(b bool) { n.flags.set(nameAddrtaken, b) } 223 func (n *Name) SetInlFormal(b bool) { n.flags.set(nameInlFormal, b) } 224 func (n *Name) SetInlLocal(b bool) { n.flags.set(nameInlLocal, b) } 225 func (n *Name) SetOpenDeferSlot(b bool) { n.flags.set(nameOpenDeferSlot, b) } 226 func (n *Name) SetLibfuzzer8BitCounter(b bool) { n.flags.set(nameLibfuzzer8BitCounter, b) } 227 func (n *Name) SetCoverageCounter(b bool) { n.flags.set(nameCoverageCounter, b) } 228 func (n *Name) SetCoverageAuxVar(b bool) { n.flags.set(nameCoverageAuxVar, b) } 229 230 // OnStack reports whether variable n may reside on the stack. 231 func (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. 246 func (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. 258 func (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. 266 func (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. 278 func (n *Name) Canonical() *Name { 279 if n.IsClosureVar() && n.Defn != nil { 280 n = n.Defn.(*Name) 281 } 282 return n 283 } 284 285 func (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 292 func (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. 300 func 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. 323 func 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. 354 func 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. 360 func 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. 369 func 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. 379 type Class uint8 380 381 //go:generate stringer -type=Class name.go 382 const ( 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 396 type Embed struct { 397 Pos src.XPos 398 Patterns []string 399 }