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