Source file src/cmd/compile/internal/ir/name.go

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

View as plain text