github.com/hikaru7719/go@v0.0.0-20181025140707-c8b2ac68906a/src/cmd/compile/internal/gc/pgen.go (about)

     1  // Copyright 2011 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 gc
     6  
     7  import (
     8  	"cmd/compile/internal/ssa"
     9  	"cmd/compile/internal/types"
    10  	"cmd/internal/dwarf"
    11  	"cmd/internal/obj"
    12  	"cmd/internal/objabi"
    13  	"cmd/internal/src"
    14  	"cmd/internal/sys"
    15  	"fmt"
    16  	"math/rand"
    17  	"sort"
    18  	"sync"
    19  	"time"
    20  )
    21  
    22  // "Portable" code generation.
    23  
    24  var (
    25  	nBackendWorkers int     // number of concurrent backend workers, set by a compiler flag
    26  	compilequeue    []*Node // functions waiting to be compiled
    27  )
    28  
    29  func emitptrargsmap(fn *Node) {
    30  	if fn.funcname() == "_" {
    31  		return
    32  	}
    33  	sym := lookup(fmt.Sprintf("%s.args_stackmap", fn.funcname()))
    34  	lsym := sym.Linksym()
    35  
    36  	nptr := int(fn.Type.ArgWidth() / int64(Widthptr))
    37  	bv := bvalloc(int32(nptr) * 2)
    38  	nbitmap := 1
    39  	if fn.Type.NumResults() > 0 {
    40  		nbitmap = 2
    41  	}
    42  	off := duint32(lsym, 0, uint32(nbitmap))
    43  	off = duint32(lsym, off, uint32(bv.n))
    44  
    45  	if fn.IsMethod() {
    46  		onebitwalktype1(fn.Type.Recvs(), 0, bv)
    47  	}
    48  	if fn.Type.NumParams() > 0 {
    49  		onebitwalktype1(fn.Type.Params(), 0, bv)
    50  	}
    51  	off = dbvec(lsym, off, bv)
    52  
    53  	if fn.Type.NumResults() > 0 {
    54  		onebitwalktype1(fn.Type.Results(), 0, bv)
    55  		off = dbvec(lsym, off, bv)
    56  	}
    57  
    58  	ggloblsym(lsym, int32(off), obj.RODATA|obj.LOCAL)
    59  }
    60  
    61  // cmpstackvarlt reports whether the stack variable a sorts before b.
    62  //
    63  // Sort the list of stack variables. Autos after anything else,
    64  // within autos, unused after used, within used, things with
    65  // pointers first, zeroed things first, and then decreasing size.
    66  // Because autos are laid out in decreasing addresses
    67  // on the stack, pointers first, zeroed things first and decreasing size
    68  // really means, in memory, things with pointers needing zeroing at
    69  // the top of the stack and increasing in size.
    70  // Non-autos sort on offset.
    71  func cmpstackvarlt(a, b *Node) bool {
    72  	if (a.Class() == PAUTO) != (b.Class() == PAUTO) {
    73  		return b.Class() == PAUTO
    74  	}
    75  
    76  	if a.Class() != PAUTO {
    77  		return a.Xoffset < b.Xoffset
    78  	}
    79  
    80  	if a.Name.Used() != b.Name.Used() {
    81  		return a.Name.Used()
    82  	}
    83  
    84  	ap := types.Haspointers(a.Type)
    85  	bp := types.Haspointers(b.Type)
    86  	if ap != bp {
    87  		return ap
    88  	}
    89  
    90  	ap = a.Name.Needzero()
    91  	bp = b.Name.Needzero()
    92  	if ap != bp {
    93  		return ap
    94  	}
    95  
    96  	if a.Type.Width != b.Type.Width {
    97  		return a.Type.Width > b.Type.Width
    98  	}
    99  
   100  	return a.Sym.Name < b.Sym.Name
   101  }
   102  
   103  // byStackvar implements sort.Interface for []*Node using cmpstackvarlt.
   104  type byStackVar []*Node
   105  
   106  func (s byStackVar) Len() int           { return len(s) }
   107  func (s byStackVar) Less(i, j int) bool { return cmpstackvarlt(s[i], s[j]) }
   108  func (s byStackVar) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
   109  
   110  func (s *ssafn) AllocFrame(f *ssa.Func) {
   111  	s.stksize = 0
   112  	s.stkptrsize = 0
   113  	fn := s.curfn.Func
   114  
   115  	// Mark the PAUTO's unused.
   116  	for _, ln := range fn.Dcl {
   117  		if ln.Class() == PAUTO {
   118  			ln.Name.SetUsed(false)
   119  		}
   120  	}
   121  
   122  	for _, l := range f.RegAlloc {
   123  		if ls, ok := l.(ssa.LocalSlot); ok {
   124  			ls.N.(*Node).Name.SetUsed(true)
   125  		}
   126  	}
   127  
   128  	scratchUsed := false
   129  	for _, b := range f.Blocks {
   130  		for _, v := range b.Values {
   131  			if n, ok := v.Aux.(*Node); ok {
   132  				switch n.Class() {
   133  				case PPARAM, PPARAMOUT:
   134  					// Don't modify nodfp; it is a global.
   135  					if n != nodfp {
   136  						n.Name.SetUsed(true)
   137  					}
   138  				case PAUTO:
   139  					n.Name.SetUsed(true)
   140  				}
   141  			}
   142  			if !scratchUsed {
   143  				scratchUsed = v.Op.UsesScratch()
   144  			}
   145  
   146  		}
   147  	}
   148  
   149  	if f.Config.NeedsFpScratch && scratchUsed {
   150  		s.scratchFpMem = tempAt(src.NoXPos, s.curfn, types.Types[TUINT64])
   151  	}
   152  
   153  	sort.Sort(byStackVar(fn.Dcl))
   154  
   155  	// Reassign stack offsets of the locals that are used.
   156  	for i, n := range fn.Dcl {
   157  		if n.Op != ONAME || n.Class() != PAUTO {
   158  			continue
   159  		}
   160  		if !n.Name.Used() {
   161  			fn.Dcl = fn.Dcl[:i]
   162  			break
   163  		}
   164  
   165  		dowidth(n.Type)
   166  		w := n.Type.Width
   167  		if w >= thearch.MAXWIDTH || w < 0 {
   168  			Fatalf("bad width")
   169  		}
   170  		s.stksize += w
   171  		s.stksize = Rnd(s.stksize, int64(n.Type.Align))
   172  		if types.Haspointers(n.Type) {
   173  			s.stkptrsize = s.stksize
   174  		}
   175  		if thearch.LinkArch.InFamily(sys.MIPS, sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64, sys.S390X) {
   176  			s.stksize = Rnd(s.stksize, int64(Widthptr))
   177  		}
   178  		n.Xoffset = -s.stksize
   179  	}
   180  
   181  	s.stksize = Rnd(s.stksize, int64(Widthreg))
   182  	s.stkptrsize = Rnd(s.stkptrsize, int64(Widthreg))
   183  }
   184  
   185  func funccompile(fn *Node) {
   186  	if Curfn != nil {
   187  		Fatalf("funccompile %v inside %v", fn.Func.Nname.Sym, Curfn.Func.Nname.Sym)
   188  	}
   189  
   190  	if fn.Type == nil {
   191  		if nerrors == 0 {
   192  			Fatalf("funccompile missing type")
   193  		}
   194  		return
   195  	}
   196  
   197  	// assign parameter offsets
   198  	dowidth(fn.Type)
   199  
   200  	if fn.Nbody.Len() == 0 {
   201  		emitptrargsmap(fn)
   202  		return
   203  	}
   204  
   205  	dclcontext = PAUTO
   206  	Curfn = fn
   207  
   208  	compile(fn)
   209  
   210  	Curfn = nil
   211  	dclcontext = PEXTERN
   212  }
   213  
   214  func compile(fn *Node) {
   215  	saveerrors()
   216  
   217  	order(fn)
   218  	if nerrors != 0 {
   219  		return
   220  	}
   221  
   222  	walk(fn)
   223  	if nerrors != 0 {
   224  		return
   225  	}
   226  	if instrumenting {
   227  		instrument(fn)
   228  	}
   229  
   230  	// From this point, there should be no uses of Curfn. Enforce that.
   231  	Curfn = nil
   232  
   233  	// Set up the function's LSym early to avoid data races with the assemblers.
   234  	fn.Func.initLSym()
   235  
   236  	// Make sure type syms are declared for all types that might
   237  	// be types of stack objects. We need to do this here
   238  	// because symbols must be allocated before the parallel
   239  	// phase of the compiler.
   240  	if fn.Func.lsym != nil { // not func _(){}
   241  		for _, n := range fn.Func.Dcl {
   242  			switch n.Class() {
   243  			case PPARAM, PPARAMOUT, PAUTO:
   244  				if livenessShouldTrack(n) && n.Addrtaken() {
   245  					dtypesym(n.Type)
   246  					// Also make sure we allocate a linker symbol
   247  					// for the stack object data, for the same reason.
   248  					if fn.Func.lsym.Func.StackObjects == nil {
   249  						fn.Func.lsym.Func.StackObjects = lookup(fmt.Sprintf("%s.stkobj", fn.funcname())).Linksym()
   250  					}
   251  				}
   252  			}
   253  		}
   254  	}
   255  
   256  	if compilenow() {
   257  		compileSSA(fn, 0)
   258  	} else {
   259  		compilequeue = append(compilequeue, fn)
   260  	}
   261  }
   262  
   263  // compilenow reports whether to compile immediately.
   264  // If functions are not compiled immediately,
   265  // they are enqueued in compilequeue,
   266  // which is drained by compileFunctions.
   267  func compilenow() bool {
   268  	return nBackendWorkers == 1 && Debug_compilelater == 0
   269  }
   270  
   271  const maxStackSize = 1 << 30
   272  
   273  // compileSSA builds an SSA backend function,
   274  // uses it to generate a plist,
   275  // and flushes that plist to machine code.
   276  // worker indicates which of the backend workers is doing the processing.
   277  func compileSSA(fn *Node, worker int) {
   278  	f := buildssa(fn, worker)
   279  	// Note: check arg size to fix issue 25507.
   280  	if f.Frontend().(*ssafn).stksize >= maxStackSize || fn.Type.ArgWidth() >= maxStackSize {
   281  		largeStackFramesMu.Lock()
   282  		largeStackFrames = append(largeStackFrames, fn.Pos)
   283  		largeStackFramesMu.Unlock()
   284  		return
   285  	}
   286  	pp := newProgs(fn, worker)
   287  	defer pp.Free()
   288  	genssa(f, pp)
   289  	// Check frame size again.
   290  	// The check above included only the space needed for local variables.
   291  	// After genssa, the space needed includes local variables and the callee arg region.
   292  	// We must do this check prior to calling pp.Flush.
   293  	// If there are any oversized stack frames,
   294  	// the assembler may emit inscrutable complaints about invalid instructions.
   295  	if pp.Text.To.Offset >= maxStackSize {
   296  		largeStackFramesMu.Lock()
   297  		largeStackFrames = append(largeStackFrames, fn.Pos)
   298  		largeStackFramesMu.Unlock()
   299  		return
   300  	}
   301  
   302  	pp.Flush() // assemble, fill in boilerplate, etc.
   303  	// fieldtrack must be called after pp.Flush. See issue 20014.
   304  	fieldtrack(pp.Text.From.Sym, fn.Func.FieldTrack)
   305  }
   306  
   307  func init() {
   308  	if raceEnabled {
   309  		rand.Seed(time.Now().UnixNano())
   310  	}
   311  }
   312  
   313  // compileFunctions compiles all functions in compilequeue.
   314  // It fans out nBackendWorkers to do the work
   315  // and waits for them to complete.
   316  func compileFunctions() {
   317  	if len(compilequeue) != 0 {
   318  		sizeCalculationDisabled = true // not safe to calculate sizes concurrently
   319  		if raceEnabled {
   320  			// Randomize compilation order to try to shake out races.
   321  			tmp := make([]*Node, len(compilequeue))
   322  			perm := rand.Perm(len(compilequeue))
   323  			for i, v := range perm {
   324  				tmp[v] = compilequeue[i]
   325  			}
   326  			copy(compilequeue, tmp)
   327  		} else {
   328  			// Compile the longest functions first,
   329  			// since they're most likely to be the slowest.
   330  			// This helps avoid stragglers.
   331  			obj.SortSlice(compilequeue, func(i, j int) bool {
   332  				return compilequeue[i].Nbody.Len() > compilequeue[j].Nbody.Len()
   333  			})
   334  		}
   335  		var wg sync.WaitGroup
   336  		Ctxt.InParallel = true
   337  		c := make(chan *Node, nBackendWorkers)
   338  		for i := 0; i < nBackendWorkers; i++ {
   339  			wg.Add(1)
   340  			go func(worker int) {
   341  				for fn := range c {
   342  					compileSSA(fn, worker)
   343  				}
   344  				wg.Done()
   345  			}(i)
   346  		}
   347  		for _, fn := range compilequeue {
   348  			c <- fn
   349  		}
   350  		close(c)
   351  		compilequeue = nil
   352  		wg.Wait()
   353  		Ctxt.InParallel = false
   354  		sizeCalculationDisabled = false
   355  	}
   356  }
   357  
   358  func debuginfo(fnsym *obj.LSym, curfn interface{}) ([]dwarf.Scope, dwarf.InlCalls) {
   359  	fn := curfn.(*Node)
   360  	if fn.Func.Nname != nil {
   361  		if expect := fn.Func.Nname.Sym.Linksym(); fnsym != expect {
   362  			Fatalf("unexpected fnsym: %v != %v", fnsym, expect)
   363  		}
   364  	}
   365  
   366  	var automDecls []*Node
   367  	// Populate Automs for fn.
   368  	for _, n := range fn.Func.Dcl {
   369  		if n.Op != ONAME { // might be OTYPE or OLITERAL
   370  			continue
   371  		}
   372  		var name obj.AddrName
   373  		switch n.Class() {
   374  		case PAUTO:
   375  			if !n.Name.Used() {
   376  				// Text == nil -> generating abstract function
   377  				if fnsym.Func.Text != nil {
   378  					Fatalf("debuginfo unused node (AllocFrame should truncate fn.Func.Dcl)")
   379  				}
   380  				continue
   381  			}
   382  			name = obj.NAME_AUTO
   383  		case PPARAM, PPARAMOUT:
   384  			name = obj.NAME_PARAM
   385  		default:
   386  			continue
   387  		}
   388  		automDecls = append(automDecls, n)
   389  		gotype := ngotype(n).Linksym()
   390  		fnsym.Func.Autom = append(fnsym.Func.Autom, &obj.Auto{
   391  			Asym:    Ctxt.Lookup(n.Sym.Name),
   392  			Aoffset: int32(n.Xoffset),
   393  			Name:    name,
   394  			Gotype:  gotype,
   395  		})
   396  	}
   397  
   398  	decls, dwarfVars := createDwarfVars(fnsym, fn.Func, automDecls)
   399  
   400  	var varScopes []ScopeID
   401  	for _, decl := range decls {
   402  		pos := decl.Pos
   403  		if decl.Name.Defn != nil && (decl.Name.Captured() || decl.Name.Byval()) {
   404  			// It's not clear which position is correct for captured variables here:
   405  			// * decl.Pos is the wrong position for captured variables, in the inner
   406  			//   function, but it is the right position in the outer function.
   407  			// * decl.Name.Defn is nil for captured variables that were arguments
   408  			//   on the outer function, however the decl.Pos for those seems to be
   409  			//   correct.
   410  			// * decl.Name.Defn is the "wrong" thing for variables declared in the
   411  			//   header of a type switch, it's their position in the header, rather
   412  			//   than the position of the case statement. In principle this is the
   413  			//   right thing, but here we prefer the latter because it makes each
   414  			//   instance of the header variable local to the lexical block of its
   415  			//   case statement.
   416  			// This code is probably wrong for type switch variables that are also
   417  			// captured.
   418  			pos = decl.Name.Defn.Pos
   419  		}
   420  		varScopes = append(varScopes, findScope(fn.Func.Marks, pos))
   421  	}
   422  
   423  	scopes := assembleScopes(fnsym, fn, dwarfVars, varScopes)
   424  	var inlcalls dwarf.InlCalls
   425  	if genDwarfInline > 0 {
   426  		inlcalls = assembleInlines(fnsym, dwarfVars)
   427  	}
   428  	return scopes, inlcalls
   429  }
   430  
   431  // createSimpleVars creates a DWARF entry for every variable declared in the
   432  // function, claiming that they are permanently on the stack.
   433  func createSimpleVars(automDecls []*Node) ([]*Node, []*dwarf.Var, map[*Node]bool) {
   434  	var vars []*dwarf.Var
   435  	var decls []*Node
   436  	selected := make(map[*Node]bool)
   437  	for _, n := range automDecls {
   438  		if n.IsAutoTmp() {
   439  			continue
   440  		}
   441  		var abbrev int
   442  		offs := n.Xoffset
   443  
   444  		switch n.Class() {
   445  		case PAUTO:
   446  			abbrev = dwarf.DW_ABRV_AUTO
   447  			if Ctxt.FixedFrameSize() == 0 {
   448  				offs -= int64(Widthptr)
   449  			}
   450  			if objabi.Framepointer_enabled(objabi.GOOS, objabi.GOARCH) || objabi.GOARCH == "arm64" {
   451  				// There is a word space for FP on ARM64 even if the frame pointer is disabled
   452  				offs -= int64(Widthptr)
   453  			}
   454  
   455  		case PPARAM, PPARAMOUT:
   456  			abbrev = dwarf.DW_ABRV_PARAM
   457  			offs += Ctxt.FixedFrameSize()
   458  		default:
   459  			Fatalf("createSimpleVars unexpected type %v for node %v", n.Class(), n)
   460  		}
   461  
   462  		selected[n] = true
   463  		typename := dwarf.InfoPrefix + typesymname(n.Type)
   464  		decls = append(decls, n)
   465  		inlIndex := 0
   466  		if genDwarfInline > 1 {
   467  			if n.InlFormal() || n.InlLocal() {
   468  				inlIndex = posInlIndex(n.Pos) + 1
   469  				if n.InlFormal() {
   470  					abbrev = dwarf.DW_ABRV_PARAM
   471  				}
   472  			}
   473  		}
   474  		declpos := Ctxt.InnermostPos(n.Pos)
   475  		vars = append(vars, &dwarf.Var{
   476  			Name:          n.Sym.Name,
   477  			IsReturnValue: n.Class() == PPARAMOUT,
   478  			IsInlFormal:   n.InlFormal(),
   479  			Abbrev:        abbrev,
   480  			StackOffset:   int32(offs),
   481  			Type:          Ctxt.Lookup(typename),
   482  			DeclFile:      declpos.RelFilename(),
   483  			DeclLine:      declpos.RelLine(),
   484  			DeclCol:       declpos.Col(),
   485  			InlIndex:      int32(inlIndex),
   486  			ChildIndex:    -1,
   487  		})
   488  	}
   489  	return decls, vars, selected
   490  }
   491  
   492  // createComplexVars creates recomposed DWARF vars with location lists,
   493  // suitable for describing optimized code.
   494  func createComplexVars(fn *Func) ([]*Node, []*dwarf.Var, map[*Node]bool) {
   495  	debugInfo := fn.DebugInfo
   496  
   497  	// Produce a DWARF variable entry for each user variable.
   498  	var decls []*Node
   499  	var vars []*dwarf.Var
   500  	ssaVars := make(map[*Node]bool)
   501  
   502  	for varID, dvar := range debugInfo.Vars {
   503  		n := dvar.(*Node)
   504  		ssaVars[n] = true
   505  		for _, slot := range debugInfo.VarSlots[varID] {
   506  			ssaVars[debugInfo.Slots[slot].N.(*Node)] = true
   507  		}
   508  
   509  		if dvar := createComplexVar(fn, ssa.VarID(varID)); dvar != nil {
   510  			decls = append(decls, n)
   511  			vars = append(vars, dvar)
   512  		}
   513  	}
   514  
   515  	return decls, vars, ssaVars
   516  }
   517  
   518  // createDwarfVars process fn, returning a list of DWARF variables and the
   519  // Nodes they represent.
   520  func createDwarfVars(fnsym *obj.LSym, fn *Func, automDecls []*Node) ([]*Node, []*dwarf.Var) {
   521  	// Collect a raw list of DWARF vars.
   522  	var vars []*dwarf.Var
   523  	var decls []*Node
   524  	var selected map[*Node]bool
   525  	if Ctxt.Flag_locationlists && Ctxt.Flag_optimize && fn.DebugInfo != nil {
   526  		decls, vars, selected = createComplexVars(fn)
   527  	} else {
   528  		decls, vars, selected = createSimpleVars(automDecls)
   529  	}
   530  
   531  	var dcl []*Node
   532  	if fnsym.WasInlined() {
   533  		dcl = preInliningDcls(fnsym)
   534  	} else {
   535  		dcl = automDecls
   536  	}
   537  
   538  	// If optimization is enabled, the list above will typically be
   539  	// missing some of the original pre-optimization variables in the
   540  	// function (they may have been promoted to registers, folded into
   541  	// constants, dead-coded away, etc). Here we add back in entries
   542  	// for selected missing vars. Note that the recipe below creates a
   543  	// conservative location. The idea here is that we want to
   544  	// communicate to the user that "yes, there is a variable named X
   545  	// in this function, but no, I don't have enough information to
   546  	// reliably report its contents."
   547  	for _, n := range dcl {
   548  		if _, found := selected[n]; found {
   549  			continue
   550  		}
   551  		c := n.Sym.Name[0]
   552  		if c == '.' || n.Type.IsUntyped() {
   553  			continue
   554  		}
   555  		typename := dwarf.InfoPrefix + typesymname(n.Type)
   556  		decls = append(decls, n)
   557  		abbrev := dwarf.DW_ABRV_AUTO_LOCLIST
   558  		if n.Class() == PPARAM || n.Class() == PPARAMOUT {
   559  			abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
   560  		}
   561  		inlIndex := 0
   562  		if genDwarfInline > 1 {
   563  			if n.InlFormal() || n.InlLocal() {
   564  				inlIndex = posInlIndex(n.Pos) + 1
   565  				if n.InlFormal() {
   566  					abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
   567  				}
   568  			}
   569  		}
   570  		declpos := Ctxt.InnermostPos(n.Pos)
   571  		vars = append(vars, &dwarf.Var{
   572  			Name:          n.Sym.Name,
   573  			IsReturnValue: n.Class() == PPARAMOUT,
   574  			Abbrev:        abbrev,
   575  			StackOffset:   int32(n.Xoffset),
   576  			Type:          Ctxt.Lookup(typename),
   577  			DeclFile:      declpos.RelFilename(),
   578  			DeclLine:      declpos.RelLine(),
   579  			DeclCol:       declpos.Col(),
   580  			InlIndex:      int32(inlIndex),
   581  			ChildIndex:    -1,
   582  		})
   583  		// Append a "deleted auto" entry to the autom list so as to
   584  		// insure that the type in question is picked up by the linker.
   585  		// See issue 22941.
   586  		gotype := ngotype(n).Linksym()
   587  		fnsym.Func.Autom = append(fnsym.Func.Autom, &obj.Auto{
   588  			Asym:    Ctxt.Lookup(n.Sym.Name),
   589  			Aoffset: int32(-1),
   590  			Name:    obj.NAME_DELETED_AUTO,
   591  			Gotype:  gotype,
   592  		})
   593  
   594  	}
   595  
   596  	return decls, vars
   597  }
   598  
   599  // Given a function that was inlined at some point during the
   600  // compilation, return a sorted list of nodes corresponding to the
   601  // autos/locals in that function prior to inlining. If this is a
   602  // function that is not local to the package being compiled, then the
   603  // names of the variables may have been "versioned" to avoid conflicts
   604  // with local vars; disregard this versioning when sorting.
   605  func preInliningDcls(fnsym *obj.LSym) []*Node {
   606  	fn := Ctxt.DwFixups.GetPrecursorFunc(fnsym).(*Node)
   607  	var rdcl []*Node
   608  	for _, n := range fn.Func.Inl.Dcl {
   609  		c := n.Sym.Name[0]
   610  		// Avoid reporting "_" parameters, since if there are more than
   611  		// one, it can result in a collision later on, as in #23179.
   612  		if unversion(n.Sym.Name) == "_" || c == '.' || n.Type.IsUntyped() {
   613  			continue
   614  		}
   615  		rdcl = append(rdcl, n)
   616  	}
   617  	return rdcl
   618  }
   619  
   620  // stackOffset returns the stack location of a LocalSlot relative to the
   621  // stack pointer, suitable for use in a DWARF location entry. This has nothing
   622  // to do with its offset in the user variable.
   623  func stackOffset(slot ssa.LocalSlot) int32 {
   624  	n := slot.N.(*Node)
   625  	var base int64
   626  	switch n.Class() {
   627  	case PAUTO:
   628  		if Ctxt.FixedFrameSize() == 0 {
   629  			base -= int64(Widthptr)
   630  		}
   631  		if objabi.Framepointer_enabled(objabi.GOOS, objabi.GOARCH) || objabi.GOARCH == "arm64" {
   632  			// There is a word space for FP on ARM64 even if the frame pointer is disabled
   633  			base -= int64(Widthptr)
   634  		}
   635  	case PPARAM, PPARAMOUT:
   636  		base += Ctxt.FixedFrameSize()
   637  	}
   638  	return int32(base + n.Xoffset + slot.Off)
   639  }
   640  
   641  // createComplexVar builds a single DWARF variable entry and location list.
   642  func createComplexVar(fn *Func, varID ssa.VarID) *dwarf.Var {
   643  	debug := fn.DebugInfo
   644  	n := debug.Vars[varID].(*Node)
   645  
   646  	var abbrev int
   647  	switch n.Class() {
   648  	case PAUTO:
   649  		abbrev = dwarf.DW_ABRV_AUTO_LOCLIST
   650  	case PPARAM, PPARAMOUT:
   651  		abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
   652  	default:
   653  		return nil
   654  	}
   655  
   656  	gotype := ngotype(n).Linksym()
   657  	typename := dwarf.InfoPrefix + gotype.Name[len("type."):]
   658  	inlIndex := 0
   659  	if genDwarfInline > 1 {
   660  		if n.InlFormal() || n.InlLocal() {
   661  			inlIndex = posInlIndex(n.Pos) + 1
   662  			if n.InlFormal() {
   663  				abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
   664  			}
   665  		}
   666  	}
   667  	declpos := Ctxt.InnermostPos(n.Pos)
   668  	dvar := &dwarf.Var{
   669  		Name:          n.Sym.Name,
   670  		IsReturnValue: n.Class() == PPARAMOUT,
   671  		IsInlFormal:   n.InlFormal(),
   672  		Abbrev:        abbrev,
   673  		Type:          Ctxt.Lookup(typename),
   674  		// The stack offset is used as a sorting key, so for decomposed
   675  		// variables just give it the first one. It's not used otherwise.
   676  		// This won't work well if the first slot hasn't been assigned a stack
   677  		// location, but it's not obvious how to do better.
   678  		StackOffset: stackOffset(debug.Slots[debug.VarSlots[varID][0]]),
   679  		DeclFile:    declpos.RelFilename(),
   680  		DeclLine:    declpos.RelLine(),
   681  		DeclCol:     declpos.Col(),
   682  		InlIndex:    int32(inlIndex),
   683  		ChildIndex:  -1,
   684  	}
   685  	list := debug.LocationLists[varID]
   686  	if len(list) != 0 {
   687  		dvar.PutLocationList = func(listSym, startPC dwarf.Sym) {
   688  			debug.PutLocationList(list, Ctxt, listSym.(*obj.LSym), startPC.(*obj.LSym))
   689  		}
   690  	}
   691  	return dvar
   692  }
   693  
   694  // fieldtrack adds R_USEFIELD relocations to fnsym to record any
   695  // struct fields that it used.
   696  func fieldtrack(fnsym *obj.LSym, tracked map[*types.Sym]struct{}) {
   697  	if fnsym == nil {
   698  		return
   699  	}
   700  	if objabi.Fieldtrack_enabled == 0 || len(tracked) == 0 {
   701  		return
   702  	}
   703  
   704  	trackSyms := make([]*types.Sym, 0, len(tracked))
   705  	for sym := range tracked {
   706  		trackSyms = append(trackSyms, sym)
   707  	}
   708  	sort.Sort(symByName(trackSyms))
   709  	for _, sym := range trackSyms {
   710  		r := obj.Addrel(fnsym)
   711  		r.Sym = sym.Linksym()
   712  		r.Type = objabi.R_USEFIELD
   713  	}
   714  }
   715  
   716  type symByName []*types.Sym
   717  
   718  func (a symByName) Len() int           { return len(a) }
   719  func (a symByName) Less(i, j int) bool { return a[i].Name < a[j].Name }
   720  func (a symByName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }