...

Source file src/pkg/cmd/compile/internal/gc/pgen.go

     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		"internal/race"
    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(fn *Node) {
    31		if fn.funcname() == "_" {
    32			return
    33		}
    34		sym := lookup(fmt.Sprintf("%s.args_stackmap", fn.funcname()))
    35		lsym := sym.Linksym()
    36	
    37		nptr := int(fn.Type.ArgWidth() / int64(Widthptr))
    38		bv := bvalloc(int32(nptr) * 2)
    39		nbitmap := 1
    40		if fn.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 fn.IsMethod() {
    47			onebitwalktype1(fn.Type.Recvs(), 0, bv)
    48		}
    49		if fn.Type.NumParams() > 0 {
    50			onebitwalktype1(fn.Type.Params(), 0, bv)
    51		}
    52		off = dbvec(lsym, off, bv)
    53	
    54		if fn.Type.NumResults() > 0 {
    55			onebitwalktype1(fn.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		lastHasPtr := false
   158		for i, n := range fn.Dcl {
   159			if n.Op != ONAME || n.Class() != PAUTO {
   160				continue
   161			}
   162			if !n.Name.Used() {
   163				fn.Dcl = fn.Dcl[:i]
   164				break
   165			}
   166	
   167			dowidth(n.Type)
   168			w := n.Type.Width
   169			if w >= thearch.MAXWIDTH || w < 0 {
   170				Fatalf("bad width")
   171			}
   172			if w == 0 && lastHasPtr {
   173				// Pad between a pointer-containing object and a zero-sized object.
   174				// This prevents a pointer to the zero-sized object from being interpreted
   175				// as a pointer to the pointer-containing object (and causing it
   176				// to be scanned when it shouldn't be). See issue 24993.
   177				w = 1
   178			}
   179			s.stksize += w
   180			s.stksize = Rnd(s.stksize, int64(n.Type.Align))
   181			if types.Haspointers(n.Type) {
   182				s.stkptrsize = s.stksize
   183				lastHasPtr = true
   184			} else {
   185				lastHasPtr = false
   186			}
   187			if thearch.LinkArch.InFamily(sys.MIPS, sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64, sys.S390X) {
   188				s.stksize = Rnd(s.stksize, int64(Widthptr))
   189			}
   190			n.Xoffset = -s.stksize
   191		}
   192	
   193		s.stksize = Rnd(s.stksize, int64(Widthreg))
   194		s.stkptrsize = Rnd(s.stkptrsize, int64(Widthreg))
   195	}
   196	
   197	func funccompile(fn *Node) {
   198		if Curfn != nil {
   199			Fatalf("funccompile %v inside %v", fn.Func.Nname.Sym, Curfn.Func.Nname.Sym)
   200		}
   201	
   202		if fn.Type == nil {
   203			if nerrors == 0 {
   204				Fatalf("funccompile missing type")
   205			}
   206			return
   207		}
   208	
   209		// assign parameter offsets
   210		dowidth(fn.Type)
   211	
   212		if fn.Nbody.Len() == 0 {
   213			// Initialize ABI wrappers if necessary.
   214			fn.Func.initLSym(false)
   215			emitptrargsmap(fn)
   216			return
   217		}
   218	
   219		dclcontext = PAUTO
   220		Curfn = fn
   221	
   222		compile(fn)
   223	
   224		Curfn = nil
   225		dclcontext = PEXTERN
   226	}
   227	
   228	func compile(fn *Node) {
   229		saveerrors()
   230	
   231		order(fn)
   232		if nerrors != 0 {
   233			return
   234		}
   235	
   236		walk(fn)
   237		if nerrors != 0 {
   238			return
   239		}
   240		if instrumenting {
   241			instrument(fn)
   242		}
   243	
   244		// From this point, there should be no uses of Curfn. Enforce that.
   245		Curfn = nil
   246	
   247		if fn.funcname() == "_" {
   248			// We don't need to generate code for this function, just report errors in its body.
   249			// At this point we've generated any errors needed.
   250			// (Beyond here we generate only non-spec errors, like "stack frame too large".)
   251			// See issue 29870.
   252			return
   253		}
   254	
   255		// Set up the function's LSym early to avoid data races with the assemblers.
   256		fn.Func.initLSym(true)
   257	
   258		// Make sure type syms are declared for all types that might
   259		// be types of stack objects. We need to do this here
   260		// because symbols must be allocated before the parallel
   261		// phase of the compiler.
   262		for _, n := range fn.Func.Dcl {
   263			switch n.Class() {
   264			case PPARAM, PPARAMOUT, PAUTO:
   265				if livenessShouldTrack(n) && n.Addrtaken() {
   266					dtypesym(n.Type)
   267					// Also make sure we allocate a linker symbol
   268					// for the stack object data, for the same reason.
   269					if fn.Func.lsym.Func.StackObjects == nil {
   270						fn.Func.lsym.Func.StackObjects = Ctxt.Lookup(fn.Func.lsym.Name + ".stkobj")
   271					}
   272				}
   273			}
   274		}
   275	
   276		if compilenow() {
   277			compileSSA(fn, 0)
   278		} else {
   279			compilequeue = append(compilequeue, fn)
   280		}
   281	}
   282	
   283	// compilenow reports whether to compile immediately.
   284	// If functions are not compiled immediately,
   285	// they are enqueued in compilequeue,
   286	// which is drained by compileFunctions.
   287	func compilenow() bool {
   288		return nBackendWorkers == 1 && Debug_compilelater == 0
   289	}
   290	
   291	const maxStackSize = 1 << 30
   292	
   293	// compileSSA builds an SSA backend function,
   294	// uses it to generate a plist,
   295	// and flushes that plist to machine code.
   296	// worker indicates which of the backend workers is doing the processing.
   297	func compileSSA(fn *Node, worker int) {
   298		f := buildssa(fn, worker)
   299		// Note: check arg size to fix issue 25507.
   300		if f.Frontend().(*ssafn).stksize >= maxStackSize || fn.Type.ArgWidth() >= maxStackSize {
   301			largeStackFramesMu.Lock()
   302			largeStackFrames = append(largeStackFrames, largeStack{locals: f.Frontend().(*ssafn).stksize, args: fn.Type.ArgWidth(), pos: fn.Pos})
   303			largeStackFramesMu.Unlock()
   304			return
   305		}
   306		pp := newProgs(fn, worker)
   307		defer pp.Free()
   308		genssa(f, pp)
   309		// Check frame size again.
   310		// The check above included only the space needed for local variables.
   311		// After genssa, the space needed includes local variables and the callee arg region.
   312		// We must do this check prior to calling pp.Flush.
   313		// If there are any oversized stack frames,
   314		// the assembler may emit inscrutable complaints about invalid instructions.
   315		if pp.Text.To.Offset >= maxStackSize {
   316			largeStackFramesMu.Lock()
   317			locals := f.Frontend().(*ssafn).stksize
   318			largeStackFrames = append(largeStackFrames, largeStack{locals: locals, args: fn.Type.ArgWidth(), callee: pp.Text.To.Offset - locals, pos: fn.Pos})
   319			largeStackFramesMu.Unlock()
   320			return
   321		}
   322	
   323		pp.Flush() // assemble, fill in boilerplate, etc.
   324		// fieldtrack must be called after pp.Flush. See issue 20014.
   325		fieldtrack(pp.Text.From.Sym, fn.Func.FieldTrack)
   326	}
   327	
   328	func init() {
   329		if race.Enabled {
   330			rand.Seed(time.Now().UnixNano())
   331		}
   332	}
   333	
   334	// compileFunctions compiles all functions in compilequeue.
   335	// It fans out nBackendWorkers to do the work
   336	// and waits for them to complete.
   337	func compileFunctions() {
   338		if len(compilequeue) != 0 {
   339			sizeCalculationDisabled = true // not safe to calculate sizes concurrently
   340			if race.Enabled {
   341				// Randomize compilation order to try to shake out races.
   342				tmp := make([]*Node, len(compilequeue))
   343				perm := rand.Perm(len(compilequeue))
   344				for i, v := range perm {
   345					tmp[v] = compilequeue[i]
   346				}
   347				copy(compilequeue, tmp)
   348			} else {
   349				// Compile the longest functions first,
   350				// since they're most likely to be the slowest.
   351				// This helps avoid stragglers.
   352				sort.Slice(compilequeue, func(i, j int) bool {
   353					return compilequeue[i].Nbody.Len() > compilequeue[j].Nbody.Len()
   354				})
   355			}
   356			var wg sync.WaitGroup
   357			Ctxt.InParallel = true
   358			c := make(chan *Node, nBackendWorkers)
   359			for i := 0; i < nBackendWorkers; i++ {
   360				wg.Add(1)
   361				go func(worker int) {
   362					for fn := range c {
   363						compileSSA(fn, worker)
   364					}
   365					wg.Done()
   366				}(i)
   367			}
   368			for _, fn := range compilequeue {
   369				c <- fn
   370			}
   371			close(c)
   372			compilequeue = nil
   373			wg.Wait()
   374			Ctxt.InParallel = false
   375			sizeCalculationDisabled = false
   376		}
   377	}
   378	
   379	func debuginfo(fnsym *obj.LSym, curfn interface{}) ([]dwarf.Scope, dwarf.InlCalls) {
   380		fn := curfn.(*Node)
   381		if fn.Func.Nname != nil {
   382			if expect := fn.Func.Nname.Sym.Linksym(); fnsym != expect {
   383				Fatalf("unexpected fnsym: %v != %v", fnsym, expect)
   384			}
   385		}
   386	
   387		var automDecls []*Node
   388		// Populate Automs for fn.
   389		for _, n := range fn.Func.Dcl {
   390			if n.Op != ONAME { // might be OTYPE or OLITERAL
   391				continue
   392			}
   393			var name obj.AddrName
   394			switch n.Class() {
   395			case PAUTO:
   396				if !n.Name.Used() {
   397					// Text == nil -> generating abstract function
   398					if fnsym.Func.Text != nil {
   399						Fatalf("debuginfo unused node (AllocFrame should truncate fn.Func.Dcl)")
   400					}
   401					continue
   402				}
   403				name = obj.NAME_AUTO
   404			case PPARAM, PPARAMOUT:
   405				name = obj.NAME_PARAM
   406			default:
   407				continue
   408			}
   409			automDecls = append(automDecls, n)
   410			gotype := ngotype(n).Linksym()
   411			fnsym.Func.Autom = append(fnsym.Func.Autom, &obj.Auto{
   412				Asym:    Ctxt.Lookup(n.Sym.Name),
   413				Aoffset: int32(n.Xoffset),
   414				Name:    name,
   415				Gotype:  gotype,
   416			})
   417		}
   418	
   419		decls, dwarfVars := createDwarfVars(fnsym, fn.Func, automDecls)
   420	
   421		var varScopes []ScopeID
   422		for _, decl := range decls {
   423			pos := decl.Pos
   424			if decl.Name.Defn != nil && (decl.Name.Captured() || decl.Name.Byval()) {
   425				// It's not clear which position is correct for captured variables here:
   426				// * decl.Pos is the wrong position for captured variables, in the inner
   427				//   function, but it is the right position in the outer function.
   428				// * decl.Name.Defn is nil for captured variables that were arguments
   429				//   on the outer function, however the decl.Pos for those seems to be
   430				//   correct.
   431				// * decl.Name.Defn is the "wrong" thing for variables declared in the
   432				//   header of a type switch, it's their position in the header, rather
   433				//   than the position of the case statement. In principle this is the
   434				//   right thing, but here we prefer the latter because it makes each
   435				//   instance of the header variable local to the lexical block of its
   436				//   case statement.
   437				// This code is probably wrong for type switch variables that are also
   438				// captured.
   439				pos = decl.Name.Defn.Pos
   440			}
   441			varScopes = append(varScopes, findScope(fn.Func.Marks, pos))
   442		}
   443	
   444		scopes := assembleScopes(fnsym, fn, dwarfVars, varScopes)
   445		var inlcalls dwarf.InlCalls
   446		if genDwarfInline > 0 {
   447			inlcalls = assembleInlines(fnsym, dwarfVars)
   448		}
   449		return scopes, inlcalls
   450	}
   451	
   452	// createSimpleVars creates a DWARF entry for every variable declared in the
   453	// function, claiming that they are permanently on the stack.
   454	func createSimpleVars(automDecls []*Node) ([]*Node, []*dwarf.Var, map[*Node]bool) {
   455		var vars []*dwarf.Var
   456		var decls []*Node
   457		selected := make(map[*Node]bool)
   458		for _, n := range automDecls {
   459			if n.IsAutoTmp() {
   460				continue
   461			}
   462	
   463			decls = append(decls, n)
   464			vars = append(vars, createSimpleVar(n))
   465			selected[n] = true
   466		}
   467		return decls, vars, selected
   468	}
   469	
   470	func createSimpleVar(n *Node) *dwarf.Var {
   471		var abbrev int
   472		offs := n.Xoffset
   473	
   474		switch n.Class() {
   475		case PAUTO:
   476			abbrev = dwarf.DW_ABRV_AUTO
   477			if Ctxt.FixedFrameSize() == 0 {
   478				offs -= int64(Widthptr)
   479			}
   480			if objabi.Framepointer_enabled(objabi.GOOS, objabi.GOARCH) || objabi.GOARCH == "arm64" {
   481				// There is a word space for FP on ARM64 even if the frame pointer is disabled
   482				offs -= int64(Widthptr)
   483			}
   484	
   485		case PPARAM, PPARAMOUT:
   486			abbrev = dwarf.DW_ABRV_PARAM
   487			offs += Ctxt.FixedFrameSize()
   488		default:
   489			Fatalf("createSimpleVar unexpected class %v for node %v", n.Class(), n)
   490		}
   491	
   492		typename := dwarf.InfoPrefix + typesymname(n.Type)
   493		inlIndex := 0
   494		if genDwarfInline > 1 {
   495			if n.InlFormal() || n.InlLocal() {
   496				inlIndex = posInlIndex(n.Pos) + 1
   497				if n.InlFormal() {
   498					abbrev = dwarf.DW_ABRV_PARAM
   499				}
   500			}
   501		}
   502		declpos := Ctxt.InnermostPos(n.Pos)
   503		return &dwarf.Var{
   504			Name:          n.Sym.Name,
   505			IsReturnValue: n.Class() == PPARAMOUT,
   506			IsInlFormal:   n.InlFormal(),
   507			Abbrev:        abbrev,
   508			StackOffset:   int32(offs),
   509			Type:          Ctxt.Lookup(typename),
   510			DeclFile:      declpos.RelFilename(),
   511			DeclLine:      declpos.RelLine(),
   512			DeclCol:       declpos.Col(),
   513			InlIndex:      int32(inlIndex),
   514			ChildIndex:    -1,
   515		}
   516	}
   517	
   518	// createComplexVars creates recomposed DWARF vars with location lists,
   519	// suitable for describing optimized code.
   520	func createComplexVars(fn *Func) ([]*Node, []*dwarf.Var, map[*Node]bool) {
   521		debugInfo := fn.DebugInfo
   522	
   523		// Produce a DWARF variable entry for each user variable.
   524		var decls []*Node
   525		var vars []*dwarf.Var
   526		ssaVars := make(map[*Node]bool)
   527	
   528		for varID, dvar := range debugInfo.Vars {
   529			n := dvar.(*Node)
   530			ssaVars[n] = true
   531			for _, slot := range debugInfo.VarSlots[varID] {
   532				ssaVars[debugInfo.Slots[slot].N.(*Node)] = true
   533			}
   534	
   535			if dvar := createComplexVar(fn, ssa.VarID(varID)); dvar != nil {
   536				decls = append(decls, n)
   537				vars = append(vars, dvar)
   538			}
   539		}
   540	
   541		return decls, vars, ssaVars
   542	}
   543	
   544	// createDwarfVars process fn, returning a list of DWARF variables and the
   545	// Nodes they represent.
   546	func createDwarfVars(fnsym *obj.LSym, fn *Func, automDecls []*Node) ([]*Node, []*dwarf.Var) {
   547		// Collect a raw list of DWARF vars.
   548		var vars []*dwarf.Var
   549		var decls []*Node
   550		var selected map[*Node]bool
   551		if Ctxt.Flag_locationlists && Ctxt.Flag_optimize && fn.DebugInfo != nil {
   552			decls, vars, selected = createComplexVars(fn)
   553		} else {
   554			decls, vars, selected = createSimpleVars(automDecls)
   555		}
   556	
   557		dcl := automDecls
   558		if fnsym.WasInlined() {
   559			dcl = preInliningDcls(fnsym)
   560		}
   561	
   562		// If optimization is enabled, the list above will typically be
   563		// missing some of the original pre-optimization variables in the
   564		// function (they may have been promoted to registers, folded into
   565		// constants, dead-coded away, etc).  Input arguments not eligible
   566		// for SSA optimization are also missing.  Here we add back in entries
   567		// for selected missing vars. Note that the recipe below creates a
   568		// conservative location. The idea here is that we want to
   569		// communicate to the user that "yes, there is a variable named X
   570		// in this function, but no, I don't have enough information to
   571		// reliably report its contents."
   572		// For non-SSA-able arguments, however, the correct information
   573		// is known -- they have a single home on the stack.
   574		for _, n := range dcl {
   575			if _, found := selected[n]; found {
   576				continue
   577			}
   578			c := n.Sym.Name[0]
   579			if c == '.' || n.Type.IsUntyped() {
   580				continue
   581			}
   582			if n.Class() == PPARAM && !canSSAType(n.Type) {
   583				// SSA-able args get location lists, and may move in and
   584				// out of registers, so those are handled elsewhere.
   585				// Autos and named output params seem to get handled
   586				// with VARDEF, which creates location lists.
   587				// Args not of SSA-able type are treated here; they
   588				// are homed on the stack in a single place for the
   589				// entire call.
   590				vars = append(vars, createSimpleVar(n))
   591				decls = append(decls, n)
   592				continue
   593			}
   594			typename := dwarf.InfoPrefix + typesymname(n.Type)
   595			decls = append(decls, n)
   596			abbrev := dwarf.DW_ABRV_AUTO_LOCLIST
   597			isReturnValue := (n.Class() == PPARAMOUT)
   598			if n.Class() == PPARAM || n.Class() == PPARAMOUT {
   599				abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
   600			} else if n.Class() == PAUTOHEAP {
   601				// If dcl in question has been promoted to heap, do a bit
   602				// of extra work to recover original class (auto or param);
   603				// see issue 30908. This insures that we get the proper
   604				// signature in the abstract function DIE, but leaves a
   605				// misleading location for the param (we want pointer-to-heap
   606				// and not stack).
   607				// TODO(thanm): generate a better location expression
   608				stackcopy := n.Name.Param.Stackcopy
   609				if stackcopy != nil && (stackcopy.Class() == PPARAM || stackcopy.Class() == PPARAMOUT) {
   610					abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
   611					isReturnValue = (stackcopy.Class() == PPARAMOUT)
   612				}
   613			}
   614			inlIndex := 0
   615			if genDwarfInline > 1 {
   616				if n.InlFormal() || n.InlLocal() {
   617					inlIndex = posInlIndex(n.Pos) + 1
   618					if n.InlFormal() {
   619						abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
   620					}
   621				}
   622			}
   623			declpos := Ctxt.InnermostPos(n.Pos)
   624			vars = append(vars, &dwarf.Var{
   625				Name:          n.Sym.Name,
   626				IsReturnValue: isReturnValue,
   627				Abbrev:        abbrev,
   628				StackOffset:   int32(n.Xoffset),
   629				Type:          Ctxt.Lookup(typename),
   630				DeclFile:      declpos.RelFilename(),
   631				DeclLine:      declpos.RelLine(),
   632				DeclCol:       declpos.Col(),
   633				InlIndex:      int32(inlIndex),
   634				ChildIndex:    -1,
   635			})
   636			// Append a "deleted auto" entry to the autom list so as to
   637			// insure that the type in question is picked up by the linker.
   638			// See issue 22941.
   639			gotype := ngotype(n).Linksym()
   640			fnsym.Func.Autom = append(fnsym.Func.Autom, &obj.Auto{
   641				Asym:    Ctxt.Lookup(n.Sym.Name),
   642				Aoffset: int32(-1),
   643				Name:    obj.NAME_DELETED_AUTO,
   644				Gotype:  gotype,
   645			})
   646	
   647		}
   648	
   649		return decls, vars
   650	}
   651	
   652	// Given a function that was inlined at some point during the
   653	// compilation, return a sorted list of nodes corresponding to the
   654	// autos/locals in that function prior to inlining. If this is a
   655	// function that is not local to the package being compiled, then the
   656	// names of the variables may have been "versioned" to avoid conflicts
   657	// with local vars; disregard this versioning when sorting.
   658	func preInliningDcls(fnsym *obj.LSym) []*Node {
   659		fn := Ctxt.DwFixups.GetPrecursorFunc(fnsym).(*Node)
   660		var rdcl []*Node
   661		for _, n := range fn.Func.Inl.Dcl {
   662			c := n.Sym.Name[0]
   663			// Avoid reporting "_" parameters, since if there are more than
   664			// one, it can result in a collision later on, as in #23179.
   665			if unversion(n.Sym.Name) == "_" || c == '.' || n.Type.IsUntyped() {
   666				continue
   667			}
   668			rdcl = append(rdcl, n)
   669		}
   670		return rdcl
   671	}
   672	
   673	// stackOffset returns the stack location of a LocalSlot relative to the
   674	// stack pointer, suitable for use in a DWARF location entry. This has nothing
   675	// to do with its offset in the user variable.
   676	func stackOffset(slot ssa.LocalSlot) int32 {
   677		n := slot.N.(*Node)
   678		var base int64
   679		switch n.Class() {
   680		case PAUTO:
   681			if Ctxt.FixedFrameSize() == 0 {
   682				base -= int64(Widthptr)
   683			}
   684			if objabi.Framepointer_enabled(objabi.GOOS, objabi.GOARCH) || objabi.GOARCH == "arm64" {
   685				// There is a word space for FP on ARM64 even if the frame pointer is disabled
   686				base -= int64(Widthptr)
   687			}
   688		case PPARAM, PPARAMOUT:
   689			base += Ctxt.FixedFrameSize()
   690		}
   691		return int32(base + n.Xoffset + slot.Off)
   692	}
   693	
   694	// createComplexVar builds a single DWARF variable entry and location list.
   695	func createComplexVar(fn *Func, varID ssa.VarID) *dwarf.Var {
   696		debug := fn.DebugInfo
   697		n := debug.Vars[varID].(*Node)
   698	
   699		var abbrev int
   700		switch n.Class() {
   701		case PAUTO:
   702			abbrev = dwarf.DW_ABRV_AUTO_LOCLIST
   703		case PPARAM, PPARAMOUT:
   704			abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
   705		default:
   706			return nil
   707		}
   708	
   709		gotype := ngotype(n).Linksym()
   710		typename := dwarf.InfoPrefix + gotype.Name[len("type."):]
   711		inlIndex := 0
   712		if genDwarfInline > 1 {
   713			if n.InlFormal() || n.InlLocal() {
   714				inlIndex = posInlIndex(n.Pos) + 1
   715				if n.InlFormal() {
   716					abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
   717				}
   718			}
   719		}
   720		declpos := Ctxt.InnermostPos(n.Pos)
   721		dvar := &dwarf.Var{
   722			Name:          n.Sym.Name,
   723			IsReturnValue: n.Class() == PPARAMOUT,
   724			IsInlFormal:   n.InlFormal(),
   725			Abbrev:        abbrev,
   726			Type:          Ctxt.Lookup(typename),
   727			// The stack offset is used as a sorting key, so for decomposed
   728			// variables just give it the first one. It's not used otherwise.
   729			// This won't work well if the first slot hasn't been assigned a stack
   730			// location, but it's not obvious how to do better.
   731			StackOffset: stackOffset(debug.Slots[debug.VarSlots[varID][0]]),
   732			DeclFile:    declpos.RelFilename(),
   733			DeclLine:    declpos.RelLine(),
   734			DeclCol:     declpos.Col(),
   735			InlIndex:    int32(inlIndex),
   736			ChildIndex:  -1,
   737		}
   738		list := debug.LocationLists[varID]
   739		if len(list) != 0 {
   740			dvar.PutLocationList = func(listSym, startPC dwarf.Sym) {
   741				debug.PutLocationList(list, Ctxt, listSym.(*obj.LSym), startPC.(*obj.LSym))
   742			}
   743		}
   744		return dvar
   745	}
   746	
   747	// fieldtrack adds R_USEFIELD relocations to fnsym to record any
   748	// struct fields that it used.
   749	func fieldtrack(fnsym *obj.LSym, tracked map[*types.Sym]struct{}) {
   750		if fnsym == nil {
   751			return
   752		}
   753		if objabi.Fieldtrack_enabled == 0 || len(tracked) == 0 {
   754			return
   755		}
   756	
   757		trackSyms := make([]*types.Sym, 0, len(tracked))
   758		for sym := range tracked {
   759			trackSyms = append(trackSyms, sym)
   760		}
   761		sort.Sort(symByName(trackSyms))
   762		for _, sym := range trackSyms {
   763			r := obj.Addrel(fnsym)
   764			r.Sym = sym.Linksym()
   765			r.Type = objabi.R_USEFIELD
   766		}
   767	}
   768	
   769	type symByName []*types.Sym
   770	
   771	func (a symByName) Len() int           { return len(a) }
   772	func (a symByName) Less(i, j int) bool { return a[i].Name < a[j].Name }
   773	func (a symByName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
   774	

View as plain text