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