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