github.com/corona10/go@v0.0.0-20180224231303-7a218942be57/src/cmd/compile/internal/ssa/debug.go (about)

     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  package ssa
     5  
     6  import (
     7  	"cmd/internal/dwarf"
     8  	"cmd/internal/obj"
     9  	"encoding/hex"
    10  	"fmt"
    11  	"sort"
    12  	"strings"
    13  )
    14  
    15  type SlotID int32
    16  type VarID int32
    17  
    18  // A FuncDebug contains all the debug information for the variables in a
    19  // function. Variables are identified by their LocalSlot, which may be the
    20  // result of decomposing a larger variable.
    21  type FuncDebug struct {
    22  	// Slots is all the slots used in the debug info, indexed by their SlotID.
    23  	Slots []LocalSlot
    24  	// The user variables, indexed by VarID.
    25  	Vars []GCNode
    26  	// The slots that make up each variable, indexed by VarID.
    27  	VarSlots [][]SlotID
    28  	// The location list data, indexed by VarID. Must be processed by PutLocationList.
    29  	LocationLists [][]byte
    30  
    31  	// Filled in by the user. Translates Block and Value ID to PC.
    32  	GetPC func(ID, ID) int64
    33  }
    34  
    35  type BlockDebug struct {
    36  	// Whether the block had any changes to user variables at all.
    37  	relevant bool
    38  	// State at the end of the block if it's fully processed. Immutable once initialized.
    39  	endState []liveSlot
    40  }
    41  
    42  // A liveSlot is a slot that's live in loc at entry/exit of a block.
    43  type liveSlot struct {
    44  	// An inlined VarLoc, so it packs into 16 bytes instead of 20.
    45  	Registers RegisterSet
    46  	StackOffset
    47  
    48  	slot SlotID
    49  }
    50  
    51  func (loc liveSlot) absent() bool {
    52  	return loc.Registers == 0 && !loc.onStack()
    53  }
    54  
    55  // StackOffset encodes whether a value is on the stack and if so, where. It is
    56  // a 31-bit integer followed by a presence flag at the low-order bit.
    57  type StackOffset int32
    58  
    59  func (s StackOffset) onStack() bool {
    60  	return s != 0
    61  }
    62  
    63  func (s StackOffset) stackOffsetValue() int32 {
    64  	return int32(s) >> 1
    65  }
    66  
    67  // stateAtPC is the current state of all variables at some point.
    68  type stateAtPC struct {
    69  	// The location of each known slot, indexed by SlotID.
    70  	slots []VarLoc
    71  	// The slots present in each register, indexed by register number.
    72  	registers [][]SlotID
    73  }
    74  
    75  // reset fills state with the live variables from live.
    76  func (state *stateAtPC) reset(live []liveSlot) {
    77  	slots, registers := state.slots, state.registers
    78  	for i := range slots {
    79  		slots[i] = VarLoc{}
    80  	}
    81  	for i := range registers {
    82  		registers[i] = registers[i][:0]
    83  	}
    84  	for _, live := range live {
    85  		slots[live.slot] = VarLoc{live.Registers, live.StackOffset}
    86  		if live.Registers == 0 {
    87  			continue
    88  		}
    89  
    90  		mask := uint64(live.Registers)
    91  		for {
    92  			if mask == 0 {
    93  				break
    94  			}
    95  			reg := uint8(TrailingZeros64(mask))
    96  			mask &^= 1 << reg
    97  
    98  			registers[reg] = append(registers[reg], SlotID(live.slot))
    99  		}
   100  	}
   101  	state.slots, state.registers = slots, registers
   102  }
   103  
   104  func (s *debugState) LocString(loc VarLoc) string {
   105  	if loc.absent() {
   106  		return "<nil>"
   107  	}
   108  
   109  	var storage []string
   110  	if loc.onStack() {
   111  		storage = append(storage, "stack")
   112  	}
   113  
   114  	mask := uint64(loc.Registers)
   115  	for {
   116  		if mask == 0 {
   117  			break
   118  		}
   119  		reg := uint8(TrailingZeros64(mask))
   120  		mask &^= 1 << reg
   121  
   122  		storage = append(storage, s.registers[reg].String())
   123  	}
   124  	return strings.Join(storage, ",")
   125  }
   126  
   127  // A VarLoc describes the storage for part of a user variable.
   128  type VarLoc struct {
   129  	// The registers this variable is available in. There can be more than
   130  	// one in various situations, e.g. it's being moved between registers.
   131  	Registers RegisterSet
   132  
   133  	StackOffset
   134  }
   135  
   136  func (loc VarLoc) absent() bool {
   137  	return loc.Registers == 0 && !loc.onStack()
   138  }
   139  
   140  var BlockStart = &Value{
   141  	ID:  -10000,
   142  	Op:  OpInvalid,
   143  	Aux: "BlockStart",
   144  }
   145  
   146  var BlockEnd = &Value{
   147  	ID:  -20000,
   148  	Op:  OpInvalid,
   149  	Aux: "BlockEnd",
   150  }
   151  
   152  // RegisterSet is a bitmap of registers, indexed by Register.num.
   153  type RegisterSet uint64
   154  
   155  // unexpected is used to indicate an inconsistency or bug in the debug info
   156  // generation process. These are not fixable by users. At time of writing,
   157  // changing this to a Fprintf(os.Stderr) and running make.bash generates
   158  // thousands of warnings.
   159  func (s *debugState) unexpected(v *Value, msg string, args ...interface{}) {
   160  	s.f.Logf("unexpected at "+fmt.Sprint(v.ID)+":"+msg, args...)
   161  }
   162  
   163  func (s *debugState) logf(msg string, args ...interface{}) {
   164  	s.f.Logf(msg, args...)
   165  }
   166  
   167  type debugState struct {
   168  	// See FuncDebug.
   169  	slots    []LocalSlot
   170  	vars     []GCNode
   171  	varSlots [][]SlotID
   172  	lists    [][]byte
   173  
   174  	// The user variable that each slot rolls up to, indexed by SlotID.
   175  	slotVars []VarID
   176  
   177  	f              *Func
   178  	loggingEnabled bool
   179  	registers      []Register
   180  	stackOffset    func(LocalSlot) int32
   181  	ctxt           *obj.Link
   182  
   183  	// The names (slots) associated with each value, indexed by Value ID.
   184  	valueNames [][]SlotID
   185  
   186  	// The current state of whatever analysis is running.
   187  	currentState stateAtPC
   188  	liveCount    []int
   189  	changedVars  *sparseSet
   190  
   191  	// The pending location list entry for each user variable, indexed by VarID.
   192  	pendingEntries []pendingEntry
   193  
   194  	varParts           map[GCNode][]SlotID
   195  	blockDebug         []BlockDebug
   196  	pendingSlotLocs    []VarLoc
   197  	liveSlots          []liveSlot
   198  	liveSlotSliceBegin int
   199  	partsByVarOffset   sort.Interface
   200  }
   201  
   202  func (state *debugState) initializeCache(f *Func, numVars, numSlots int) {
   203  	// One blockDebug per block. Initialized in allocBlock.
   204  	if cap(state.blockDebug) < f.NumBlocks() {
   205  		state.blockDebug = make([]BlockDebug, f.NumBlocks())
   206  	} else {
   207  		// This local variable, and the ones like it below, enable compiler
   208  		// optimizations. Don't inline them.
   209  		b := state.blockDebug[:f.NumBlocks()]
   210  		for i := range b {
   211  			b[i] = BlockDebug{}
   212  		}
   213  	}
   214  
   215  	// A list of slots per Value. Reuse the previous child slices.
   216  	if cap(state.valueNames) < f.NumValues() {
   217  		old := state.valueNames
   218  		state.valueNames = make([][]SlotID, f.NumValues())
   219  		copy(state.valueNames, old)
   220  	}
   221  	vn := state.valueNames[:f.NumValues()]
   222  	for i := range vn {
   223  		vn[i] = vn[i][:0]
   224  	}
   225  
   226  	// Slot and register contents for currentState. Cleared by reset().
   227  	if cap(state.currentState.slots) < numSlots {
   228  		state.currentState.slots = make([]VarLoc, numSlots)
   229  	} else {
   230  		state.currentState.slots = state.currentState.slots[:numSlots]
   231  	}
   232  	if cap(state.currentState.registers) < len(state.registers) {
   233  		state.currentState.registers = make([][]SlotID, len(state.registers))
   234  	} else {
   235  		state.currentState.registers = state.currentState.registers[:len(state.registers)]
   236  	}
   237  
   238  	// Used many times by mergePredecessors.
   239  	if cap(state.liveCount) < numSlots {
   240  		state.liveCount = make([]int, numSlots)
   241  	} else {
   242  		state.liveCount = state.liveCount[:numSlots]
   243  	}
   244  
   245  	// A relatively small slice, but used many times as the return from processValue.
   246  	state.changedVars = newSparseSet(numVars)
   247  
   248  	// A pending entry per user variable, with space to track each of its pieces.
   249  	numPieces := 0
   250  	for i := range state.varSlots {
   251  		numPieces += len(state.varSlots[i])
   252  	}
   253  	if cap(state.pendingSlotLocs) < numPieces {
   254  		state.pendingSlotLocs = make([]VarLoc, numPieces)
   255  	} else {
   256  		psl := state.pendingSlotLocs[:numPieces]
   257  		for i := range psl {
   258  			psl[i] = VarLoc{}
   259  		}
   260  	}
   261  	if cap(state.pendingEntries) < numVars {
   262  		state.pendingEntries = make([]pendingEntry, numVars)
   263  	}
   264  	pe := state.pendingEntries[:numVars]
   265  	freePieceIdx := 0
   266  	for varID, slots := range state.varSlots {
   267  		pe[varID] = pendingEntry{
   268  			pieces: state.pendingSlotLocs[freePieceIdx : freePieceIdx+len(slots)],
   269  		}
   270  		freePieceIdx += len(slots)
   271  	}
   272  	state.pendingEntries = pe
   273  
   274  	if cap(state.lists) < numVars {
   275  		state.lists = make([][]byte, numVars)
   276  	} else {
   277  		state.lists = state.lists[:numVars]
   278  		for i := range state.lists {
   279  			state.lists[i] = nil
   280  		}
   281  	}
   282  
   283  	state.liveSlots = state.liveSlots[:0]
   284  	state.liveSlotSliceBegin = 0
   285  }
   286  
   287  func (state *debugState) allocBlock(b *Block) *BlockDebug {
   288  	return &state.blockDebug[b.ID]
   289  }
   290  
   291  func (state *debugState) appendLiveSlot(ls liveSlot) {
   292  	state.liveSlots = append(state.liveSlots, ls)
   293  }
   294  
   295  func (state *debugState) getLiveSlotSlice() []liveSlot {
   296  	s := state.liveSlots[state.liveSlotSliceBegin:]
   297  	state.liveSlotSliceBegin = len(state.liveSlots)
   298  	return s
   299  }
   300  
   301  func (s *debugState) blockEndStateString(b *BlockDebug) string {
   302  	endState := stateAtPC{slots: make([]VarLoc, len(s.slots)), registers: make([][]SlotID, len(s.registers))}
   303  	endState.reset(b.endState)
   304  	return s.stateString(endState)
   305  }
   306  
   307  func (s *debugState) stateString(state stateAtPC) string {
   308  	var strs []string
   309  	for slotID, loc := range state.slots {
   310  		if !loc.absent() {
   311  			strs = append(strs, fmt.Sprintf("\t%v = %v\n", s.slots[slotID], s.LocString(loc)))
   312  		}
   313  	}
   314  
   315  	strs = append(strs, "\n")
   316  	for reg, slots := range state.registers {
   317  		if len(slots) != 0 {
   318  			var slotStrs []string
   319  			for _, slot := range slots {
   320  				slotStrs = append(slotStrs, s.slots[slot].String())
   321  			}
   322  			strs = append(strs, fmt.Sprintf("\t%v = %v\n", &s.registers[reg], slotStrs))
   323  		}
   324  	}
   325  
   326  	if len(strs) == 1 {
   327  		return "(no vars)\n"
   328  	}
   329  	return strings.Join(strs, "")
   330  }
   331  
   332  // BuildFuncDebug returns debug information for f.
   333  // f must be fully processed, so that each Value is where it will be when
   334  // machine code is emitted.
   335  func BuildFuncDebug(ctxt *obj.Link, f *Func, loggingEnabled bool, stackOffset func(LocalSlot) int32) *FuncDebug {
   336  	if f.RegAlloc == nil {
   337  		f.Fatalf("BuildFuncDebug on func %v that has not been fully processed", f)
   338  	}
   339  	state := &f.Cache.debugState
   340  	state.loggingEnabled = loggingEnabled
   341  	state.f = f
   342  	state.registers = f.Config.registers
   343  	state.stackOffset = stackOffset
   344  	state.ctxt = ctxt
   345  
   346  	if state.varParts == nil {
   347  		state.varParts = make(map[GCNode][]SlotID)
   348  	} else {
   349  		for n := range state.varParts {
   350  			delete(state.varParts, n)
   351  		}
   352  	}
   353  
   354  	// Recompose any decomposed variables, and establish the canonical
   355  	// IDs for each var and slot by filling out state.vars and state.slots.
   356  
   357  	state.slots = state.slots[:0]
   358  	state.vars = state.vars[:0]
   359  	for i, slot := range f.Names {
   360  		state.slots = append(state.slots, slot)
   361  		if slot.N.IsSynthetic() {
   362  			continue
   363  		}
   364  
   365  		topSlot := &slot
   366  		for topSlot.SplitOf != nil {
   367  			topSlot = topSlot.SplitOf
   368  		}
   369  		if _, ok := state.varParts[topSlot.N]; !ok {
   370  			state.vars = append(state.vars, topSlot.N)
   371  		}
   372  		state.varParts[topSlot.N] = append(state.varParts[topSlot.N], SlotID(i))
   373  	}
   374  
   375  	// Fill in the var<->slot mappings.
   376  	if cap(state.varSlots) < len(state.vars) {
   377  		state.varSlots = make([][]SlotID, len(state.vars))
   378  	} else {
   379  		state.varSlots = state.varSlots[:len(state.vars)]
   380  		for i := range state.varSlots {
   381  			state.varSlots[i] = state.varSlots[i][:0]
   382  		}
   383  	}
   384  	if cap(state.slotVars) < len(state.slots) {
   385  		state.slotVars = make([]VarID, len(state.slots))
   386  	} else {
   387  		state.slotVars = state.slotVars[:len(state.slots)]
   388  	}
   389  
   390  	if state.partsByVarOffset == nil {
   391  		state.partsByVarOffset = &partsByVarOffset{}
   392  	}
   393  	for varID, n := range state.vars {
   394  		parts := state.varParts[n]
   395  		state.varSlots[varID] = parts
   396  		for _, slotID := range parts {
   397  			state.slotVars[slotID] = VarID(varID)
   398  		}
   399  		*state.partsByVarOffset.(*partsByVarOffset) = partsByVarOffset{parts, state.slots}
   400  		sort.Sort(state.partsByVarOffset)
   401  	}
   402  
   403  	state.initializeCache(f, len(state.varParts), len(state.slots))
   404  
   405  	for i, slot := range f.Names {
   406  		if slot.N.IsSynthetic() {
   407  			continue
   408  		}
   409  		for _, value := range f.NamedValues[slot] {
   410  			state.valueNames[value.ID] = append(state.valueNames[value.ID], SlotID(i))
   411  		}
   412  	}
   413  
   414  	blockLocs := state.liveness()
   415  	state.buildLocationLists(blockLocs)
   416  
   417  	return &FuncDebug{
   418  		Slots:         state.slots,
   419  		VarSlots:      state.varSlots,
   420  		Vars:          state.vars,
   421  		LocationLists: state.lists,
   422  	}
   423  }
   424  
   425  // liveness walks the function in control flow order, calculating the start
   426  // and end state of each block.
   427  func (state *debugState) liveness() []*BlockDebug {
   428  	blockLocs := make([]*BlockDebug, state.f.NumBlocks())
   429  
   430  	// Reverse postorder: visit a block after as many as possible of its
   431  	// predecessors have been visited.
   432  	po := state.f.Postorder()
   433  	for i := len(po) - 1; i >= 0; i-- {
   434  		b := po[i]
   435  
   436  		// Build the starting state for the block from the final
   437  		// state of its predecessors.
   438  		startState, startValid := state.mergePredecessors(b, blockLocs)
   439  		changed := false
   440  		if state.loggingEnabled {
   441  			state.logf("Processing %v, initial state:\n%v", b, state.stateString(state.currentState))
   442  		}
   443  
   444  		// Update locs/registers with the effects of each Value.
   445  		for _, v := range b.Values {
   446  			slots := state.valueNames[v.ID]
   447  
   448  			// Loads and stores inherit the names of their sources.
   449  			var source *Value
   450  			switch v.Op {
   451  			case OpStoreReg:
   452  				source = v.Args[0]
   453  			case OpLoadReg:
   454  				switch a := v.Args[0]; a.Op {
   455  				case OpArg:
   456  					source = a
   457  				case OpStoreReg:
   458  					source = a.Args[0]
   459  				default:
   460  					state.unexpected(v, "load with unexpected source op %v", a)
   461  				}
   462  			}
   463  			// Update valueNames with the source so that later steps
   464  			// don't need special handling.
   465  			if source != nil {
   466  				slots = append(slots, state.valueNames[source.ID]...)
   467  				state.valueNames[v.ID] = slots
   468  			}
   469  
   470  			reg, _ := state.f.getHome(v.ID).(*Register)
   471  			c := state.processValue(v, slots, reg)
   472  			changed = changed || c
   473  		}
   474  
   475  		if state.loggingEnabled {
   476  			state.f.Logf("Block %v done, locs:\n%v", b, state.stateString(state.currentState))
   477  		}
   478  
   479  		locs := state.allocBlock(b)
   480  		locs.relevant = changed
   481  		if !changed && startValid {
   482  			locs.endState = startState
   483  		} else {
   484  			for slotID, slotLoc := range state.currentState.slots {
   485  				if slotLoc.absent() {
   486  					continue
   487  				}
   488  				state.appendLiveSlot(liveSlot{slot: SlotID(slotID), Registers: slotLoc.Registers, StackOffset: slotLoc.StackOffset})
   489  			}
   490  			locs.endState = state.getLiveSlotSlice()
   491  		}
   492  		blockLocs[b.ID] = locs
   493  	}
   494  	return blockLocs
   495  }
   496  
   497  // mergePredecessors takes the end state of each of b's predecessors and
   498  // intersects them to form the starting state for b. It returns that state in
   499  // the BlockDebug, and fills state.currentState with it.
   500  func (state *debugState) mergePredecessors(b *Block, blockLocs []*BlockDebug) ([]liveSlot, bool) {
   501  	// Filter out back branches.
   502  	var predsBuf [10]*Block
   503  	preds := predsBuf[:0]
   504  	for _, pred := range b.Preds {
   505  		if blockLocs[pred.b.ID] != nil {
   506  			preds = append(preds, pred.b)
   507  		}
   508  	}
   509  
   510  	if state.loggingEnabled {
   511  		// The logf below would cause preds to be heap-allocated if
   512  		// it were passed directly.
   513  		preds2 := make([]*Block, len(preds))
   514  		copy(preds2, preds)
   515  		state.logf("Merging %v into %v\n", preds2, b)
   516  	}
   517  
   518  	if len(preds) == 0 {
   519  		if state.loggingEnabled {
   520  		}
   521  		state.currentState.reset(nil)
   522  		return nil, true
   523  	}
   524  
   525  	p0 := blockLocs[preds[0].ID].endState
   526  	if len(preds) == 1 {
   527  		state.currentState.reset(p0)
   528  		return p0, true
   529  	}
   530  
   531  	if state.loggingEnabled {
   532  		state.logf("Starting %v with state from %v:\n%v", b, preds[0], state.blockEndStateString(blockLocs[preds[0].ID]))
   533  	}
   534  
   535  	slotLocs := state.currentState.slots
   536  	for _, predSlot := range p0 {
   537  		slotLocs[predSlot.slot] = VarLoc{predSlot.Registers, predSlot.StackOffset}
   538  		state.liveCount[predSlot.slot] = 1
   539  	}
   540  	for i := 1; i < len(preds); i++ {
   541  		if state.loggingEnabled {
   542  			state.logf("Merging in state from %v:\n%v", preds[i], state.blockEndStateString(blockLocs[preds[i].ID]))
   543  		}
   544  		for _, predSlot := range blockLocs[preds[i].ID].endState {
   545  			state.liveCount[predSlot.slot]++
   546  			liveLoc := slotLocs[predSlot.slot]
   547  			if !liveLoc.onStack() || !predSlot.onStack() || liveLoc.StackOffset != predSlot.StackOffset {
   548  				liveLoc.StackOffset = 0
   549  			}
   550  			liveLoc.Registers &= predSlot.Registers
   551  			slotLocs[predSlot.slot] = liveLoc
   552  		}
   553  	}
   554  
   555  	// Check if the final state is the same as the first predecessor's
   556  	// final state, and reuse it if so. In principle it could match any,
   557  	// but it's probably not worth checking more than the first.
   558  	unchanged := true
   559  	for _, predSlot := range p0 {
   560  		if state.liveCount[predSlot.slot] != len(preds) ||
   561  			slotLocs[predSlot.slot].Registers != predSlot.Registers ||
   562  			slotLocs[predSlot.slot].StackOffset != predSlot.StackOffset {
   563  			unchanged = false
   564  			break
   565  		}
   566  	}
   567  	if unchanged {
   568  		if state.loggingEnabled {
   569  			state.logf("After merge, %v matches %v exactly.\n", b, preds[0])
   570  		}
   571  		state.currentState.reset(p0)
   572  		return p0, true
   573  	}
   574  
   575  	for reg := range state.currentState.registers {
   576  		state.currentState.registers[reg] = state.currentState.registers[reg][:0]
   577  	}
   578  
   579  	// A slot is live if it was seen in all predecessors, and they all had
   580  	// some storage in common.
   581  	for slotID := range p0 {
   582  		slotLoc := slotLocs[slotID]
   583  
   584  		if state.liveCount[slotID] != len(preds) {
   585  			// Seen in only some predecessors. Clear it out.
   586  			slotLocs[slotID] = VarLoc{}
   587  			continue
   588  		}
   589  
   590  		// Present in all predecessors.
   591  		mask := uint64(slotLoc.Registers)
   592  		for {
   593  			if mask == 0 {
   594  				break
   595  			}
   596  			reg := uint8(TrailingZeros64(mask))
   597  			mask &^= 1 << reg
   598  
   599  			state.currentState.registers[reg] = append(state.currentState.registers[reg], SlotID(slotID))
   600  		}
   601  	}
   602  	return nil, false
   603  }
   604  
   605  // processValue updates locs and state.registerContents to reflect v, a value with
   606  // the names in vSlots and homed in vReg.  "v" becomes visible after execution of
   607  // the instructions evaluating it. It returns which VarIDs were modified by the
   608  // Value's execution.
   609  func (state *debugState) processValue(v *Value, vSlots []SlotID, vReg *Register) bool {
   610  	locs := state.currentState
   611  	changed := false
   612  	setSlot := func(slot SlotID, loc VarLoc) {
   613  		changed = true
   614  		state.changedVars.add(ID(state.slotVars[slot]))
   615  		state.currentState.slots[slot] = loc
   616  	}
   617  
   618  	// Handle any register clobbering. Call operations, for example,
   619  	// clobber all registers even though they don't explicitly write to
   620  	// them.
   621  	clobbers := uint64(opcodeTable[v.Op].reg.clobbers)
   622  	for {
   623  		if clobbers == 0 {
   624  			break
   625  		}
   626  		reg := uint8(TrailingZeros64(clobbers))
   627  		clobbers &^= 1 << reg
   628  
   629  		for _, slot := range locs.registers[reg] {
   630  			if state.loggingEnabled {
   631  				state.logf("at %v: %v clobbered out of %v\n", v.ID, state.slots[slot], &state.registers[reg])
   632  			}
   633  
   634  			last := locs.slots[slot]
   635  			if last.absent() {
   636  				state.f.Fatalf("at %v: slot %v in register %v with no location entry", v, state.slots[slot], &state.registers[reg])
   637  				continue
   638  			}
   639  			regs := last.Registers &^ (1 << uint8(reg))
   640  			setSlot(slot, VarLoc{regs, last.StackOffset})
   641  		}
   642  
   643  		locs.registers[reg] = locs.registers[reg][:0]
   644  	}
   645  
   646  	switch {
   647  	case v.Op == OpArg:
   648  		home := state.f.getHome(v.ID).(LocalSlot)
   649  		stackOffset := state.stackOffset(home)<<1 | 1
   650  		for _, slot := range vSlots {
   651  			if state.loggingEnabled {
   652  				state.logf("at %v: arg %v now on stack in location %v\n", v.ID, state.slots[slot], home)
   653  				if last := locs.slots[slot]; !last.absent() {
   654  					state.unexpected(v, "Arg op on already-live slot %v", state.slots[slot])
   655  				}
   656  			}
   657  
   658  			setSlot(slot, VarLoc{0, StackOffset(stackOffset)})
   659  		}
   660  
   661  	case v.Op == OpStoreReg:
   662  		home := state.f.getHome(v.ID).(LocalSlot)
   663  		stackOffset := state.stackOffset(home)<<1 | 1
   664  		for _, slot := range vSlots {
   665  			last := locs.slots[slot]
   666  			if last.absent() {
   667  				state.unexpected(v, "spill of unnamed register %s\n", vReg)
   668  				break
   669  			}
   670  
   671  			setSlot(slot, VarLoc{last.Registers, StackOffset(stackOffset)})
   672  			if state.loggingEnabled {
   673  				state.logf("at %v: %v spilled to stack location %v\n", v.ID, state.slots[slot], home)
   674  			}
   675  		}
   676  
   677  	case vReg != nil:
   678  		if state.loggingEnabled {
   679  			newSlots := make([]bool, len(state.slots))
   680  			for _, slot := range vSlots {
   681  				newSlots[slot] = true
   682  			}
   683  
   684  			for _, slot := range locs.registers[vReg.num] {
   685  				if !newSlots[slot] {
   686  					state.logf("at %v: overwrote %v in register %v\n", v, state.slots[slot], vReg)
   687  				}
   688  			}
   689  		}
   690  
   691  		for _, slot := range locs.registers[vReg.num] {
   692  			last := locs.slots[slot]
   693  			setSlot(slot, VarLoc{last.Registers &^ (1 << uint8(vReg.num)), last.StackOffset})
   694  		}
   695  		locs.registers[vReg.num] = locs.registers[vReg.num][:0]
   696  		locs.registers[vReg.num] = append(locs.registers[vReg.num], vSlots...)
   697  		for _, slot := range vSlots {
   698  			if state.loggingEnabled {
   699  				state.logf("at %v: %v now in %s\n", v.ID, state.slots[slot], vReg)
   700  			}
   701  
   702  			last := locs.slots[slot]
   703  			setSlot(slot, VarLoc{1<<uint8(vReg.num) | last.Registers, last.StackOffset})
   704  		}
   705  	}
   706  	return changed
   707  }
   708  
   709  // varOffset returns the offset of slot within the user variable it was
   710  // decomposed from. This has nothing to do with its stack offset.
   711  func varOffset(slot LocalSlot) int64 {
   712  	offset := slot.Off
   713  	s := &slot
   714  	for ; s.SplitOf != nil; s = s.SplitOf {
   715  		offset += s.SplitOffset
   716  	}
   717  	return offset
   718  }
   719  
   720  type partsByVarOffset struct {
   721  	slotIDs []SlotID
   722  	slots   []LocalSlot
   723  }
   724  
   725  func (a partsByVarOffset) Len() int { return len(a.slotIDs) }
   726  func (a partsByVarOffset) Less(i, j int) bool {
   727  	return varOffset(a.slots[a.slotIDs[i]]) < varOffset(a.slots[a.slotIDs[i]])
   728  }
   729  func (a partsByVarOffset) Swap(i, j int) { a.slotIDs[i], a.slotIDs[j] = a.slotIDs[j], a.slotIDs[i] }
   730  
   731  // A pendingEntry represents the beginning of a location list entry, missing
   732  // only its end coordinate.
   733  type pendingEntry struct {
   734  	present                bool
   735  	startBlock, startValue ID
   736  	// The location of each piece of the variable, in the same order as the
   737  	// SlotIDs in varParts.
   738  	pieces []VarLoc
   739  }
   740  
   741  func (e *pendingEntry) clear() {
   742  	e.present = false
   743  	e.startBlock = 0
   744  	e.startValue = 0
   745  	for i := range e.pieces {
   746  		e.pieces[i] = VarLoc{}
   747  	}
   748  }
   749  
   750  // canMerge returns true if the location description for new is the same as
   751  // pending.
   752  func canMerge(pending, new VarLoc) bool {
   753  	if pending.absent() && new.absent() {
   754  		return true
   755  	}
   756  	if pending.absent() || new.absent() {
   757  		return false
   758  	}
   759  	if pending.onStack() {
   760  		return pending.StackOffset == new.StackOffset
   761  	}
   762  	if pending.Registers != 0 && new.Registers != 0 {
   763  		return firstReg(pending.Registers) == firstReg(new.Registers)
   764  	}
   765  	return false
   766  }
   767  
   768  // firstReg returns the first register in set that is present.
   769  func firstReg(set RegisterSet) uint8 {
   770  	if set == 0 {
   771  		// This is wrong, but there seem to be some situations where we
   772  		// produce locations with no storage.
   773  		return 0
   774  	}
   775  	return uint8(TrailingZeros64(uint64(set)))
   776  }
   777  
   778  // buildLocationLists builds location lists for all the user variables in
   779  // state.f, using the information about block state in blockLocs.
   780  // The returned location lists are not fully complete. They are in terms of
   781  // SSA values rather than PCs, and have no base address/end entries. They will
   782  // be finished by PutLocationList.
   783  func (state *debugState) buildLocationLists(blockLocs []*BlockDebug) {
   784  	// Run through the function in program text order, building up location
   785  	// lists as we go. The heavy lifting has mostly already been done.
   786  	for _, b := range state.f.Blocks {
   787  		if !blockLocs[b.ID].relevant {
   788  			continue
   789  		}
   790  
   791  		state.mergePredecessors(b, blockLocs)
   792  
   793  		phisPending := false
   794  		for _, v := range b.Values {
   795  			slots := state.valueNames[v.ID]
   796  			reg, _ := state.f.getHome(v.ID).(*Register)
   797  			changed := state.processValue(v, slots, reg)
   798  
   799  			if v.Op == OpPhi {
   800  				if changed {
   801  					phisPending = true
   802  				}
   803  				continue
   804  			}
   805  
   806  			if !changed && !phisPending {
   807  				continue
   808  			}
   809  
   810  			phisPending = false
   811  			for _, varID := range state.changedVars.contents() {
   812  				state.updateVar(VarID(varID), v, state.currentState.slots)
   813  			}
   814  			state.changedVars.clear()
   815  		}
   816  
   817  	}
   818  
   819  	if state.loggingEnabled {
   820  		state.logf("location lists:\n")
   821  	}
   822  
   823  	// Flush any leftover entries live at the end of the last block.
   824  	for varID := range state.lists {
   825  		state.writePendingEntry(VarID(varID), state.f.Blocks[len(state.f.Blocks)-1].ID, BlockEnd.ID)
   826  		list := state.lists[varID]
   827  		if len(list) == 0 {
   828  			continue
   829  		}
   830  
   831  		if state.loggingEnabled {
   832  			state.logf("\t%v : %q\n", state.vars[varID], hex.EncodeToString(state.lists[varID]))
   833  		}
   834  	}
   835  }
   836  
   837  // updateVar updates the pending location list entry for varID to
   838  // reflect the new locations in curLoc, caused by v.
   839  func (state *debugState) updateVar(varID VarID, v *Value, curLoc []VarLoc) {
   840  	// Assemble the location list entry with whatever's live.
   841  	empty := true
   842  	for _, slotID := range state.varSlots[varID] {
   843  		if !curLoc[slotID].absent() {
   844  			empty = false
   845  			break
   846  		}
   847  	}
   848  	pending := &state.pendingEntries[varID]
   849  	if empty {
   850  		state.writePendingEntry(varID, v.Block.ID, v.ID)
   851  		pending.clear()
   852  		return
   853  	}
   854  
   855  	// Extend the previous entry if possible.
   856  	if pending.present {
   857  		merge := true
   858  		for i, slotID := range state.varSlots[varID] {
   859  			if !canMerge(pending.pieces[i], curLoc[slotID]) {
   860  				merge = false
   861  				break
   862  			}
   863  		}
   864  		if merge {
   865  			return
   866  		}
   867  	}
   868  
   869  	state.writePendingEntry(varID, v.Block.ID, v.ID)
   870  	pending.present = true
   871  	pending.startBlock = v.Block.ID
   872  	pending.startValue = v.ID
   873  	for i, slot := range state.varSlots[varID] {
   874  		pending.pieces[i] = curLoc[slot]
   875  	}
   876  	return
   877  
   878  }
   879  
   880  // writePendingEntry writes out the pending entry for varID, if any,
   881  // terminated at endBlock/Value.
   882  func (state *debugState) writePendingEntry(varID VarID, endBlock, endValue ID) {
   883  	pending := state.pendingEntries[varID]
   884  	if !pending.present {
   885  		return
   886  	}
   887  
   888  	// Pack the start/end coordinates into the start/end addresses
   889  	// of the entry, for decoding by PutLocationList.
   890  	start, startOK := encodeValue(state.ctxt, pending.startBlock, pending.startValue)
   891  	end, endOK := encodeValue(state.ctxt, endBlock, endValue)
   892  	if !startOK || !endOK {
   893  		// If someone writes a function that uses >65K values,
   894  		// they get incomplete debug info on 32-bit platforms.
   895  		return
   896  	}
   897  	list := state.lists[varID]
   898  	list = appendPtr(state.ctxt, list, start)
   899  	list = appendPtr(state.ctxt, list, end)
   900  	// Where to write the length of the location description once
   901  	// we know how big it is.
   902  	sizeIdx := len(list)
   903  	list = list[:len(list)+2]
   904  
   905  	if state.loggingEnabled {
   906  		var partStrs []string
   907  		for i, slot := range state.varSlots[varID] {
   908  			partStrs = append(partStrs, fmt.Sprintf("%v@%v", state.slots[slot], state.LocString(pending.pieces[i])))
   909  		}
   910  		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, " "))
   911  	}
   912  
   913  	for i, slotID := range state.varSlots[varID] {
   914  		loc := pending.pieces[i]
   915  		slot := state.slots[slotID]
   916  
   917  		if !loc.absent() {
   918  			if loc.onStack() {
   919  				if loc.stackOffsetValue() == 0 {
   920  					list = append(list, dwarf.DW_OP_call_frame_cfa)
   921  				} else {
   922  					list = append(list, dwarf.DW_OP_fbreg)
   923  					list = dwarf.AppendSleb128(list, int64(loc.stackOffsetValue()))
   924  				}
   925  			} else {
   926  				regnum := state.ctxt.Arch.DWARFRegisters[state.registers[firstReg(loc.Registers)].ObjNum()]
   927  				if regnum < 32 {
   928  					list = append(list, dwarf.DW_OP_reg0+byte(regnum))
   929  				} else {
   930  					list = append(list, dwarf.DW_OP_regx)
   931  					list = dwarf.AppendUleb128(list, uint64(regnum))
   932  				}
   933  			}
   934  		}
   935  
   936  		if len(state.varSlots[varID]) > 1 {
   937  			list = append(list, dwarf.DW_OP_piece)
   938  			list = dwarf.AppendUleb128(list, uint64(slot.Type.Size()))
   939  		}
   940  	}
   941  	state.ctxt.Arch.ByteOrder.PutUint16(list[sizeIdx:], uint16(len(list)-sizeIdx-2))
   942  	state.lists[varID] = list
   943  }
   944  
   945  // PutLocationList adds list (a location list in its intermediate representation) to listSym.
   946  func (debugInfo *FuncDebug) PutLocationList(list []byte, ctxt *obj.Link, listSym, startPC *obj.LSym) {
   947  	getPC := debugInfo.GetPC
   948  	// Re-read list, translating its address from block/value ID to PC.
   949  	for i := 0; i < len(list); {
   950  		translate := func() {
   951  			bv := readPtr(ctxt, list[i:])
   952  			pc := getPC(decodeValue(ctxt, bv))
   953  			writePtr(ctxt, list[i:], uint64(pc))
   954  			i += ctxt.Arch.PtrSize
   955  		}
   956  		translate()
   957  		translate()
   958  		i += 2 + int(ctxt.Arch.ByteOrder.Uint16(list[i:]))
   959  	}
   960  
   961  	// Base address entry.
   962  	listSym.WriteInt(ctxt, listSym.Size, ctxt.Arch.PtrSize, ^0)
   963  	listSym.WriteAddr(ctxt, listSym.Size, ctxt.Arch.PtrSize, startPC, 0)
   964  	// Location list contents, now with real PCs.
   965  	listSym.WriteBytes(ctxt, listSym.Size, list)
   966  	// End entry.
   967  	listSym.WriteInt(ctxt, listSym.Size, ctxt.Arch.PtrSize, 0)
   968  	listSym.WriteInt(ctxt, listSym.Size, ctxt.Arch.PtrSize, 0)
   969  }
   970  
   971  // Pack a value and block ID into an address-sized uint, returning ~0 if they
   972  // don't fit.
   973  func encodeValue(ctxt *obj.Link, b, v ID) (uint64, bool) {
   974  	if ctxt.Arch.PtrSize == 8 {
   975  		result := uint64(b)<<32 | uint64(uint32(v))
   976  		//ctxt.Logf("b %#x (%d) v %#x (%d) -> %#x\n", b, b, v, v, result)
   977  		return result, true
   978  	}
   979  	if ctxt.Arch.PtrSize != 4 {
   980  		panic("unexpected pointer size")
   981  	}
   982  	if ID(int16(b)) != b || ID(int16(v)) != v {
   983  		return 0, false
   984  	}
   985  	return uint64(b)<<16 | uint64(uint16(v)), true
   986  }
   987  
   988  // Unpack a value and block ID encoded by encodeValue.
   989  func decodeValue(ctxt *obj.Link, word uint64) (ID, ID) {
   990  	if ctxt.Arch.PtrSize == 8 {
   991  		b, v := ID(word>>32), ID(word)
   992  		//ctxt.Logf("%#x -> b %#x (%d) v %#x (%d)\n", word, b, b, v, v)
   993  		return b, v
   994  	}
   995  	if ctxt.Arch.PtrSize != 4 {
   996  		panic("unexpected pointer size")
   997  	}
   998  	return ID(word >> 16), ID(word)
   999  }
  1000  
  1001  // Append a pointer-sized uint to buf.
  1002  func appendPtr(ctxt *obj.Link, buf []byte, word uint64) []byte {
  1003  	if cap(buf) < len(buf)+20 {
  1004  		b := make([]byte, len(buf), 20+cap(buf)*2)
  1005  		copy(b, buf)
  1006  		buf = b
  1007  	}
  1008  	writeAt := len(buf)
  1009  	buf = buf[0 : len(buf)+ctxt.Arch.PtrSize]
  1010  	writePtr(ctxt, buf[writeAt:], word)
  1011  	return buf
  1012  }
  1013  
  1014  // Write a pointer-sized uint to the beginning of buf.
  1015  func writePtr(ctxt *obj.Link, buf []byte, word uint64) {
  1016  	switch ctxt.Arch.PtrSize {
  1017  	case 4:
  1018  		ctxt.Arch.ByteOrder.PutUint32(buf, uint32(word))
  1019  	case 8:
  1020  		ctxt.Arch.ByteOrder.PutUint64(buf, word)
  1021  	default:
  1022  		panic("unexpected pointer size")
  1023  	}
  1024  
  1025  }
  1026  
  1027  // Read a pointer-sized uint from the beginning of buf.
  1028  func readPtr(ctxt *obj.Link, buf []byte) uint64 {
  1029  	switch ctxt.Arch.PtrSize {
  1030  	case 4:
  1031  		return uint64(ctxt.Arch.ByteOrder.Uint32(buf))
  1032  	case 8:
  1033  		return ctxt.Arch.ByteOrder.Uint64(buf)
  1034  	default:
  1035  		panic("unexpected pointer size")
  1036  	}
  1037  
  1038  }