1
2
3
4
5 package liveness
6
7 import (
8 "cmd/compile/internal/base"
9 "cmd/compile/internal/bitvec"
10 "cmd/compile/internal/ir"
11 "cmd/compile/internal/ssa"
12 "cmd/internal/src"
13 "fmt"
14 "os"
15 "path/filepath"
16 "slices"
17 "sort"
18 "strings"
19 )
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 type MergeLocalsState struct {
41
42 vars []*ir.Name
43
44 partition map[*ir.Name][]int
45 }
46
47
48
49 type candRegion struct {
50 st, en int
51 }
52
53
54
55
56 type cstate struct {
57 fn *ir.Func
58 f *ssa.Func
59 lv *Liveness
60 cands []*ir.Name
61 nameToSlot map[*ir.Name]int32
62 regions []candRegion
63 indirectUE map[ssa.ID][]*ir.Name
64 ivs []Intervals
65 hashDeselected map[*ir.Name]bool
66 trace int
67 }
68
69
70
71
72 func MergeLocals(fn *ir.Func, f *ssa.Func) *MergeLocalsState {
73
74
75
76
77 cs := &cstate{
78 fn: fn,
79 f: f,
80 trace: base.Debug.MergeLocalsTrace,
81 }
82 cs.collectMergeCandidates()
83 if len(cs.regions) == 0 {
84 return nil
85 }
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105 cs.lv = newliveness(fn, f, cs.cands, cs.nameToSlot, 0)
106 cs.lv.conservativeWrites = true
107 cs.lv.prologue()
108 cs.lv.solve()
109
110
111
112 cs.computeIntervals()
113
114
115 rv := cs.performMerging()
116 if err := rv.check(); err != nil {
117 base.FatalfAt(fn.Pos(), "invalid mergelocals state: %v", err)
118 }
119 return rv
120 }
121
122
123
124 func (mls *MergeLocalsState) Subsumed(n *ir.Name) bool {
125 if sl, ok := mls.partition[n]; ok && mls.vars[sl[0]] != n {
126 return true
127 }
128 return false
129 }
130
131
132
133 func (mls *MergeLocalsState) IsLeader(n *ir.Name) bool {
134 if sl, ok := mls.partition[n]; ok && mls.vars[sl[0]] == n {
135 return true
136 }
137 return false
138 }
139
140
141 func (mls *MergeLocalsState) Leader(n *ir.Name) *ir.Name {
142 if sl, ok := mls.partition[n]; ok {
143 if mls.vars[sl[0]] == n {
144 panic("variable is not subsumed")
145 }
146 return mls.vars[sl[0]]
147 }
148 panic("not a merge candidate")
149 }
150
151
152 func (mls *MergeLocalsState) Followers(n *ir.Name, tmp []*ir.Name) []*ir.Name {
153 tmp = tmp[:0]
154 sl, ok := mls.partition[n]
155 if !ok {
156 panic("no entry for leader")
157 }
158 if mls.vars[sl[0]] != n {
159 panic("followers invoked on subsumed var")
160 }
161 for _, k := range sl[1:] {
162 tmp = append(tmp, mls.vars[k])
163 }
164 slices.SortStableFunc(tmp, func(a, b *ir.Name) int {
165 return strings.Compare(a.Sym().Name, b.Sym().Name)
166 })
167 return tmp
168 }
169
170
171
172 func (mls *MergeLocalsState) EstSavings() (int, int) {
173 totnp := 0
174 totp := 0
175 for n := range mls.partition {
176 if mls.Subsumed(n) {
177 sz := int(n.Type().Size())
178 if n.Type().HasPointers() {
179 totp += sz
180 } else {
181 totnp += sz
182 }
183 }
184 }
185 return totnp, totp
186 }
187
188
189
190 func (mls *MergeLocalsState) check() error {
191 if mls == nil {
192 return nil
193 }
194 used := make(map[int]bool)
195 seenv := make(map[*ir.Name]int)
196 for ii, v := range mls.vars {
197 if prev, ok := seenv[v]; ok {
198 return fmt.Errorf("duplicate var %q in vslots: %d and %d\n",
199 v.Sym().Name, ii, prev)
200 }
201 seenv[v] = ii
202 }
203 for k, sl := range mls.partition {
204
205 if len(sl) < 2 {
206 return fmt.Errorf("k=%q v=%+v slice len %d invalid",
207 k.Sym().Name, sl, len(sl))
208 }
209
210 for i, v := range sl {
211 if v < 0 || v > len(mls.vars)-1 {
212 return fmt.Errorf("k=%q v=+%v slpos %d vslot %d out of range of m.v", k.Sym().Name, sl, i, v)
213 }
214 }
215 }
216 for k, sl := range mls.partition {
217 foundk := false
218 for i, v := range sl {
219 vv := mls.vars[v]
220 if i == 0 {
221 if !mls.IsLeader(vv) {
222 return fmt.Errorf("k=%s v=+%v slpos 0 vslot %d IsLeader(%q) is false should be true", k.Sym().Name, sl, v, vv.Sym().Name)
223 }
224 } else {
225 if !mls.Subsumed(vv) {
226 return fmt.Errorf("k=%s v=+%v slpos %d vslot %d Subsumed(%q) is false should be true", k.Sym().Name, sl, i, v, vv.Sym().Name)
227 }
228 if mls.Leader(vv) != mls.vars[sl[0]] {
229 return fmt.Errorf("k=%s v=+%v slpos %d vslot %d Leader(%q) got %v want %v", k.Sym().Name, sl, i, v, vv.Sym().Name, mls.Leader(vv), mls.vars[sl[0]])
230 }
231 }
232 if vv == k {
233 foundk = true
234 if used[v] {
235 return fmt.Errorf("k=%s v=+%v val slice used violation at slpos %d vslot %d", k.Sym().Name, sl, i, v)
236 }
237 used[v] = true
238 }
239 }
240 if !foundk {
241 return fmt.Errorf("k=%s v=+%v slice value missing k", k.Sym().Name, sl)
242 }
243 vl := mls.vars[sl[0]]
244 for _, v := range sl[1:] {
245 vv := mls.vars[v]
246 if vv.Type().Size() > vl.Type().Size() {
247 return fmt.Errorf("k=%s v=+%v follower %s size %d larger than leader %s size %d", k.Sym().Name, sl, vv.Sym().Name, vv.Type().Size(), vl.Sym().Name, vl.Type().Size())
248 }
249 if vv.Type().HasPointers() && !vl.Type().HasPointers() {
250 return fmt.Errorf("k=%s v=+%v follower %s hasptr=true but leader %s hasptr=false", k.Sym().Name, sl, vv.Sym().Name, vl.Sym().Name)
251 }
252 if vv.Type().Alignment() > vl.Type().Alignment() {
253 return fmt.Errorf("k=%s v=+%v follower %s align %d greater than leader %s align %d", k.Sym().Name, sl, vv.Sym().Name, vv.Type().Alignment(), vl.Sym().Name, vl.Type().Alignment())
254 }
255 }
256 }
257 for i := range used {
258 if !used[i] {
259 return fmt.Errorf("pos %d var %q unused", i, mls.vars[i])
260 }
261 }
262 return nil
263 }
264
265 func (mls *MergeLocalsState) String() string {
266 var leaders []*ir.Name
267 for n, sl := range mls.partition {
268 if n == mls.vars[sl[0]] {
269 leaders = append(leaders, n)
270 }
271 }
272 slices.SortFunc(leaders, func(a, b *ir.Name) int {
273 return strings.Compare(a.Sym().Name, b.Sym().Name)
274 })
275 var sb strings.Builder
276 for _, n := range leaders {
277 sb.WriteString(n.Sym().Name + ":")
278 sl := mls.partition[n]
279 for _, k := range sl[1:] {
280 n := mls.vars[k]
281 sb.WriteString(" " + n.Sym().Name)
282 }
283 sb.WriteString("\n")
284 }
285 return sb.String()
286 }
287
288
289
290
291
292
293
294
295
296 func (cs *cstate) collectMergeCandidates() {
297 var cands []*ir.Name
298
299
300
301
302 for _, n := range cs.fn.Dcl {
303 if !n.Used() {
304 continue
305 }
306 if !ssa.IsMergeCandidate(n) {
307 continue
308 }
309 cands = append(cands, n)
310 }
311 if len(cands) < 2 {
312 return
313 }
314
315
316 sort.SliceStable(cands, func(i, j int) bool {
317 return nameLess(cands[i], cands[j])
318 })
319
320 if cs.trace > 1 {
321 fmt.Fprintf(os.Stderr, "=-= raw cand list for func %v:\n", cs.fn)
322 for i := range cands {
323 dumpCand(cands[i], i)
324 }
325 }
326
327
328
329 initial, _ := cs.genRegions(cands)
330 if len(initial) < 2 {
331 return
332 }
333
334
335 cs.setupHashBisection(initial)
336
337
338
339
340
341 cs.cands, cs.regions = cs.populateIndirectUseTable(initial)
342 if len(cs.cands) < 2 {
343 return
344 }
345
346
347
348
349 cs.nameToSlot = make(map[*ir.Name]int32)
350 for i, n := range cs.cands {
351 cs.nameToSlot[n] = int32(i)
352 }
353
354 if cs.trace > 1 {
355 fmt.Fprintf(os.Stderr, "=-= pruned candidate list for fn %v:\n", cs.fn)
356 for i := range cs.cands {
357 dumpCand(cs.cands[i], i)
358 }
359 }
360 }
361
362
363
364 func (cs *cstate) genRegions(cands []*ir.Name) ([]*ir.Name, []candRegion) {
365 var pruned []*ir.Name
366 var regions []candRegion
367 st := 0
368 for {
369 en := nextRegion(cands, st)
370 if en == -1 {
371 break
372 }
373 if st == en {
374
375 st++
376 continue
377 }
378 pst := len(pruned)
379 pen := pst + (en - st)
380 if cs.trace > 1 {
381 fmt.Fprintf(os.Stderr, "=-= addregion st=%d en=%d: add part %d -> %d\n", st, en, pst, pen)
382 }
383
384
385 pruned = append(pruned, cands[st:en+1]...)
386 regions = append(regions, candRegion{st: pst, en: pen})
387 st = en + 1
388 }
389 if len(pruned) < 2 {
390 return nil, nil
391 }
392 return pruned, regions
393 }
394
395 func (cs *cstate) dumpFunc() {
396 fmt.Fprintf(os.Stderr, "=-= mergelocalsdumpfunc %v:\n", cs.fn)
397 ii := 0
398 for k, b := range cs.f.Blocks {
399 fmt.Fprintf(os.Stderr, "b%d:\n", k)
400 for _, v := range b.Values {
401 pos := base.Ctxt.PosTable.Pos(v.Pos)
402 fmt.Fprintf(os.Stderr, "=-= %d L%d|C%d %s\n", ii, pos.RelLine(), pos.RelCol(), v.LongString())
403 ii++
404 }
405 }
406 }
407
408 func (cs *cstate) dumpFuncIfSelected() {
409 if base.Debug.MergeLocalsDumpFunc == "" {
410 return
411 }
412 if !strings.HasSuffix(fmt.Sprintf("%v", cs.fn),
413 base.Debug.MergeLocalsDumpFunc) {
414 return
415 }
416 cs.dumpFunc()
417 }
418
419
420
421
422
423
424 func (cs *cstate) setupHashBisection(cands []*ir.Name) {
425 if base.Debug.MergeLocalsHash == "" {
426 return
427 }
428 deselected := make(map[*ir.Name]bool)
429 selCount := 0
430 for _, cand := range cands {
431 if !base.MergeLocalsHash.MatchPosWithInfo(cand.Pos(), "mergelocals", nil) {
432 deselected[cand] = true
433 } else {
434 deselected[cand] = false
435 selCount++
436 }
437 }
438 if selCount < len(cands) {
439 cs.hashDeselected = deselected
440 }
441 if base.Debug.MergeLocalsHTrace != 0 && selCount >= 2 {
442 cs.trace = base.Debug.MergeLocalsHTrace
443 }
444 }
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470 func (cs *cstate) populateIndirectUseTable(cands []*ir.Name) ([]*ir.Name, []candRegion) {
471
472
473 indirectUE := make(map[ssa.ID][]*ir.Name)
474
475
476
477 rawcands := make(map[*ir.Name]struct{})
478
479
480
481 pendingUses := make(map[ssa.ID]nameCount)
482
483
484
485 blockIndirectUE := make(map[ssa.ID][]*ir.Name)
486
487
488 evicted := make(map[*ir.Name]bool)
489 for _, n := range cands {
490 rawcands[n] = struct{}{}
491 }
492 for k := 0; k < len(cs.f.Blocks); k++ {
493 clear(pendingUses)
494 clear(blockIndirectUE)
495 b := cs.f.Blocks[k]
496 for _, v := range b.Values {
497 if n, e := affectedVar(v); n != nil {
498 if _, ok := rawcands[n]; ok {
499 if e&ssa.SymAddr != 0 && v.Uses != 0 {
500
501 if _, ok := pendingUses[v.ID]; ok {
502
503 base.FatalfAt(v.Pos, "internal error: apparent multiple defs for SSA value %d", v.ID)
504 }
505
506
507
508 pendingUses[v.ID] = nameCount{n: n, count: v.Uses}
509 if cs.trace > 2 {
510 fmt.Fprintf(os.Stderr, "=-= SymAddr(%s) on %s\n",
511 n.Sym().Name, v.LongString())
512 }
513 }
514 }
515 }
516 for idx, arg := range v.Args {
517 if nc, ok := pendingUses[arg.ID]; ok {
518 if !v.AddrSinkArg(idx) {
519
520
521 continue
522 }
523
524
525
526 if cs.trace > 2 {
527 fmt.Fprintf(os.Stderr, "=-= add indirectUE(%s) count=%d on %s\n", nc.n.Sym().Name, nc.count, v.LongString())
528 }
529 blockIndirectUE[v.ID] = append(blockIndirectUE[v.ID], nc.n)
530 nc.count--
531 if nc.count == 0 {
532
533
534 if cs.trace > 2 {
535 fmt.Fprintf(os.Stderr, "=-= last use of v%d\n",
536 arg.ID)
537 }
538 delete(pendingUses, arg.ID)
539 } else {
540
541
542 pendingUses[arg.ID] = nc
543 }
544 }
545 }
546 }
547
548
549
550
551
552
553
554
555 clear(evicted)
556 if len(pendingUses) != 0 {
557 for id, nc := range pendingUses {
558 if cs.trace > 2 {
559 fmt.Fprintf(os.Stderr, "=-= evicting %q due to pendingUse %d count %d\n", nc.n.Sym().Name, id, nc.count)
560 }
561 delete(rawcands, nc.n)
562 evicted[nc.n] = true
563 }
564 }
565
566
567 for id, sl := range blockIndirectUE {
568 for _, n := range sl {
569 if evicted[n] {
570 continue
571 }
572 indirectUE[id] = append(indirectUE[id], n)
573 if cs.trace > 2 {
574 fmt.Fprintf(os.Stderr, "=-= add final indUE v%d name %s\n", id, n.Sym().Name)
575 }
576 }
577 }
578 }
579 if len(rawcands) < 2 {
580 return nil, nil
581 }
582 cs.indirectUE = indirectUE
583 if cs.trace > 2 {
584 fmt.Fprintf(os.Stderr, "=-= iuetab:\n")
585 ids := make([]ssa.ID, 0, len(indirectUE))
586 for k := range indirectUE {
587 ids = append(ids, k)
588 }
589 slices.Sort(ids)
590 for _, id := range ids {
591 fmt.Fprintf(os.Stderr, " v%d:", id)
592 for _, n := range indirectUE[id] {
593 fmt.Fprintf(os.Stderr, " %s", n.Sym().Name)
594 }
595 fmt.Fprintf(os.Stderr, "\n")
596 }
597 }
598
599 pruned := cands[:0]
600 for k := range rawcands {
601 pruned = append(pruned, k)
602 }
603 sort.Slice(pruned, func(i, j int) bool {
604 return nameLess(pruned[i], pruned[j])
605 })
606 var regions []candRegion
607 pruned, regions = cs.genRegions(pruned)
608 if len(pruned) < 2 {
609 return nil, nil
610 }
611 return pruned, regions
612 }
613
614 type nameCount struct {
615 n *ir.Name
616 count int32
617 }
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634 func nameLess(ci, cj *ir.Name) bool {
635 if ci.Type().HasPointers() != cj.Type().HasPointers() {
636 return ci.Type().HasPointers()
637 }
638 if ci.Type().Alignment() != cj.Type().Alignment() {
639 return cj.Type().Alignment() < ci.Type().Alignment()
640 }
641 if ci.Type().Size() != cj.Type().Size() {
642 return cj.Type().Size() < ci.Type().Size()
643 }
644 if ci.Sym().Name != cj.Sym().Name {
645 return ci.Sym().Name < cj.Sym().Name
646 }
647 return fmt.Sprintf("%v", ci.Pos()) < fmt.Sprintf("%v", cj.Pos())
648 }
649
650
651
652
653
654
655 func nextRegion(cands []*ir.Name, idx int) int {
656 n := len(cands)
657 if idx >= n {
658 return -1
659 }
660 c0 := cands[idx]
661 szprev := c0.Type().Size()
662 alnprev := c0.Type().Alignment()
663 for j := idx + 1; j < n; j++ {
664 cj := cands[j]
665 szj := cj.Type().Size()
666 if szj > szprev {
667 return j - 1
668 }
669 alnj := cj.Type().Alignment()
670 if alnj > alnprev {
671 return j - 1
672 }
673 szprev = szj
674 alnprev = alnj
675 }
676 return n - 1
677 }
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693 func (cs *cstate) mergeVisitRegion(mls *MergeLocalsState, st, en int) {
694 if cs.trace > 1 {
695 fmt.Fprintf(os.Stderr, "=-= mergeVisitRegion(st=%d, en=%d)\n", st, en)
696 }
697 n := en - st + 1
698 used := bitvec.New(int32(n))
699
700 nxt := func(slot int) int {
701 for c := slot - st; c < n; c++ {
702 if used.Get(int32(c)) {
703 continue
704 }
705 return c + st
706 }
707 return -1
708 }
709
710 navail := n
711 cands := cs.cands
712 ivs := cs.ivs
713 if cs.trace > 1 {
714 fmt.Fprintf(os.Stderr, " =-= navail = %d\n", navail)
715 }
716 for navail >= 2 {
717 leader := nxt(st)
718 used.Set(int32(leader - st))
719 navail--
720
721 if cs.trace > 1 {
722 fmt.Fprintf(os.Stderr, " =-= begin leader %d used=%s\n", leader,
723 used.String())
724 }
725 elems := []int{leader}
726 lints := ivs[leader]
727
728 for succ := nxt(leader + 1); succ != -1; succ = nxt(succ + 1) {
729
730
731 if cs.hashDeselected != nil && cs.hashDeselected[cands[succ]] {
732 continue
733 }
734
735 if used.Get(int32(succ - st)) {
736 continue
737 }
738 if cs.trace > 1 {
739 fmt.Fprintf(os.Stderr, " =-= overlap of %d[%v] {%s} with %d[%v] {%s} is: %v\n", leader, cands[leader], lints.String(), succ, cands[succ], ivs[succ].String(), lints.Overlaps(ivs[succ]))
740 }
741
742
743 if lints.Overlaps(ivs[succ]) {
744 continue
745 } else {
746
747 elems = append(elems, succ)
748 lints = lints.Merge(ivs[succ])
749 }
750 }
751 if len(elems) > 1 {
752
753
754 off := len(mls.vars)
755 sl := make([]int, len(elems))
756 for i, candslot := range elems {
757 sl[i] = off + i
758 mls.vars = append(mls.vars, cands[candslot])
759 mls.partition[cands[candslot]] = sl
760 }
761 navail -= (len(elems) - 1)
762 for i := range elems {
763 used.Set(int32(elems[i] - st))
764 }
765 if cs.trace > 1 {
766 fmt.Fprintf(os.Stderr, "=-= overlapping %+v:\n", sl)
767 for i := range sl {
768 dumpCand(mls.vars[sl[i]], sl[i])
769 }
770 for i, v := range elems {
771 fmt.Fprintf(os.Stderr, "=-= %d: sl=%d %s\n", i, v, ivs[v])
772 }
773 }
774 }
775 }
776 }
777
778
779
780
781 func (cs *cstate) performMerging() *MergeLocalsState {
782 cands := cs.cands
783
784 mls := &MergeLocalsState{
785 partition: make(map[*ir.Name][]int),
786 }
787
788
789 if cs.trace > 1 {
790 fmt.Fprintf(os.Stderr, "=-= cands live before overlap:\n")
791 for i := range cands {
792 c := cands[i]
793 fmt.Fprintf(os.Stderr, "%d: %v sz=%d ivs=%s\n",
794 i, c.Sym().Name, c.Type().Size(), cs.ivs[i].String())
795 }
796 fmt.Fprintf(os.Stderr, "=-= regions (%d): ", len(cs.regions))
797 for _, cr := range cs.regions {
798 fmt.Fprintf(os.Stderr, " [%d,%d]", cr.st, cr.en)
799 }
800 fmt.Fprintf(os.Stderr, "\n")
801 }
802
803
804
805 for _, cr := range cs.regions {
806 cs.mergeVisitRegion(mls, cr.st, cr.en)
807 }
808 if len(mls.vars) == 0 {
809 return nil
810 }
811 return mls
812 }
813
814
815
816
817
818 func (cs *cstate) computeIntervals() {
819 lv := cs.lv
820 ibuilders := make([]IntervalsBuilder, len(cs.cands))
821 nvars := int32(len(lv.vars))
822 liveout := bitvec.New(nvars)
823
824 cs.dumpFuncIfSelected()
825
826
827 ninstr := 0
828 for _, b := range lv.f.Blocks {
829 ninstr += len(b.Values)
830 }
831
832 iidx := ninstr - 1
833
834
835 for k := len(lv.f.Blocks) - 1; k >= 0; k-- {
836 b := lv.f.Blocks[k]
837 be := lv.blockEffects(b)
838
839 if cs.trace > 2 {
840 fmt.Fprintf(os.Stderr, "=-= liveout from tail of b%d: ", k)
841 for j := range lv.vars {
842 if be.liveout.Get(int32(j)) {
843 fmt.Fprintf(os.Stderr, " %q", lv.vars[j].Sym().Name)
844 }
845 }
846 fmt.Fprintf(os.Stderr, "\n")
847 }
848
849
850
851
852
853
854
855 for j := range lv.vars {
856 isLive := liveout.Get(int32(j))
857 blockLiveOut := be.liveout.Get(int32(j))
858 if isLive {
859 if !blockLiveOut {
860 if cs.trace > 2 {
861 fmt.Fprintf(os.Stderr, "=+= at instr %d block boundary kill of %v\n", iidx, lv.vars[j])
862 }
863 ibuilders[j].Kill(iidx)
864 }
865 } else if blockLiveOut {
866 if cs.trace > 2 {
867 fmt.Fprintf(os.Stderr, "=+= at block-end instr %d %v becomes live\n",
868 iidx, lv.vars[j])
869 }
870 ibuilders[j].Live(iidx)
871 }
872 }
873
874
875
876 liveout.Copy(be.liveout)
877
878
879 for i := len(b.Values) - 1; i >= 0; i-- {
880 v := b.Values[i]
881
882 if cs.trace > 2 {
883 fmt.Fprintf(os.Stderr, "=-= b%d instr %d: %s\n", k, iidx, v.LongString())
884 }
885
886
887
888 pos, e := lv.valueEffects(v)
889 becomeslive := e&uevar != 0
890 iskilled := e&varkill != 0
891 if becomeslive && iskilled {
892
893
894 panic("should never happen")
895 }
896 if iskilled && liveout.Get(pos) {
897 ibuilders[pos].Kill(iidx)
898 liveout.Unset(pos)
899 if cs.trace > 2 {
900 fmt.Fprintf(os.Stderr, "=+= at instr %d kill of %v\n",
901 iidx, lv.vars[pos])
902 }
903 } else if becomeslive && !liveout.Get(pos) {
904 ibuilders[pos].Live(iidx)
905 liveout.Set(pos)
906 if cs.trace > 2 {
907 fmt.Fprintf(os.Stderr, "=+= at instr %d upwards-exposed use of %v\n",
908 iidx, lv.vars[pos])
909 }
910 }
911
912 if cs.indirectUE != nil {
913
914 ues := cs.indirectUE[v.ID]
915 for _, n := range ues {
916 if pos, ok := lv.idx[n]; ok {
917 if !liveout.Get(pos) {
918 ibuilders[pos].Live(iidx)
919 liveout.Set(pos)
920 if cs.trace > 2 {
921 fmt.Fprintf(os.Stderr, "=+= at instr %d v%d indirect upwards-exposed use of %v\n", iidx, v.ID, lv.vars[pos])
922 }
923 }
924 }
925 }
926 }
927 iidx--
928 }
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981 const checkLiveOnEntry = false
982 if checkLiveOnEntry && b == lv.f.Entry {
983 for j, v := range lv.vars {
984 if liveout.Get(int32(j)) {
985 lv.f.Fatalf("%v %L recorded as live on entry",
986 lv.fn.Nname, v)
987 }
988 }
989 }
990 }
991 if iidx != -1 {
992 panic("iidx underflow")
993 }
994
995
996 ivs := make([]Intervals, len(cs.cands))
997 for i := range cs.cands {
998 var err error
999 ivs[i], err = ibuilders[i].Finish()
1000 if err != nil {
1001 cs.dumpFunc()
1002 base.FatalfAt(cs.cands[i].Pos(), "interval construct error for var %q in func %q (%d instrs): %v", cs.cands[i].Sym().Name, ir.FuncName(cs.fn), ninstr, err)
1003 }
1004 }
1005 cs.ivs = ivs
1006 }
1007
1008 func fmtFullPos(p src.XPos) string {
1009 var sb strings.Builder
1010 sep := ""
1011 base.Ctxt.AllPos(p, func(pos src.Pos) {
1012 sb.WriteString(sep)
1013 sep = "|"
1014 file := filepath.Base(pos.Filename())
1015 fmt.Fprintf(&sb, "%s:%d:%d", file, pos.Line(), pos.Col())
1016 })
1017 return sb.String()
1018 }
1019
1020 func dumpCand(c *ir.Name, i int) {
1021 fmt.Fprintf(os.Stderr, " %d: %s %q sz=%d hp=%v align=%d t=%v\n",
1022 i, fmtFullPos(c.Pos()), c.Sym().Name, c.Type().Size(),
1023 c.Type().HasPointers(), c.Type().Alignment(), c.Type())
1024 }
1025
1026
1027 func MakeMergeLocalsState(partition map[*ir.Name][]int, vars []*ir.Name) (*MergeLocalsState, error) {
1028 mls := &MergeLocalsState{partition: partition, vars: vars}
1029 if err := mls.check(); err != nil {
1030 return nil, err
1031 }
1032 return mls, nil
1033 }
1034
View as plain text