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