github.com/goproxy0/go@v0.0.0-20171111080102-49cc0c489d2c/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"
    17  	"math/rand"
    18  	"sort"
    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  		c := make(chan *Node, nBackendWorkers)
   283  		for i := 0; i < nBackendWorkers; i++ {
   284  			wg.Add(1)
   285  			go func(worker int) {
   286  				for fn := range c {
   287  					compileSSA(fn, worker)
   288  				}
   289  				wg.Done()
   290  			}(i)
   291  		}
   292  		for _, fn := range compilequeue {
   293  			c <- fn
   294  		}
   295  		close(c)
   296  		compilequeue = nil
   297  		wg.Wait()
   298  		sizeCalculationDisabled = false
   299  	}
   300  }
   301  
   302  func debuginfo(fnsym *obj.LSym, curfn interface{}) []dwarf.Scope {
   303  	fn := curfn.(*Node)
   304  	debugInfo := fn.Func.DebugInfo
   305  	fn.Func.DebugInfo = nil
   306  	if expect := fn.Func.Nname.Sym.Linksym(); fnsym != expect {
   307  		Fatalf("unexpected fnsym: %v != %v", fnsym, expect)
   308  	}
   309  
   310  	var automDecls []*Node
   311  	// Populate Automs for fn.
   312  	for _, n := range fn.Func.Dcl {
   313  		if n.Op != ONAME { // might be OTYPE or OLITERAL
   314  			continue
   315  		}
   316  		var name obj.AddrName
   317  		switch n.Class() {
   318  		case PAUTO:
   319  			if !n.Name.Used() {
   320  				Fatalf("debuginfo unused node (AllocFrame should truncate fn.Func.Dcl)")
   321  			}
   322  			name = obj.NAME_AUTO
   323  		case PPARAM, PPARAMOUT:
   324  			name = obj.NAME_PARAM
   325  		default:
   326  			continue
   327  		}
   328  		automDecls = append(automDecls, n)
   329  		gotype := ngotype(n).Linksym()
   330  		fnsym.Func.Autom = append(fnsym.Func.Autom, &obj.Auto{
   331  			Asym:    Ctxt.Lookup(n.Sym.Name),
   332  			Aoffset: int32(n.Xoffset),
   333  			Name:    name,
   334  			Gotype:  gotype,
   335  		})
   336  	}
   337  
   338  	var dwarfVars []*dwarf.Var
   339  	var decls []*Node
   340  	if Ctxt.Flag_locationlists && Ctxt.Flag_optimize {
   341  		decls, dwarfVars = createComplexVars(fnsym, debugInfo, automDecls)
   342  	} else {
   343  		decls, dwarfVars = createSimpleVars(automDecls)
   344  	}
   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  	return assembleScopes(fnsym, fn, dwarfVars, varScopes)
   369  }
   370  
   371  // createSimpleVars creates a DWARF entry for every variable declared in the
   372  // function, claiming that they are permanently on the stack.
   373  func createSimpleVars(automDecls []*Node) ([]*Node, []*dwarf.Var) {
   374  	var vars []*dwarf.Var
   375  	var decls []*Node
   376  	for _, n := range automDecls {
   377  		if n.IsAutoTmp() {
   378  			continue
   379  		}
   380  		var abbrev int
   381  		offs := n.Xoffset
   382  
   383  		switch n.Class() {
   384  		case PAUTO:
   385  			abbrev = dwarf.DW_ABRV_AUTO
   386  			if Ctxt.FixedFrameSize() == 0 {
   387  				offs -= int64(Widthptr)
   388  			}
   389  			if objabi.Framepointer_enabled(objabi.GOOS, objabi.GOARCH) {
   390  				offs -= int64(Widthptr)
   391  			}
   392  
   393  		case PPARAM, PPARAMOUT:
   394  			abbrev = dwarf.DW_ABRV_PARAM
   395  			offs += Ctxt.FixedFrameSize()
   396  		default:
   397  			Fatalf("createSimpleVars unexpected type %v for node %v", n.Class(), n)
   398  		}
   399  
   400  		typename := dwarf.InfoPrefix + typesymname(n.Type)
   401  		decls = append(decls, n)
   402  		vars = append(vars, &dwarf.Var{
   403  			Name:          n.Sym.Name,
   404  			IsReturnValue: n.Class() == PPARAMOUT,
   405  			Abbrev:        abbrev,
   406  			StackOffset:   int32(offs),
   407  			Type:          Ctxt.Lookup(typename),
   408  			DeclLine:      n.Pos.Line(),
   409  		})
   410  	}
   411  	return decls, vars
   412  }
   413  
   414  type varPart struct {
   415  	varOffset int64
   416  	slot      ssa.SlotID
   417  }
   418  
   419  func createComplexVars(fnsym *obj.LSym, debugInfo *ssa.FuncDebug, automDecls []*Node) ([]*Node, []*dwarf.Var) {
   420  	for _, blockDebug := range debugInfo.Blocks {
   421  		for _, locList := range blockDebug.Variables {
   422  			for _, loc := range locList.Locations {
   423  				if loc.StartProg != nil {
   424  					loc.StartPC = loc.StartProg.Pc
   425  				}
   426  				if loc.EndProg != nil {
   427  					loc.EndPC = loc.EndProg.Pc
   428  				} else {
   429  					loc.EndPC = fnsym.Size
   430  				}
   431  				if Debug_locationlist == 0 {
   432  					loc.EndProg = nil
   433  					loc.StartProg = nil
   434  				}
   435  			}
   436  		}
   437  	}
   438  
   439  	// Group SSA variables by the user variable they were decomposed from.
   440  	varParts := map[*Node][]varPart{}
   441  	ssaVars := make(map[*Node]bool)
   442  	for slotID, slot := range debugInfo.VarSlots {
   443  		for slot.SplitOf != nil {
   444  			slot = slot.SplitOf
   445  		}
   446  		n := slot.N.(*Node)
   447  		ssaVars[n] = true
   448  		varParts[n] = append(varParts[n], varPart{varOffset(slot), ssa.SlotID(slotID)})
   449  	}
   450  
   451  	// Produce a DWARF variable entry for each user variable.
   452  	// Don't iterate over the map -- that's nondeterministic, and
   453  	// createComplexVar has side effects. Instead, go by slot.
   454  	var decls []*Node
   455  	var vars []*dwarf.Var
   456  	for _, slot := range debugInfo.VarSlots {
   457  		for slot.SplitOf != nil {
   458  			slot = slot.SplitOf
   459  		}
   460  		n := slot.N.(*Node)
   461  		parts := varParts[n]
   462  		if parts == nil {
   463  			continue
   464  		}
   465  		// Don't work on this variable again, no matter how many slots it has.
   466  		delete(varParts, n)
   467  
   468  		// Get the order the parts need to be in to represent the memory
   469  		// of the decomposed user variable.
   470  		sort.Sort(partsByVarOffset(parts))
   471  
   472  		if dvar := createComplexVar(debugInfo, n, parts); dvar != nil {
   473  			decls = append(decls, n)
   474  			vars = append(vars, dvar)
   475  		}
   476  	}
   477  
   478  	// The machinery above will create a dwarf.Var for only those
   479  	// variables that are decomposed into SSA names. Fill in the list
   480  	// with entries for the remaining variables (including things too
   481  	// big to decompose). Since optimization is enabled, the recipe
   482  	// below creates a conservative location. The idea here is that we
   483  	// want to communicate to the user that "yes, there is a variable
   484  	// named X in this function, but no, I don't have enough
   485  	// information to reliably report its contents."
   486  	for _, n := range automDecls {
   487  		if _, found := ssaVars[n]; found {
   488  			continue
   489  		}
   490  		c := n.Sym.Name[0]
   491  		if c == '~' || c == '.' {
   492  			continue
   493  		}
   494  		typename := dwarf.InfoPrefix + typesymname(n.Type)
   495  		decls = append(decls, n)
   496  		abbrev := dwarf.DW_ABRV_AUTO_LOCLIST
   497  		if n.Class() == PPARAM || n.Class() == PPARAMOUT {
   498  			abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
   499  		}
   500  		vars = append(vars, &dwarf.Var{
   501  			Name:          n.Sym.Name,
   502  			IsReturnValue: n.Class() == PPARAMOUT,
   503  			Abbrev:        abbrev,
   504  			StackOffset:   int32(n.Xoffset),
   505  			Type:          Ctxt.Lookup(typename),
   506  			DeclLine:      n.Pos.Line(),
   507  		})
   508  	}
   509  
   510  	return decls, vars
   511  }
   512  
   513  // varOffset returns the offset of slot within the user variable it was
   514  // decomposed from. This has nothing to do with its stack offset.
   515  func varOffset(slot *ssa.LocalSlot) int64 {
   516  	offset := slot.Off
   517  	for ; slot.SplitOf != nil; slot = slot.SplitOf {
   518  		offset += slot.SplitOffset
   519  	}
   520  	return offset
   521  }
   522  
   523  type partsByVarOffset []varPart
   524  
   525  func (a partsByVarOffset) Len() int           { return len(a) }
   526  func (a partsByVarOffset) Less(i, j int) bool { return a[i].varOffset < a[j].varOffset }
   527  func (a partsByVarOffset) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
   528  
   529  // stackOffset returns the stack location of a LocalSlot relative to the
   530  // stack pointer, suitable for use in a DWARF location entry. This has nothing
   531  // to do with its offset in the user variable.
   532  func stackOffset(slot *ssa.LocalSlot) int32 {
   533  	n := slot.N.(*Node)
   534  	var base int64
   535  	switch n.Class() {
   536  	case PAUTO:
   537  		if Ctxt.FixedFrameSize() == 0 {
   538  			base -= int64(Widthptr)
   539  		}
   540  		if objabi.Framepointer_enabled(objabi.GOOS, objabi.GOARCH) {
   541  			base -= int64(Widthptr)
   542  		}
   543  	case PPARAM, PPARAMOUT:
   544  		base += Ctxt.FixedFrameSize()
   545  	}
   546  	return int32(base + n.Xoffset + slot.Off)
   547  }
   548  
   549  // createComplexVar builds a DWARF variable entry and location list representing n.
   550  func createComplexVar(debugInfo *ssa.FuncDebug, n *Node, parts []varPart) *dwarf.Var {
   551  	slots := debugInfo.Slots
   552  	var offs int64 // base stack offset for this kind of variable
   553  	var abbrev int
   554  	switch n.Class() {
   555  	case PAUTO:
   556  		abbrev = dwarf.DW_ABRV_AUTO_LOCLIST
   557  		if Ctxt.FixedFrameSize() == 0 {
   558  			offs -= int64(Widthptr)
   559  		}
   560  		if objabi.Framepointer_enabled(objabi.GOOS, objabi.GOARCH) {
   561  			offs -= int64(Widthptr)
   562  		}
   563  
   564  	case PPARAM, PPARAMOUT:
   565  		abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
   566  		offs += Ctxt.FixedFrameSize()
   567  	default:
   568  		return nil
   569  	}
   570  
   571  	gotype := ngotype(n).Linksym()
   572  	typename := dwarf.InfoPrefix + gotype.Name[len("type."):]
   573  	dvar := &dwarf.Var{
   574  		Name:   n.Sym.Name,
   575  		Abbrev: abbrev,
   576  		Type:   Ctxt.Lookup(typename),
   577  		// The stack offset is used as a sorting key, so for decomposed
   578  		// variables just give it the lowest one. It's not used otherwise.
   579  		// This won't work well if the first slot hasn't been assigned a stack
   580  		// location, but it's not obvious how to do better.
   581  		StackOffset: int32(stackOffset(slots[parts[0].slot])),
   582  		DeclLine:    n.Pos.Line(),
   583  	}
   584  
   585  	if Debug_locationlist != 0 {
   586  		Ctxt.Logf("Building location list for %+v. Parts:\n", n)
   587  		for _, part := range parts {
   588  			Ctxt.Logf("\t%v => %v\n", debugInfo.Slots[part.slot], debugInfo.SlotLocsString(part.slot))
   589  		}
   590  	}
   591  
   592  	// Given a variable that's been decomposed into multiple parts,
   593  	// its location list may need a new entry after the beginning or
   594  	// end of every location entry for each of its parts. For example:
   595  	//
   596  	// [variable]    [pc range]
   597  	// string.ptr    |----|-----|    |----|
   598  	// string.len    |------------|  |--|
   599  	// ... needs a location list like:
   600  	// string        |----|-----|-|  |--|-|
   601  	//
   602  	// Note that location entries may or may not line up with each other,
   603  	// and some of the result will only have one or the other part.
   604  	//
   605  	// To build the resulting list:
   606  	// - keep a "current" pointer for each part
   607  	// - find the next transition point
   608  	// - advance the current pointer for each part up to that transition point
   609  	// - build the piece for the range between that transition point and the next
   610  	// - repeat
   611  
   612  	type locID struct {
   613  		block int
   614  		loc   int
   615  	}
   616  	findLoc := func(part varPart, id locID) *ssa.VarLoc {
   617  		if id.block >= len(debugInfo.Blocks) {
   618  			return nil
   619  		}
   620  		return debugInfo.Blocks[id.block].Variables[part.slot].Locations[id.loc]
   621  	}
   622  	nextLoc := func(part varPart, id locID) (locID, *ssa.VarLoc) {
   623  		// Check if there's another loc in this block
   624  		id.loc++
   625  		if b := debugInfo.Blocks[id.block]; b != nil && id.loc < len(b.Variables[part.slot].Locations) {
   626  			return id, findLoc(part, id)
   627  		}
   628  		// Find the next block that has a loc for this part.
   629  		id.loc = 0
   630  		id.block++
   631  		for ; id.block < len(debugInfo.Blocks); id.block++ {
   632  			if b := debugInfo.Blocks[id.block]; b != nil && len(b.Variables[part.slot].Locations) != 0 {
   633  				return id, findLoc(part, id)
   634  			}
   635  		}
   636  		return id, nil
   637  	}
   638  	curLoc := make([]locID, len(slots))
   639  	// Position each pointer at the first entry for its slot.
   640  	for _, part := range parts {
   641  		if b := debugInfo.Blocks[0]; b != nil && len(b.Variables[part.slot].Locations) != 0 {
   642  			// Block 0 has an entry; no need to advance.
   643  			continue
   644  		}
   645  		curLoc[part.slot], _ = nextLoc(part, curLoc[part.slot])
   646  	}
   647  
   648  	// findBoundaryAfter finds the next beginning or end of a piece after currentPC.
   649  	findBoundaryAfter := func(currentPC int64) int64 {
   650  		min := int64(math.MaxInt64)
   651  		for _, part := range parts {
   652  			// For each part, find the first PC greater than current. Doesn't
   653  			// matter if it's a start or an end, since we're looking for any boundary.
   654  			// If it's the new winner, save it.
   655  		onePart:
   656  			for i, loc := curLoc[part.slot], findLoc(part, curLoc[part.slot]); loc != nil; i, loc = nextLoc(part, i) {
   657  				for _, pc := range [2]int64{loc.StartPC, loc.EndPC} {
   658  					if pc > currentPC {
   659  						if pc < min {
   660  							min = pc
   661  						}
   662  						break onePart
   663  					}
   664  				}
   665  			}
   666  		}
   667  		return min
   668  	}
   669  	var start int64
   670  	end := findBoundaryAfter(0)
   671  	for {
   672  		// Advance to the next chunk.
   673  		start = end
   674  		end = findBoundaryAfter(start)
   675  		if end == math.MaxInt64 {
   676  			break
   677  		}
   678  
   679  		dloc := dwarf.Location{StartPC: start, EndPC: end}
   680  		if Debug_locationlist != 0 {
   681  			Ctxt.Logf("Processing range %x -> %x\n", start, end)
   682  		}
   683  
   684  		// Advance curLoc to the last location that starts before/at start.
   685  		// After this loop, if there's a location that covers [start, end), it will be current.
   686  		// Otherwise the current piece will be too early.
   687  		for _, part := range parts {
   688  			choice := locID{-1, -1}
   689  			for i, loc := curLoc[part.slot], findLoc(part, curLoc[part.slot]); loc != nil; i, loc = nextLoc(part, i) {
   690  				if loc.StartPC > start {
   691  					break //overshot
   692  				}
   693  				choice = i // best yet
   694  			}
   695  			if choice.block != -1 {
   696  				curLoc[part.slot] = choice
   697  			}
   698  			if Debug_locationlist != 0 {
   699  				Ctxt.Logf("\t %v => %v", slots[part.slot], curLoc[part.slot])
   700  			}
   701  		}
   702  		if Debug_locationlist != 0 {
   703  			Ctxt.Logf("\n")
   704  		}
   705  		// Assemble the location list entry for this chunk.
   706  		present := 0
   707  		for _, part := range parts {
   708  			dpiece := dwarf.Piece{
   709  				Length: slots[part.slot].Type.Size(),
   710  			}
   711  			loc := findLoc(part, curLoc[part.slot])
   712  			if loc == nil || start >= loc.EndPC || end <= loc.StartPC {
   713  				if Debug_locationlist != 0 {
   714  					Ctxt.Logf("\t%v: missing", slots[part.slot])
   715  				}
   716  				dpiece.Missing = true
   717  				dloc.Pieces = append(dloc.Pieces, dpiece)
   718  				continue
   719  			}
   720  			present++
   721  			if Debug_locationlist != 0 {
   722  				Ctxt.Logf("\t%v: %v", slots[part.slot], debugInfo.Blocks[curLoc[part.slot].block].LocString(loc))
   723  			}
   724  			if loc.OnStack {
   725  				dpiece.OnStack = true
   726  				dpiece.StackOffset = stackOffset(slots[loc.StackLocation])
   727  			} else {
   728  				for reg := 0; reg < len(debugInfo.Registers); reg++ {
   729  					if loc.Registers&(1<<uint8(reg)) != 0 {
   730  						dpiece.RegNum = Ctxt.Arch.DWARFRegisters[debugInfo.Registers[reg].ObjNum()]
   731  					}
   732  				}
   733  			}
   734  			dloc.Pieces = append(dloc.Pieces, dpiece)
   735  		}
   736  		if present == 0 {
   737  			if Debug_locationlist != 0 {
   738  				Ctxt.Logf(" -> totally missing\n")
   739  			}
   740  			continue
   741  		}
   742  		// Extend the previous entry if possible.
   743  		if len(dvar.LocationList) > 0 {
   744  			prev := &dvar.LocationList[len(dvar.LocationList)-1]
   745  			if prev.EndPC == dloc.StartPC && len(prev.Pieces) == len(dloc.Pieces) {
   746  				equal := true
   747  				for i := range prev.Pieces {
   748  					if prev.Pieces[i] != dloc.Pieces[i] {
   749  						equal = false
   750  					}
   751  				}
   752  				if equal {
   753  					prev.EndPC = end
   754  					if Debug_locationlist != 0 {
   755  						Ctxt.Logf("-> merged with previous, now %#v\n", prev)
   756  					}
   757  					continue
   758  				}
   759  			}
   760  		}
   761  		dvar.LocationList = append(dvar.LocationList, dloc)
   762  		if Debug_locationlist != 0 {
   763  			Ctxt.Logf("-> added: %#v\n", dloc)
   764  		}
   765  	}
   766  	return dvar
   767  }
   768  
   769  // fieldtrack adds R_USEFIELD relocations to fnsym to record any
   770  // struct fields that it used.
   771  func fieldtrack(fnsym *obj.LSym, tracked map[*types.Sym]struct{}) {
   772  	if fnsym == nil {
   773  		return
   774  	}
   775  	if objabi.Fieldtrack_enabled == 0 || len(tracked) == 0 {
   776  		return
   777  	}
   778  
   779  	trackSyms := make([]*types.Sym, 0, len(tracked))
   780  	for sym := range tracked {
   781  		trackSyms = append(trackSyms, sym)
   782  	}
   783  	sort.Sort(symByName(trackSyms))
   784  	for _, sym := range trackSyms {
   785  		r := obj.Addrel(fnsym)
   786  		r.Sym = sym.Linksym()
   787  		r.Type = objabi.R_USEFIELD
   788  	}
   789  }
   790  
   791  type symByName []*types.Sym
   792  
   793  func (a symByName) Len() int           { return len(a) }
   794  func (a symByName) Less(i, j int) bool { return a[i].Name < a[j].Name }
   795  func (a symByName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }