Source file src/cmd/compile/internal/ssa/debug.go

     1  // Copyright 2017 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 ssa
     6  
     7  import (
     8  	"cmd/compile/internal/abi"
     9  	"cmd/compile/internal/abt"
    10  	"cmd/compile/internal/ir"
    11  	"cmd/compile/internal/types"
    12  	"cmd/internal/dwarf"
    13  	"cmd/internal/obj"
    14  	"cmd/internal/src"
    15  	"cmp"
    16  	"encoding/hex"
    17  	"fmt"
    18  	"internal/buildcfg"
    19  	"math/bits"
    20  	"slices"
    21  	"strings"
    22  )
    23  
    24  type SlotID int32
    25  type VarID int32
    26  
    27  // A FuncDebug contains all the debug information for the variables in a
    28  // function. Variables are identified by their LocalSlot, which may be
    29  // the result of decomposing a larger variable.
    30  type FuncDebug struct {
    31  	// Slots is all the slots used in the debug info, indexed by their SlotID.
    32  	Slots []LocalSlot
    33  	// The user variables, indexed by VarID.
    34  	Vars []*ir.Name
    35  	// The slots that make up each variable, indexed by VarID.
    36  	VarSlots [][]SlotID
    37  	// The location list data, indexed by VarID. Must be processed by PutLocationList.
    38  	LocationLists [][]byte
    39  	// Register-resident output parameters for the function. This is filled in at
    40  	// SSA generation time.
    41  	RegOutputParams []*ir.Name
    42  	// Variable declarations that were removed during optimization
    43  	OptDcl []*ir.Name
    44  	// The ssa.Func.EntryID value, used to build location lists for
    45  	// return values promoted to heap in later DWARF generation.
    46  	EntryID ID
    47  
    48  	// Filled in by the user. Translates Block and Value ID to PC.
    49  	//
    50  	// NOTE: block is only used if value is BlockStart.ID or BlockEnd.ID.
    51  	// Otherwise, it is ignored.
    52  	GetPC func(block, value ID) int64
    53  }
    54  
    55  type BlockDebug struct {
    56  	// State at the start and end of the block. These are initialized,
    57  	// and updated from new information that flows on back edges.
    58  	startState, endState abt.T
    59  	// Use these to avoid excess work in the merge. If none of the
    60  	// predecessors has changed since the last check, the old answer is
    61  	// still good.
    62  	lastCheckedTime, lastChangedTime int32
    63  	// Whether the block had any changes to user variables at all.
    64  	relevant bool
    65  	// false until the block has been processed at least once. This
    66  	// affects how the merge is done; the goal is to maximize sharing
    67  	// and avoid allocation.
    68  	everProcessed bool
    69  }
    70  
    71  // A liveSlot is a slot that's live in loc at entry/exit of a block.
    72  type liveSlot struct {
    73  	VarLoc
    74  }
    75  
    76  func (ls *liveSlot) String() string {
    77  	return fmt.Sprintf("0x%x.%d.%d", ls.Registers, ls.stackOffsetValue(), int32(ls.StackOffset)&1)
    78  }
    79  
    80  func (ls liveSlot) absent() bool {
    81  	return ls.Registers == 0 && !ls.onStack()
    82  }
    83  
    84  // StackOffset encodes whether a value is on the stack and if so, where.
    85  // It is a 31-bit integer followed by a presence flag at the low-order
    86  // bit.
    87  type StackOffset int32
    88  
    89  func (s StackOffset) onStack() bool {
    90  	return s != 0
    91  }
    92  
    93  func (s StackOffset) stackOffsetValue() int32 {
    94  	return int32(s) >> 1
    95  }
    96  
    97  // stateAtPC is the current state of all variables at some point.
    98  type stateAtPC struct {
    99  	// The location of each known slot, indexed by SlotID.
   100  	slots []VarLoc
   101  	// The slots present in each register, indexed by register number.
   102  	registers [][]SlotID
   103  }
   104  
   105  // reset fills state with the live variables from live.
   106  func (state *stateAtPC) reset(live abt.T) {
   107  	slots, registers := state.slots, state.registers
   108  	clear(slots)
   109  	for i := range registers {
   110  		registers[i] = registers[i][:0]
   111  	}
   112  	for it := live.Iterator(); !it.Done(); {
   113  		k, d := it.Next()
   114  		live := d.(*liveSlot)
   115  		slots[k] = live.VarLoc
   116  		if live.VarLoc.Registers == 0 {
   117  			continue
   118  		}
   119  
   120  		mask := uint64(live.VarLoc.Registers)
   121  		for {
   122  			if mask == 0 {
   123  				break
   124  			}
   125  			reg := uint8(bits.TrailingZeros64(mask))
   126  			mask &^= 1 << reg
   127  
   128  			registers[reg] = append(registers[reg], SlotID(k))
   129  		}
   130  	}
   131  	state.slots, state.registers = slots, registers
   132  }
   133  
   134  func (s *debugState) LocString(loc VarLoc) string {
   135  	if loc.absent() {
   136  		return "<nil>"
   137  	}
   138  
   139  	var storage []string
   140  	if loc.onStack() {
   141  		storage = append(storage, fmt.Sprintf("@%+d", loc.stackOffsetValue()))
   142  	}
   143  
   144  	mask := uint64(loc.Registers)
   145  	for {
   146  		if mask == 0 {
   147  			break
   148  		}
   149  		reg := uint8(bits.TrailingZeros64(mask))
   150  		mask &^= 1 << reg
   151  
   152  		storage = append(storage, s.registers[reg].String())
   153  	}
   154  	return strings.Join(storage, ",")
   155  }
   156  
   157  // A VarLoc describes the storage for part of a user variable.
   158  type VarLoc struct {
   159  	// The registers this variable is available in. There can be more than
   160  	// one in various situations, e.g. it's being moved between registers.
   161  	Registers RegisterSet
   162  
   163  	StackOffset
   164  }
   165  
   166  func (loc VarLoc) absent() bool {
   167  	return loc.Registers == 0 && !loc.onStack()
   168  }
   169  
   170  func (loc VarLoc) intersect(other VarLoc) VarLoc {
   171  	if !loc.onStack() || !other.onStack() || loc.StackOffset != other.StackOffset {
   172  		loc.StackOffset = 0
   173  	}
   174  	loc.Registers &= other.Registers
   175  	return loc
   176  }
   177  
   178  var BlockStart = &Value{
   179  	ID:  -10000,
   180  	Op:  OpInvalid,
   181  	Aux: StringToAux("BlockStart"),
   182  }
   183  
   184  var BlockEnd = &Value{
   185  	ID:  -20000,
   186  	Op:  OpInvalid,
   187  	Aux: StringToAux("BlockEnd"),
   188  }
   189  
   190  var FuncEnd = &Value{
   191  	ID:  -30000,
   192  	Op:  OpInvalid,
   193  	Aux: StringToAux("FuncEnd"),
   194  }
   195  
   196  // RegisterSet is a bitmap of registers, indexed by Register.num.
   197  type RegisterSet uint64
   198  
   199  // logf prints debug-specific logging to stdout (always stdout) if the
   200  // current function is tagged by GOSSAFUNC (for ssa output directed
   201  // either to stdout or html).
   202  func (s *debugState) logf(msg string, args ...interface{}) {
   203  	if s.f.PrintOrHtmlSSA {
   204  		fmt.Printf(msg, args...)
   205  	}
   206  }
   207  
   208  type debugState struct {
   209  	// See FuncDebug.
   210  	slots    []LocalSlot
   211  	vars     []*ir.Name
   212  	varSlots [][]SlotID
   213  	lists    [][]byte
   214  
   215  	// The user variable that each slot rolls up to, indexed by SlotID.
   216  	slotVars []VarID
   217  
   218  	f             *Func
   219  	loggingLevel  int
   220  	convergeCount int // testing; iterate over block debug state this many times
   221  	registers     []Register
   222  	stackOffset   func(LocalSlot) int32
   223  	ctxt          *obj.Link
   224  
   225  	// The names (slots) associated with each value, indexed by Value ID.
   226  	valueNames [][]SlotID
   227  
   228  	// The current state of whatever analysis is running.
   229  	currentState stateAtPC
   230  	changedVars  *sparseSet
   231  	changedSlots *sparseSet
   232  
   233  	// The pending location list entry for each user variable, indexed by VarID.
   234  	pendingEntries []pendingEntry
   235  
   236  	varParts        map[*ir.Name][]SlotID
   237  	blockDebug      []BlockDebug
   238  	pendingSlotLocs []VarLoc
   239  }
   240  
   241  func (state *debugState) initializeCache(f *Func, numVars, numSlots int) {
   242  	// One blockDebug per block. Initialized in allocBlock.
   243  	if cap(state.blockDebug) < f.NumBlocks() {
   244  		state.blockDebug = make([]BlockDebug, f.NumBlocks())
   245  	} else {
   246  		clear(state.blockDebug[:f.NumBlocks()])
   247  	}
   248  
   249  	// A list of slots per Value. Reuse the previous child slices.
   250  	if cap(state.valueNames) < f.NumValues() {
   251  		old := state.valueNames
   252  		state.valueNames = make([][]SlotID, f.NumValues())
   253  		copy(state.valueNames, old)
   254  	}
   255  	vn := state.valueNames[:f.NumValues()]
   256  	for i := range vn {
   257  		vn[i] = vn[i][:0]
   258  	}
   259  
   260  	// Slot and register contents for currentState. Cleared by reset().
   261  	if cap(state.currentState.slots) < numSlots {
   262  		state.currentState.slots = make([]VarLoc, numSlots)
   263  	} else {
   264  		state.currentState.slots = state.currentState.slots[:numSlots]
   265  	}
   266  	if cap(state.currentState.registers) < len(state.registers) {
   267  		state.currentState.registers = make([][]SlotID, len(state.registers))
   268  	} else {
   269  		state.currentState.registers = state.currentState.registers[:len(state.registers)]
   270  	}
   271  
   272  	// A relatively small slice, but used many times as the return from processValue.
   273  	state.changedVars = newSparseSet(numVars)
   274  	state.changedSlots = newSparseSet(numSlots)
   275  
   276  	// A pending entry per user variable, with space to track each of its pieces.
   277  	numPieces := 0
   278  	for i := range state.varSlots {
   279  		numPieces += len(state.varSlots[i])
   280  	}
   281  	if cap(state.pendingSlotLocs) < numPieces {
   282  		state.pendingSlotLocs = make([]VarLoc, numPieces)
   283  	} else {
   284  		clear(state.pendingSlotLocs[:numPieces])
   285  	}
   286  	if cap(state.pendingEntries) < numVars {
   287  		state.pendingEntries = make([]pendingEntry, numVars)
   288  	}
   289  	pe := state.pendingEntries[:numVars]
   290  	freePieceIdx := 0
   291  	for varID, slots := range state.varSlots {
   292  		pe[varID] = pendingEntry{
   293  			pieces: state.pendingSlotLocs[freePieceIdx : freePieceIdx+len(slots)],
   294  		}
   295  		freePieceIdx += len(slots)
   296  	}
   297  	state.pendingEntries = pe
   298  
   299  	if cap(state.lists) < numVars {
   300  		state.lists = make([][]byte, numVars)
   301  	} else {
   302  		state.lists = state.lists[:numVars]
   303  		clear(state.lists)
   304  	}
   305  }
   306  
   307  func (state *debugState) allocBlock(b *Block) *BlockDebug {
   308  	return &state.blockDebug[b.ID]
   309  }
   310  
   311  func (s *debugState) blockEndStateString(b *BlockDebug) string {
   312  	endState := stateAtPC{slots: make([]VarLoc, len(s.slots)), registers: make([][]SlotID, len(s.registers))}
   313  	endState.reset(b.endState)
   314  	return s.stateString(endState)
   315  }
   316  
   317  func (s *debugState) stateString(state stateAtPC) string {
   318  	var strs []string
   319  	for slotID, loc := range state.slots {
   320  		if !loc.absent() {
   321  			strs = append(strs, fmt.Sprintf("\t%v = %v\n", s.slots[slotID], s.LocString(loc)))
   322  		}
   323  	}
   324  
   325  	strs = append(strs, "\n")
   326  	for reg, slots := range state.registers {
   327  		if len(slots) != 0 {
   328  			var slotStrs []string
   329  			for _, slot := range slots {
   330  				slotStrs = append(slotStrs, s.slots[slot].String())
   331  			}
   332  			strs = append(strs, fmt.Sprintf("\t%v = %v\n", &s.registers[reg], slotStrs))
   333  		}
   334  	}
   335  
   336  	if len(strs) == 1 {
   337  		return "(no vars)\n"
   338  	}
   339  	return strings.Join(strs, "")
   340  }
   341  
   342  // slotCanonicalizer is a table used to lookup and canonicalize
   343  // LocalSlot's in a type insensitive way (e.g. taking into account the
   344  // base name, offset, and width of the slot, but ignoring the slot
   345  // type).
   346  type slotCanonicalizer struct {
   347  	slmap  map[slotKey]SlKeyIdx
   348  	slkeys []LocalSlot
   349  }
   350  
   351  func newSlotCanonicalizer() *slotCanonicalizer {
   352  	return &slotCanonicalizer{
   353  		slmap:  make(map[slotKey]SlKeyIdx),
   354  		slkeys: []LocalSlot{LocalSlot{N: nil}},
   355  	}
   356  }
   357  
   358  type SlKeyIdx uint32
   359  
   360  const noSlot = SlKeyIdx(0)
   361  
   362  // slotKey is a type-insensitive encapsulation of a LocalSlot; it
   363  // is used to key a map within slotCanonicalizer.
   364  type slotKey struct {
   365  	name        *ir.Name
   366  	offset      int64
   367  	width       int64
   368  	splitOf     SlKeyIdx // idx in slkeys slice in slotCanonicalizer
   369  	splitOffset int64
   370  }
   371  
   372  // lookup looks up a LocalSlot in the slot canonicalizer "sc", returning
   373  // a canonical index for the slot, and adding it to the table if need
   374  // be. Return value is the canonical slot index, and a boolean indicating
   375  // whether the slot was found in the table already (TRUE => found).
   376  func (sc *slotCanonicalizer) lookup(ls LocalSlot) (SlKeyIdx, bool) {
   377  	split := noSlot
   378  	if ls.SplitOf != nil {
   379  		split, _ = sc.lookup(*ls.SplitOf)
   380  	}
   381  	k := slotKey{
   382  		name: ls.N, offset: ls.Off, width: ls.Type.Size(),
   383  		splitOf: split, splitOffset: ls.SplitOffset,
   384  	}
   385  	if idx, ok := sc.slmap[k]; ok {
   386  		return idx, true
   387  	}
   388  	rv := SlKeyIdx(len(sc.slkeys))
   389  	sc.slkeys = append(sc.slkeys, ls)
   390  	sc.slmap[k] = rv
   391  	return rv, false
   392  }
   393  
   394  func (sc *slotCanonicalizer) canonSlot(idx SlKeyIdx) LocalSlot {
   395  	return sc.slkeys[idx]
   396  }
   397  
   398  // PopulateABIInRegArgOps examines the entry block of the function
   399  // and looks for incoming parameters that have missing or partial
   400  // OpArg{Int,Float}Reg values, inserting additional values in
   401  // cases where they are missing. Example:
   402  //
   403  //	func foo(s string, used int, notused int) int {
   404  //	  return len(s) + used
   405  //	}
   406  //
   407  // In the function above, the incoming parameter "used" is fully live,
   408  // "notused" is not live, and "s" is partially live (only the length
   409  // field of the string is used). At the point where debug value
   410  // analysis runs, we might expect to see an entry block with:
   411  //
   412  //	b1:
   413  //	  v4 = ArgIntReg <uintptr> {s+8} [0] : BX
   414  //	  v5 = ArgIntReg <int> {used} [0] : CX
   415  //
   416  // While this is an accurate picture of the live incoming params,
   417  // we also want to have debug locations for non-live params (or
   418  // their non-live pieces), e.g. something like
   419  //
   420  //	b1:
   421  //	  v9 = ArgIntReg <*uint8> {s+0} [0] : AX
   422  //	  v4 = ArgIntReg <uintptr> {s+8} [0] : BX
   423  //	  v5 = ArgIntReg <int> {used} [0] : CX
   424  //	  v10 = ArgIntReg <int> {unused} [0] : DI
   425  //
   426  // This function examines the live OpArg{Int,Float}Reg values and
   427  // synthesizes new (dead) values for the non-live params or the
   428  // non-live pieces of partially live params.
   429  func PopulateABIInRegArgOps(f *Func) {
   430  	pri := f.ABISelf.ABIAnalyzeFuncType(f.Type)
   431  
   432  	// When manufacturing new slots that correspond to splits of
   433  	// composite parameters, we want to avoid creating a new sub-slot
   434  	// that differs from some existing sub-slot only by type, since
   435  	// the debug location analysis will treat that slot as a separate
   436  	// entity. To achieve this, create a lookup table of existing
   437  	// slots that is type-insenstitive.
   438  	sc := newSlotCanonicalizer()
   439  	for _, sl := range f.Names {
   440  		sc.lookup(*sl)
   441  	}
   442  
   443  	// Add slot -> value entry to f.NamedValues if not already present.
   444  	addToNV := func(v *Value, sl LocalSlot) {
   445  		values, ok := f.NamedValues[sl]
   446  		if !ok {
   447  			// Haven't seen this slot yet.
   448  			sla := f.localSlotAddr(sl)
   449  			f.Names = append(f.Names, sla)
   450  		} else {
   451  			for _, ev := range values {
   452  				if v == ev {
   453  					return
   454  				}
   455  			}
   456  		}
   457  		values = append(values, v)
   458  		f.NamedValues[sl] = values
   459  	}
   460  
   461  	newValues := []*Value{}
   462  
   463  	abiRegIndexToRegister := func(reg abi.RegIndex) int8 {
   464  		i := f.ABISelf.FloatIndexFor(reg)
   465  		if i >= 0 { // float PR
   466  			return f.Config.floatParamRegs[i]
   467  		} else {
   468  			return f.Config.intParamRegs[reg]
   469  		}
   470  	}
   471  
   472  	// Helper to construct a new OpArg{Float,Int}Reg op value.
   473  	var pos src.XPos
   474  	if len(f.Entry.Values) != 0 {
   475  		pos = f.Entry.Values[0].Pos
   476  	}
   477  	synthesizeOpIntFloatArg := func(n *ir.Name, t *types.Type, reg abi.RegIndex, sl LocalSlot) *Value {
   478  		aux := &AuxNameOffset{n, sl.Off}
   479  		op, auxInt := ArgOpAndRegisterFor(reg, f.ABISelf)
   480  		v := f.newValueNoBlock(op, t, pos)
   481  		v.AuxInt = auxInt
   482  		v.Aux = aux
   483  		v.Args = nil
   484  		v.Block = f.Entry
   485  		newValues = append(newValues, v)
   486  		addToNV(v, sl)
   487  		f.setHome(v, &f.Config.registers[abiRegIndexToRegister(reg)])
   488  		return v
   489  	}
   490  
   491  	// Make a pass through the entry block looking for
   492  	// OpArg{Int,Float}Reg ops. Record the slots they use in a table
   493  	// ("sc"). We use a type-insensitive lookup for the slot table,
   494  	// since the type we get from the ABI analyzer won't always match
   495  	// what the compiler uses when creating OpArg{Int,Float}Reg ops.
   496  	for _, v := range f.Entry.Values {
   497  		if v.Op == OpArgIntReg || v.Op == OpArgFloatReg {
   498  			aux := v.Aux.(*AuxNameOffset)
   499  			sl := LocalSlot{N: aux.Name, Type: v.Type, Off: aux.Offset}
   500  			// install slot in lookup table
   501  			idx, _ := sc.lookup(sl)
   502  			// add to f.NamedValues if not already present
   503  			addToNV(v, sc.canonSlot(idx))
   504  		} else if v.Op.IsCall() {
   505  			// if we hit a call, we've gone too far.
   506  			break
   507  		}
   508  	}
   509  
   510  	// Now make a pass through the ABI in-params, looking for params
   511  	// or pieces of params that we didn't encounter in the loop above.
   512  	for _, inp := range pri.InParams() {
   513  		if !isNamedRegParam(inp) {
   514  			continue
   515  		}
   516  		n := inp.Name
   517  
   518  		// Param is spread across one or more registers. Walk through
   519  		// each piece to see whether we've seen an arg reg op for it.
   520  		types, offsets := inp.RegisterTypesAndOffsets()
   521  		for k, t := range types {
   522  			// Note: this recipe for creating a LocalSlot is designed
   523  			// to be compatible with the one used in expand_calls.go
   524  			// as opposed to decompose.go. The expand calls code just
   525  			// takes the base name and creates an offset into it,
   526  			// without using the SplitOf/SplitOffset fields. The code
   527  			// in decompose.go does the opposite -- it creates a
   528  			// LocalSlot object with "Off" set to zero, but with
   529  			// SplitOf pointing to a parent slot, and SplitOffset
   530  			// holding the offset into the parent object.
   531  			pieceSlot := LocalSlot{N: n, Type: t, Off: offsets[k]}
   532  
   533  			// Look up this piece to see if we've seen a reg op
   534  			// for it. If not, create one.
   535  			_, found := sc.lookup(pieceSlot)
   536  			if !found {
   537  				// This slot doesn't appear in the map, meaning it
   538  				// corresponds to an in-param that is not live, or
   539  				// a portion of an in-param that is not live/used.
   540  				// Add a new dummy OpArg{Int,Float}Reg for it.
   541  				synthesizeOpIntFloatArg(n, t, inp.Registers[k],
   542  					pieceSlot)
   543  			}
   544  		}
   545  	}
   546  
   547  	// Insert the new values into the head of the block.
   548  	f.Entry.Values = append(newValues, f.Entry.Values...)
   549  }
   550  
   551  // BuildFuncDebug builds debug information for f, placing the results
   552  // in "rval". f must be fully processed, so that each Value is where it
   553  // will be when machine code is emitted.
   554  func BuildFuncDebug(ctxt *obj.Link, f *Func, loggingLevel int, stackOffset func(LocalSlot) int32, rval *FuncDebug) {
   555  	if f.RegAlloc == nil {
   556  		f.Fatalf("BuildFuncDebug on func %v that has not been fully processed", f)
   557  	}
   558  	state := &f.Cache.debugState
   559  	state.loggingLevel = loggingLevel % 1000
   560  
   561  	// A specific number demands exactly that many iterations. Under
   562  	// particular circumstances it make require more than the total of
   563  	// 2 passes implied by a single run through liveness and a single
   564  	// run through location list generation.
   565  	state.convergeCount = loggingLevel / 1000
   566  	state.f = f
   567  	state.registers = f.Config.registers
   568  	state.stackOffset = stackOffset
   569  	state.ctxt = ctxt
   570  
   571  	if buildcfg.Experiment.RegabiArgs {
   572  		PopulateABIInRegArgOps(f)
   573  	}
   574  
   575  	if state.loggingLevel > 0 {
   576  		state.logf("Generating location lists for function %q\n", f.Name)
   577  	}
   578  
   579  	if state.varParts == nil {
   580  		state.varParts = make(map[*ir.Name][]SlotID)
   581  	} else {
   582  		clear(state.varParts)
   583  	}
   584  
   585  	// Recompose any decomposed variables, and establish the canonical
   586  	// IDs for each var and slot by filling out state.vars and state.slots.
   587  
   588  	state.slots = state.slots[:0]
   589  	state.vars = state.vars[:0]
   590  	for i, slot := range f.Names {
   591  		state.slots = append(state.slots, *slot)
   592  		if ir.IsSynthetic(slot.N) || !IsVarWantedForDebug(slot.N) {
   593  			continue
   594  		}
   595  
   596  		topSlot := slot
   597  		for topSlot.SplitOf != nil {
   598  			topSlot = topSlot.SplitOf
   599  		}
   600  		if _, ok := state.varParts[topSlot.N]; !ok {
   601  			state.vars = append(state.vars, topSlot.N)
   602  		}
   603  		state.varParts[topSlot.N] = append(state.varParts[topSlot.N], SlotID(i))
   604  	}
   605  
   606  	// Recreate the LocalSlot for each stack-only variable.
   607  	// This would probably be better as an output from stackframe.
   608  	for _, b := range f.Blocks {
   609  		for _, v := range b.Values {
   610  			if v.Op == OpVarDef {
   611  				n := v.Aux.(*ir.Name)
   612  				if ir.IsSynthetic(n) || !IsVarWantedForDebug(n) {
   613  					continue
   614  				}
   615  
   616  				if _, ok := state.varParts[n]; !ok {
   617  					slot := LocalSlot{N: n, Type: v.Type, Off: 0}
   618  					state.slots = append(state.slots, slot)
   619  					state.varParts[n] = []SlotID{SlotID(len(state.slots) - 1)}
   620  					state.vars = append(state.vars, n)
   621  				}
   622  			}
   623  		}
   624  	}
   625  
   626  	// Fill in the var<->slot mappings.
   627  	if cap(state.varSlots) < len(state.vars) {
   628  		state.varSlots = make([][]SlotID, len(state.vars))
   629  	} else {
   630  		state.varSlots = state.varSlots[:len(state.vars)]
   631  		for i := range state.varSlots {
   632  			state.varSlots[i] = state.varSlots[i][:0]
   633  		}
   634  	}
   635  	if cap(state.slotVars) < len(state.slots) {
   636  		state.slotVars = make([]VarID, len(state.slots))
   637  	} else {
   638  		state.slotVars = state.slotVars[:len(state.slots)]
   639  	}
   640  
   641  	for varID, n := range state.vars {
   642  		parts := state.varParts[n]
   643  		slices.SortFunc(parts, func(a, b SlotID) int {
   644  			return cmp.Compare(varOffset(state.slots[a]), varOffset(state.slots[b]))
   645  		})
   646  
   647  		state.varSlots[varID] = parts
   648  		for _, slotID := range parts {
   649  			state.slotVars[slotID] = VarID(varID)
   650  		}
   651  	}
   652  
   653  	state.initializeCache(f, len(state.varParts), len(state.slots))
   654  
   655  	for i, slot := range f.Names {
   656  		if ir.IsSynthetic(slot.N) || !IsVarWantedForDebug(slot.N) {
   657  			continue
   658  		}
   659  		for _, value := range f.NamedValues[*slot] {
   660  			state.valueNames[value.ID] = append(state.valueNames[value.ID], SlotID(i))
   661  		}
   662  	}
   663  
   664  	blockLocs := state.liveness()
   665  	state.buildLocationLists(blockLocs)
   666  
   667  	// Populate "rval" with what we've computed.
   668  	rval.Slots = state.slots
   669  	rval.VarSlots = state.varSlots
   670  	rval.Vars = state.vars
   671  	rval.LocationLists = state.lists
   672  }
   673  
   674  // liveness walks the function in control flow order, calculating the start
   675  // and end state of each block.
   676  func (state *debugState) liveness() []*BlockDebug {
   677  	blockLocs := make([]*BlockDebug, state.f.NumBlocks())
   678  	counterTime := int32(1)
   679  
   680  	// Reverse postorder: visit a block after as many as possible of its
   681  	// predecessors have been visited.
   682  	po := state.f.Postorder()
   683  	converged := false
   684  
   685  	// The iteration rule is that by default, run until converged, but
   686  	// if a particular iteration count is specified, run that many
   687  	// iterations, no more, no less.  A count is specified as the
   688  	// thousands digit of the location lists debug flag,
   689  	// e.g. -d=locationlists=4000
   690  	keepGoing := func(k int) bool {
   691  		if state.convergeCount == 0 {
   692  			return !converged
   693  		}
   694  		return k < state.convergeCount
   695  	}
   696  	for k := 0; keepGoing(k); k++ {
   697  		if state.loggingLevel > 0 {
   698  			state.logf("Liveness pass %d\n", k)
   699  		}
   700  		converged = true
   701  		for i := len(po) - 1; i >= 0; i-- {
   702  			b := po[i]
   703  			locs := blockLocs[b.ID]
   704  			if locs == nil {
   705  				locs = state.allocBlock(b)
   706  				blockLocs[b.ID] = locs
   707  			}
   708  
   709  			// Build the starting state for the block from the final
   710  			// state of its predecessors.
   711  			startState, blockChanged := state.mergePredecessors(b, blockLocs, nil, false)
   712  			locs.lastCheckedTime = counterTime
   713  			counterTime++
   714  			if state.loggingLevel > 1 {
   715  				state.logf("Processing %v, block changed %v, initial state:\n%v", b, blockChanged, state.stateString(state.currentState))
   716  			}
   717  
   718  			if blockChanged {
   719  				// If the start did not change, then the old endState is good
   720  				converged = false
   721  				changed := false
   722  				state.changedSlots.clear()
   723  
   724  				// Update locs/registers with the effects of each Value.
   725  				for _, v := range b.Values {
   726  					slots := state.valueNames[v.ID]
   727  
   728  					// Loads and stores inherit the names of their sources.
   729  					var source *Value
   730  					switch v.Op {
   731  					case OpStoreReg:
   732  						source = v.Args[0]
   733  					case OpLoadReg:
   734  						switch a := v.Args[0]; a.Op {
   735  						case OpArg, OpPhi:
   736  							source = a
   737  						case OpStoreReg:
   738  							source = a.Args[0]
   739  						default:
   740  							if state.loggingLevel > 1 {
   741  								state.logf("at %v: load with unexpected source op: %v (%v)\n", v, a.Op, a)
   742  							}
   743  						}
   744  					}
   745  					// Update valueNames with the source so that later steps
   746  					// don't need special handling.
   747  					if source != nil && k == 0 {
   748  						// limit to k == 0 otherwise there are duplicates.
   749  						slots = append(slots, state.valueNames[source.ID]...)
   750  						state.valueNames[v.ID] = slots
   751  					}
   752  
   753  					reg, _ := state.f.getHome(v.ID).(*Register)
   754  					c := state.processValue(v, slots, reg)
   755  					changed = changed || c
   756  				}
   757  
   758  				if state.loggingLevel > 1 {
   759  					state.logf("Block %v done, locs:\n%v", b, state.stateString(state.currentState))
   760  				}
   761  
   762  				locs.relevant = locs.relevant || changed
   763  				if !changed {
   764  					locs.endState = startState
   765  				} else {
   766  					for _, id := range state.changedSlots.contents() {
   767  						slotID := SlotID(id)
   768  						slotLoc := state.currentState.slots[slotID]
   769  						if slotLoc.absent() {
   770  							startState.Delete(int32(slotID))
   771  							continue
   772  						}
   773  						old := startState.Find(int32(slotID)) // do NOT replace existing values
   774  						if oldLS, ok := old.(*liveSlot); !ok || oldLS.VarLoc != slotLoc {
   775  							startState.Insert(int32(slotID),
   776  								&liveSlot{VarLoc: slotLoc})
   777  						}
   778  					}
   779  					locs.endState = startState
   780  				}
   781  				locs.lastChangedTime = counterTime
   782  			}
   783  			counterTime++
   784  		}
   785  	}
   786  	return blockLocs
   787  }
   788  
   789  // mergePredecessors takes the end state of each of b's predecessors and
   790  // intersects them to form the starting state for b. It puts that state
   791  // in blockLocs[b.ID].startState, and fills state.currentState with it.
   792  // It returns the start state and whether this is changed from the
   793  // previously approximated value of startState for this block.  After
   794  // the first call, subsequent calls can only shrink startState.
   795  //
   796  // Passing forLocationLists=true enables additional side-effects that
   797  // are necessary for building location lists but superfluous while still
   798  // iterating to an answer.
   799  //
   800  // If previousBlock is non-nil, it registers changes vs. that block's
   801  // end state in state.changedVars. Note that previousBlock will often
   802  // not be a predecessor.
   803  //
   804  // Note that mergePredecessors behaves slightly differently between
   805  // first and subsequent calls for a block.  For the first call, the
   806  // starting state is approximated by taking the state from the
   807  // predecessor whose state is smallest, and removing any elements not
   808  // in all the other predecessors; this makes the smallest number of
   809  // changes and shares the most state.  On subsequent calls the old
   810  // value of startState is adjusted with new information; this is judged
   811  // to do the least amount of extra work.
   812  //
   813  // To improve performance, each block's state information is marked with
   814  // lastChanged and lastChecked "times" so unchanged predecessors can be
   815  // skipped on after-the-first iterations.  Doing this allows extra
   816  // iterations by the caller to be almost free.
   817  //
   818  // It is important to know that the set representation used for
   819  // startState, endState, and merges can share data for two sets where
   820  // one is a small delta from the other.  Doing this does require a
   821  // little care in how sets are updated, both in mergePredecessors, and
   822  // using its result.
   823  func (state *debugState) mergePredecessors(b *Block, blockLocs []*BlockDebug, previousBlock *Block, forLocationLists bool) (abt.T, bool) {
   824  	// Filter out back branches.
   825  	var predsBuf [10]*Block
   826  
   827  	preds := predsBuf[:0]
   828  	locs := blockLocs[b.ID]
   829  
   830  	blockChanged := !locs.everProcessed // the first time it always changes.
   831  	updating := locs.everProcessed
   832  
   833  	// For the first merge, exclude predecessors that have not been seen yet.
   834  	// I.e., backedges.
   835  	for _, pred := range b.Preds {
   836  		if bl := blockLocs[pred.b.ID]; bl != nil && bl.everProcessed {
   837  			// crucially, a self-edge has bl != nil, but bl.everProcessed is false the first time.
   838  			preds = append(preds, pred.b)
   839  		}
   840  	}
   841  
   842  	locs.everProcessed = true
   843  
   844  	if state.loggingLevel > 1 {
   845  		// The logf below would cause preds to be heap-allocated if
   846  		// it were passed directly.
   847  		preds2 := make([]*Block, len(preds))
   848  		copy(preds2, preds)
   849  		state.logf("Merging %v into %v (changed=%d, checked=%d)\n", preds2, b, locs.lastChangedTime, locs.lastCheckedTime)
   850  	}
   851  
   852  	state.changedVars.clear()
   853  
   854  	markChangedVars := func(slots, merged abt.T) {
   855  		if !forLocationLists {
   856  			return
   857  		}
   858  		// Fill changedVars with those that differ between the previous
   859  		// block (in the emit order, not necessarily a flow predecessor)
   860  		// and the start state for this block.
   861  		for it := slots.Iterator(); !it.Done(); {
   862  			k, v := it.Next()
   863  			m := merged.Find(k)
   864  			if m == nil || v.(*liveSlot).VarLoc != m.(*liveSlot).VarLoc {
   865  				state.changedVars.add(ID(state.slotVars[k]))
   866  			}
   867  		}
   868  	}
   869  
   870  	reset := func(ourStartState abt.T) {
   871  		if !(forLocationLists || blockChanged) {
   872  			// there is no change and this is not for location lists, do
   873  			// not bother to reset currentState because it will not be
   874  			// examined.
   875  			return
   876  		}
   877  		state.currentState.reset(ourStartState)
   878  	}
   879  
   880  	// Zero predecessors
   881  	if len(preds) == 0 {
   882  		if previousBlock != nil {
   883  			state.f.Fatalf("Function %v, block %s with no predecessors is not first block, has previous %s", state.f, b.String(), previousBlock.String())
   884  		}
   885  		// startState is empty
   886  		reset(abt.T{})
   887  		return abt.T{}, blockChanged
   888  	}
   889  
   890  	// One predecessor
   891  	l0 := blockLocs[preds[0].ID]
   892  	p0 := l0.endState
   893  	if len(preds) == 1 {
   894  		if previousBlock != nil && preds[0].ID != previousBlock.ID {
   895  			// Change from previous block is its endState minus the predecessor's endState
   896  			markChangedVars(blockLocs[previousBlock.ID].endState, p0)
   897  		}
   898  		locs.startState = p0
   899  		blockChanged = blockChanged || l0.lastChangedTime > locs.lastCheckedTime
   900  		reset(p0)
   901  		return p0, blockChanged
   902  	}
   903  
   904  	// More than one predecessor
   905  
   906  	if updating {
   907  		// After the first approximation, i.e., when updating, results
   908  		// can only get smaller, because initially backedge
   909  		// predecessors do not participate in the intersection.  This
   910  		// means that for the update, given the prior approximation of
   911  		// startState, there is no need to re-intersect with unchanged
   912  		// blocks.  Therefore remove unchanged blocks from the
   913  		// predecessor list.
   914  		for i := len(preds) - 1; i >= 0; i-- {
   915  			pred := preds[i]
   916  			if blockLocs[pred.ID].lastChangedTime > locs.lastCheckedTime {
   917  				continue // keep this predecessor
   918  			}
   919  			preds[i] = preds[len(preds)-1]
   920  			preds = preds[:len(preds)-1]
   921  			if state.loggingLevel > 2 {
   922  				state.logf("Pruned b%d, lastChanged was %d but b%d lastChecked is %d\n", pred.ID, blockLocs[pred.ID].lastChangedTime, b.ID, locs.lastCheckedTime)
   923  			}
   924  		}
   925  		// Check for an early out; this should always hit for the update
   926  		// if there are no cycles.
   927  		if len(preds) == 0 {
   928  			blockChanged = false
   929  
   930  			reset(locs.startState)
   931  			if state.loggingLevel > 2 {
   932  				state.logf("Early out, no predecessors changed since last check\n")
   933  			}
   934  			if previousBlock != nil {
   935  				markChangedVars(blockLocs[previousBlock.ID].endState, locs.startState)
   936  			}
   937  			return locs.startState, blockChanged
   938  		}
   939  	}
   940  
   941  	baseID := preds[0].ID
   942  	baseState := p0
   943  
   944  	// Choose the predecessor with the smallest endState for intersection work
   945  	for _, pred := range preds[1:] {
   946  		if blockLocs[pred.ID].endState.Size() < baseState.Size() {
   947  			baseState = blockLocs[pred.ID].endState
   948  			baseID = pred.ID
   949  		}
   950  	}
   951  
   952  	if state.loggingLevel > 2 {
   953  		state.logf("Starting %v with state from b%v:\n%v", b, baseID, state.blockEndStateString(blockLocs[baseID]))
   954  		for _, pred := range preds {
   955  			if pred.ID == baseID {
   956  				continue
   957  			}
   958  			state.logf("Merging in state from %v:\n%v", pred, state.blockEndStateString(blockLocs[pred.ID]))
   959  		}
   960  	}
   961  
   962  	state.currentState.reset(abt.T{})
   963  	// The normal logic of "reset" is included in the intersection loop below.
   964  
   965  	slotLocs := state.currentState.slots
   966  
   967  	// If this is the first call, do updates on the "baseState"; if this
   968  	// is a subsequent call, tweak the startState instead. Note that
   969  	// these "set" values are values; there are no side effects to
   970  	// other values as these are modified.
   971  	newState := baseState
   972  	if updating {
   973  		newState = blockLocs[b.ID].startState
   974  	}
   975  
   976  	for it := newState.Iterator(); !it.Done(); {
   977  		k, d := it.Next()
   978  		thisSlot := d.(*liveSlot)
   979  		x := thisSlot.VarLoc
   980  		x0 := x // initial value in newState
   981  
   982  		// Intersect this slot with the slot in all the predecessors
   983  		for _, other := range preds {
   984  			if !updating && other.ID == baseID {
   985  				continue
   986  			}
   987  			otherSlot := blockLocs[other.ID].endState.Find(k)
   988  			if otherSlot == nil {
   989  				x = VarLoc{}
   990  				break
   991  			}
   992  			y := otherSlot.(*liveSlot).VarLoc
   993  			x = x.intersect(y)
   994  			if x.absent() {
   995  				x = VarLoc{}
   996  				break
   997  			}
   998  		}
   999  
  1000  		// Delete if necessary, but not otherwise (in order to maximize sharing).
  1001  		if x.absent() {
  1002  			if !x0.absent() {
  1003  				blockChanged = true
  1004  				newState.Delete(k)
  1005  			}
  1006  			slotLocs[k] = VarLoc{}
  1007  			continue
  1008  		}
  1009  		if x != x0 {
  1010  			blockChanged = true
  1011  			newState.Insert(k, &liveSlot{VarLoc: x})
  1012  		}
  1013  
  1014  		slotLocs[k] = x
  1015  		mask := uint64(x.Registers)
  1016  		for {
  1017  			if mask == 0 {
  1018  				break
  1019  			}
  1020  			reg := uint8(bits.TrailingZeros64(mask))
  1021  			mask &^= 1 << reg
  1022  			state.currentState.registers[reg] = append(state.currentState.registers[reg], SlotID(k))
  1023  		}
  1024  	}
  1025  
  1026  	if previousBlock != nil {
  1027  		markChangedVars(blockLocs[previousBlock.ID].endState, newState)
  1028  	}
  1029  	locs.startState = newState
  1030  	return newState, blockChanged
  1031  }
  1032  
  1033  // processValue updates locs and state.registerContents to reflect v, a
  1034  // value with the names in vSlots and homed in vReg.  "v" becomes
  1035  // visible after execution of the instructions evaluating it. It
  1036  // returns which VarIDs were modified by the Value's execution.
  1037  func (state *debugState) processValue(v *Value, vSlots []SlotID, vReg *Register) bool {
  1038  	locs := state.currentState
  1039  	changed := false
  1040  	setSlot := func(slot SlotID, loc VarLoc) {
  1041  		changed = true
  1042  		state.changedVars.add(ID(state.slotVars[slot]))
  1043  		state.changedSlots.add(ID(slot))
  1044  		state.currentState.slots[slot] = loc
  1045  	}
  1046  
  1047  	// Handle any register clobbering. Call operations, for example,
  1048  	// clobber all registers even though they don't explicitly write to
  1049  	// them.
  1050  	clobbers := uint64(opcodeTable[v.Op].reg.clobbers)
  1051  	for {
  1052  		if clobbers == 0 {
  1053  			break
  1054  		}
  1055  		reg := uint8(bits.TrailingZeros64(clobbers))
  1056  		clobbers &^= 1 << reg
  1057  
  1058  		for _, slot := range locs.registers[reg] {
  1059  			if state.loggingLevel > 1 {
  1060  				state.logf("at %v: %v clobbered out of %v\n", v, state.slots[slot], &state.registers[reg])
  1061  			}
  1062  
  1063  			last := locs.slots[slot]
  1064  			if last.absent() {
  1065  				state.f.Fatalf("at %v: slot %v in register %v with no location entry", v, state.slots[slot], &state.registers[reg])
  1066  				continue
  1067  			}
  1068  			regs := last.Registers &^ (1 << reg)
  1069  			setSlot(slot, VarLoc{regs, last.StackOffset})
  1070  		}
  1071  
  1072  		locs.registers[reg] = locs.registers[reg][:0]
  1073  	}
  1074  
  1075  	switch {
  1076  	case v.Op == OpVarDef:
  1077  		n := v.Aux.(*ir.Name)
  1078  		if ir.IsSynthetic(n) || !IsVarWantedForDebug(n) {
  1079  			break
  1080  		}
  1081  
  1082  		slotID := state.varParts[n][0]
  1083  		var stackOffset StackOffset
  1084  		if v.Op == OpVarDef {
  1085  			stackOffset = StackOffset(state.stackOffset(state.slots[slotID])<<1 | 1)
  1086  		}
  1087  		setSlot(slotID, VarLoc{0, stackOffset})
  1088  		if state.loggingLevel > 1 {
  1089  			if v.Op == OpVarDef {
  1090  				state.logf("at %v: stack-only var %v now live\n", v, state.slots[slotID])
  1091  			} else {
  1092  				state.logf("at %v: stack-only var %v now dead\n", v, state.slots[slotID])
  1093  			}
  1094  		}
  1095  
  1096  	case v.Op == OpArg:
  1097  		home := state.f.getHome(v.ID).(LocalSlot)
  1098  		stackOffset := state.stackOffset(home)<<1 | 1
  1099  		for _, slot := range vSlots {
  1100  			if state.loggingLevel > 1 {
  1101  				state.logf("at %v: arg %v now on stack in location %v\n", v, state.slots[slot], home)
  1102  				if last := locs.slots[slot]; !last.absent() {
  1103  					state.logf("at %v: unexpected arg op on already-live slot %v\n", v, state.slots[slot])
  1104  				}
  1105  			}
  1106  
  1107  			setSlot(slot, VarLoc{0, StackOffset(stackOffset)})
  1108  		}
  1109  
  1110  	case v.Op == OpStoreReg:
  1111  		home := state.f.getHome(v.ID).(LocalSlot)
  1112  		stackOffset := state.stackOffset(home)<<1 | 1
  1113  		for _, slot := range vSlots {
  1114  			last := locs.slots[slot]
  1115  			if last.absent() {
  1116  				if state.loggingLevel > 1 {
  1117  					state.logf("at %v: unexpected spill of unnamed register %s\n", v, vReg)
  1118  				}
  1119  				break
  1120  			}
  1121  
  1122  			setSlot(slot, VarLoc{last.Registers, StackOffset(stackOffset)})
  1123  			if state.loggingLevel > 1 {
  1124  				state.logf("at %v: %v spilled to stack location %v@%d\n", v, state.slots[slot], home, state.stackOffset(home))
  1125  			}
  1126  		}
  1127  
  1128  	case vReg != nil:
  1129  		if state.loggingLevel > 1 {
  1130  			newSlots := make([]bool, len(state.slots))
  1131  			for _, slot := range vSlots {
  1132  				newSlots[slot] = true
  1133  			}
  1134  
  1135  			for _, slot := range locs.registers[vReg.num] {
  1136  				if !newSlots[slot] {
  1137  					state.logf("at %v: overwrote %v in register %v\n", v, state.slots[slot], vReg)
  1138  				}
  1139  			}
  1140  		}
  1141  
  1142  		for _, slot := range locs.registers[vReg.num] {
  1143  			last := locs.slots[slot]
  1144  			setSlot(slot, VarLoc{last.Registers &^ (1 << uint8(vReg.num)), last.StackOffset})
  1145  		}
  1146  		locs.registers[vReg.num] = locs.registers[vReg.num][:0]
  1147  		locs.registers[vReg.num] = append(locs.registers[vReg.num], vSlots...)
  1148  		for _, slot := range vSlots {
  1149  			if state.loggingLevel > 1 {
  1150  				state.logf("at %v: %v now in %s\n", v, state.slots[slot], vReg)
  1151  			}
  1152  
  1153  			last := locs.slots[slot]
  1154  			setSlot(slot, VarLoc{1<<uint8(vReg.num) | last.Registers, last.StackOffset})
  1155  		}
  1156  	}
  1157  	return changed
  1158  }
  1159  
  1160  // varOffset returns the offset of slot within the user variable it was
  1161  // decomposed from. This has nothing to do with its stack offset.
  1162  func varOffset(slot LocalSlot) int64 {
  1163  	offset := slot.Off
  1164  	s := &slot
  1165  	for ; s.SplitOf != nil; s = s.SplitOf {
  1166  		offset += s.SplitOffset
  1167  	}
  1168  	return offset
  1169  }
  1170  
  1171  // A pendingEntry represents the beginning of a location list entry, missing
  1172  // only its end coordinate.
  1173  type pendingEntry struct {
  1174  	present                bool
  1175  	startBlock, startValue ID
  1176  	// The location of each piece of the variable, in the same order as the
  1177  	// SlotIDs in varParts.
  1178  	pieces []VarLoc
  1179  }
  1180  
  1181  func (e *pendingEntry) clear() {
  1182  	e.present = false
  1183  	e.startBlock = 0
  1184  	e.startValue = 0
  1185  	clear(e.pieces)
  1186  }
  1187  
  1188  // canMerge reports whether a new location description is a superset
  1189  // of the (non-empty) pending location description, if so, the two
  1190  // can be merged (i.e., pending is still a valid and useful location
  1191  // description).
  1192  func canMerge(pending, new VarLoc) bool {
  1193  	if pending.absent() && new.absent() {
  1194  		return true
  1195  	}
  1196  	if pending.absent() || new.absent() {
  1197  		return false
  1198  	}
  1199  	// pending is not absent, therefore it has either a stack mapping,
  1200  	// or registers, or both.
  1201  	if pending.onStack() && pending.StackOffset != new.StackOffset {
  1202  		// if pending has a stack offset, then new must also, and it
  1203  		// must be the same (StackOffset encodes onStack).
  1204  		return false
  1205  	}
  1206  	if pending.Registers&new.Registers != pending.Registers {
  1207  		// There is at least one register in pending not mentioned in new.
  1208  		return false
  1209  	}
  1210  	return true
  1211  }
  1212  
  1213  // firstReg returns the first register in set that is present.
  1214  func firstReg(set RegisterSet) uint8 {
  1215  	if set == 0 {
  1216  		// This is wrong, but there seem to be some situations where we
  1217  		// produce locations with no storage.
  1218  		return 0
  1219  	}
  1220  	return uint8(bits.TrailingZeros64(uint64(set)))
  1221  }
  1222  
  1223  // buildLocationLists builds location lists for all the user variables
  1224  // in state.f, using the information about block state in blockLocs.
  1225  // The returned location lists are not fully complete. They are in
  1226  // terms of SSA values rather than PCs, and have no base address/end
  1227  // entries. They will be finished by PutLocationList.
  1228  func (state *debugState) buildLocationLists(blockLocs []*BlockDebug) {
  1229  	// Run through the function in program text order, building up location
  1230  	// lists as we go. The heavy lifting has mostly already been done.
  1231  
  1232  	var prevBlock *Block
  1233  	for _, b := range state.f.Blocks {
  1234  		state.mergePredecessors(b, blockLocs, prevBlock, true)
  1235  
  1236  		// Handle any differences among predecessor blocks and previous block (perhaps not a predecessor)
  1237  		for _, varID := range state.changedVars.contents() {
  1238  			state.updateVar(VarID(varID), b, BlockStart)
  1239  		}
  1240  		state.changedVars.clear()
  1241  
  1242  		if !blockLocs[b.ID].relevant {
  1243  			continue
  1244  		}
  1245  
  1246  		mustBeFirst := func(v *Value) bool {
  1247  			return v.Op == OpPhi || v.Op.isLoweredGetClosurePtr() ||
  1248  				v.Op == OpArgIntReg || v.Op == OpArgFloatReg
  1249  		}
  1250  
  1251  		blockPrologComplete := func(v *Value) bool {
  1252  			if b.ID != state.f.Entry.ID {
  1253  				return !opcodeTable[v.Op].zeroWidth
  1254  			} else {
  1255  				return v.Op == OpInitMem
  1256  			}
  1257  		}
  1258  
  1259  		// Examine the prolog portion of the block to process special
  1260  		// zero-width ops such as Arg, Phi, LoweredGetClosurePtr (etc)
  1261  		// whose lifetimes begin at the block starting point. In an
  1262  		// entry block, allow for the possibility that we may see Arg
  1263  		// ops that appear _after_ other non-zero-width operations.
  1264  		// Example:
  1265  		//
  1266  		//   v33 = ArgIntReg <uintptr> {foo+0} [0] : AX (foo)
  1267  		//   v34 = ArgIntReg <uintptr> {bar+0} [0] : BX (bar)
  1268  		//   ...
  1269  		//   v77 = StoreReg <unsafe.Pointer> v67 : ctx+8[unsafe.Pointer]
  1270  		//   v78 = StoreReg <unsafe.Pointer> v68 : ctx[unsafe.Pointer]
  1271  		//   v79 = Arg <*uint8> {args} : args[*uint8] (args[*uint8])
  1272  		//   v80 = Arg <int> {args} [8] : args+8[int] (args+8[int])
  1273  		//   ...
  1274  		//   v1 = InitMem <mem>
  1275  		//
  1276  		// We can stop scanning the initial portion of the block when
  1277  		// we either see the InitMem op (for entry blocks) or the
  1278  		// first non-zero-width op (for other blocks).
  1279  		for idx := 0; idx < len(b.Values); idx++ {
  1280  			v := b.Values[idx]
  1281  			if blockPrologComplete(v) {
  1282  				break
  1283  			}
  1284  			// Consider only "lifetime begins at block start" ops.
  1285  			if !mustBeFirst(v) && v.Op != OpArg {
  1286  				continue
  1287  			}
  1288  			slots := state.valueNames[v.ID]
  1289  			reg, _ := state.f.getHome(v.ID).(*Register)
  1290  			changed := state.processValue(v, slots, reg) // changed == added to state.changedVars
  1291  			if changed {
  1292  				for _, varID := range state.changedVars.contents() {
  1293  					state.updateVar(VarID(varID), v.Block, BlockStart)
  1294  				}
  1295  				state.changedVars.clear()
  1296  			}
  1297  		}
  1298  
  1299  		// Now examine the block again, handling things other than the
  1300  		// "begins at block start" lifetimes.
  1301  		zeroWidthPending := false
  1302  		prologComplete := false
  1303  		// expect to see values in pattern (apc)* (zerowidth|real)*
  1304  		for _, v := range b.Values {
  1305  			if blockPrologComplete(v) {
  1306  				prologComplete = true
  1307  			}
  1308  			slots := state.valueNames[v.ID]
  1309  			reg, _ := state.f.getHome(v.ID).(*Register)
  1310  			changed := state.processValue(v, slots, reg) // changed == added to state.changedVars
  1311  
  1312  			if opcodeTable[v.Op].zeroWidth {
  1313  				if prologComplete && mustBeFirst(v) {
  1314  					panic(fmt.Errorf("Unexpected placement of op '%s' appearing after non-pseudo-op at beginning of block %s in %s\n%s", v.LongString(), b, b.Func.Name, b.Func))
  1315  				}
  1316  				if changed {
  1317  					if mustBeFirst(v) || v.Op == OpArg {
  1318  						// already taken care of above
  1319  						continue
  1320  					}
  1321  					zeroWidthPending = true
  1322  				}
  1323  				continue
  1324  			}
  1325  			if !changed && !zeroWidthPending {
  1326  				continue
  1327  			}
  1328  
  1329  			// Not zero-width; i.e., a "real" instruction.
  1330  			zeroWidthPending = false
  1331  			for _, varID := range state.changedVars.contents() {
  1332  				state.updateVar(VarID(varID), v.Block, v)
  1333  			}
  1334  			state.changedVars.clear()
  1335  		}
  1336  		for _, varID := range state.changedVars.contents() {
  1337  			state.updateVar(VarID(varID), b, BlockEnd)
  1338  		}
  1339  
  1340  		prevBlock = b
  1341  	}
  1342  
  1343  	if state.loggingLevel > 0 {
  1344  		state.logf("location lists:\n")
  1345  	}
  1346  
  1347  	// Flush any leftover entries live at the end of the last block.
  1348  	for varID := range state.lists {
  1349  		state.writePendingEntry(VarID(varID), -1, FuncEnd.ID)
  1350  		list := state.lists[varID]
  1351  		if state.loggingLevel > 0 {
  1352  			if len(list) == 0 {
  1353  				state.logf("\t%v : empty list\n", state.vars[varID])
  1354  			} else {
  1355  				state.logf("\t%v : %q\n", state.vars[varID], hex.EncodeToString(state.lists[varID]))
  1356  			}
  1357  		}
  1358  	}
  1359  }
  1360  
  1361  // updateVar updates the pending location list entry for varID to
  1362  // reflect the new locations in curLoc, beginning at v in block b.
  1363  // v may be one of the special values indicating block start or end.
  1364  func (state *debugState) updateVar(varID VarID, b *Block, v *Value) {
  1365  	curLoc := state.currentState.slots
  1366  	// Assemble the location list entry with whatever's live.
  1367  	empty := true
  1368  	for _, slotID := range state.varSlots[varID] {
  1369  		if !curLoc[slotID].absent() {
  1370  			empty = false
  1371  			break
  1372  		}
  1373  	}
  1374  	pending := &state.pendingEntries[varID]
  1375  	if empty {
  1376  		state.writePendingEntry(varID, b.ID, v.ID)
  1377  		pending.clear()
  1378  		return
  1379  	}
  1380  
  1381  	// Extend the previous entry if possible.
  1382  	if pending.present {
  1383  		merge := true
  1384  		for i, slotID := range state.varSlots[varID] {
  1385  			if !canMerge(pending.pieces[i], curLoc[slotID]) {
  1386  				merge = false
  1387  				break
  1388  			}
  1389  		}
  1390  		if merge {
  1391  			return
  1392  		}
  1393  	}
  1394  
  1395  	state.writePendingEntry(varID, b.ID, v.ID)
  1396  	pending.present = true
  1397  	pending.startBlock = b.ID
  1398  	pending.startValue = v.ID
  1399  	for i, slot := range state.varSlots[varID] {
  1400  		pending.pieces[i] = curLoc[slot]
  1401  	}
  1402  }
  1403  
  1404  // writePendingEntry writes out the pending entry for varID, if any,
  1405  // terminated at endBlock/Value.
  1406  func (state *debugState) writePendingEntry(varID VarID, endBlock, endValue ID) {
  1407  	pending := state.pendingEntries[varID]
  1408  	if !pending.present {
  1409  		return
  1410  	}
  1411  
  1412  	// Pack the start/end coordinates into the start/end addresses
  1413  	// of the entry, for decoding by PutLocationList.
  1414  	start, startOK := encodeValue(state.ctxt, pending.startBlock, pending.startValue)
  1415  	end, endOK := encodeValue(state.ctxt, endBlock, endValue)
  1416  	if !startOK || !endOK {
  1417  		// If someone writes a function that uses >65K values,
  1418  		// they get incomplete debug info on 32-bit platforms.
  1419  		return
  1420  	}
  1421  	if start == end {
  1422  		if state.loggingLevel > 1 {
  1423  			// Printf not logf so not gated by GOSSAFUNC; this should fire very rarely.
  1424  			// TODO this fires a lot, need to figure out why.
  1425  			state.logf("Skipping empty location list for %v in %s\n", state.vars[varID], state.f.Name)
  1426  		}
  1427  		return
  1428  	}
  1429  
  1430  	list := state.lists[varID]
  1431  	list = appendPtr(state.ctxt, list, start)
  1432  	list = appendPtr(state.ctxt, list, end)
  1433  	// Where to write the length of the location description once
  1434  	// we know how big it is.
  1435  	sizeIdx := len(list)
  1436  	list = list[:len(list)+2]
  1437  
  1438  	if state.loggingLevel > 1 {
  1439  		var partStrs []string
  1440  		for i, slot := range state.varSlots[varID] {
  1441  			partStrs = append(partStrs, fmt.Sprintf("%v@%v", state.slots[slot], state.LocString(pending.pieces[i])))
  1442  		}
  1443  		state.logf("Add entry for %v: \tb%vv%v-b%vv%v = \t%v\n", state.vars[varID], pending.startBlock, pending.startValue, endBlock, endValue, strings.Join(partStrs, " "))
  1444  	}
  1445  
  1446  	for i, slotID := range state.varSlots[varID] {
  1447  		loc := pending.pieces[i]
  1448  		slot := state.slots[slotID]
  1449  
  1450  		if !loc.absent() {
  1451  			if loc.onStack() {
  1452  				if loc.stackOffsetValue() == 0 {
  1453  					list = append(list, dwarf.DW_OP_call_frame_cfa)
  1454  				} else {
  1455  					list = append(list, dwarf.DW_OP_fbreg)
  1456  					list = dwarf.AppendSleb128(list, int64(loc.stackOffsetValue()))
  1457  				}
  1458  			} else {
  1459  				regnum := state.ctxt.Arch.DWARFRegisters[state.registers[firstReg(loc.Registers)].ObjNum()]
  1460  				if regnum < 32 {
  1461  					list = append(list, dwarf.DW_OP_reg0+byte(regnum))
  1462  				} else {
  1463  					list = append(list, dwarf.DW_OP_regx)
  1464  					list = dwarf.AppendUleb128(list, uint64(regnum))
  1465  				}
  1466  			}
  1467  		}
  1468  
  1469  		if len(state.varSlots[varID]) > 1 {
  1470  			list = append(list, dwarf.DW_OP_piece)
  1471  			list = dwarf.AppendUleb128(list, uint64(slot.Type.Size()))
  1472  		}
  1473  	}
  1474  	state.ctxt.Arch.ByteOrder.PutUint16(list[sizeIdx:], uint16(len(list)-sizeIdx-2))
  1475  	state.lists[varID] = list
  1476  }
  1477  
  1478  // PutLocationList adds list (a location list in its intermediate
  1479  // representation) to listSym.
  1480  func (debugInfo *FuncDebug) PutLocationList(list []byte, ctxt *obj.Link, listSym, startPC *obj.LSym) {
  1481  	if buildcfg.Experiment.Dwarf5 {
  1482  		debugInfo.PutLocationListDwarf5(list, ctxt, listSym, startPC)
  1483  	} else {
  1484  		debugInfo.PutLocationListDwarf4(list, ctxt, listSym, startPC)
  1485  	}
  1486  }
  1487  
  1488  // PutLocationListDwarf5 adds list (a location list in its intermediate
  1489  // representation) to listSym in DWARF 5 format. NB: this is a somewhat
  1490  // hacky implementation in that it actually reads a DWARF4 encoded
  1491  // info from list (with all its DWARF4-specific quirks) then re-encodes
  1492  // it in DWARF5. It would probably be better at some point to have
  1493  // ssa/debug encode the list in a version-independent form and then
  1494  // have this func (and PutLocationListDwarf4) intoduce the quirks.
  1495  func (debugInfo *FuncDebug) PutLocationListDwarf5(list []byte, ctxt *obj.Link, listSym, startPC *obj.LSym) {
  1496  	getPC := debugInfo.GetPC
  1497  
  1498  	// base address entry
  1499  	listSym.WriteInt(ctxt, listSym.Size, 1, dwarf.DW_LLE_base_addressx)
  1500  	listSym.WriteDwTxtAddrx(ctxt, listSym.Size, startPC, ctxt.DwTextCount*2)
  1501  
  1502  	var stbuf, enbuf [10]byte
  1503  	stb, enb := stbuf[:], enbuf[:]
  1504  	// Re-read list, translating its address from block/value ID to PC.
  1505  	for i := 0; i < len(list); {
  1506  		begin := getPC(decodeValue(ctxt, readPtr(ctxt, list[i:])))
  1507  		end := getPC(decodeValue(ctxt, readPtr(ctxt, list[i+ctxt.Arch.PtrSize:])))
  1508  
  1509  		// Write LLE_offset_pair tag followed by payload (ULEB for start
  1510  		// and then end).
  1511  		listSym.WriteInt(ctxt, listSym.Size, 1, dwarf.DW_LLE_offset_pair)
  1512  		stb, enb = stb[:0], enb[:0]
  1513  		stb = dwarf.AppendUleb128(stb, uint64(begin))
  1514  		enb = dwarf.AppendUleb128(enb, uint64(end))
  1515  		listSym.WriteBytes(ctxt, listSym.Size, stb)
  1516  		listSym.WriteBytes(ctxt, listSym.Size, enb)
  1517  
  1518  		// The encoded data in "list" is in DWARF4 format, which uses
  1519  		// a 2-byte length; DWARF5 uses an LEB-encoded value for this
  1520  		// length. Read the length and then re-encode it.
  1521  		i += 2 * ctxt.Arch.PtrSize
  1522  		datalen := int(ctxt.Arch.ByteOrder.Uint16(list[i:]))
  1523  		i += 2
  1524  		stb = stb[:0]
  1525  		stb = dwarf.AppendUleb128(stb, uint64(datalen))
  1526  		listSym.WriteBytes(ctxt, listSym.Size, stb)               // copy length
  1527  		listSym.WriteBytes(ctxt, listSym.Size, list[i:i+datalen]) // loc desc
  1528  
  1529  		i += datalen
  1530  	}
  1531  
  1532  	// Terminator
  1533  	listSym.WriteInt(ctxt, listSym.Size, 1, dwarf.DW_LLE_end_of_list)
  1534  }
  1535  
  1536  // PutLocationListDwarf4 adds list (a location list in its intermediate
  1537  // representation) to listSym in DWARF 4 format.
  1538  func (debugInfo *FuncDebug) PutLocationListDwarf4(list []byte, ctxt *obj.Link, listSym, startPC *obj.LSym) {
  1539  	getPC := debugInfo.GetPC
  1540  
  1541  	if ctxt.UseBASEntries {
  1542  		listSym.WriteInt(ctxt, listSym.Size, ctxt.Arch.PtrSize, ^0)
  1543  		listSym.WriteAddr(ctxt, listSym.Size, ctxt.Arch.PtrSize, startPC, 0)
  1544  	}
  1545  
  1546  	// Re-read list, translating its address from block/value ID to PC.
  1547  	for i := 0; i < len(list); {
  1548  		begin := getPC(decodeValue(ctxt, readPtr(ctxt, list[i:])))
  1549  		end := getPC(decodeValue(ctxt, readPtr(ctxt, list[i+ctxt.Arch.PtrSize:])))
  1550  
  1551  		// Horrible hack. If a range contains only zero-width
  1552  		// instructions, e.g. an Arg, and it's at the beginning of the
  1553  		// function, this would be indistinguishable from an
  1554  		// end entry. Fudge it.
  1555  		if begin == 0 && end == 0 {
  1556  			end = 1
  1557  		}
  1558  
  1559  		if ctxt.UseBASEntries {
  1560  			listSym.WriteInt(ctxt, listSym.Size, ctxt.Arch.PtrSize, int64(begin))
  1561  			listSym.WriteInt(ctxt, listSym.Size, ctxt.Arch.PtrSize, int64(end))
  1562  		} else {
  1563  			listSym.WriteCURelativeAddr(ctxt, listSym.Size, startPC, int64(begin))
  1564  			listSym.WriteCURelativeAddr(ctxt, listSym.Size, startPC, int64(end))
  1565  		}
  1566  
  1567  		i += 2 * ctxt.Arch.PtrSize
  1568  		datalen := 2 + int(ctxt.Arch.ByteOrder.Uint16(list[i:]))
  1569  		listSym.WriteBytes(ctxt, listSym.Size, list[i:i+datalen]) // copy datalen and location encoding
  1570  		i += datalen
  1571  	}
  1572  
  1573  	// Location list contents, now with real PCs.
  1574  	// End entry.
  1575  	listSym.WriteInt(ctxt, listSym.Size, ctxt.Arch.PtrSize, 0)
  1576  	listSym.WriteInt(ctxt, listSym.Size, ctxt.Arch.PtrSize, 0)
  1577  }
  1578  
  1579  // Pack a value and block ID into an address-sized uint, returning
  1580  // encoded value and boolean indicating whether the encoding succeeded.
  1581  // For 32-bit architectures the process may fail for very large
  1582  // procedures(the theory being that it's ok to have degraded debug
  1583  // quality in this case).
  1584  func encodeValue(ctxt *obj.Link, b, v ID) (uint64, bool) {
  1585  	if ctxt.Arch.PtrSize == 8 {
  1586  		result := uint64(b)<<32 | uint64(uint32(v))
  1587  		//ctxt.Logf("b %#x (%d) v %#x (%d) -> %#x\n", b, b, v, v, result)
  1588  		return result, true
  1589  	}
  1590  	if ctxt.Arch.PtrSize != 4 {
  1591  		panic("unexpected pointer size")
  1592  	}
  1593  	if ID(int16(b)) != b || ID(int16(v)) != v {
  1594  		return 0, false
  1595  	}
  1596  	return uint64(b)<<16 | uint64(uint16(v)), true
  1597  }
  1598  
  1599  // Unpack a value and block ID encoded by encodeValue.
  1600  func decodeValue(ctxt *obj.Link, word uint64) (ID, ID) {
  1601  	if ctxt.Arch.PtrSize == 8 {
  1602  		b, v := ID(word>>32), ID(word)
  1603  		//ctxt.Logf("%#x -> b %#x (%d) v %#x (%d)\n", word, b, b, v, v)
  1604  		return b, v
  1605  	}
  1606  	if ctxt.Arch.PtrSize != 4 {
  1607  		panic("unexpected pointer size")
  1608  	}
  1609  	return ID(word >> 16), ID(int16(word))
  1610  }
  1611  
  1612  // Append a pointer-sized uint to buf.
  1613  func appendPtr(ctxt *obj.Link, buf []byte, word uint64) []byte {
  1614  	if cap(buf) < len(buf)+20 {
  1615  		b := make([]byte, len(buf), 20+cap(buf)*2)
  1616  		copy(b, buf)
  1617  		buf = b
  1618  	}
  1619  	writeAt := len(buf)
  1620  	buf = buf[0 : len(buf)+ctxt.Arch.PtrSize]
  1621  	writePtr(ctxt, buf[writeAt:], word)
  1622  	return buf
  1623  }
  1624  
  1625  // Write a pointer-sized uint to the beginning of buf.
  1626  func writePtr(ctxt *obj.Link, buf []byte, word uint64) {
  1627  	switch ctxt.Arch.PtrSize {
  1628  	case 4:
  1629  		ctxt.Arch.ByteOrder.PutUint32(buf, uint32(word))
  1630  	case 8:
  1631  		ctxt.Arch.ByteOrder.PutUint64(buf, word)
  1632  	default:
  1633  		panic("unexpected pointer size")
  1634  	}
  1635  
  1636  }
  1637  
  1638  // Read a pointer-sized uint from the beginning of buf.
  1639  func readPtr(ctxt *obj.Link, buf []byte) uint64 {
  1640  	switch ctxt.Arch.PtrSize {
  1641  	case 4:
  1642  		return uint64(ctxt.Arch.ByteOrder.Uint32(buf))
  1643  	case 8:
  1644  		return ctxt.Arch.ByteOrder.Uint64(buf)
  1645  	default:
  1646  		panic("unexpected pointer size")
  1647  	}
  1648  
  1649  }
  1650  
  1651  // SetupLocList creates the initial portion of a location list for a
  1652  // user variable. It emits the encoded start/end of the range and a
  1653  // placeholder for the size. Return value is the new list plus the
  1654  // slot in the list holding the size (to be updated later).
  1655  func SetupLocList(ctxt *obj.Link, entryID ID, list []byte, st, en ID) ([]byte, int) {
  1656  	start, startOK := encodeValue(ctxt, entryID, st)
  1657  	end, endOK := encodeValue(ctxt, entryID, en)
  1658  	if !startOK || !endOK {
  1659  		// This could happen if someone writes a function that uses
  1660  		// >65K values on a 32-bit platform. Hopefully a degraded debugging
  1661  		// experience is ok in that case.
  1662  		return nil, 0
  1663  	}
  1664  	list = appendPtr(ctxt, list, start)
  1665  	list = appendPtr(ctxt, list, end)
  1666  
  1667  	// Where to write the length of the location description once
  1668  	// we know how big it is.
  1669  	sizeIdx := len(list)
  1670  	list = list[:len(list)+2]
  1671  	return list, sizeIdx
  1672  }
  1673  
  1674  // locatePrologEnd walks the entry block of a function with incoming
  1675  // register arguments and locates the last instruction in the prolog
  1676  // that spills a register arg. It returns the ID of that instruction,
  1677  // and (where appropriate) the prolog's lowered closure ptr store inst.
  1678  //
  1679  // Example:
  1680  //
  1681  //	b1:
  1682  //	    v3 = ArgIntReg <int> {p1+0} [0] : AX
  1683  //	    ... more arg regs ..
  1684  //	    v4 = ArgFloatReg <float32> {f1+0} [0] : X0
  1685  //	    v52 = MOVQstore <mem> {p1} v2 v3 v1
  1686  //	    ... more stores ...
  1687  //	    v68 = MOVSSstore <mem> {f4} v2 v67 v66
  1688  //	    v38 = MOVQstoreconst <mem> {blob} [val=0,off=0] v2 v32
  1689  //
  1690  // Important: locatePrologEnd is expected to work properly only with
  1691  // optimization turned off (e.g. "-N"). If optimization is enabled
  1692  // we can't be assured of finding all input arguments spilled in the
  1693  // entry block prolog.
  1694  func locatePrologEnd(f *Func, needCloCtx bool) (ID, *Value) {
  1695  
  1696  	// returns true if this instruction looks like it moves an ABI
  1697  	// register (or context register for rangefunc bodies) to the
  1698  	// stack, along with the value being stored.
  1699  	isRegMoveLike := func(v *Value) (bool, ID) {
  1700  		n, ok := v.Aux.(*ir.Name)
  1701  		var r ID
  1702  		if (!ok || n.Class != ir.PPARAM) && !needCloCtx {
  1703  			return false, r
  1704  		}
  1705  		regInputs, memInputs, spInputs := 0, 0, 0
  1706  		for _, a := range v.Args {
  1707  			if a.Op == OpArgIntReg || a.Op == OpArgFloatReg ||
  1708  				(needCloCtx && a.Op.isLoweredGetClosurePtr()) {
  1709  				regInputs++
  1710  				r = a.ID
  1711  			} else if a.Type.IsMemory() {
  1712  				memInputs++
  1713  			} else if a.Op == OpSP {
  1714  				spInputs++
  1715  			} else {
  1716  				return false, r
  1717  			}
  1718  		}
  1719  		return v.Type.IsMemory() && memInputs == 1 &&
  1720  			regInputs == 1 && spInputs == 1, r
  1721  	}
  1722  
  1723  	// OpArg*Reg values we've seen so far on our forward walk,
  1724  	// for which we have not yet seen a corresponding spill.
  1725  	regArgs := make([]ID, 0, 32)
  1726  
  1727  	// removeReg tries to remove a value from regArgs, returning true
  1728  	// if found and removed, or false otherwise.
  1729  	removeReg := func(r ID) bool {
  1730  		for i := 0; i < len(regArgs); i++ {
  1731  			if regArgs[i] == r {
  1732  				regArgs = slices.Delete(regArgs, i, i+1)
  1733  				return true
  1734  			}
  1735  		}
  1736  		return false
  1737  	}
  1738  
  1739  	// Walk forwards through the block. When we see OpArg*Reg, record
  1740  	// the value it produces in the regArgs list. When see a store that uses
  1741  	// the value, remove the entry. When we hit the last store (use)
  1742  	// then we've arrived at the end of the prolog.
  1743  	var cloRegStore *Value
  1744  	for k, v := range f.Entry.Values {
  1745  		if v.Op == OpArgIntReg || v.Op == OpArgFloatReg {
  1746  			regArgs = append(regArgs, v.ID)
  1747  			continue
  1748  		}
  1749  		if needCloCtx && v.Op.isLoweredGetClosurePtr() {
  1750  			regArgs = append(regArgs, v.ID)
  1751  			cloRegStore = v
  1752  			continue
  1753  		}
  1754  		if ok, r := isRegMoveLike(v); ok {
  1755  			if removed := removeReg(r); removed {
  1756  				if len(regArgs) == 0 {
  1757  					// Found our last spill; return the value after
  1758  					// it. Note that it is possible that this spill is
  1759  					// the last instruction in the block. If so, then
  1760  					// return the "end of block" sentinel.
  1761  					if k < len(f.Entry.Values)-1 {
  1762  						return f.Entry.Values[k+1].ID, cloRegStore
  1763  					}
  1764  					return BlockEnd.ID, cloRegStore
  1765  				}
  1766  			}
  1767  		}
  1768  		if v.Op.IsCall() {
  1769  			// if we hit a call, we've gone too far.
  1770  			return v.ID, cloRegStore
  1771  		}
  1772  	}
  1773  	// nothing found
  1774  	return ID(-1), cloRegStore
  1775  }
  1776  
  1777  // isNamedRegParam returns true if the param corresponding to "p"
  1778  // is a named, non-blank input parameter assigned to one or more
  1779  // registers.
  1780  func isNamedRegParam(p abi.ABIParamAssignment) bool {
  1781  	if p.Name == nil {
  1782  		return false
  1783  	}
  1784  	n := p.Name
  1785  	if n.Sym() == nil || n.Sym().IsBlank() {
  1786  		return false
  1787  	}
  1788  	if len(p.Registers) == 0 {
  1789  		return false
  1790  	}
  1791  	return true
  1792  }
  1793  
  1794  // BuildFuncDebugNoOptimized populates a FuncDebug object "rval" with
  1795  // entries corresponding to the register-resident input parameters for
  1796  // the function "f"; it is used when we are compiling without
  1797  // optimization but the register ABI is enabled. For each reg param,
  1798  // it constructs a 2-element location list: the first element holds
  1799  // the input register, and the second element holds the stack location
  1800  // of the param (the assumption being that when optimization is off,
  1801  // each input param reg will be spilled in the prolog). In addition
  1802  // to the register params, here we also build location lists (where
  1803  // appropriate for the ".closureptr" compiler-synthesized variable
  1804  // needed by the debugger for range func bodies.
  1805  func BuildFuncDebugNoOptimized(ctxt *obj.Link, f *Func, loggingEnabled bool, stackOffset func(LocalSlot) int32, rval *FuncDebug) {
  1806  	needCloCtx := f.CloSlot != nil
  1807  	pri := f.ABISelf.ABIAnalyzeFuncType(f.Type)
  1808  
  1809  	// Look to see if we have any named register-promoted parameters,
  1810  	// and/or whether we need location info for the ".closureptr"
  1811  	// synthetic variable; if not bail early and let the caller sort
  1812  	// things out for the remainder of the params/locals.
  1813  	numRegParams := 0
  1814  	for _, inp := range pri.InParams() {
  1815  		if isNamedRegParam(inp) {
  1816  			numRegParams++
  1817  		}
  1818  	}
  1819  	if numRegParams == 0 && !needCloCtx {
  1820  		return
  1821  	}
  1822  
  1823  	state := debugState{f: f}
  1824  
  1825  	if loggingEnabled {
  1826  		state.logf("generating -N reg param loc lists for func %q\n", f.Name)
  1827  	}
  1828  
  1829  	// cloReg stores the obj register num that the context register
  1830  	// appears in within the function prolog, where appropriate.
  1831  	var cloReg int16
  1832  
  1833  	extraForCloCtx := 0
  1834  	if needCloCtx {
  1835  		extraForCloCtx = 1
  1836  	}
  1837  
  1838  	// Allocate location lists.
  1839  	rval.LocationLists = make([][]byte, numRegParams+extraForCloCtx)
  1840  
  1841  	// Locate the value corresponding to the last spill of
  1842  	// an input register.
  1843  	afterPrologVal, cloRegStore := locatePrologEnd(f, needCloCtx)
  1844  
  1845  	if needCloCtx {
  1846  		reg, _ := state.f.getHome(cloRegStore.ID).(*Register)
  1847  		cloReg = reg.ObjNum()
  1848  		if loggingEnabled {
  1849  			state.logf("needCloCtx is true for func %q, cloreg=%v\n",
  1850  				f.Name, reg)
  1851  		}
  1852  	}
  1853  
  1854  	addVarSlot := func(name *ir.Name, typ *types.Type) {
  1855  		sl := LocalSlot{N: name, Type: typ, Off: 0}
  1856  		rval.Vars = append(rval.Vars, name)
  1857  		rval.Slots = append(rval.Slots, sl)
  1858  		slid := len(rval.VarSlots)
  1859  		rval.VarSlots = append(rval.VarSlots, []SlotID{SlotID(slid)})
  1860  	}
  1861  
  1862  	// Make an initial pass to populate the vars/slots for our return
  1863  	// value, covering first the input parameters and then (if needed)
  1864  	// the special ".closureptr" var for rangefunc bodies.
  1865  	params := []abi.ABIParamAssignment{}
  1866  	for _, inp := range pri.InParams() {
  1867  		if !isNamedRegParam(inp) {
  1868  			// will be sorted out elsewhere
  1869  			continue
  1870  		}
  1871  		if !IsVarWantedForDebug(inp.Name) {
  1872  			continue
  1873  		}
  1874  		addVarSlot(inp.Name, inp.Type)
  1875  		params = append(params, inp)
  1876  	}
  1877  	if needCloCtx {
  1878  		addVarSlot(f.CloSlot, f.CloSlot.Type())
  1879  		cloAssign := abi.ABIParamAssignment{
  1880  			Type:      f.CloSlot.Type(),
  1881  			Name:      f.CloSlot,
  1882  			Registers: []abi.RegIndex{0}, // dummy
  1883  		}
  1884  		params = append(params, cloAssign)
  1885  	}
  1886  
  1887  	// Walk the input params again and process the register-resident elements.
  1888  	pidx := 0
  1889  	for _, inp := range params {
  1890  		if !isNamedRegParam(inp) {
  1891  			// will be sorted out elsewhere
  1892  			continue
  1893  		}
  1894  		if !IsVarWantedForDebug(inp.Name) {
  1895  			continue
  1896  		}
  1897  
  1898  		sl := rval.Slots[pidx]
  1899  		n := rval.Vars[pidx]
  1900  
  1901  		if afterPrologVal == ID(-1) {
  1902  			// This can happen for degenerate functions with infinite
  1903  			// loops such as that in issue 45948. In such cases, leave
  1904  			// the var/slot set up for the param, but don't try to
  1905  			// emit a location list.
  1906  			if loggingEnabled {
  1907  				state.logf("locatePrologEnd failed, skipping %v\n", n)
  1908  			}
  1909  			pidx++
  1910  			continue
  1911  		}
  1912  
  1913  		// Param is arriving in one or more registers. We need a 2-element
  1914  		// location expression for it. First entry in location list
  1915  		// will correspond to lifetime in input registers.
  1916  		list, sizeIdx := SetupLocList(ctxt, f.Entry.ID, rval.LocationLists[pidx],
  1917  			BlockStart.ID, afterPrologVal)
  1918  		if list == nil {
  1919  			pidx++
  1920  			continue
  1921  		}
  1922  		if loggingEnabled {
  1923  			state.logf("param %v:\n  [<entry>, %d]:\n", n, afterPrologVal)
  1924  		}
  1925  		rtypes, _ := inp.RegisterTypesAndOffsets()
  1926  		padding := make([]uint64, 0, 32)
  1927  		padding = inp.ComputePadding(padding)
  1928  		for k, r := range inp.Registers {
  1929  			var reg int16
  1930  			if n == f.CloSlot {
  1931  				reg = cloReg
  1932  			} else {
  1933  				reg = ObjRegForAbiReg(r, f.Config)
  1934  			}
  1935  			dwreg := ctxt.Arch.DWARFRegisters[reg]
  1936  			if dwreg < 32 {
  1937  				list = append(list, dwarf.DW_OP_reg0+byte(dwreg))
  1938  			} else {
  1939  				list = append(list, dwarf.DW_OP_regx)
  1940  				list = dwarf.AppendUleb128(list, uint64(dwreg))
  1941  			}
  1942  			if loggingEnabled {
  1943  				state.logf("    piece %d -> dwreg %d", k, dwreg)
  1944  			}
  1945  			if len(inp.Registers) > 1 {
  1946  				list = append(list, dwarf.DW_OP_piece)
  1947  				ts := rtypes[k].Size()
  1948  				list = dwarf.AppendUleb128(list, uint64(ts))
  1949  				if padding[k] > 0 {
  1950  					if loggingEnabled {
  1951  						state.logf(" [pad %d bytes]", padding[k])
  1952  					}
  1953  					list = append(list, dwarf.DW_OP_piece)
  1954  					list = dwarf.AppendUleb128(list, padding[k])
  1955  				}
  1956  			}
  1957  			if loggingEnabled {
  1958  				state.logf("\n")
  1959  			}
  1960  		}
  1961  		// fill in length of location expression element
  1962  		ctxt.Arch.ByteOrder.PutUint16(list[sizeIdx:], uint16(len(list)-sizeIdx-2))
  1963  
  1964  		// Second entry in the location list will be the stack home
  1965  		// of the param, once it has been spilled.  Emit that now.
  1966  		list, sizeIdx = SetupLocList(ctxt, f.Entry.ID, list,
  1967  			afterPrologVal, FuncEnd.ID)
  1968  		if list == nil {
  1969  			pidx++
  1970  			continue
  1971  		}
  1972  		soff := stackOffset(sl)
  1973  		if soff == 0 {
  1974  			list = append(list, dwarf.DW_OP_call_frame_cfa)
  1975  		} else {
  1976  			list = append(list, dwarf.DW_OP_fbreg)
  1977  			list = dwarf.AppendSleb128(list, int64(soff))
  1978  		}
  1979  		if loggingEnabled {
  1980  			state.logf("  [%d, <end>): stackOffset=%d\n", afterPrologVal, soff)
  1981  		}
  1982  
  1983  		// fill in size
  1984  		ctxt.Arch.ByteOrder.PutUint16(list[sizeIdx:], uint16(len(list)-sizeIdx-2))
  1985  
  1986  		rval.LocationLists[pidx] = list
  1987  		pidx++
  1988  	}
  1989  }
  1990  
  1991  // IsVarWantedForDebug returns true if the debug info for the node should
  1992  // be generated.
  1993  // For example, internal variables for range-over-func loops have little
  1994  // value to users, so we don't generate debug info for them.
  1995  func IsVarWantedForDebug(n ir.Node) bool {
  1996  	name := n.Sym().Name
  1997  	if len(name) > 0 && name[0] == '&' {
  1998  		name = name[1:]
  1999  	}
  2000  	if len(name) > 0 && name[0] == '#' {
  2001  		// #yield is used by delve.
  2002  		return strings.HasPrefix(name, "#yield")
  2003  	}
  2004  	return true
  2005  }
  2006  

View as plain text