1
2
3
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 "fmt"
17 "internal/buildcfg"
18 "math/bits"
19 "slices"
20 "strings"
21 )
22
23 type SlotID int32
24 type VarID int32
25
26
27
28
29 type FuncDebug struct {
30
31 Slots []LocalSlot
32
33 Vars []*ir.Name
34
35 VarSlots [][]SlotID
36
37 LocationLists [][]LocListEntry
38
39
40 RegOutputParams []*ir.Name
41
42 OptDcl []*ir.Name
43
44
45 EntryID ID
46
47
48
49
50
51 GetPC func(block, value ID) int64
52 }
53
54
55
56
57 type LocListEntry struct {
58 StartBlock, StartValue ID
59 EndBlock, EndValue ID
60 Expr []byte
61 }
62
63 type BlockDebug struct {
64
65
66 startState, endState abt.T
67
68
69
70 lastCheckedTime, lastChangedTime int32
71
72 relevant bool
73
74
75
76 everProcessed bool
77 }
78
79
80 type liveSlot struct {
81 VarLoc
82 }
83
84 func (ls *liveSlot) String() string {
85 return fmt.Sprintf("0x%x.%d.%d", ls.Registers, ls.stackOffsetValue(), int32(ls.StackOffset)&1)
86 }
87
88
89
90
91 type StackOffset int32
92
93 func (s StackOffset) onStack() bool {
94 return s != 0
95 }
96
97 func (s StackOffset) stackOffsetValue() int32 {
98 return int32(s) >> 1
99 }
100
101
102 type stateAtPC struct {
103
104 slots []VarLoc
105
106 registers [][]SlotID
107 }
108
109
110 func (state *stateAtPC) reset(live abt.T) {
111 slots, registers := state.slots, state.registers
112 clear(slots)
113 for i := range registers {
114 registers[i] = registers[i][:0]
115 }
116 for it := live.Iterator(); !it.Done(); {
117 k, d := it.Next()
118 live := d.(*liveSlot)
119 slots[k] = live.VarLoc
120 if live.VarLoc.Registers == 0 {
121 continue
122 }
123
124 mask := uint64(live.VarLoc.Registers)
125 for {
126 if mask == 0 {
127 break
128 }
129 reg := uint8(bits.TrailingZeros64(mask))
130 mask &^= 1 << reg
131
132 registers[reg] = append(registers[reg], SlotID(k))
133 }
134 }
135 state.slots, state.registers = slots, registers
136 }
137
138 func (s *debugState) LocString(loc VarLoc) string {
139 if loc.absent() {
140 return "<nil>"
141 }
142
143 var storage []string
144 if loc.onStack() {
145 storage = append(storage, fmt.Sprintf("@%+d", loc.stackOffsetValue()))
146 }
147
148 mask := uint64(loc.Registers)
149 for {
150 if mask == 0 {
151 break
152 }
153 reg := uint8(bits.TrailingZeros64(mask))
154 mask &^= 1 << reg
155
156 storage = append(storage, s.registers[reg].String())
157 }
158 return strings.Join(storage, ",")
159 }
160
161
162 type VarLoc struct {
163
164
165 Registers RegisterSet
166
167 StackOffset
168 }
169
170 func (loc VarLoc) absent() bool {
171 return loc.Registers == 0 && !loc.onStack()
172 }
173
174 func (loc VarLoc) intersect(other VarLoc) VarLoc {
175 if !loc.onStack() || !other.onStack() || loc.StackOffset != other.StackOffset {
176 loc.StackOffset = 0
177 }
178 loc.Registers &= other.Registers
179 return loc
180 }
181
182 var BlockStart = &Value{
183 ID: -10000,
184 Op: OpInvalid,
185 Aux: StringToAux("BlockStart"),
186 }
187
188 var BlockEnd = &Value{
189 ID: -20000,
190 Op: OpInvalid,
191 Aux: StringToAux("BlockEnd"),
192 }
193
194 var FuncEnd = &Value{
195 ID: -30000,
196 Op: OpInvalid,
197 Aux: StringToAux("FuncEnd"),
198 }
199
200
201 type RegisterSet uint64
202
203
204
205
206 func (s *debugState) logf(msg string, args ...any) {
207 if s.f.PrintOrHtmlSSA {
208 fmt.Printf(msg, args...)
209 }
210 }
211
212 type debugState struct {
213
214 slots []LocalSlot
215 vars []*ir.Name
216 varSlots [][]SlotID
217 lists [][]LocListEntry
218
219
220 slotVars []VarID
221
222 f *Func
223 loggingLevel int
224 convergeCount int
225 registers []Register
226 stackOffset func(LocalSlot) int32
227 ctxt *obj.Link
228
229
230 valueNames [][]SlotID
231
232
233 currentState stateAtPC
234 changedVars *sparseSet
235 changedSlots *sparseSet
236
237
238 pendingEntries []pendingEntry
239
240 varParts map[*ir.Name][]SlotID
241 blockDebug []BlockDebug
242 pendingSlotLocs []VarLoc
243 }
244
245 func (state *debugState) initializeCache(f *Func, numVars, numSlots int) {
246
247 if cap(state.blockDebug) < f.NumBlocks() {
248 state.blockDebug = make([]BlockDebug, f.NumBlocks())
249 } else {
250 clear(state.blockDebug[:f.NumBlocks()])
251 }
252
253
254 if cap(state.valueNames) < f.NumValues() {
255 old := state.valueNames
256 state.valueNames = make([][]SlotID, f.NumValues())
257 copy(state.valueNames, old)
258 }
259 vn := state.valueNames[:f.NumValues()]
260 for i := range vn {
261 vn[i] = vn[i][:0]
262 }
263
264
265 if cap(state.currentState.slots) < numSlots {
266 state.currentState.slots = make([]VarLoc, numSlots)
267 } else {
268 state.currentState.slots = state.currentState.slots[:numSlots]
269 }
270 if cap(state.currentState.registers) < len(state.registers) {
271 state.currentState.registers = make([][]SlotID, len(state.registers))
272 } else {
273 state.currentState.registers = state.currentState.registers[:len(state.registers)]
274 }
275
276
277 state.changedVars = newSparseSet(numVars)
278 state.changedSlots = newSparseSet(numSlots)
279
280
281 numPieces := 0
282 for i := range state.varSlots {
283 numPieces += len(state.varSlots[i])
284 }
285 if cap(state.pendingSlotLocs) < numPieces {
286 state.pendingSlotLocs = make([]VarLoc, numPieces)
287 } else {
288 clear(state.pendingSlotLocs[:numPieces])
289 }
290 if cap(state.pendingEntries) < numVars {
291 state.pendingEntries = make([]pendingEntry, numVars)
292 }
293 pe := state.pendingEntries[:numVars]
294 freePieceIdx := 0
295 for varID, slots := range state.varSlots {
296 pe[varID] = pendingEntry{
297 pieces: state.pendingSlotLocs[freePieceIdx : freePieceIdx+len(slots)],
298 }
299 freePieceIdx += len(slots)
300 }
301 state.pendingEntries = pe
302
303 if cap(state.lists) < numVars {
304 state.lists = make([][]LocListEntry, numVars)
305 } else {
306 state.lists = state.lists[:numVars]
307 clear(state.lists)
308 }
309 }
310
311 func (state *debugState) allocBlock(b *Block) *BlockDebug {
312 return &state.blockDebug[b.ID]
313 }
314
315 func (s *debugState) blockEndStateString(b *BlockDebug) string {
316 endState := stateAtPC{slots: make([]VarLoc, len(s.slots)), registers: make([][]SlotID, len(s.registers))}
317 endState.reset(b.endState)
318 return s.stateString(endState)
319 }
320
321 func (s *debugState) stateString(state stateAtPC) string {
322 var strs []string
323 for slotID, loc := range state.slots {
324 if !loc.absent() {
325 strs = append(strs, fmt.Sprintf("\t%v = %v\n", s.slots[slotID], s.LocString(loc)))
326 }
327 }
328
329 strs = append(strs, "\n")
330 for reg, slots := range state.registers {
331 if len(slots) != 0 {
332 var slotStrs []string
333 for _, slot := range slots {
334 slotStrs = append(slotStrs, s.slots[slot].String())
335 }
336 strs = append(strs, fmt.Sprintf("\t%v = %v\n", &s.registers[reg], slotStrs))
337 }
338 }
339
340 if len(strs) == 1 {
341 return "(no vars)\n"
342 }
343 return strings.Join(strs, "")
344 }
345
346
347
348
349
350 type slotCanonicalizer struct {
351 slmap map[slotKey]SlKeyIdx
352 slkeys []LocalSlot
353 }
354
355 func newSlotCanonicalizer() *slotCanonicalizer {
356 return &slotCanonicalizer{
357 slmap: make(map[slotKey]SlKeyIdx),
358 slkeys: []LocalSlot{LocalSlot{N: nil}},
359 }
360 }
361
362 type SlKeyIdx uint32
363
364 const noSlot = SlKeyIdx(0)
365
366
367
368 type slotKey struct {
369 name *ir.Name
370 offset int64
371 width int64
372 splitOf SlKeyIdx
373 splitOffset int64
374 }
375
376
377
378
379
380 func (sc *slotCanonicalizer) lookup(ls LocalSlot) (SlKeyIdx, bool) {
381 split := noSlot
382 if ls.SplitOf != nil {
383 split, _ = sc.lookup(*ls.SplitOf)
384 }
385 k := slotKey{
386 name: ls.N, offset: ls.Off, width: ls.Type.Size(),
387 splitOf: split, splitOffset: ls.SplitOffset,
388 }
389 if idx, ok := sc.slmap[k]; ok {
390 return idx, true
391 }
392 rv := SlKeyIdx(len(sc.slkeys))
393 sc.slkeys = append(sc.slkeys, ls)
394 sc.slmap[k] = rv
395 return rv, false
396 }
397
398 func (sc *slotCanonicalizer) canonSlot(idx SlKeyIdx) LocalSlot {
399 return sc.slkeys[idx]
400 }
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433 func PopulateABIInRegArgOps(f *Func) {
434 pri := f.ABISelf.ABIAnalyzeFuncType(f.Type)
435
436
437
438
439
440
441
442 sc := newSlotCanonicalizer()
443 for _, sl := range f.Names {
444 sc.lookup(*sl)
445 }
446
447
448 addToNV := func(v *Value, sl LocalSlot) {
449 values, ok := f.NamedValues[sl]
450 if !ok {
451
452 sla := f.localSlotAddr(sl)
453 f.Names = append(f.Names, sla)
454 } else {
455 for _, ev := range values {
456 if v == ev {
457 return
458 }
459 }
460 }
461 values = append(values, v)
462 f.NamedValues[sl] = values
463 }
464
465 newValues := []*Value{}
466
467 abiRegIndexToRegister := func(reg abi.RegIndex) int8 {
468 i := f.ABISelf.FloatIndexFor(reg)
469 if i >= 0 {
470 return f.Config.floatParamRegs[i]
471 } else {
472 return f.Config.intParamRegs[reg]
473 }
474 }
475
476
477 var pos src.XPos
478 if len(f.Entry.Values) != 0 {
479 pos = f.Entry.Values[0].Pos
480 }
481 synthesizeOpIntFloatArg := func(n *ir.Name, t *types.Type, reg abi.RegIndex, sl LocalSlot) *Value {
482 aux := &AuxNameOffset{n, sl.Off}
483 op, auxInt := ArgOpAndRegisterFor(reg, f.ABISelf)
484 v := f.newValueNoBlock(op, t, pos)
485 v.AuxInt = auxInt
486 v.Aux = aux
487 v.Args = nil
488 v.Block = f.Entry
489 newValues = append(newValues, v)
490 addToNV(v, sl)
491 f.setHome(v, &f.Config.registers[abiRegIndexToRegister(reg)])
492 return v
493 }
494
495
496
497
498
499
500 for _, v := range f.Entry.Values {
501 if v.Op == OpArgIntReg || v.Op == OpArgFloatReg {
502 aux := v.Aux.(*AuxNameOffset)
503 sl := LocalSlot{N: aux.Name, Type: v.Type, Off: aux.Offset}
504
505 idx, _ := sc.lookup(sl)
506
507 addToNV(v, sc.canonSlot(idx))
508 } else if v.Op.IsCall() {
509
510 break
511 }
512 }
513
514
515
516 for _, inp := range pri.InParams() {
517 if !isNamedRegParam(inp) {
518 continue
519 }
520 n := inp.Name
521
522
523
524 types, offsets := inp.RegisterTypesAndOffsets()
525 for k, t := range types {
526
527
528
529
530
531
532
533
534
535 pieceSlot := LocalSlot{N: n, Type: t, Off: offsets[k]}
536
537
538
539 _, found := sc.lookup(pieceSlot)
540 if !found {
541
542
543
544
545 synthesizeOpIntFloatArg(n, t, inp.Registers[k],
546 pieceSlot)
547 }
548 }
549 }
550
551
552 f.Entry.Values = append(newValues, f.Entry.Values...)
553 }
554
555
556
557
558 func BuildFuncDebug(ctxt *obj.Link, f *Func, loggingLevel int, stackOffset func(LocalSlot) int32, rval *FuncDebug) {
559 if f.RegAlloc == nil {
560 f.Fatalf("BuildFuncDebug on func %v that has not been fully processed", f)
561 }
562 state := &f.Cache.debugState
563 state.loggingLevel = loggingLevel % 1000
564
565
566
567
568
569 state.convergeCount = loggingLevel / 1000
570 state.f = f
571 state.registers = f.Config.registers
572 state.stackOffset = stackOffset
573 state.ctxt = ctxt
574
575 if buildcfg.Experiment.RegabiArgs {
576 PopulateABIInRegArgOps(f)
577 }
578
579 if state.loggingLevel > 0 {
580 state.logf("Generating location lists for function %q\n", f.Name)
581 }
582
583 if state.varParts == nil {
584 state.varParts = make(map[*ir.Name][]SlotID)
585 } else {
586 clear(state.varParts)
587 }
588
589
590
591
592 state.slots = state.slots[:0]
593 state.vars = state.vars[:0]
594 for i, slot := range f.Names {
595 state.slots = append(state.slots, *slot)
596 if ir.IsSynthetic(slot.N) || !IsVarWantedForDebug(slot.N) {
597 continue
598 }
599
600 topSlot := slot
601 for topSlot.SplitOf != nil {
602 topSlot = topSlot.SplitOf
603 }
604 if _, ok := state.varParts[topSlot.N]; !ok {
605 state.vars = append(state.vars, topSlot.N)
606 }
607 state.varParts[topSlot.N] = append(state.varParts[topSlot.N], SlotID(i))
608 }
609
610
611
612 for _, b := range f.Blocks {
613 for _, v := range b.Values {
614 if v.Op == OpVarDef {
615 n := v.Aux.(*ir.Name)
616 if ir.IsSynthetic(n) || !IsVarWantedForDebug(n) {
617 continue
618 }
619
620 if _, ok := state.varParts[n]; !ok {
621 slot := LocalSlot{N: n, Type: v.Type, Off: 0}
622 state.slots = append(state.slots, slot)
623 state.varParts[n] = []SlotID{SlotID(len(state.slots) - 1)}
624 state.vars = append(state.vars, n)
625 }
626 }
627 }
628 }
629
630
631 if cap(state.varSlots) < len(state.vars) {
632 state.varSlots = make([][]SlotID, len(state.vars))
633 } else {
634 state.varSlots = state.varSlots[:len(state.vars)]
635 for i := range state.varSlots {
636 state.varSlots[i] = state.varSlots[i][:0]
637 }
638 }
639 if cap(state.slotVars) < len(state.slots) {
640 state.slotVars = make([]VarID, len(state.slots))
641 } else {
642 state.slotVars = state.slotVars[:len(state.slots)]
643 }
644
645 for varID, n := range state.vars {
646 parts := state.varParts[n]
647 slices.SortFunc(parts, func(a, b SlotID) int {
648 return cmp.Compare(varOffset(state.slots[a]), varOffset(state.slots[b]))
649 })
650
651 state.varSlots[varID] = parts
652 for _, slotID := range parts {
653 state.slotVars[slotID] = VarID(varID)
654 }
655 }
656
657 state.initializeCache(f, len(state.varParts), len(state.slots))
658
659 for i, slot := range f.Names {
660 if ir.IsSynthetic(slot.N) || !IsVarWantedForDebug(slot.N) {
661 continue
662 }
663 for _, value := range f.NamedValues[*slot] {
664 state.valueNames[value.ID] = append(state.valueNames[value.ID], SlotID(i))
665 }
666 }
667
668 blockLocs := state.liveness()
669 state.buildLocationLists(blockLocs)
670
671
672 rval.Slots = state.slots
673 rval.VarSlots = state.varSlots
674 rval.Vars = state.vars
675 rval.LocationLists = state.lists
676 }
677
678
679
680 func (state *debugState) liveness() []*BlockDebug {
681 blockLocs := make([]*BlockDebug, state.f.NumBlocks())
682 counterTime := int32(1)
683
684
685
686 po := state.f.Postorder()
687 converged := false
688
689
690
691
692
693
694 keepGoing := func(k int) bool {
695 if state.convergeCount == 0 {
696 return !converged
697 }
698 return k < state.convergeCount
699 }
700 for k := 0; keepGoing(k); k++ {
701 if state.loggingLevel > 0 {
702 state.logf("Liveness pass %d\n", k)
703 }
704 converged = true
705 for i := len(po) - 1; i >= 0; i-- {
706 b := po[i]
707 locs := blockLocs[b.ID]
708 if locs == nil {
709 locs = state.allocBlock(b)
710 blockLocs[b.ID] = locs
711 }
712
713
714
715 startState, blockChanged := state.mergePredecessors(b, blockLocs, nil, false)
716 locs.lastCheckedTime = counterTime
717 counterTime++
718 if state.loggingLevel > 1 {
719 state.logf("Processing %v, block changed %v, initial state:\n%v", b, blockChanged, state.stateString(state.currentState))
720 }
721
722 if blockChanged {
723
724 converged = false
725 changed := false
726 state.changedSlots.clear()
727
728
729 for _, v := range b.Values {
730 slots := state.valueNames[v.ID]
731
732
733 var source *Value
734 switch v.Op {
735 case OpStoreReg:
736 source = v.Args[0]
737 case OpLoadReg:
738 switch a := v.Args[0]; a.Op {
739 case OpArg, OpPhi:
740 source = a
741 case OpStoreReg:
742 source = a.Args[0]
743 default:
744 if state.loggingLevel > 1 {
745 state.logf("at %v: load with unexpected source op: %v (%v)\n", v, a.Op, a)
746 }
747 }
748 }
749
750
751 if source != nil && k == 0 {
752
753 slots = append(slots, state.valueNames[source.ID]...)
754 state.valueNames[v.ID] = slots
755 }
756
757 reg, _ := state.f.getHome(v.ID).(*Register)
758 c := state.processValue(v, slots, reg)
759 changed = changed || c
760 }
761
762 if state.loggingLevel > 1 {
763 state.logf("Block %v done, locs:\n%v", b, state.stateString(state.currentState))
764 }
765
766 locs.relevant = locs.relevant || changed
767 if !changed {
768 locs.endState = startState
769 } else {
770 for _, id := range state.changedSlots.contents() {
771 slotID := SlotID(id)
772 slotLoc := state.currentState.slots[slotID]
773 if slotLoc.absent() {
774 startState.Delete(int32(slotID))
775 continue
776 }
777 old := startState.Find(int32(slotID))
778 if oldLS, ok := old.(*liveSlot); !ok || oldLS.VarLoc != slotLoc {
779 startState.Insert(int32(slotID),
780 &liveSlot{VarLoc: slotLoc})
781 }
782 }
783 locs.endState = startState
784 }
785 locs.lastChangedTime = counterTime
786 }
787 counterTime++
788 }
789 }
790 return blockLocs
791 }
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827 func (state *debugState) mergePredecessors(b *Block, blockLocs []*BlockDebug, previousBlock *Block, forLocationLists bool) (abt.T, bool) {
828
829 var predsBuf [10]*Block
830
831 preds := predsBuf[:0]
832 locs := blockLocs[b.ID]
833
834 blockChanged := !locs.everProcessed
835 updating := locs.everProcessed
836
837
838
839 for _, pred := range b.Preds {
840 if bl := blockLocs[pred.b.ID]; bl != nil && bl.everProcessed {
841
842 preds = append(preds, pred.b)
843 }
844 }
845
846 locs.everProcessed = true
847
848 if state.loggingLevel > 1 {
849
850
851 preds2 := make([]*Block, len(preds))
852 copy(preds2, preds)
853 state.logf("Merging %v into %v (changed=%d, checked=%d)\n", preds2, b, locs.lastChangedTime, locs.lastCheckedTime)
854 }
855
856 state.changedVars.clear()
857
858 markChangedVars := func(slots, merged abt.T) {
859 if !forLocationLists {
860 return
861 }
862
863
864
865 for it := slots.Iterator(); !it.Done(); {
866 k, v := it.Next()
867 m := merged.Find(k)
868 if m == nil || v.(*liveSlot).VarLoc != m.(*liveSlot).VarLoc {
869 state.changedVars.add(ID(state.slotVars[k]))
870 }
871 }
872 }
873
874 reset := func(ourStartState abt.T) {
875 if !(forLocationLists || blockChanged) {
876
877
878
879 return
880 }
881 state.currentState.reset(ourStartState)
882 }
883
884
885 if len(preds) == 0 {
886 if previousBlock != nil {
887 state.f.Fatalf("Function %v, block %s with no predecessors is not first block, has previous %s", state.f, b.String(), previousBlock.String())
888 }
889
890 reset(abt.T{})
891 return abt.T{}, blockChanged
892 }
893
894
895 l0 := blockLocs[preds[0].ID]
896 p0 := l0.endState
897 if len(preds) == 1 {
898 if previousBlock != nil && preds[0].ID != previousBlock.ID {
899
900 markChangedVars(blockLocs[previousBlock.ID].endState, p0)
901 }
902 locs.startState = p0
903 blockChanged = blockChanged || l0.lastChangedTime > locs.lastCheckedTime
904 reset(p0)
905 return p0, blockChanged
906 }
907
908
909
910 if updating {
911
912
913
914
915
916
917
918 for i := len(preds) - 1; i >= 0; i-- {
919 pred := preds[i]
920 if blockLocs[pred.ID].lastChangedTime > locs.lastCheckedTime {
921 continue
922 }
923 preds[i] = preds[len(preds)-1]
924 preds = preds[:len(preds)-1]
925 if state.loggingLevel > 2 {
926 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)
927 }
928 }
929
930
931 if len(preds) == 0 {
932 blockChanged = false
933
934 reset(locs.startState)
935 if state.loggingLevel > 2 {
936 state.logf("Early out, no predecessors changed since last check\n")
937 }
938 if previousBlock != nil {
939 markChangedVars(blockLocs[previousBlock.ID].endState, locs.startState)
940 }
941 return locs.startState, blockChanged
942 }
943 }
944
945 baseID := preds[0].ID
946 baseState := p0
947
948
949 for _, pred := range preds[1:] {
950 if blockLocs[pred.ID].endState.Size() < baseState.Size() {
951 baseState = blockLocs[pred.ID].endState
952 baseID = pred.ID
953 }
954 }
955
956 if state.loggingLevel > 2 {
957 state.logf("Starting %v with state from b%v:\n%v", b, baseID, state.blockEndStateString(blockLocs[baseID]))
958 for _, pred := range preds {
959 if pred.ID == baseID {
960 continue
961 }
962 state.logf("Merging in state from %v:\n%v", pred, state.blockEndStateString(blockLocs[pred.ID]))
963 }
964 }
965
966 state.currentState.reset(abt.T{})
967
968
969 slotLocs := state.currentState.slots
970
971
972
973
974
975 newState := baseState
976 if updating {
977 newState = blockLocs[b.ID].startState
978 }
979
980 for it := newState.Iterator(); !it.Done(); {
981 k, d := it.Next()
982 thisSlot := d.(*liveSlot)
983 x := thisSlot.VarLoc
984 x0 := x
985
986
987 for _, other := range preds {
988 if !updating && other.ID == baseID {
989 continue
990 }
991 otherSlot := blockLocs[other.ID].endState.Find(k)
992 if otherSlot == nil {
993 x = VarLoc{}
994 break
995 }
996 y := otherSlot.(*liveSlot).VarLoc
997 x = x.intersect(y)
998 if x.absent() {
999 x = VarLoc{}
1000 break
1001 }
1002 }
1003
1004
1005 if x.absent() {
1006 if !x0.absent() {
1007 blockChanged = true
1008 newState.Delete(k)
1009 }
1010 slotLocs[k] = VarLoc{}
1011 continue
1012 }
1013 if x != x0 {
1014 blockChanged = true
1015 newState.Insert(k, &liveSlot{VarLoc: x})
1016 }
1017
1018 slotLocs[k] = x
1019 mask := uint64(x.Registers)
1020 for {
1021 if mask == 0 {
1022 break
1023 }
1024 reg := uint8(bits.TrailingZeros64(mask))
1025 mask &^= 1 << reg
1026 state.currentState.registers[reg] = append(state.currentState.registers[reg], SlotID(k))
1027 }
1028 }
1029
1030 if previousBlock != nil {
1031 markChangedVars(blockLocs[previousBlock.ID].endState, newState)
1032 }
1033 locs.startState = newState
1034 return newState, blockChanged
1035 }
1036
1037
1038
1039
1040
1041 func (state *debugState) processValue(v *Value, vSlots []SlotID, vReg *Register) bool {
1042 locs := state.currentState
1043 changed := false
1044 setSlot := func(slot SlotID, loc VarLoc) {
1045 changed = true
1046 state.changedVars.add(ID(state.slotVars[slot]))
1047 state.changedSlots.add(ID(slot))
1048 state.currentState.slots[slot] = loc
1049 }
1050
1051
1052
1053
1054 clobbers := opcodeTable[v.Op].reg.clobbers
1055 for {
1056 if clobbers.empty() {
1057 break
1058 }
1059 reg := pickReg(clobbers)
1060 clobbers = clobbers.removeReg(reg)
1061
1062 for _, slot := range locs.registers[reg] {
1063 if state.loggingLevel > 1 {
1064 state.logf("at %v: %v clobbered out of %v\n", v, state.slots[slot], &state.registers[reg])
1065 }
1066
1067 last := locs.slots[slot]
1068 if last.absent() {
1069 state.f.Fatalf("at %v: slot %v in register %v with no location entry", v, state.slots[slot], &state.registers[reg])
1070 continue
1071 }
1072 regs := last.Registers &^ (1 << reg)
1073 setSlot(slot, VarLoc{regs, last.StackOffset})
1074 }
1075
1076 locs.registers[reg] = locs.registers[reg][:0]
1077 }
1078
1079 switch {
1080 case v.Op == OpVarDef:
1081 n := v.Aux.(*ir.Name)
1082 if ir.IsSynthetic(n) || !IsVarWantedForDebug(n) {
1083 break
1084 }
1085
1086 slotID := state.varParts[n][0]
1087 var stackOffset StackOffset
1088 if v.Op == OpVarDef {
1089 stackOffset = StackOffset(state.stackOffset(state.slots[slotID])<<1 | 1)
1090 }
1091 setSlot(slotID, VarLoc{0, stackOffset})
1092 if state.loggingLevel > 1 {
1093 if v.Op == OpVarDef {
1094 state.logf("at %v: stack-only var %v now live\n", v, state.slots[slotID])
1095 } else {
1096 state.logf("at %v: stack-only var %v now dead\n", v, state.slots[slotID])
1097 }
1098 }
1099
1100 case v.Op == OpArg:
1101 home := state.f.getHome(v.ID).(LocalSlot)
1102 stackOffset := state.stackOffset(home)<<1 | 1
1103 for _, slot := range vSlots {
1104 if state.loggingLevel > 1 {
1105 state.logf("at %v: arg %v now on stack in location %v\n", v, state.slots[slot], home)
1106 if last := locs.slots[slot]; !last.absent() {
1107 state.logf("at %v: unexpected arg op on already-live slot %v\n", v, state.slots[slot])
1108 }
1109 }
1110
1111 setSlot(slot, VarLoc{0, StackOffset(stackOffset)})
1112 }
1113
1114 case v.Op == OpStoreReg:
1115 home := state.f.getHome(v.ID).(LocalSlot)
1116 stackOffset := state.stackOffset(home)<<1 | 1
1117 for _, slot := range vSlots {
1118 last := locs.slots[slot]
1119 if last.absent() {
1120 if state.loggingLevel > 1 {
1121 state.logf("at %v: unexpected spill of unnamed register %s\n", v, vReg)
1122 }
1123 break
1124 }
1125
1126 setSlot(slot, VarLoc{last.Registers, StackOffset(stackOffset)})
1127 if state.loggingLevel > 1 {
1128 state.logf("at %v: %v spilled to stack location %v@%d\n", v, state.slots[slot], home, state.stackOffset(home))
1129 }
1130 }
1131
1132 case vReg != nil:
1133 if state.loggingLevel > 1 {
1134 newSlots := make([]bool, len(state.slots))
1135 for _, slot := range vSlots {
1136 newSlots[slot] = true
1137 }
1138
1139 for _, slot := range locs.registers[vReg.num] {
1140 if !newSlots[slot] {
1141 state.logf("at %v: overwrote %v in register %v\n", v, state.slots[slot], vReg)
1142 }
1143 }
1144 }
1145
1146 for _, slot := range locs.registers[vReg.num] {
1147 last := locs.slots[slot]
1148 setSlot(slot, VarLoc{last.Registers &^ (1 << uint8(vReg.num)), last.StackOffset})
1149 }
1150 locs.registers[vReg.num] = locs.registers[vReg.num][:0]
1151 locs.registers[vReg.num] = append(locs.registers[vReg.num], vSlots...)
1152 for _, slot := range vSlots {
1153 if state.loggingLevel > 1 {
1154 state.logf("at %v: %v now in %s\n", v, state.slots[slot], vReg)
1155 }
1156
1157 last := locs.slots[slot]
1158 setSlot(slot, VarLoc{1<<uint8(vReg.num) | last.Registers, last.StackOffset})
1159 }
1160 }
1161 return changed
1162 }
1163
1164
1165
1166 func varOffset(slot LocalSlot) int64 {
1167 offset := slot.Off
1168 s := &slot
1169 for ; s.SplitOf != nil; s = s.SplitOf {
1170 offset += s.SplitOffset
1171 }
1172 return offset
1173 }
1174
1175
1176
1177 type pendingEntry struct {
1178 present bool
1179 startBlock, startValue ID
1180
1181
1182 pieces []VarLoc
1183 }
1184
1185 func (e *pendingEntry) clear() {
1186 e.present = false
1187 e.startBlock = 0
1188 e.startValue = 0
1189 clear(e.pieces)
1190 }
1191
1192
1193
1194
1195
1196 func canMerge(pending, new VarLoc) bool {
1197 if pending.absent() && new.absent() {
1198 return true
1199 }
1200 if pending.absent() || new.absent() {
1201 return false
1202 }
1203
1204
1205 if pending.onStack() && pending.StackOffset != new.StackOffset {
1206
1207
1208 return false
1209 }
1210 if pending.Registers&new.Registers != pending.Registers {
1211
1212 return false
1213 }
1214 return true
1215 }
1216
1217
1218 func firstReg(set RegisterSet) uint8 {
1219 if set == 0 {
1220
1221
1222 return 0
1223 }
1224 return uint8(bits.TrailingZeros64(uint64(set)))
1225 }
1226
1227
1228
1229
1230
1231
1232 func (state *debugState) buildLocationLists(blockLocs []*BlockDebug) {
1233
1234
1235
1236 var prevBlock *Block
1237 for _, b := range state.f.Blocks {
1238 state.mergePredecessors(b, blockLocs, prevBlock, true)
1239
1240
1241 for _, varID := range state.changedVars.contents() {
1242 state.updateVar(VarID(varID), b, BlockStart)
1243 }
1244 state.changedVars.clear()
1245
1246 if !blockLocs[b.ID].relevant {
1247 continue
1248 }
1249
1250 mustBeFirst := func(v *Value) bool {
1251 return v.Op == OpPhi || v.Op.isLoweredGetClosurePtr() ||
1252 v.Op == OpArgIntReg || v.Op == OpArgFloatReg
1253 }
1254
1255 blockPrologComplete := func(v *Value) bool {
1256 if b.ID != state.f.Entry.ID {
1257 return !opcodeTable[v.Op].zeroWidth
1258 } else {
1259 return v.Op == OpInitMem
1260 }
1261 }
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283 for idx := 0; idx < len(b.Values); idx++ {
1284 v := b.Values[idx]
1285 if blockPrologComplete(v) {
1286 break
1287 }
1288
1289 if !mustBeFirst(v) && v.Op != OpArg {
1290 continue
1291 }
1292 slots := state.valueNames[v.ID]
1293 reg, _ := state.f.getHome(v.ID).(*Register)
1294 changed := state.processValue(v, slots, reg)
1295 if changed {
1296 for _, varID := range state.changedVars.contents() {
1297 state.updateVar(VarID(varID), v.Block, BlockStart)
1298 }
1299 state.changedVars.clear()
1300 }
1301 }
1302
1303
1304
1305 zeroWidthPending := false
1306 prologComplete := false
1307
1308 for _, v := range b.Values {
1309 if blockPrologComplete(v) {
1310 prologComplete = true
1311 }
1312 slots := state.valueNames[v.ID]
1313 reg, _ := state.f.getHome(v.ID).(*Register)
1314 changed := state.processValue(v, slots, reg)
1315
1316 if opcodeTable[v.Op].zeroWidth {
1317 if prologComplete && mustBeFirst(v) {
1318 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))
1319 }
1320 if changed {
1321 if mustBeFirst(v) || v.Op == OpArg {
1322
1323 continue
1324 }
1325 zeroWidthPending = true
1326 }
1327 continue
1328 }
1329 if !changed && !zeroWidthPending {
1330 continue
1331 }
1332
1333
1334 zeroWidthPending = false
1335 for _, varID := range state.changedVars.contents() {
1336 state.updateVar(VarID(varID), v.Block, v)
1337 }
1338 state.changedVars.clear()
1339 }
1340 for _, varID := range state.changedVars.contents() {
1341 state.updateVar(VarID(varID), b, BlockEnd)
1342 }
1343
1344 prevBlock = b
1345 }
1346
1347 if state.loggingLevel > 0 {
1348 state.logf("location lists:\n")
1349 }
1350
1351
1352 for varID := range state.lists {
1353 state.writePendingEntry(VarID(varID), -1, FuncEnd.ID)
1354 list := state.lists[varID]
1355 if state.loggingLevel > 0 {
1356 if len(list) == 0 {
1357 state.logf("\t%v : empty list\n", state.vars[varID])
1358 } else {
1359 state.logf("\t%v : %d entries\n", state.vars[varID], len(list))
1360 }
1361 }
1362 }
1363 }
1364
1365
1366
1367
1368 func (state *debugState) updateVar(varID VarID, b *Block, v *Value) {
1369 curLoc := state.currentState.slots
1370
1371 empty := true
1372 for _, slotID := range state.varSlots[varID] {
1373 if !curLoc[slotID].absent() {
1374 empty = false
1375 break
1376 }
1377 }
1378 pending := &state.pendingEntries[varID]
1379 if empty {
1380 state.writePendingEntry(varID, b.ID, v.ID)
1381 pending.clear()
1382 return
1383 }
1384
1385
1386 if pending.present {
1387 merge := true
1388 for i, slotID := range state.varSlots[varID] {
1389 if !canMerge(pending.pieces[i], curLoc[slotID]) {
1390 merge = false
1391 break
1392 }
1393 }
1394 if merge {
1395 return
1396 }
1397 }
1398
1399 state.writePendingEntry(varID, b.ID, v.ID)
1400 pending.present = true
1401 pending.startBlock = b.ID
1402 pending.startValue = v.ID
1403 for i, slot := range state.varSlots[varID] {
1404 pending.pieces[i] = curLoc[slot]
1405 }
1406 }
1407
1408
1409
1410 func (state *debugState) writePendingEntry(varID VarID, endBlock, endValue ID) {
1411 pending := state.pendingEntries[varID]
1412 if !pending.present {
1413 return
1414 }
1415
1416
1417 if pending.startBlock == endBlock && pending.startValue == endValue {
1418 if state.loggingLevel > 1 {
1419 state.logf("Skipping empty location list for %v in %s\n", state.vars[varID], state.f.Name)
1420 }
1421 return
1422 }
1423
1424 if state.loggingLevel > 1 {
1425 var partStrs []string
1426 for i, slot := range state.varSlots[varID] {
1427 partStrs = append(partStrs, fmt.Sprintf("%v@%v", state.slots[slot], state.LocString(pending.pieces[i])))
1428 }
1429 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, " "))
1430 }
1431
1432
1433 var expr []byte
1434 for i, slotID := range state.varSlots[varID] {
1435 loc := pending.pieces[i]
1436 slot := state.slots[slotID]
1437
1438 if !loc.absent() {
1439 if loc.onStack() {
1440 if loc.stackOffsetValue() == 0 {
1441 expr = append(expr, dwarf.DW_OP_call_frame_cfa)
1442 } else {
1443 expr = append(expr, dwarf.DW_OP_fbreg)
1444 expr = dwarf.AppendSleb128(expr, int64(loc.stackOffsetValue()))
1445 }
1446 } else {
1447 regnum := state.ctxt.Arch.DWARFRegisters[state.registers[firstReg(loc.Registers)].ObjNum()]
1448 if regnum < 32 {
1449 expr = append(expr, dwarf.DW_OP_reg0+byte(regnum))
1450 } else {
1451 expr = append(expr, dwarf.DW_OP_regx)
1452 expr = dwarf.AppendUleb128(expr, uint64(regnum))
1453 }
1454 }
1455 }
1456
1457 if len(state.varSlots[varID]) > 1 {
1458 expr = append(expr, dwarf.DW_OP_piece)
1459 expr = dwarf.AppendUleb128(expr, uint64(slot.Type.Size()))
1460 }
1461 }
1462
1463 entry := LocListEntry{
1464 StartBlock: pending.startBlock,
1465 StartValue: pending.startValue,
1466 EndBlock: endBlock,
1467 EndValue: endValue,
1468 Expr: expr,
1469 }
1470 state.lists[varID] = append(state.lists[varID], entry)
1471 }
1472
1473
1474
1475 func (debugInfo *FuncDebug) PutLocationList(entries []LocListEntry, ctxt *obj.Link, listSym, startPC *obj.LSym) {
1476 if buildcfg.Experiment.Dwarf5 {
1477 debugInfo.PutLocationListDwarf5(entries, ctxt, listSym, startPC)
1478 } else {
1479 debugInfo.PutLocationListDwarf4(entries, ctxt, listSym, startPC)
1480 }
1481 }
1482
1483
1484
1485 func (debugInfo *FuncDebug) PutLocationListDwarf5(entries []LocListEntry, ctxt *obj.Link, listSym, startPC *obj.LSym) {
1486 getPC := debugInfo.GetPC
1487
1488
1489 listSym.WriteInt(ctxt, listSym.Size, 1, dwarf.DW_LLE_base_addressx)
1490 listSym.WriteDwTxtAddrx(ctxt, listSym.Size, startPC, ctxt.DwTextCount*2)
1491
1492 var stbuf, enbuf [10]byte
1493 for _, entry := range entries {
1494 begin := getPC(entry.StartBlock, entry.StartValue)
1495 end := getPC(entry.EndBlock, entry.EndValue)
1496
1497
1498
1499 listSym.WriteInt(ctxt, listSym.Size, 1, dwarf.DW_LLE_offset_pair)
1500 stb := stbuf[:0]
1501 enb := enbuf[:0]
1502 stb = dwarf.AppendUleb128(stb, uint64(begin))
1503 enb = dwarf.AppendUleb128(enb, uint64(end))
1504 listSym.WriteBytes(ctxt, listSym.Size, stb)
1505 listSym.WriteBytes(ctxt, listSym.Size, enb)
1506
1507
1508 stb = stbuf[:0]
1509 stb = dwarf.AppendUleb128(stb, uint64(len(entry.Expr)))
1510 listSym.WriteBytes(ctxt, listSym.Size, stb)
1511 listSym.WriteBytes(ctxt, listSym.Size, entry.Expr)
1512 }
1513
1514
1515 listSym.WriteInt(ctxt, listSym.Size, 1, dwarf.DW_LLE_end_of_list)
1516 }
1517
1518
1519
1520 func (debugInfo *FuncDebug) PutLocationListDwarf4(entries []LocListEntry, ctxt *obj.Link, listSym, startPC *obj.LSym) {
1521 getPC := debugInfo.GetPC
1522
1523 if ctxt.UseBASEntries {
1524 listSym.WriteInt(ctxt, listSym.Size, ctxt.Arch.PtrSize, ^0)
1525 listSym.WriteAddr(ctxt, listSym.Size, ctxt.Arch.PtrSize, startPC, 0)
1526 }
1527
1528 for _, entry := range entries {
1529 begin := getPC(entry.StartBlock, entry.StartValue)
1530 end := getPC(entry.EndBlock, entry.EndValue)
1531
1532
1533
1534
1535
1536 if begin == 0 && end == 0 {
1537 end = 1
1538 }
1539
1540 if ctxt.UseBASEntries {
1541 listSym.WriteInt(ctxt, listSym.Size, ctxt.Arch.PtrSize, begin)
1542 listSym.WriteInt(ctxt, listSym.Size, ctxt.Arch.PtrSize, end)
1543 } else {
1544 listSym.WriteCURelativeAddr(ctxt, listSym.Size, startPC, begin)
1545 listSym.WriteCURelativeAddr(ctxt, listSym.Size, startPC, end)
1546 }
1547
1548
1549 listSym.WriteInt(ctxt, listSym.Size, 2, int64(len(entry.Expr)))
1550 listSym.WriteBytes(ctxt, listSym.Size, entry.Expr)
1551 }
1552
1553
1554 listSym.WriteInt(ctxt, listSym.Size, ctxt.Arch.PtrSize, 0)
1555 listSym.WriteInt(ctxt, listSym.Size, ctxt.Arch.PtrSize, 0)
1556 }
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578 func locatePrologEnd(f *Func, needCloCtx bool) (ID, *Value) {
1579
1580
1581
1582
1583 isRegMoveLike := func(v *Value) (bool, ID) {
1584 n, ok := v.Aux.(*ir.Name)
1585 var r ID
1586 if (!ok || n.Class != ir.PPARAM) && !needCloCtx {
1587 return false, r
1588 }
1589 regInputs, memInputs, spInputs := 0, 0, 0
1590 for _, a := range v.Args {
1591 if a.Op == OpArgIntReg || a.Op == OpArgFloatReg ||
1592 (needCloCtx && a.Op.isLoweredGetClosurePtr()) {
1593 regInputs++
1594 r = a.ID
1595 } else if a.Type.IsMemory() {
1596 memInputs++
1597 } else if a.Op == OpSP {
1598 spInputs++
1599 } else {
1600 return false, r
1601 }
1602 }
1603 return v.Type.IsMemory() && memInputs == 1 &&
1604 regInputs == 1 && spInputs == 1, r
1605 }
1606
1607
1608
1609 regArgs := make([]ID, 0, 32)
1610
1611
1612
1613 removeReg := func(r ID) bool {
1614 for i := 0; i < len(regArgs); i++ {
1615 if regArgs[i] == r {
1616 regArgs = slices.Delete(regArgs, i, i+1)
1617 return true
1618 }
1619 }
1620 return false
1621 }
1622
1623
1624
1625
1626
1627 var cloRegStore *Value
1628 for k, v := range f.Entry.Values {
1629 if v.Op == OpArgIntReg || v.Op == OpArgFloatReg {
1630 regArgs = append(regArgs, v.ID)
1631 continue
1632 }
1633 if needCloCtx && v.Op.isLoweredGetClosurePtr() {
1634 regArgs = append(regArgs, v.ID)
1635 cloRegStore = v
1636 continue
1637 }
1638 if ok, r := isRegMoveLike(v); ok {
1639 if removed := removeReg(r); removed {
1640 if len(regArgs) == 0 {
1641
1642
1643
1644
1645 if k < len(f.Entry.Values)-1 {
1646 return f.Entry.Values[k+1].ID, cloRegStore
1647 }
1648 return BlockEnd.ID, cloRegStore
1649 }
1650 }
1651 }
1652 if v.Op.IsCall() {
1653
1654 return v.ID, cloRegStore
1655 }
1656 }
1657
1658 return ID(-1), cloRegStore
1659 }
1660
1661
1662
1663
1664 func isNamedRegParam(p abi.ABIParamAssignment) bool {
1665 if p.Name == nil {
1666 return false
1667 }
1668 n := p.Name
1669 if n.Sym() == nil || n.Sym().IsBlank() {
1670 return false
1671 }
1672 if len(p.Registers) == 0 {
1673 return false
1674 }
1675 return true
1676 }
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689 func BuildFuncDebugNoOptimized(ctxt *obj.Link, f *Func, loggingEnabled bool, stackOffset func(LocalSlot) int32, rval *FuncDebug) {
1690 needCloCtx := f.CloSlot != nil
1691 pri := f.ABISelf.ABIAnalyzeFuncType(f.Type)
1692
1693
1694
1695
1696
1697 numRegParams := 0
1698 for _, inp := range pri.InParams() {
1699 if isNamedRegParam(inp) {
1700 numRegParams++
1701 }
1702 }
1703 if numRegParams == 0 && !needCloCtx {
1704 return
1705 }
1706
1707 state := debugState{f: f}
1708
1709 if loggingEnabled {
1710 state.logf("generating -N reg param loc lists for func %q\n", f.Name)
1711 }
1712
1713
1714
1715 var cloReg int16
1716
1717 extraForCloCtx := 0
1718 if needCloCtx {
1719 extraForCloCtx = 1
1720 }
1721
1722
1723 rval.LocationLists = make([][]LocListEntry, numRegParams+extraForCloCtx)
1724
1725
1726
1727 afterPrologVal, cloRegStore := locatePrologEnd(f, needCloCtx)
1728
1729 if needCloCtx {
1730 reg, _ := state.f.getHome(cloRegStore.ID).(*Register)
1731 cloReg = reg.ObjNum()
1732 if loggingEnabled {
1733 state.logf("needCloCtx is true for func %q, cloreg=%v\n",
1734 f.Name, reg)
1735 }
1736 }
1737
1738 addVarSlot := func(name *ir.Name, typ *types.Type) {
1739 sl := LocalSlot{N: name, Type: typ, Off: 0}
1740 rval.Vars = append(rval.Vars, name)
1741 rval.Slots = append(rval.Slots, sl)
1742 slid := len(rval.VarSlots)
1743 rval.VarSlots = append(rval.VarSlots, []SlotID{SlotID(slid)})
1744 }
1745
1746
1747
1748
1749 params := []abi.ABIParamAssignment{}
1750 for _, inp := range pri.InParams() {
1751 if !isNamedRegParam(inp) {
1752
1753 continue
1754 }
1755 if !IsVarWantedForDebug(inp.Name) {
1756 continue
1757 }
1758 addVarSlot(inp.Name, inp.Type)
1759 params = append(params, inp)
1760 }
1761 if needCloCtx {
1762 addVarSlot(f.CloSlot, f.CloSlot.Type())
1763 cloAssign := abi.ABIParamAssignment{
1764 Type: f.CloSlot.Type(),
1765 Name: f.CloSlot,
1766 Registers: []abi.RegIndex{0},
1767 }
1768 params = append(params, cloAssign)
1769 }
1770
1771
1772 pidx := 0
1773 for _, inp := range params {
1774 if !isNamedRegParam(inp) {
1775
1776 continue
1777 }
1778 if !IsVarWantedForDebug(inp.Name) {
1779 continue
1780 }
1781
1782 sl := rval.Slots[pidx]
1783 n := rval.Vars[pidx]
1784
1785 if afterPrologVal == ID(-1) {
1786
1787
1788
1789
1790 if loggingEnabled {
1791 state.logf("locatePrologEnd failed, skipping %v\n", n)
1792 }
1793 pidx++
1794 continue
1795 }
1796
1797
1798
1799
1800 if loggingEnabled {
1801 state.logf("param %v:\n [<entry>, %d]:\n", n, afterPrologVal)
1802 }
1803 var regExpr []byte
1804 rtypes, _ := inp.RegisterTypesAndOffsets()
1805 padding := make([]uint64, 0, 32)
1806 padding = inp.ComputePadding(padding)
1807 for k, r := range inp.Registers {
1808 var reg int16
1809 if n == f.CloSlot {
1810 reg = cloReg
1811 } else {
1812 reg = ObjRegForAbiReg(r, f.Config)
1813 }
1814 dwreg := ctxt.Arch.DWARFRegisters[reg]
1815 if dwreg < 32 {
1816 regExpr = append(regExpr, dwarf.DW_OP_reg0+byte(dwreg))
1817 } else {
1818 regExpr = append(regExpr, dwarf.DW_OP_regx)
1819 regExpr = dwarf.AppendUleb128(regExpr, uint64(dwreg))
1820 }
1821 if loggingEnabled {
1822 state.logf(" piece %d -> dwreg %d", k, dwreg)
1823 }
1824 if len(inp.Registers) > 1 {
1825 regExpr = append(regExpr, dwarf.DW_OP_piece)
1826 ts := rtypes[k].Size()
1827 regExpr = dwarf.AppendUleb128(regExpr, uint64(ts))
1828 if padding[k] > 0 {
1829 if loggingEnabled {
1830 state.logf(" [pad %d bytes]", padding[k])
1831 }
1832 regExpr = append(regExpr, dwarf.DW_OP_piece)
1833 regExpr = dwarf.AppendUleb128(regExpr, padding[k])
1834 }
1835 }
1836 if loggingEnabled {
1837 state.logf("\n")
1838 }
1839 }
1840 rval.LocationLists[pidx] = append(rval.LocationLists[pidx], LocListEntry{
1841 StartBlock: f.Entry.ID,
1842 StartValue: BlockStart.ID,
1843 EndBlock: f.Entry.ID,
1844 EndValue: afterPrologVal,
1845 Expr: regExpr,
1846 })
1847
1848
1849
1850 var stackExpr []byte
1851 soff := stackOffset(sl)
1852 if soff == 0 {
1853 stackExpr = append(stackExpr, dwarf.DW_OP_call_frame_cfa)
1854 } else {
1855 stackExpr = append(stackExpr, dwarf.DW_OP_fbreg)
1856 stackExpr = dwarf.AppendSleb128(stackExpr, int64(soff))
1857 }
1858 if loggingEnabled {
1859 state.logf(" [%d, <end>): stackOffset=%d\n", afterPrologVal, soff)
1860 }
1861
1862 rval.LocationLists[pidx] = append(rval.LocationLists[pidx], LocListEntry{
1863 StartBlock: f.Entry.ID,
1864 StartValue: afterPrologVal,
1865 EndBlock: f.Entry.ID,
1866 EndValue: FuncEnd.ID,
1867 Expr: stackExpr,
1868 })
1869
1870 pidx++
1871 }
1872 }
1873
1874
1875
1876
1877
1878 func IsVarWantedForDebug(n ir.Node) bool {
1879 name := n.Sym().Name
1880 if len(name) > 0 && name[0] == '&' {
1881 name = name[1:]
1882 }
1883 if len(name) > 0 && name[0] == '#' {
1884
1885 return strings.HasPrefix(name, "#yield")
1886 }
1887 return true
1888 }
1889
View as plain text