1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114 package ssa
115
116 import (
117 "cmd/compile/internal/base"
118 "cmd/compile/internal/ir"
119 "cmd/compile/internal/ssa/block"
120 "cmd/compile/internal/ssa/ssabase"
121 "cmd/compile/internal/types"
122 "cmd/internal/src"
123 "cmd/internal/sys"
124 "cmp"
125 "fmt"
126 "internal/buildcfg"
127 "math"
128 "math/bits"
129 "slices"
130 "unsafe"
131 )
132
133 const (
134 moveSpills = iota
135 logSpills
136 regDebug
137 stackDebug
138 )
139
140
141
142 const (
143 likelyDistance = 1
144 normalDistance = 10
145 unlikelyDistance = 100
146 )
147
148
149
150 func regalloc(f *Func) {
151 var s regAllocState
152 s.init(f)
153 s.regalloc(f)
154 s.close()
155 }
156
157 type register uint8
158
159 const noRegister register = 255
160
161
162 var noRegisters [32]register = [32]register{
163 noRegister, noRegister, noRegister, noRegister, noRegister, noRegister, noRegister, noRegister,
164 noRegister, noRegister, noRegister, noRegister, noRegister, noRegister, noRegister, noRegister,
165 noRegister, noRegister, noRegister, noRegister, noRegister, noRegister, noRegister, noRegister,
166 noRegister, noRegister, noRegister, noRegister, noRegister, noRegister, noRegister, noRegister,
167 }
168
169
170 type regMask struct {
171 v1, v2 uint64
172 }
173
174 func (r regMask) intersect(s regMask) regMask {
175 return regMask{r.v1 & s.v1, r.v2 & s.v2}
176 }
177
178 func (r regMask) union(s regMask) regMask {
179 return regMask{r.v1 | s.v1, r.v2 | s.v2}
180 }
181
182 func (r regMask) minus(s regMask) regMask {
183 return regMask{r.v1 &^ s.v1, r.v2 &^ s.v2}
184 }
185
186 func (r regMask) empty() bool {
187 return r.v1 == 0 && r.v2 == 0
188 }
189
190 func (r regMask) pickReg() register {
191 if r.empty() {
192 panic("can't pick a register from an empty set")
193 }
194
195 if r.v1 != 0 {
196 return register(bits.TrailingZeros64(r.v1))
197 }
198 return register(bits.TrailingZeros64(r.v2) + 64)
199 }
200
201 func regMaskAt(i register) regMask {
202 if i < 64 {
203 return regMask{v1: 1 << i}
204 }
205 return regMask{v2: 1 << (i - 64)}
206 }
207
208 func (r regMask) addReg(i register) regMask {
209 if i < 64 {
210 return regMask{r.v1 | 1<<i, r.v2}
211 }
212 return regMask{r.v1, r.v2 | 1<<(i-64)}
213 }
214
215 func (r regMask) removeReg(i register) regMask {
216 if i < 64 {
217 return regMask{r.v1 &^ (1 << i), r.v2}
218 }
219 return regMask{r.v1, r.v2 &^ (1 << (i - 64))}
220 }
221
222 func (r regMask) hasReg(i register) bool {
223 if i < 64 {
224 return (r.v1>>i)&1 != 0
225 }
226 return (r.v2>>(i-64))&1 != 0
227 }
228
229 func (m regMask) String() string {
230 s := ""
231 for r := register(0); !m.empty(); r++ {
232 if !m.hasReg(r) {
233 continue
234 }
235 m = m.removeReg(r)
236 if s != "" {
237 s += " "
238 }
239 s += fmt.Sprintf("r%d", r)
240 }
241 return s
242 }
243
244 func (s *regAllocState) RegMaskString(m regMask) string {
245 str := ""
246 for r := register(0); !m.empty(); r++ {
247 if !m.hasReg(r) {
248 continue
249 }
250 m = m.removeReg(r)
251 if str != "" {
252 str += " "
253 }
254 str += s.registers[r].String()
255 }
256 return str
257 }
258
259
260 func countRegs(r regMask) int {
261 return bits.OnesCount64(r.v1) + bits.OnesCount64(r.v2)
262 }
263
264
265 func (s *regAllocState) pickReg(rm regMask) register {
266 if s.f.Config.ctxt.Arch.Arch == sys.ArchRISCV64 {
267
268 riscv64CompressedMask := rm.intersect(regMask{v1: 0x0000ff000000ff00})
269 if !riscv64CompressedMask.empty() {
270 rm = riscv64CompressedMask
271 }
272 }
273 return rm.pickReg()
274 }
275
276 type use struct {
277
278
279
280
281
282 dist int32
283 pos src.XPos
284 next *use
285 }
286
287
288 type valState struct {
289 regs regMask
290 uses *use
291 spill *Value
292 restoreMin int32
293 restoreMax int32
294 needReg bool
295 rematerializeable bool
296 }
297
298 type regState struct {
299 v *Value
300 c *Value
301
302 }
303
304 type regAllocState struct {
305 f *Func
306
307 sdom SparseTree
308 registers []ssabase.Register
309 numRegs register
310 SPReg register
311 SBReg register
312 GReg register
313 ZeroIntReg register
314 allocatable regMask
315
316
317
318
319 live [][]liveInfo
320
321
322
323
324 desired []desiredState
325
326
327 values []valState
328
329
330 sp, sb ID
331
332
333
334 orig []*Value
335
336
337
338 regs []regState
339
340
341 nospill regMask
342
343
344 used regMask
345
346
347 usedSinceBlockStart regMask
348
349
350 tmpused regMask
351
352
353 curBlock *Block
354
355
356 freeUseRecords *use
357
358
359
360 endRegs [][]endReg
361
362
363
364 startRegs [][]startReg
365
366
367
368
369 startRegsMask regMask
370
371
372 spillLive [][]ID
373
374
375
376 copies map[*Value]bool
377
378 loopnest *loopnest
379
380
381 visitOrder []*Block
382
383
384 blockOrder []int32
385
386
387 doClobber bool
388
389
390
391
392
393
394 nextCall []int32
395
396
397
398 curIdx int
399 }
400
401 type endReg struct {
402 r register
403 v *Value
404 c *Value
405 }
406
407 type startReg struct {
408 r register
409 v *Value
410 c *Value
411 pos src.XPos
412 }
413
414
415 func (s *regAllocState) freeReg(r register) {
416 if !s.allocatable.hasReg(r) && !s.isGReg(r) {
417 return
418 }
419 v := s.regs[r].v
420 if v == nil {
421 s.f.Fatalf("tried to free an already free register %d\n", r)
422 }
423
424
425 if s.f.pass.debug > regDebug {
426 fmt.Printf("freeReg %s (dump %s/%s)\n", &s.registers[r], v, s.regs[r].c)
427 }
428 s.regs[r] = regState{}
429 s.values[v.ID].regs = s.values[v.ID].regs.removeReg(r)
430 s.used = s.used.removeReg(r)
431 }
432
433
434 func (s *regAllocState) freeRegs(m regMask) {
435 for !m.intersect(s.used).empty() {
436 s.freeReg(s.pickReg(m.intersect(s.used)))
437 }
438 }
439
440
441 func (s *regAllocState) clobberRegs(m regMask) {
442 m = m.intersect(s.allocatable.intersect(s.f.Config.gpRegMask))
443 for !m.empty() {
444 r := s.pickReg(m)
445 m = m.removeReg(r)
446 x := s.curBlock.NewValue0(src.NoXPos, OpClobberReg, types.TypeVoid)
447 s.f.setHome(x, &s.registers[r])
448 }
449 }
450
451
452
453 func (s *regAllocState) setOrig(c *Value, v *Value) {
454 if int(c.ID) >= cap(s.orig) {
455 x := s.f.Cache.allocValueSlice(int(c.ID) + 1)
456 copy(x, s.orig)
457 s.f.Cache.freeValueSlice(s.orig)
458 s.orig = x
459 }
460 for int(c.ID) >= len(s.orig) {
461 s.orig = append(s.orig, nil)
462 }
463 if s.orig[c.ID] != nil {
464 s.f.Fatalf("orig value set twice %s %s", c, v)
465 }
466 s.orig[c.ID] = s.orig[v.ID]
467 }
468
469
470
471 func (s *regAllocState) assignReg(r register, v *Value, c *Value) {
472 if s.f.pass.debug > regDebug {
473 fmt.Printf("assignReg %s %s/%s\n", &s.registers[r], v, c)
474 }
475
476 s.values[v.ID].regs = s.values[v.ID].regs.addReg(r)
477 s.f.setHome(c, &s.registers[r])
478
479
480 if !s.allocatable.hasReg(r) && !s.isGReg(r) {
481 return
482 }
483 if s.regs[r].v != nil {
484 s.f.Fatalf("tried to assign register %d to %s/%s but it is already used by %s", r, v, c, s.regs[r].v)
485 }
486 s.regs[r] = regState{v, c}
487 s.used = s.used.addReg(r)
488 }
489
490
491
492
493 func (s *regAllocState) allocReg(mask regMask, v *Value) register {
494 if v.OnWasmStack {
495 return noRegister
496 }
497
498 mask = mask.intersect(s.allocatable)
499 mask = mask.minus(s.nospill)
500 if mask.empty() {
501 s.f.Fatalf("no register available for %s", v.LongString())
502 }
503
504
505 if !mask.minus(s.used).empty() {
506 r := s.pickReg(mask.minus(s.used))
507 s.usedSinceBlockStart = s.usedSinceBlockStart.addReg(r)
508 return r
509 }
510
511
512
513
514
515
516
517
518
519
520
521 var r register
522 maxuse := int32(-1)
523 for t := register(0); t < s.numRegs; t++ {
524 if !mask.hasReg(t) {
525 continue
526 }
527 v := s.regs[t].v
528 if n := s.values[v.ID].uses.dist; n > maxuse {
529
530
531 r = t
532 maxuse = n
533 }
534 }
535 if maxuse == -1 {
536 s.f.Fatalf("couldn't find register to spill")
537 }
538
539 if s.f.Config.ctxt.Arch.Arch == sys.ArchWasm {
540
541
542
543 s.freeReg(r)
544 return r
545 }
546
547
548
549 v2 := s.regs[r].v
550 m := s.compatRegs(v2.Type).minus(s.used).minus(s.tmpused).removeReg(r)
551 if !m.empty() && !s.values[v2.ID].rematerializeable && countRegs(s.values[v2.ID].regs) == 1 {
552 s.usedSinceBlockStart = s.usedSinceBlockStart.addReg(r)
553 r2 := s.pickReg(m)
554 c := s.curBlock.NewValue1(v2.Pos, OpCopy, v2.Type, s.regs[r].c)
555 s.copies[c] = false
556 if s.f.pass.debug > regDebug {
557 fmt.Printf("copy %s to %s : %s\n", v2, c, &s.registers[r2])
558 }
559 s.setOrig(c, v2)
560 s.assignReg(r2, v2, c)
561 }
562
563
564
565
566 if !s.usedSinceBlockStart.hasReg(r) {
567 if s.startRegsMask.hasReg(r) {
568 if s.f.pass.debug > regDebug {
569 fmt.Printf("dropped from startRegs: %s\n", &s.registers[r])
570 }
571 s.startRegsMask = s.startRegsMask.removeReg(r)
572 }
573 }
574
575 s.freeReg(r)
576 s.usedSinceBlockStart = s.usedSinceBlockStart.addReg(r)
577 return r
578 }
579
580
581
582 func (s *regAllocState) makeSpill(v *Value, b *Block) *Value {
583 vi := &s.values[v.ID]
584 if vi.spill != nil {
585
586 vi.restoreMin = min(vi.restoreMin, s.sdom[b.ID].entry)
587 vi.restoreMax = max(vi.restoreMax, s.sdom[b.ID].exit)
588 return vi.spill
589 }
590
591
592 spill := s.f.newValueNoBlock(OpStoreReg, v.Type, v.Pos)
593
594
595 s.setOrig(spill, v)
596 vi.spill = spill
597 vi.restoreMin = s.sdom[b.ID].entry
598 vi.restoreMax = s.sdom[b.ID].exit
599 return spill
600 }
601
602
603
604
605
606
607
608 func (s *regAllocState) allocValToReg(v *Value, mask regMask, nospill bool, pos src.XPos) *Value {
609 if s.f.Config.ctxt.Arch.Arch == sys.ArchWasm && v.rematerializeable() {
610 c := v.copyIntoWithXPos(s.curBlock, pos)
611 c.OnWasmStack = true
612 s.setOrig(c, v)
613 return c
614 }
615 if v.OnWasmStack {
616 return v
617 }
618
619 vi := &s.values[v.ID]
620 pos = pos.WithNotStmt()
621
622 if !mask.intersect(vi.regs).empty() {
623 mask = mask.intersect(vi.regs)
624 r := s.pickReg(mask)
625 if mask.hasReg(s.SPReg) {
626
627
628
629 r = s.SPReg
630 }
631 if !s.allocatable.hasReg(r) {
632 return v
633 }
634 if s.regs[r].v != v || s.regs[r].c == nil {
635 panic("bad register state")
636 }
637 if nospill {
638 s.nospill = s.nospill.addReg(r)
639 }
640 s.usedSinceBlockStart = s.usedSinceBlockStart.addReg(r)
641 return s.regs[r].c
642 }
643
644 var r register
645
646 onWasmStack := nospill && s.f.Config.ctxt.Arch.Arch == sys.ArchWasm
647 if !onWasmStack {
648
649 r = s.allocReg(mask, v)
650 }
651
652
653 var c *Value
654 if !vi.regs.empty() {
655
656 var current *Value
657 if !vi.regs.minus(s.allocatable).empty() {
658
659 current = v
660 } else {
661 r2 := s.pickReg(vi.regs)
662 if s.regs[r2].v != v {
663 panic("bad register state")
664 }
665 current = s.regs[r2].c
666 s.usedSinceBlockStart = s.usedSinceBlockStart.addReg(r2)
667 }
668 c = s.curBlock.NewValue1(pos, OpCopy, v.Type, current)
669 } else if v.rematerializeable() {
670
671 c = v.copyIntoWithXPos(s.curBlock, pos)
672
673
674
675
676
677
678
679 sourceMask := s.regspec(c).outputs[0].regs
680 if mask.intersect(sourceMask).empty() && !onWasmStack {
681 s.setOrig(c, v)
682 s.assignReg(s.allocReg(sourceMask, v), v, c)
683
684
685
686
687
688
689
690
691
692
693 c = s.curBlock.NewValue1(pos, OpCopy, v.Type, c)
694 }
695 } else {
696
697 spill := s.makeSpill(v, s.curBlock)
698 if s.f.pass.debug > logSpills {
699 s.f.Warnl(vi.spill.Pos, "load spill for %v from %v", v, spill)
700 }
701 c = s.curBlock.NewValue1(pos, OpLoadReg, v.Type, spill)
702 sourceMask := s.compatRegs(v.Type)
703 if !sourceMask.hasReg(r) && !onWasmStack {
704
705
706
707 s.setOrig(c, v)
708 s.assignReg(s.allocReg(sourceMask, v), v, c)
709 c = s.curBlock.NewValue1(pos, OpCopy, v.Type, c)
710 }
711 }
712
713 s.setOrig(c, v)
714
715 if onWasmStack {
716 c.OnWasmStack = true
717 return c
718 }
719
720 s.assignReg(r, v, c)
721 if c.Op == OpLoadReg && s.isGReg(r) {
722 s.f.Fatalf("allocValToReg.OpLoadReg targeting g: " + c.LongString())
723 }
724 if nospill {
725 s.nospill = s.nospill.addReg(r)
726 }
727 return c
728 }
729
730
731 func isLeaf(f *Func) bool {
732 for _, b := range f.Blocks {
733 for _, v := range b.Values {
734 if v.Op.IsCall() && !v.Op.IsTailCall() {
735
736 return false
737 }
738 }
739 }
740 return true
741 }
742
743
744 func (v *Value) needRegister() bool {
745 return !v.Type.IsMemory() && !v.Type.IsVoid() && !v.Type.IsFlags() && !v.Type.IsTuple()
746 }
747
748 func (s *regAllocState) init(f *Func) {
749 s.f = f
750 s.f.RegAlloc = s.f.Cache.locs[:0]
751 s.registers = f.Config.registers
752 if nr := len(s.registers); nr == 0 || nr > int(noRegister) || nr > int(unsafe.Sizeof(regMask{})*8) {
753 s.f.Fatalf("bad number of registers: %d", nr)
754 } else {
755 s.numRegs = register(nr)
756 }
757
758 s.SPReg = noRegister
759 s.SBReg = noRegister
760 s.GReg = noRegister
761 s.ZeroIntReg = noRegister
762 for r := register(0); r < s.numRegs; r++ {
763 switch s.registers[r].String() {
764 case "SP":
765 s.SPReg = r
766 case "SB":
767 s.SBReg = r
768 case "g":
769 s.GReg = r
770 case "ZERO":
771 s.ZeroIntReg = r
772 }
773 }
774
775 switch noRegister {
776 case s.SPReg:
777 s.f.Fatalf("no SP register found")
778 case s.SBReg:
779 s.f.Fatalf("no SB register found")
780 case s.GReg:
781 if f.Config.hasGReg {
782 s.f.Fatalf("no g register found")
783 }
784 }
785
786
787 s.allocatable = s.f.Config.gpRegMask.union(s.f.Config.fpRegMask).union(s.f.Config.specialRegMask).union(s.f.Config.simdRegMask)
788 s.allocatable = s.allocatable.removeReg(s.SPReg)
789 s.allocatable = s.allocatable.removeReg(s.SBReg)
790 if s.f.Config.hasGReg {
791 s.allocatable = s.allocatable.removeReg(s.GReg)
792 }
793 if s.ZeroIntReg != noRegister {
794 s.allocatable = s.allocatable.removeReg(s.ZeroIntReg)
795 }
796 if buildcfg.FramePointerEnabled && s.f.Config.FPReg >= 0 {
797 s.allocatable = s.allocatable.removeReg(register(s.f.Config.FPReg))
798 }
799 if s.f.Config.LinkReg != -1 {
800 if isLeaf(f) {
801
802 s.allocatable = s.allocatable.removeReg(register(s.f.Config.LinkReg))
803 }
804 }
805 if s.f.Config.ctxt.Flag_dynlink {
806 switch s.f.Config.arch {
807 case "386":
808
809
810
811
812
813 case "amd64":
814 s.allocatable = s.allocatable.removeReg(15)
815 case "arm":
816 s.allocatable = s.allocatable.removeReg(9)
817 case "arm64":
818
819 case "loong64":
820
821 case "ppc64", "ppc64le":
822
823 case "riscv64":
824
825 case "s390x":
826 s.allocatable = s.allocatable.removeReg(11)
827 default:
828 s.f.fe.Fatalf(src.NoXPos, "arch %s not implemented", s.f.Config.arch)
829 }
830 }
831
832
833
834
835 s.visitOrder = layoutRegallocOrder(f)
836
837
838
839 s.blockOrder = make([]int32, f.NumBlocks())
840 for i, b := range s.visitOrder {
841 s.blockOrder[b.ID] = int32(i)
842 }
843
844 s.regs = make([]regState, s.numRegs)
845 nv := f.NumValues()
846 if cap(s.f.Cache.regallocValues) >= nv {
847 s.f.Cache.regallocValues = s.f.Cache.regallocValues[:nv]
848 } else {
849 s.f.Cache.regallocValues = make([]valState, nv)
850 }
851 s.values = s.f.Cache.regallocValues
852 s.orig = s.f.Cache.allocValueSlice(nv)
853 s.copies = make(map[*Value]bool)
854 for _, b := range s.visitOrder {
855 for _, v := range b.Values {
856 if v.needRegister() {
857 s.values[v.ID].needReg = true
858 s.values[v.ID].rematerializeable = v.rematerializeable()
859 s.orig[v.ID] = v
860 }
861
862
863 }
864 }
865 s.computeLive()
866
867 s.endRegs = make([][]endReg, f.NumBlocks())
868 s.startRegs = make([][]startReg, f.NumBlocks())
869 s.spillLive = make([][]ID, f.NumBlocks())
870 s.sdom = f.Sdom()
871
872
873 if f.Config.ctxt.Arch.Arch == sys.ArchWasm {
874 canLiveOnStack := f.newSparseSet(f.NumValues())
875 defer f.retSparseSet(canLiveOnStack)
876 for _, b := range f.Blocks {
877
878 canLiveOnStack.clear()
879 for _, c := range b.ControlValues() {
880 if c.Uses == 1 && !opcodeTable[c.Op].generic {
881 canLiveOnStack.add(c.ID)
882 }
883 }
884
885 for i := len(b.Values) - 1; i >= 0; i-- {
886 v := b.Values[i]
887 if canLiveOnStack.contains(v.ID) {
888 v.OnWasmStack = true
889 } else {
890
891 canLiveOnStack.clear()
892 }
893 for _, arg := range v.Args {
894
895
896
897
898
899 if arg.Uses == 1 && arg.Block == v.Block && !arg.Type.IsMemory() && !opcodeTable[arg.Op].generic {
900 canLiveOnStack.add(arg.ID)
901 }
902 }
903 }
904 }
905 }
906
907
908
909
910 if base.Flag.ClobberDeadReg && len(s.f.Blocks) <= 10000 {
911
912 s.doClobber = true
913 }
914 }
915
916 func (s *regAllocState) close() {
917 s.f.Cache.freeValueSlice(s.orig)
918 }
919
920
921
922 func (s *regAllocState) addUse(id ID, dist int32, pos src.XPos) {
923 r := s.freeUseRecords
924 if r != nil {
925 s.freeUseRecords = r.next
926 } else {
927 r = &use{}
928 }
929 r.dist = dist
930 r.pos = pos
931 r.next = s.values[id].uses
932 s.values[id].uses = r
933 if r.next != nil && dist > r.next.dist {
934 s.f.Fatalf("uses added in wrong order")
935 }
936 }
937
938
939
940 func (s *regAllocState) advanceUses(v *Value) {
941 for _, a := range v.Args {
942 if !s.values[a.ID].needReg {
943 continue
944 }
945 ai := &s.values[a.ID]
946 r := ai.uses
947 ai.uses = r.next
948 if r.next == nil || (!opcodeTable[a.Op].fixedReg && r.next.dist > s.nextCall[s.curIdx]) {
949
950 s.freeRegs(ai.regs)
951 }
952 r.next = s.freeUseRecords
953 s.freeUseRecords = r
954 }
955 s.dropIfUnused(v)
956 }
957
958
959
960 func (s *regAllocState) dropIfUnused(v *Value) {
961 if !s.values[v.ID].needReg {
962 return
963 }
964 vi := &s.values[v.ID]
965 r := vi.uses
966 nextCall := s.nextCall[s.curIdx]
967 if opcodeTable[v.Op].call {
968 if s.curIdx == len(s.nextCall)-1 {
969 nextCall = math.MaxInt32
970 } else {
971 nextCall = s.nextCall[s.curIdx+1]
972 }
973 }
974 if r == nil || (!opcodeTable[v.Op].fixedReg && r.dist > nextCall) {
975 s.freeRegs(vi.regs)
976 }
977 }
978
979
980
981
982 func (s *regAllocState) liveAfterCurrentInstruction(v *Value) bool {
983 u := s.values[v.ID].uses
984 if u == nil {
985 panic(fmt.Errorf("u is nil, v = %s, s.values[v.ID] = %v", v.LongString(), s.values[v.ID]))
986 }
987 d := u.dist
988 for u != nil && u.dist == d {
989 u = u.next
990 }
991 return u != nil && u.dist > d
992 }
993
994
995 func (s *regAllocState) setState(regs []endReg) {
996 s.freeRegs(s.used)
997 for _, x := range regs {
998 s.assignReg(x.r, x.v, x.c)
999 }
1000 }
1001
1002
1003 func (s *regAllocState) compatRegs(t *types.Type) regMask {
1004 var m regMask
1005 if t.IsTuple() || t.IsFlags() {
1006 return regMask{}
1007 }
1008 if t.IsSIMD() {
1009 if t.Size() > 8 {
1010 return s.f.Config.simdRegMask.intersect(s.allocatable)
1011 } else {
1012 if !s.f.Config.specialRegMask.empty() {
1013
1014
1015 return s.f.Config.specialRegMask.intersect(s.allocatable)
1016 }
1017
1018
1019 return s.f.Config.gpRegMask.intersect(s.allocatable)
1020 }
1021 }
1022 if t.IsFloat() || t == types.TypeInt128 {
1023 if t.Kind() == types.TFLOAT32 && !s.f.Config.fp32RegMask.empty() {
1024 m = s.f.Config.fp32RegMask
1025 } else if t.Kind() == types.TFLOAT64 && !s.f.Config.fp64RegMask.empty() {
1026 m = s.f.Config.fp64RegMask
1027 } else {
1028 m = s.f.Config.fpRegMask
1029 }
1030 } else {
1031 m = s.f.Config.gpRegMask
1032 }
1033 return m.intersect(s.allocatable)
1034 }
1035
1036
1037 func (s *regAllocState) regspec(v *Value) regInfo {
1038 op := v.Op
1039 if op == OpConvert {
1040
1041
1042
1043 m := s.allocatable.intersect(s.f.Config.gpRegMask)
1044 return regInfo{inputs: []inputInfo{{regs: m}}, outputs: []outputInfo{{regs: m}}}
1045 }
1046 if op == OpArgIntReg {
1047 reg := v.Block.Func.Config.intParamRegs[v.AuxInt8()]
1048 return regInfo{outputs: []outputInfo{{regs: regMaskAt(register(reg))}}}
1049 }
1050 if op == OpArgFloatReg {
1051 reg := v.Block.Func.Config.floatParamRegs[v.AuxInt8()]
1052 return regInfo{outputs: []outputInfo{{regs: regMaskAt(register(reg))}}}
1053 }
1054 if op.IsCall() {
1055 if ac, ok := v.Aux.(*AuxCall); ok && ac.reg != nil {
1056 return *ac.Reg(&opcodeTable[op].reg, s.f.Config)
1057 }
1058 }
1059 if op == OpMakeResult && s.f.OwnAux.reg != nil {
1060 return *s.f.OwnAux.ResultReg(s.f.Config)
1061 }
1062 return opcodeTable[op].reg
1063 }
1064
1065 func (s *regAllocState) isGReg(r register) bool {
1066 return s.f.Config.hasGReg && s.GReg == r
1067 }
1068
1069
1070 var tmpVal Value
1071
1072 func (s *regAllocState) regalloc(f *Func) {
1073 regValLiveSet := f.newSparseSet(f.NumValues())
1074 defer f.retSparseSet(regValLiveSet)
1075 var oldSched []*Value
1076 var phis []*Value
1077 var phiRegs []register
1078 var args []*Value
1079
1080
1081 var desired desiredState
1082 desiredSecondReg := map[ID][4]register{}
1083
1084
1085 type dentry struct {
1086 out [4]register
1087 in [3][4]register
1088 }
1089 var dinfo []dentry
1090
1091 if f.Entry != f.Blocks[0] {
1092 f.Fatalf("entry block must be first")
1093 }
1094
1095 for _, b := range s.visitOrder {
1096 if s.f.pass.debug > regDebug {
1097 fmt.Printf("Begin processing block %v\n", b)
1098 }
1099 s.curBlock = b
1100 s.startRegsMask = regMask{}
1101 s.usedSinceBlockStart = regMask{}
1102 clear(desiredSecondReg)
1103
1104
1105
1106 regValLiveSet.clear()
1107 if s.live != nil {
1108 for _, e := range s.live[b.ID] {
1109 s.addUse(e.ID, int32(len(b.Values))+e.dist, e.pos)
1110 regValLiveSet.add(e.ID)
1111 }
1112 }
1113 for _, v := range b.ControlValues() {
1114 if s.values[v.ID].needReg {
1115 s.addUse(v.ID, int32(len(b.Values)), b.Pos)
1116 regValLiveSet.add(v.ID)
1117 }
1118 }
1119 if cap(s.nextCall) < len(b.Values) {
1120 c := cap(s.nextCall)
1121 s.nextCall = append(s.nextCall[:c], make([]int32, len(b.Values)-c)...)
1122 } else {
1123 s.nextCall = s.nextCall[:len(b.Values)]
1124 }
1125 var nextCall int32 = math.MaxInt32
1126 for i := len(b.Values) - 1; i >= 0; i-- {
1127 v := b.Values[i]
1128 regValLiveSet.remove(v.ID)
1129 if v.Op == OpPhi {
1130
1131
1132
1133 s.nextCall[i] = nextCall
1134 continue
1135 }
1136 if opcodeTable[v.Op].call {
1137
1138 regValLiveSet.clear()
1139 if s.sp != 0 && s.values[s.sp].uses != nil {
1140 regValLiveSet.add(s.sp)
1141 }
1142 if s.sb != 0 && s.values[s.sb].uses != nil {
1143 regValLiveSet.add(s.sb)
1144 }
1145 nextCall = int32(i)
1146 }
1147 for _, a := range v.Args {
1148 if !s.values[a.ID].needReg {
1149 continue
1150 }
1151 s.addUse(a.ID, int32(i), v.Pos)
1152 regValLiveSet.add(a.ID)
1153 }
1154 s.nextCall[i] = nextCall
1155 }
1156 if s.f.pass.debug > regDebug {
1157 fmt.Printf("use distances for %s\n", b)
1158 for i := range s.values {
1159 vi := &s.values[i]
1160 u := vi.uses
1161 if u == nil {
1162 continue
1163 }
1164 fmt.Printf(" v%d:", i)
1165 for u != nil {
1166 fmt.Printf(" %d", u.dist)
1167 u = u.next
1168 }
1169 fmt.Println()
1170 }
1171 }
1172
1173
1174
1175 nphi := 0
1176 for _, v := range b.Values {
1177 if v.Op != OpPhi {
1178 break
1179 }
1180 nphi++
1181 }
1182 phis = append(phis[:0], b.Values[:nphi]...)
1183 oldSched = append(oldSched[:0], b.Values[nphi:]...)
1184 b.Values = b.Values[:0]
1185
1186
1187 if b == f.Entry {
1188
1189 if nphi > 0 {
1190 f.Fatalf("phis in entry block")
1191 }
1192 } else if len(b.Preds) == 1 {
1193
1194 s.setState(s.endRegs[b.Preds[0].b.ID])
1195 if nphi > 0 {
1196 f.Fatalf("phis in single-predecessor block")
1197 }
1198
1199
1200
1201 for r := register(0); r < s.numRegs; r++ {
1202 v := s.regs[r].v
1203 if v != nil && !regValLiveSet.contains(v.ID) {
1204 s.freeReg(r)
1205 }
1206 }
1207 } else {
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221 idx := -1
1222 for i, p := range b.Preds {
1223
1224
1225 pb := p.b
1226 if s.blockOrder[pb.ID] >= s.blockOrder[b.ID] {
1227 continue
1228 }
1229 if idx == -1 {
1230 idx = i
1231 continue
1232 }
1233 pSel := b.Preds[idx].b
1234 if len(s.spillLive[pb.ID]) < len(s.spillLive[pSel.ID]) {
1235 idx = i
1236 } else if len(s.spillLive[pb.ID]) == len(s.spillLive[pSel.ID]) {
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247 if pb.likelyBranch() && !pSel.likelyBranch() || s.blockOrder[pb.ID] < s.blockOrder[pSel.ID] {
1248 idx = i
1249 }
1250 }
1251 }
1252 if idx < 0 {
1253 f.Fatalf("bad visitOrder, no predecessor of %s has been visited before it", b)
1254 }
1255 p := b.Preds[idx].b
1256 s.setState(s.endRegs[p.ID])
1257
1258 if s.f.pass.debug > regDebug {
1259 fmt.Printf("starting merge block %s with end state of %s:\n", b, p)
1260 for _, x := range s.endRegs[p.ID] {
1261 fmt.Printf(" %s: orig:%s cache:%s\n", &s.registers[x.r], x.v, x.c)
1262 }
1263 }
1264
1265
1266
1267
1268
1269 phiRegs = phiRegs[:0]
1270 var phiUsed regMask
1271
1272 for _, v := range phis {
1273 if !s.values[v.ID].needReg {
1274 phiRegs = append(phiRegs, noRegister)
1275 continue
1276 }
1277 a := v.Args[idx]
1278
1279
1280 m := s.values[a.ID].regs.minus(phiUsed).intersect(s.allocatable)
1281 if !m.empty() {
1282 r := s.pickReg(m)
1283 phiUsed = phiUsed.addReg(r)
1284 phiRegs = append(phiRegs, r)
1285 } else {
1286 phiRegs = append(phiRegs, noRegister)
1287 }
1288 }
1289
1290
1291 for i, v := range phis {
1292 if !s.values[v.ID].needReg {
1293 continue
1294 }
1295 a := v.Args[idx]
1296 r := phiRegs[i]
1297 if r == noRegister {
1298 continue
1299 }
1300 if regValLiveSet.contains(a.ID) {
1301
1302
1303
1304
1305
1306
1307
1308
1309 m := s.compatRegs(a.Type).minus(s.used).minus(phiUsed)
1310 if !m.empty() && !s.values[a.ID].rematerializeable && countRegs(s.values[a.ID].regs) == 1 {
1311 r2 := s.pickReg(m)
1312 c := p.NewValue1(a.Pos, OpCopy, a.Type, s.regs[r].c)
1313 s.copies[c] = false
1314 if s.f.pass.debug > regDebug {
1315 fmt.Printf("copy %s to %s : %s\n", a, c, &s.registers[r2])
1316 }
1317 s.setOrig(c, a)
1318 s.assignReg(r2, a, c)
1319 s.endRegs[p.ID] = append(s.endRegs[p.ID], endReg{r2, a, c})
1320 }
1321 }
1322 s.freeReg(r)
1323 }
1324
1325
1326 b.Values = append(b.Values, phis...)
1327
1328
1329
1330 for i, v := range phis {
1331 if !s.values[v.ID].needReg {
1332 continue
1333 }
1334 if phiRegs[i] != noRegister {
1335 continue
1336 }
1337 m := s.compatRegs(v.Type).minus(phiUsed).minus(s.used)
1338
1339
1340 for i, pe := range b.Preds {
1341 if i == idx {
1342 continue
1343 }
1344 ri := noRegister
1345 for _, er := range s.endRegs[pe.b.ID] {
1346 if er.v == s.orig[v.Args[i].ID] {
1347 ri = er.r
1348 break
1349 }
1350 }
1351 if ri != noRegister && m.hasReg(ri) {
1352 m = regMaskAt(ri)
1353 break
1354 }
1355 }
1356 if !m.empty() {
1357 r := s.pickReg(m)
1358 phiRegs[i] = r
1359 phiUsed = phiUsed.addReg(r)
1360 }
1361 }
1362
1363
1364 for i, v := range phis {
1365 if !s.values[v.ID].needReg {
1366 continue
1367 }
1368 r := phiRegs[i]
1369 if r == noRegister {
1370
1371
1372 s.values[v.ID].spill = v
1373 continue
1374 }
1375
1376 s.assignReg(r, v, v)
1377 }
1378
1379
1380 for r := register(0); r < s.numRegs; r++ {
1381 if phiUsed.hasReg(r) {
1382 continue
1383 }
1384 v := s.regs[r].v
1385 if v != nil && !regValLiveSet.contains(v.ID) {
1386 s.freeReg(r)
1387 }
1388 }
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402 doomDist := int32(math.MaxInt32)
1403 if l := s.loopnest.b2l[b.ID]; l != nil && l.header == b && l.containsUnavoidableCall {
1404
1405
1406 doomDist = unlikelyDistance
1407 if len(s.nextCall) > 0 {
1408 doomDist = min(doomDist, s.nextCall[0])
1409 }
1410 }
1411
1412
1413
1414
1415
1416 regList := make([]startReg, 0, 32)
1417 for r := register(0); r < s.numRegs; r++ {
1418 v := s.regs[r].v
1419 if v == nil {
1420 continue
1421 }
1422 if phiUsed.hasReg(r) {
1423
1424
1425 continue
1426 }
1427
1428 if s.values[v.ID].uses.dist >= doomDist && s.allocatable.hasReg(r) && !opcodeTable[v.Op].fixedReg {
1429 s.freeReg(r)
1430 continue
1431 }
1432 regList = append(regList, startReg{r, v, s.regs[r].c, s.values[v.ID].uses.pos})
1433 s.startRegsMask = s.startRegsMask.addReg(r)
1434 }
1435 s.startRegs[b.ID] = make([]startReg, len(regList))
1436 copy(s.startRegs[b.ID], regList)
1437
1438 if s.f.pass.debug > regDebug {
1439 fmt.Printf("after phis\n")
1440 for _, x := range s.startRegs[b.ID] {
1441 fmt.Printf(" %s: v%d\n", &s.registers[x.r], x.v.ID)
1442 }
1443 }
1444 }
1445
1446
1447 for i, v := range phis {
1448 s.curIdx = i
1449 s.dropIfUnused(v)
1450 }
1451
1452
1453 if l := len(oldSched); cap(dinfo) < l {
1454 dinfo = make([]dentry, l)
1455 } else {
1456 dinfo = dinfo[:l]
1457 clear(dinfo)
1458 }
1459
1460
1461 if s.desired != nil {
1462 desired.copy(&s.desired[b.ID])
1463 }
1464
1465
1466
1467
1468
1469
1470 for _, e := range b.Succs {
1471 succ := e.b
1472
1473 for _, x := range s.startRegs[succ.ID] {
1474 desired.add(x.v.ID, x.r)
1475 }
1476
1477 pidx := e.i
1478 for _, v := range succ.Values {
1479 if v.Op != OpPhi {
1480 break
1481 }
1482 if !s.values[v.ID].needReg {
1483 continue
1484 }
1485 rp, ok := s.f.getHome(v.ID).(*ssabase.Register)
1486 if !ok {
1487
1488
1489
1490
1491 for _, a := range v.Args {
1492 rp, ok = s.f.getHome(a.ID).(*ssabase.Register)
1493 if ok {
1494 break
1495 }
1496 }
1497 if !ok {
1498 continue
1499 }
1500 }
1501 desired.add(v.Args[pidx].ID, register(rp.Num))
1502 }
1503 }
1504
1505
1506 for i := len(oldSched) - 1; i >= 0; i-- {
1507 v := oldSched[i]
1508 prefs := desired.remove(v.ID)
1509 regspec := s.regspec(v)
1510 desired.clobber(regspec.clobbers)
1511 for _, j := range regspec.inputs {
1512 if countRegs(j.regs) != 1 {
1513 continue
1514 }
1515 desired.clobber(j.regs)
1516 desired.add(v.Args[j.idx].ID, s.pickReg(j.regs))
1517 }
1518 if opcodeTable[v.Op].resultInArg0 || v.Op == OpAMD64ADDQconst || v.Op == OpAMD64ADDLconst || v.Op == OpSelect0 {
1519 if opcodeTable[v.Op].commutative {
1520 desired.addList(v.Args[1].ID, prefs)
1521 }
1522 desired.addList(v.Args[0].ID, prefs)
1523 }
1524
1525 dinfo[i].out = prefs
1526 for j, a := range v.Args {
1527 if j >= len(dinfo[i].in) {
1528 break
1529 }
1530 dinfo[i].in[j] = desired.get(a.ID)
1531 }
1532 if v.Op == OpSelect1 && prefs[0] != noRegister {
1533
1534
1535 desiredSecondReg[v.Args[0].ID] = prefs
1536 }
1537 }
1538
1539
1540 for idx, v := range oldSched {
1541 s.curIdx = nphi + idx
1542 tmpReg := noRegister
1543 if s.f.pass.debug > regDebug {
1544 fmt.Printf(" processing %s\n", v.LongString())
1545 }
1546 regspec := s.regspec(v)
1547 if v.Op == OpPhi {
1548 f.Fatalf("phi %s not at start of block", v)
1549 }
1550 if opcodeTable[v.Op].fixedReg {
1551 switch v.Op {
1552 case OpSP:
1553 s.assignReg(s.SPReg, v, v)
1554 s.sp = v.ID
1555 case OpSB:
1556 s.assignReg(s.SBReg, v, v)
1557 s.sb = v.ID
1558 case OpARM64ZERO, OpLOONG64ZERO, OpMIPS64ZERO:
1559 s.assignReg(s.ZeroIntReg, v, v)
1560 case OpAMD64Zero128, OpAMD64Zero256, OpAMD64Zero512:
1561 regspec := s.regspec(v)
1562 m := regspec.outputs[0].regs
1563 if countRegs(m) != 1 {
1564 f.Fatalf("bad fixed-register op %s", v)
1565 }
1566 s.assignReg(s.pickReg(m), v, v)
1567 default:
1568 f.Fatalf("unknown fixed-register op %s", v)
1569 }
1570 b.Values = append(b.Values, v)
1571 s.advanceUses(v)
1572 continue
1573 }
1574 if v.Op == OpSelect0 || v.Op == OpSelect1 || v.Op == OpSelectN {
1575 if s.values[v.ID].needReg {
1576 if v.Op == OpSelectN {
1577 s.assignReg(register(s.f.getHome(v.Args[0].ID).(LocResults)[int(v.AuxInt)].(*ssabase.Register).Num), v, v)
1578 } else {
1579 var i = 0
1580 if v.Op == OpSelect1 {
1581 i = 1
1582 }
1583 s.assignReg(register(s.f.getHome(v.Args[0].ID).(LocPair)[i].(*ssabase.Register).Num), v, v)
1584 }
1585 }
1586 b.Values = append(b.Values, v)
1587 s.advanceUses(v)
1588 continue
1589 }
1590 if v.Op == OpGetG && s.f.Config.hasGReg {
1591
1592 if s.regs[s.GReg].v != nil {
1593 s.freeReg(s.GReg)
1594 }
1595 s.assignReg(s.GReg, v, v)
1596 b.Values = append(b.Values, v)
1597 s.advanceUses(v)
1598 continue
1599 }
1600 if v.Op == OpArg {
1601
1602
1603
1604 s.values[v.ID].spill = v
1605 b.Values = append(b.Values, v)
1606 s.advanceUses(v)
1607 continue
1608 }
1609 if v.Op == OpKeepAlive {
1610
1611 s.advanceUses(v)
1612 a := v.Args[0]
1613 vi := &s.values[a.ID]
1614 if vi.regs.empty() && !vi.rematerializeable {
1615
1616
1617
1618 v.SetArg(0, s.makeSpill(a, b))
1619 } else if _, ok := a.Aux.(*ir.Name); ok && vi.rematerializeable {
1620
1621
1622
1623 v.Op = OpVarLive
1624 v.SetArgs1(v.Args[1])
1625 v.Aux = a.Aux
1626 } else {
1627
1628
1629
1630 v.Op = OpCopy
1631 v.SetArgs1(v.Args[1])
1632 }
1633 b.Values = append(b.Values, v)
1634 continue
1635 }
1636 if len(regspec.inputs) == 0 && len(regspec.outputs) == 0 {
1637
1638 if s.doClobber && v.Op.IsCall() {
1639 s.clobberRegs(regspec.clobbers)
1640 }
1641 s.freeRegs(regspec.clobbers)
1642 b.Values = append(b.Values, v)
1643 s.advanceUses(v)
1644 continue
1645 }
1646
1647 if s.values[v.ID].rematerializeable {
1648
1649
1650
1651 for _, a := range v.Args {
1652 a.Uses--
1653 }
1654 s.advanceUses(v)
1655 continue
1656 }
1657
1658 if s.f.pass.debug > regDebug {
1659 fmt.Printf("value %s\n", v.LongString())
1660 fmt.Printf(" out:")
1661 for _, r := range dinfo[idx].out {
1662 if r != noRegister {
1663 fmt.Printf(" %s", &s.registers[r])
1664 }
1665 }
1666 fmt.Println()
1667 for i := 0; i < len(v.Args) && i < 3; i++ {
1668 fmt.Printf(" in%d:", i)
1669 for _, r := range dinfo[idx].in[i] {
1670 if r != noRegister {
1671 fmt.Printf(" %s", &s.registers[r])
1672 }
1673 }
1674 fmt.Println()
1675 }
1676 }
1677
1678
1679
1680
1681 args = append(args[:0], make([]*Value, len(v.Args))...)
1682 for i, a := range v.Args {
1683 if !s.values[a.ID].needReg {
1684 args[i] = a
1685 }
1686 }
1687 for _, i := range regspec.inputs {
1688 mask := i.regs
1689 if countRegs(mask) == 1 && !mask.intersect(s.values[v.Args[i.idx].ID].regs).empty() {
1690 args[i.idx] = s.allocValToReg(v.Args[i.idx], mask, true, v.Pos)
1691 }
1692 }
1693
1694
1695
1696
1697
1698
1699 for {
1700 freed := false
1701 for _, i := range regspec.inputs {
1702 if args[i.idx] != nil {
1703 continue
1704 }
1705 mask := i.regs
1706 if countRegs(mask) == 1 && !mask.minus(s.used).empty() {
1707 args[i.idx] = s.allocValToReg(v.Args[i.idx], mask, true, v.Pos)
1708
1709
1710
1711 oldregs := s.values[v.Args[i.idx].ID].regs
1712 if oldregs.minus(regspec.clobbers).empty() || !s.liveAfterCurrentInstruction(v.Args[i.idx]) {
1713 s.freeRegs(oldregs.minus(mask).minus(s.nospill))
1714 freed = true
1715 }
1716 }
1717 }
1718 if !freed {
1719 break
1720 }
1721 }
1722
1723
1724 for _, i := range regspec.inputs {
1725 if args[i.idx] != nil {
1726 continue
1727 }
1728 mask := i.regs
1729 if mask.intersect(s.values[v.Args[i.idx].ID].regs).empty() {
1730
1731 mask = mask.intersect(s.allocatable)
1732 mask = mask.minus(s.nospill)
1733
1734 if i.idx < 3 {
1735 for _, r := range dinfo[idx].in[i.idx] {
1736 if r != noRegister && mask.minus(s.used).hasReg(r) {
1737
1738 mask = regMaskAt(r)
1739 break
1740 }
1741 }
1742 }
1743
1744 if !mask.minus(desired.avoid).empty() {
1745 mask = mask.minus(desired.avoid)
1746 }
1747 }
1748 if mask.intersect(s.values[v.Args[i.idx].ID].regs).hasReg(s.SPReg) {
1749
1750
1751
1752 mask = regMaskAt(s.SPReg)
1753 }
1754 args[i.idx] = s.allocValToReg(v.Args[i.idx], mask, true, v.Pos)
1755 }
1756
1757
1758
1759
1760 if opcodeTable[v.Op].resultInArg0 {
1761 var m regMask
1762 if !s.liveAfterCurrentInstruction(v.Args[0]) {
1763
1764 goto ok
1765 }
1766 if opcodeTable[v.Op].commutative && !s.liveAfterCurrentInstruction(v.Args[1]) {
1767 args[0], args[1] = args[1], args[0]
1768 goto ok
1769 }
1770 if s.values[v.Args[0].ID].rematerializeable {
1771
1772 goto ok
1773 }
1774 if opcodeTable[v.Op].commutative && s.values[v.Args[1].ID].rematerializeable {
1775 args[0], args[1] = args[1], args[0]
1776 goto ok
1777 }
1778 if countRegs(s.values[v.Args[0].ID].regs) >= 2 {
1779
1780 goto ok
1781 }
1782 if opcodeTable[v.Op].commutative && countRegs(s.values[v.Args[1].ID].regs) >= 2 {
1783 args[0], args[1] = args[1], args[0]
1784 goto ok
1785 }
1786
1787
1788
1789
1790
1791 m = s.compatRegs(v.Args[0].Type).minus(s.used)
1792 if m.empty() {
1793
1794
1795
1796
1797 goto ok
1798 }
1799
1800
1801 for _, r := range dinfo[idx].out {
1802 if r != noRegister && m.intersect(regspec.outputs[0].regs).hasReg(r) {
1803 m = regMaskAt(r)
1804 args[0] = s.allocValToReg(v.Args[0], m, true, v.Pos)
1805
1806
1807 goto ok
1808 }
1809 }
1810
1811
1812 for _, r := range dinfo[idx].in[0] {
1813 if r != noRegister && m.hasReg(r) {
1814 m = regMaskAt(r)
1815 c := s.allocValToReg(v.Args[0], m, true, v.Pos)
1816 s.copies[c] = false
1817
1818
1819 goto ok
1820 }
1821 }
1822 if opcodeTable[v.Op].commutative {
1823 for _, r := range dinfo[idx].in[1] {
1824 if r != noRegister && m.hasReg(r) {
1825 m = regMaskAt(r)
1826 c := s.allocValToReg(v.Args[1], m, true, v.Pos)
1827 s.copies[c] = false
1828 args[0], args[1] = args[1], args[0]
1829 goto ok
1830 }
1831 }
1832 }
1833
1834
1835 if !m.minus(desired.avoid).empty() {
1836 m = m.minus(desired.avoid)
1837 }
1838
1839 c := s.allocValToReg(v.Args[0], m, true, v.Pos)
1840 s.copies[c] = false
1841
1842
1843
1844
1845 if regspec.outputs[0].regs.hasReg(register(s.f.getHome(c.ID).(*ssabase.Register).Num)) {
1846 if rp, ok := s.f.getHome(args[0].ID).(*ssabase.Register); ok {
1847 r := register(rp.Num)
1848 for _, r2 := range dinfo[idx].in[0] {
1849 if r == r2 {
1850 args[0] = c
1851 break
1852 }
1853 }
1854 }
1855 }
1856 }
1857 ok:
1858 for i := 0; i < 2; i++ {
1859 if !(i == 0 && regspec.clobbersArg0 || i == 1 && regspec.clobbersArg1) {
1860 continue
1861 }
1862 if !s.liveAfterCurrentInstruction(v.Args[i]) {
1863
1864 continue
1865 }
1866 if s.values[v.Args[i].ID].rematerializeable {
1867
1868 continue
1869 }
1870 if countRegs(s.values[v.Args[i].ID].regs) >= 2 {
1871
1872 continue
1873 }
1874
1875 m := s.compatRegs(v.Args[i].Type).minus(s.used)
1876 if m.empty() {
1877
1878
1879
1880
1881 continue
1882 }
1883
1884 c := s.allocValToReg(v.Args[i], m, true, v.Pos)
1885 s.copies[c] = false
1886 }
1887
1888
1889
1890
1891
1892
1893
1894 if opcodeTable[v.Op].needIntTemp {
1895 m := s.allocatable.intersect(s.f.Config.gpRegMask)
1896 for _, out := range regspec.outputs {
1897 if countRegs(out.regs) == 1 {
1898 m = m.minus(out.regs)
1899 }
1900 }
1901 if !m.minus(desired.avoid).minus(s.nospill).empty() {
1902 m = m.minus(desired.avoid)
1903 }
1904 tmpReg = s.allocReg(m, &tmpVal)
1905 s.nospill = s.nospill.addReg(tmpReg)
1906 s.tmpused = s.tmpused.addReg(tmpReg)
1907 }
1908
1909 if regspec.clobbersArg0 {
1910 s.freeReg(register(s.f.getHome(args[0].ID).(*ssabase.Register).Num))
1911 }
1912 if regspec.clobbersArg1 && !(regspec.clobbersArg0 && s.f.getHome(args[0].ID) == s.f.getHome(args[1].ID)) {
1913 s.freeReg(register(s.f.getHome(args[1].ID).(*ssabase.Register).Num))
1914 }
1915
1916
1917
1918
1919
1920 if !opcodeTable[v.Op].resultNotInArgs {
1921 s.tmpused = s.nospill
1922 s.nospill = regMask{}
1923 s.advanceUses(v)
1924 }
1925
1926
1927 if s.doClobber && v.Op.IsCall() {
1928
1929
1930 s.clobberRegs(regspec.clobbers.minus(s.tmpused).minus(s.nospill))
1931 }
1932 s.freeRegs(regspec.clobbers)
1933 s.tmpused = s.tmpused.union(regspec.clobbers)
1934
1935
1936 {
1937 outRegs := noRegisters
1938 maxOutIdx := -1
1939 var used regMask
1940 if tmpReg != noRegister {
1941
1942
1943 used = used.addReg(tmpReg)
1944 }
1945 for _, out := range regspec.outputs {
1946 if out.regs.empty() {
1947 continue
1948 }
1949 mask := out.regs.intersect(s.allocatable).minus(used)
1950 if mask.empty() {
1951 s.f.Fatalf("can't find any output register %s", v.LongString())
1952 }
1953 if opcodeTable[v.Op].resultInArg0 && out.idx == 0 {
1954 if !opcodeTable[v.Op].commutative {
1955
1956 r := register(s.f.getHome(args[0].ID).(*ssabase.Register).Num)
1957 if !mask.hasReg(r) {
1958 s.f.Fatalf("resultInArg0 value's input %v cannot be an output of %s", s.f.getHome(args[0].ID).(*ssabase.Register), v.LongString())
1959 }
1960 mask = regMaskAt(r)
1961 } else {
1962
1963 r0 := register(s.f.getHome(args[0].ID).(*ssabase.Register).Num)
1964 r1 := register(s.f.getHome(args[1].ID).(*ssabase.Register).Num)
1965
1966 found := false
1967 for _, r := range dinfo[idx].out {
1968 if (r == r0 || r == r1) && mask.minus(s.used).hasReg(r) {
1969 mask = regMaskAt(r)
1970 found = true
1971 if r == r1 {
1972 args[0], args[1] = args[1], args[0]
1973 }
1974 break
1975 }
1976 }
1977 if !found {
1978
1979 mask = regMaskAt(r0)
1980 }
1981 }
1982 }
1983 if out.idx == 0 {
1984 for _, r := range dinfo[idx].out {
1985 if r != noRegister && mask.minus(s.used).hasReg(r) {
1986
1987 mask = regMaskAt(r)
1988 break
1989 }
1990 }
1991 }
1992 if out.idx == 1 {
1993 if prefs, ok := desiredSecondReg[v.ID]; ok {
1994 for _, r := range prefs {
1995 if r != noRegister && mask.minus(s.used).hasReg(r) {
1996
1997 mask = regMaskAt(r)
1998 break
1999 }
2000 }
2001 }
2002 }
2003
2004 if !mask.minus(desired.avoid).minus(s.nospill).minus(s.used).empty() {
2005 mask = mask.minus(desired.avoid)
2006 }
2007 r := s.allocReg(mask, v)
2008 if out.idx > maxOutIdx {
2009 maxOutIdx = out.idx
2010 }
2011 outRegs[out.idx] = r
2012 used = used.addReg(r)
2013 s.tmpused = s.tmpused.addReg(r)
2014 }
2015
2016 if v.Type.IsTuple() {
2017 var outLocs LocPair
2018 if r := outRegs[0]; r != noRegister {
2019 outLocs[0] = &s.registers[r]
2020 }
2021 if r := outRegs[1]; r != noRegister {
2022 outLocs[1] = &s.registers[r]
2023 }
2024 s.f.setHome(v, outLocs)
2025
2026 } else if v.Type.IsResults() {
2027
2028 outLocs := make(LocResults, maxOutIdx+1, maxOutIdx+1)
2029 for i := 0; i <= maxOutIdx; i++ {
2030 if r := outRegs[i]; r != noRegister {
2031 outLocs[i] = &s.registers[r]
2032 }
2033 }
2034 s.f.setHome(v, outLocs)
2035 } else {
2036 if r := outRegs[0]; r != noRegister {
2037 s.assignReg(r, v, v)
2038 }
2039 }
2040 if tmpReg != noRegister {
2041
2042 if s.f.tempRegs == nil {
2043 s.f.tempRegs = map[ID]*ssabase.Register{}
2044 }
2045 s.f.tempRegs[v.ID] = &s.registers[tmpReg]
2046 }
2047 }
2048
2049
2050 if opcodeTable[v.Op].resultNotInArgs {
2051 s.nospill = regMask{}
2052 s.advanceUses(v)
2053 }
2054 s.tmpused = regMask{}
2055
2056
2057 for i, a := range args {
2058 v.SetArg(i, a)
2059 }
2060 b.Values = append(b.Values, v)
2061 s.dropIfUnused(v)
2062 }
2063
2064
2065
2066 controls := append(make([]*Value, 0, 2), b.ControlValues()...)
2067
2068
2069 for i, v := range b.ControlValues() {
2070 if !s.values[v.ID].needReg {
2071 continue
2072 }
2073 if s.f.pass.debug > regDebug {
2074 fmt.Printf(" processing control %s\n", v.LongString())
2075 }
2076
2077
2078
2079 b.ReplaceControl(i, s.allocValToReg(v, s.compatRegs(v.Type), false, b.Pos))
2080 }
2081
2082
2083
2084 for _, v := range controls {
2085 vi := &s.values[v.ID]
2086 if !vi.needReg {
2087 continue
2088 }
2089
2090 u := vi.uses
2091 vi.uses = u.next
2092 if u.next == nil {
2093 s.freeRegs(vi.regs)
2094 }
2095 u.next = s.freeUseRecords
2096 s.freeUseRecords = u
2097 }
2098
2099
2100
2101
2102 if len(b.Succs) == 1 {
2103 if s.f.Config.hasGReg && s.regs[s.GReg].v != nil {
2104 s.freeReg(s.GReg)
2105 }
2106 if s.blockOrder[b.ID] > s.blockOrder[b.Succs[0].b.ID] {
2107
2108 goto badloop
2109 }
2110
2111 top := b.Succs[0].b
2112 loop := s.loopnest.b2l[top.ID]
2113 if loop == nil || loop.header != top || loop.containsUnavoidableCall {
2114 goto badloop
2115 }
2116
2117
2118 phiArgs := regValLiveSet
2119 phiArgs.clear()
2120 for _, v := range b.Succs[0].b.Values {
2121 if v.Op == OpPhi {
2122 phiArgs.add(v.Args[b.Succs[0].i].ID)
2123 }
2124 }
2125
2126
2127
2128
2129 var likelyUsedRegs regMask
2130 for _, live := range s.live[b.ID] {
2131 if live.dist < unlikelyDistance {
2132 likelyUsedRegs = likelyUsedRegs.union(s.values[live.ID].regs)
2133 }
2134 }
2135
2136
2137
2138 for _, live := range s.live[b.ID] {
2139 if live.dist >= unlikelyDistance {
2140
2141 continue
2142 }
2143 vid := live.ID
2144 vi := &s.values[vid]
2145 v := s.orig[vid]
2146 if phiArgs.contains(vid) {
2147
2148
2149
2150
2151 if !vi.regs.intersect(s.compatRegs(v.Type)).empty() {
2152 continue
2153 }
2154 } else {
2155 if !vi.regs.empty() {
2156 continue
2157 }
2158 if vi.rematerializeable {
2159
2160
2161
2162
2163
2164
2165
2166 continue
2167 }
2168 }
2169 if vi.rematerializeable && s.f.Config.ctxt.Arch.Arch == sys.ArchWasm {
2170 continue
2171 }
2172
2173
2174 m := s.compatRegs(v.Type).minus(likelyUsedRegs)
2175 if m.empty() {
2176
2177 continue
2178 }
2179
2180
2181 outerloop:
2182 for _, e := range desired.entries {
2183 if e.ID != v.ID {
2184 continue
2185 }
2186 for _, r := range e.regs {
2187 if r != noRegister && m.hasReg(r) {
2188 m = regMaskAt(r)
2189 break outerloop
2190 }
2191 }
2192 }
2193 if !m.minus(desired.avoid).empty() {
2194 m = m.minus(desired.avoid)
2195 }
2196 s.allocValToReg(v, m, false, b.Pos)
2197 likelyUsedRegs = likelyUsedRegs.union(s.values[v.ID].regs)
2198 }
2199 }
2200 badloop:
2201 ;
2202
2203
2204
2205 k := 0
2206 for r := register(0); r < s.numRegs; r++ {
2207 v := s.regs[r].v
2208 if v == nil {
2209 continue
2210 }
2211 k++
2212 }
2213 regList := make([]endReg, 0, k)
2214 for r := register(0); r < s.numRegs; r++ {
2215 v := s.regs[r].v
2216 if v == nil {
2217 continue
2218 }
2219 regList = append(regList, endReg{r, v, s.regs[r].c})
2220 }
2221 s.endRegs[b.ID] = regList
2222
2223 if checkEnabled {
2224 regValLiveSet.clear()
2225 if s.live != nil {
2226 for _, x := range s.live[b.ID] {
2227 regValLiveSet.add(x.ID)
2228 }
2229 }
2230 for r := register(0); r < s.numRegs; r++ {
2231 v := s.regs[r].v
2232 if v == nil {
2233 continue
2234 }
2235 if !regValLiveSet.contains(v.ID) {
2236 s.f.Fatalf("val %s is in reg but not live at end of %s", v, b)
2237 }
2238 }
2239 }
2240
2241
2242
2243
2244
2245 if s.live != nil {
2246 for _, e := range s.live[b.ID] {
2247 vi := &s.values[e.ID]
2248 if !vi.regs.empty() {
2249
2250 continue
2251 }
2252 if vi.rematerializeable {
2253
2254 continue
2255 }
2256 if s.f.pass.debug > regDebug {
2257 fmt.Printf("live-at-end spill for %s at %s\n", s.orig[e.ID], b)
2258 }
2259 spill := s.makeSpill(s.orig[e.ID], b)
2260 s.spillLive[b.ID] = append(s.spillLive[b.ID], spill.ID)
2261 }
2262
2263
2264
2265
2266 for _, e := range s.live[b.ID] {
2267 u := s.values[e.ID].uses
2268 if u == nil {
2269 f.Fatalf("live at end, no uses v%d", e.ID)
2270 }
2271 if u.next != nil {
2272 f.Fatalf("live at end, too many uses v%d", e.ID)
2273 }
2274 s.values[e.ID].uses = nil
2275 u.next = s.freeUseRecords
2276 s.freeUseRecords = u
2277 }
2278 }
2279
2280
2281
2282
2283
2284
2285
2286 if c := countRegs(s.startRegsMask); c != len(s.startRegs[b.ID]) {
2287 regs := make([]startReg, 0, c)
2288 for _, sr := range s.startRegs[b.ID] {
2289 if !s.startRegsMask.hasReg(sr.r) {
2290 continue
2291 }
2292 regs = append(regs, sr)
2293 }
2294 s.startRegs[b.ID] = regs
2295 }
2296 }
2297
2298
2299 s.placeSpills()
2300
2301
2302
2303 stacklive := stackalloc(s.f, s.spillLive)
2304
2305
2306 s.shuffle(stacklive)
2307
2308
2309
2310
2311 for {
2312 progress := false
2313 for c, used := range s.copies {
2314 if !used && c.Uses == 0 {
2315 if s.f.pass.debug > regDebug {
2316 fmt.Printf("delete copied value %s\n", c.LongString())
2317 }
2318 c.resetArgs()
2319 f.freeValue(c)
2320 delete(s.copies, c)
2321 progress = true
2322 }
2323 }
2324 if !progress {
2325 break
2326 }
2327 }
2328
2329 for _, b := range s.visitOrder {
2330 i := 0
2331 for _, v := range b.Values {
2332 if v.Op == OpInvalid {
2333 continue
2334 }
2335 b.Values[i] = v
2336 i++
2337 }
2338 b.Values = b.Values[:i]
2339 }
2340 }
2341
2342 func (s *regAllocState) placeSpills() {
2343 mustBeFirst := func(op Op) bool {
2344 return op.isLoweredGetClosurePtr() || op == OpPhi || op == OpArgIntReg || op == OpArgFloatReg
2345 }
2346
2347
2348
2349 start := map[ID][]*Value{}
2350
2351
2352 after := map[ID][]*Value{}
2353
2354 for i := range s.values {
2355 vi := s.values[i]
2356 spill := vi.spill
2357 if spill == nil {
2358 continue
2359 }
2360 if spill.Block != nil {
2361
2362
2363 continue
2364 }
2365 v := s.orig[i]
2366
2367
2368
2369
2370
2371 if v == nil {
2372 panic(fmt.Errorf("nil v, s.orig[%d], vi = %v, spill = %s", i, vi, spill.LongString()))
2373 }
2374 best := v.Block
2375 bestArg := v
2376 var bestDepth int16
2377 if s.loopnest != nil && s.loopnest.b2l[best.ID] != nil {
2378 bestDepth = s.loopnest.b2l[best.ID].depth
2379 }
2380 b := best
2381 const maxSpillSearch = 100
2382 for i := 0; i < maxSpillSearch; i++ {
2383
2384
2385 p := b
2386 b = nil
2387 for c := s.sdom.Child(p); c != nil && i < maxSpillSearch; c, i = s.sdom.Sibling(c), i+1 {
2388 if s.sdom[c.ID].entry <= vi.restoreMin && s.sdom[c.ID].exit >= vi.restoreMax {
2389
2390 b = c
2391 break
2392 }
2393 }
2394 if b == nil {
2395
2396 break
2397 }
2398
2399 var depth int16
2400 if s.loopnest != nil && s.loopnest.b2l[b.ID] != nil {
2401 depth = s.loopnest.b2l[b.ID].depth
2402 }
2403 if depth > bestDepth {
2404
2405 continue
2406 }
2407
2408
2409
2410 if len(b.Preds) == 1 {
2411 for _, e := range s.endRegs[b.Preds[0].b.ID] {
2412 if e.v == v {
2413
2414 best = b
2415 bestArg = e.c
2416 bestDepth = depth
2417 break
2418 }
2419 }
2420 } else {
2421 for _, e := range s.startRegs[b.ID] {
2422 if e.v == v {
2423
2424 best = b
2425 bestArg = e.c
2426 bestDepth = depth
2427 break
2428 }
2429 }
2430 }
2431 }
2432
2433
2434 spill.Block = best
2435 spill.AddArg(bestArg)
2436 if best == v.Block && !mustBeFirst(v.Op) {
2437
2438 after[v.ID] = append(after[v.ID], spill)
2439 } else {
2440
2441 start[best.ID] = append(start[best.ID], spill)
2442 }
2443 }
2444
2445
2446 var oldSched []*Value
2447 for _, b := range s.visitOrder {
2448 nfirst := 0
2449 for _, v := range b.Values {
2450 if !mustBeFirst(v.Op) {
2451 break
2452 }
2453 nfirst++
2454 }
2455 oldSched = append(oldSched[:0], b.Values[nfirst:]...)
2456 b.Values = b.Values[:nfirst]
2457 b.Values = append(b.Values, start[b.ID]...)
2458 for _, v := range oldSched {
2459 b.Values = append(b.Values, v)
2460 b.Values = append(b.Values, after[v.ID]...)
2461 }
2462 }
2463 }
2464
2465
2466 func (s *regAllocState) shuffle(stacklive [][]ID) {
2467 var e edgeState
2468 e.s = s
2469 e.cache = map[ID][]*Value{}
2470 e.contents = map[Location]contentRecord{}
2471 if s.f.pass.debug > regDebug {
2472 fmt.Printf("shuffle %s\n", s.f.Name)
2473 fmt.Println(s.f.String())
2474 }
2475
2476 for _, b := range s.visitOrder {
2477 if len(b.Preds) <= 1 {
2478 continue
2479 }
2480 e.b = b
2481 for i, edge := range b.Preds {
2482 p := edge.b
2483 e.p = p
2484 e.setup(i, s.endRegs[p.ID], s.startRegs[b.ID], stacklive[p.ID])
2485 e.process()
2486 }
2487 }
2488
2489 if s.f.pass.debug > regDebug {
2490 fmt.Printf("post shuffle %s\n", s.f.Name)
2491 fmt.Println(s.f.String())
2492 }
2493 }
2494
2495 type edgeState struct {
2496 s *regAllocState
2497 p, b *Block
2498
2499
2500 cache map[ID][]*Value
2501 cachedVals []ID
2502
2503
2504 contents map[Location]contentRecord
2505
2506
2507 destinations []dstRecord
2508 extra []dstRecord
2509
2510 usedRegs regMask
2511 uniqueRegs regMask
2512 finalRegs regMask
2513 rematerializeableRegs regMask
2514 }
2515
2516 type contentRecord struct {
2517 vid ID
2518 c *Value
2519 final bool
2520 pos src.XPos
2521 }
2522
2523 type dstRecord struct {
2524 loc Location
2525 vid ID
2526 splice **Value
2527 pos src.XPos
2528 }
2529
2530
2531 func (e *edgeState) setup(idx int, srcReg []endReg, dstReg []startReg, stacklive []ID) {
2532 if e.s.f.pass.debug > regDebug {
2533 fmt.Printf("edge %s->%s\n", e.p, e.b)
2534 }
2535
2536
2537 clear(e.cache)
2538 e.cachedVals = e.cachedVals[:0]
2539 clear(e.contents)
2540 e.usedRegs = regMask{}
2541 e.uniqueRegs = regMask{}
2542 e.finalRegs = regMask{}
2543 e.rematerializeableRegs = regMask{}
2544
2545
2546 for _, x := range srcReg {
2547 e.set(&e.s.registers[x.r], x.v.ID, x.c, false, src.NoXPos)
2548 }
2549
2550 for _, spillID := range stacklive {
2551 v := e.s.orig[spillID]
2552 spill := e.s.values[v.ID].spill
2553 if !e.s.sdom.IsAncestorEq(spill.Block, e.p) {
2554
2555
2556
2557
2558
2559
2560
2561
2562 continue
2563 }
2564 e.set(e.s.f.getHome(spillID), v.ID, spill, false, src.NoXPos)
2565 }
2566
2567
2568 dsts := e.destinations[:0]
2569 for _, x := range dstReg {
2570 dsts = append(dsts, dstRecord{&e.s.registers[x.r], x.v.ID, nil, x.pos})
2571 }
2572
2573 for _, v := range e.b.Values {
2574 if v.Op != OpPhi {
2575 break
2576 }
2577 loc := e.s.f.getHome(v.ID)
2578 if loc == nil {
2579 continue
2580 }
2581 dsts = append(dsts, dstRecord{loc, v.Args[idx].ID, &v.Args[idx], v.Pos})
2582 }
2583 e.destinations = dsts
2584
2585 if e.s.f.pass.debug > regDebug {
2586 for _, vid := range e.cachedVals {
2587 a := e.cache[vid]
2588 for _, c := range a {
2589 fmt.Printf("src %s: v%d cache=%s\n", e.s.f.getHome(c.ID), vid, c)
2590 }
2591 }
2592 for _, d := range e.destinations {
2593 fmt.Printf("dst %s: v%d\n", d.loc, d.vid)
2594 }
2595 }
2596 }
2597
2598
2599 func (e *edgeState) process() {
2600 dsts := e.destinations
2601
2602
2603 for len(dsts) > 0 {
2604 i := 0
2605 for _, d := range dsts {
2606 if !e.processDest(d.loc, d.vid, d.splice, d.pos) {
2607
2608 dsts[i] = d
2609 i++
2610 }
2611 }
2612 if i < len(dsts) {
2613
2614 dsts = dsts[:i]
2615
2616
2617 dsts = append(dsts, e.extra...)
2618 e.extra = e.extra[:0]
2619 continue
2620 }
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644 d := dsts[0]
2645 loc := d.loc
2646 vid := e.contents[loc].vid
2647 c := e.contents[loc].c
2648 r := e.findRegFor(c.Type)
2649 if e.s.f.pass.debug > regDebug {
2650 fmt.Printf("breaking cycle with v%d in %s:%s\n", vid, loc, c)
2651 }
2652 e.erase(r)
2653 pos := d.pos.WithNotStmt()
2654 if _, isReg := loc.(*ssabase.Register); isReg {
2655 c = e.p.NewValue1(pos, OpCopy, c.Type, c)
2656 } else {
2657 c = e.p.NewValue1(pos, OpLoadReg, c.Type, c)
2658 }
2659 e.set(r, vid, c, false, pos)
2660 if c.Op == OpLoadReg && e.s.isGReg(register(r.(*ssabase.Register).Num)) {
2661 e.s.f.Fatalf("process.OpLoadReg targeting g: " + c.LongString())
2662 }
2663 }
2664 }
2665
2666
2667
2668 func (e *edgeState) processDest(loc Location, vid ID, splice **Value, pos src.XPos) bool {
2669 pos = pos.WithNotStmt()
2670 occupant := e.contents[loc]
2671 if occupant.vid == vid {
2672
2673 e.contents[loc] = contentRecord{vid, occupant.c, true, pos}
2674 if splice != nil {
2675 (*splice).Uses--
2676 *splice = occupant.c
2677 occupant.c.Uses++
2678 }
2679
2680
2681
2682 if _, ok := e.s.copies[occupant.c]; ok {
2683
2684 e.s.copies[occupant.c] = true
2685 }
2686 return true
2687 }
2688
2689
2690 if len(e.cache[occupant.vid]) == 1 && !e.s.values[occupant.vid].rematerializeable && !opcodeTable[e.s.orig[occupant.vid].Op].fixedReg {
2691
2692
2693 return false
2694 }
2695
2696
2697 v := e.s.orig[vid]
2698 var c *Value
2699 var src Location
2700 if e.s.f.pass.debug > regDebug {
2701 fmt.Printf("moving v%d to %s\n", vid, loc)
2702 fmt.Printf("sources of v%d:", vid)
2703 }
2704 if opcodeTable[v.Op].fixedReg {
2705 c = v
2706 src = e.s.f.getHome(v.ID)
2707 } else {
2708 for _, w := range e.cache[vid] {
2709 h := e.s.f.getHome(w.ID)
2710 if e.s.f.pass.debug > regDebug {
2711 fmt.Printf(" %s:%s", h, w)
2712 }
2713 _, isreg := h.(*ssabase.Register)
2714 if src == nil || isreg {
2715 c = w
2716 src = h
2717 }
2718 }
2719 }
2720 if e.s.f.pass.debug > regDebug {
2721 if src != nil {
2722 fmt.Printf(" [use %s]\n", src)
2723 } else {
2724 fmt.Printf(" [no source]\n")
2725 }
2726 }
2727 _, dstReg := loc.(*ssabase.Register)
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739 e.erase(loc)
2740 var x *Value
2741 if c == nil || e.s.values[vid].rematerializeable {
2742 if !e.s.values[vid].rematerializeable {
2743 e.s.f.Fatalf("can't find source for %s->%s: %s\n", e.p, e.b, v.LongString())
2744 }
2745 if dstReg {
2746
2747
2748
2749
2750 if !e.s.regspec(v).outputs[0].regs.hasReg(register(loc.(*ssabase.Register).Num)) {
2751 _, srcReg := src.(*ssabase.Register)
2752 if srcReg {
2753
2754
2755 x = e.p.NewValue1(pos, OpCopy, c.Type, c)
2756 } else {
2757
2758 x = v.copyInto(e.p)
2759 r := e.findRegFor(x.Type)
2760 e.erase(r)
2761
2762 e.set(r, vid, x, false, pos)
2763
2764 x = e.p.NewValue1(pos, OpCopy, x.Type, x)
2765 }
2766 } else {
2767 x = v.copyInto(e.p)
2768 }
2769 } else {
2770
2771
2772 r := e.findRegFor(v.Type)
2773 e.erase(r)
2774 x = v.copyIntoWithXPos(e.p, pos)
2775 e.set(r, vid, x, false, pos)
2776
2777
2778
2779 x = e.p.NewValue1(pos, OpStoreReg, loc.(LocalSlot).Type, x)
2780 }
2781 } else {
2782
2783 _, srcReg := src.(*ssabase.Register)
2784 if srcReg {
2785 if dstReg {
2786 x = e.p.NewValue1(pos, OpCopy, c.Type, c)
2787 } else {
2788 x = e.p.NewValue1(pos, OpStoreReg, loc.(LocalSlot).Type, c)
2789 }
2790 } else {
2791 if dstReg {
2792 x = e.p.NewValue1(pos, OpLoadReg, c.Type, c)
2793 } else {
2794
2795 r := e.findRegFor(c.Type)
2796 e.erase(r)
2797 t := e.p.NewValue1(pos, OpLoadReg, c.Type, c)
2798 e.set(r, vid, t, false, pos)
2799 x = e.p.NewValue1(pos, OpStoreReg, loc.(LocalSlot).Type, t)
2800 }
2801 }
2802 }
2803 e.set(loc, vid, x, true, pos)
2804 if x.Op == OpLoadReg && e.s.isGReg(register(loc.(*ssabase.Register).Num)) {
2805 e.s.f.Fatalf("processDest.OpLoadReg targeting g: " + x.LongString())
2806 }
2807 if splice != nil {
2808 (*splice).Uses--
2809 *splice = x
2810 x.Uses++
2811 }
2812 return true
2813 }
2814
2815
2816 func (e *edgeState) set(loc Location, vid ID, c *Value, final bool, pos src.XPos) {
2817 e.s.f.setHome(c, loc)
2818 e.contents[loc] = contentRecord{vid, c, final, pos}
2819 a := e.cache[vid]
2820 if len(a) == 0 {
2821 e.cachedVals = append(e.cachedVals, vid)
2822 }
2823 a = append(a, c)
2824 e.cache[vid] = a
2825 if r, ok := loc.(*ssabase.Register); ok {
2826 if e.usedRegs.hasReg(register(r.Num)) {
2827 e.s.f.Fatalf("%v is already set (v%d/%v)", r, vid, c)
2828 }
2829 e.usedRegs = e.usedRegs.addReg(register(r.Num))
2830 if final {
2831 e.finalRegs = e.finalRegs.addReg(register(r.Num))
2832 }
2833 if len(a) == 1 {
2834 e.uniqueRegs = e.uniqueRegs.addReg(register(r.Num))
2835 }
2836 if len(a) == 2 {
2837 if t, ok := e.s.f.getHome(a[0].ID).(*ssabase.Register); ok {
2838 e.uniqueRegs = e.uniqueRegs.removeReg(register(t.Num))
2839 }
2840 }
2841 if e.s.values[vid].rematerializeable {
2842 e.rematerializeableRegs = e.rematerializeableRegs.addReg(register(r.Num))
2843 }
2844 }
2845 if e.s.f.pass.debug > regDebug {
2846 fmt.Printf("%s\n", c.LongString())
2847 fmt.Printf("v%d now available in %s:%s\n", vid, loc, c)
2848 }
2849 }
2850
2851
2852 func (e *edgeState) erase(loc Location) {
2853 cr := e.contents[loc]
2854 if cr.c == nil {
2855 return
2856 }
2857 vid := cr.vid
2858
2859 if cr.final {
2860
2861
2862
2863 e.extra = append(e.extra, dstRecord{loc, cr.vid, nil, cr.pos})
2864 }
2865
2866
2867 a := e.cache[vid]
2868 for i, c := range a {
2869 if e.s.f.getHome(c.ID) == loc {
2870 if e.s.f.pass.debug > regDebug {
2871 fmt.Printf("v%d no longer available in %s:%s\n", vid, loc, c)
2872 }
2873 a[i], a = a[len(a)-1], a[:len(a)-1]
2874 break
2875 }
2876 }
2877 e.cache[vid] = a
2878
2879
2880 if r, ok := loc.(*ssabase.Register); ok {
2881 e.usedRegs = e.usedRegs.removeReg(register(r.Num))
2882 if cr.final {
2883 e.finalRegs = e.finalRegs.removeReg(register(r.Num))
2884 }
2885 e.rematerializeableRegs = e.rematerializeableRegs.removeReg(register(r.Num))
2886 }
2887 if len(a) == 1 {
2888 if r, ok := e.s.f.getHome(a[0].ID).(*ssabase.Register); ok {
2889 e.uniqueRegs = e.uniqueRegs.addReg(register(r.Num))
2890 }
2891 }
2892 }
2893
2894
2895 func (e *edgeState) findRegFor(typ *types.Type) Location {
2896
2897 m := e.s.compatRegs(typ)
2898
2899
2900
2901
2902
2903
2904 x := m.minus(e.usedRegs)
2905 if !x.empty() {
2906 return &e.s.registers[e.s.pickReg(x)]
2907 }
2908 x = m.minus(e.uniqueRegs).minus(e.finalRegs)
2909 if !x.empty() {
2910 return &e.s.registers[e.s.pickReg(x)]
2911 }
2912 x = m.minus(e.uniqueRegs)
2913 if !x.empty() {
2914 return &e.s.registers[e.s.pickReg(x)]
2915 }
2916 x = m.intersect(e.rematerializeableRegs)
2917 if !x.empty() {
2918 return &e.s.registers[e.s.pickReg(x)]
2919 }
2920
2921
2922
2923 for _, vid := range e.cachedVals {
2924 a := e.cache[vid]
2925 for _, c := range a {
2926 if r, ok := e.s.f.getHome(c.ID).(*ssabase.Register); ok && m.hasReg(register(r.Num)) {
2927 if !c.rematerializeable() {
2928 x := e.p.NewValue1(c.Pos, OpStoreReg, c.Type, c)
2929
2930 t := LocalSlot{N: e.s.f.NewLocal(c.Pos, c.Type), Type: c.Type}
2931
2932 e.set(t, vid, x, false, c.Pos)
2933 if e.s.f.pass.debug > regDebug {
2934 fmt.Printf(" SPILL %s->%s %s\n", r, t, x.LongString())
2935 }
2936 }
2937
2938
2939
2940 return r
2941 }
2942 }
2943 }
2944
2945 fmt.Printf("m:%d unique:%d final:%d rematerializable:%d\n", m, e.uniqueRegs, e.finalRegs, e.rematerializeableRegs)
2946 for _, vid := range e.cachedVals {
2947 a := e.cache[vid]
2948 for _, c := range a {
2949 fmt.Printf("v%d: %s %s\n", vid, c, e.s.f.getHome(c.ID))
2950 }
2951 }
2952 e.s.f.Fatalf("can't find empty register on edge %s->%s", e.p, e.b)
2953 return nil
2954 }
2955
2956
2957
2958 func (v *Value) rematerializeable() bool {
2959 if !opcodeTable[v.Op].rematerializeable {
2960 return false
2961 }
2962 for _, a := range v.Args {
2963
2964
2965 if !opcodeTable[a.Op].fixedReg {
2966 return false
2967 }
2968 }
2969 return true
2970 }
2971
2972 type liveInfo struct {
2973 ID ID
2974 dist int32
2975 pos src.XPos
2976 }
2977
2978
2979
2980
2981 func (s *regAllocState) computeLive() {
2982 f := s.f
2983
2984
2985 if len(f.Blocks) == 1 {
2986 return
2987 }
2988 po := f.postorder()
2989 s.live = make([][]liveInfo, f.NumBlocks())
2990 s.desired = make([]desiredState, f.NumBlocks())
2991 s.loopnest = f.loopnest()
2992
2993 rematIDs := make([]ID, 0, 64)
2994
2995 live := f.newSparseMapPos(f.NumValues())
2996 defer f.retSparseMapPos(live)
2997 t := f.newSparseMapPos(f.NumValues())
2998 defer f.retSparseMapPos(t)
2999
3000 s.loopnest.computeUnavoidableCalls()
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016 var loopLiveIn map[*loop][]liveInfo
3017 var numCalls []int32
3018 if len(s.loopnest.loops) > 0 && !s.loopnest.hasIrreducible {
3019 loopLiveIn = make(map[*loop][]liveInfo)
3020 numCalls = f.Cache.allocInt32Slice(f.NumBlocks())
3021 defer f.Cache.freeInt32Slice(numCalls)
3022 }
3023
3024 for {
3025 changed := false
3026
3027 for _, b := range po {
3028
3029 live.clear()
3030 for _, e := range s.live[b.ID] {
3031 live.set(e.ID, e.dist, e.pos)
3032 }
3033 update := false
3034
3035 for _, e := range b.Succs {
3036 succ := e.b
3037 delta := branchDistance(b, succ)
3038 for _, v := range succ.Values {
3039 if v.Op != OpPhi {
3040 break
3041 }
3042 arg := v.Args[e.i]
3043 if s.values[arg.ID].needReg && (!live.contains(arg.ID) || delta < live.get(arg.ID)) {
3044 live.set(arg.ID, delta, v.Pos)
3045 update = true
3046 }
3047 }
3048 }
3049 if update {
3050 s.live[b.ID] = updateLive(live, s.live[b.ID])
3051 }
3052
3053
3054 c := live.contents()
3055 for i := range c {
3056 c[i].val += int32(len(b.Values))
3057 }
3058
3059
3060 for _, c := range b.ControlValues() {
3061 if s.values[c.ID].needReg {
3062 live.set(c.ID, int32(len(b.Values)), b.Pos)
3063 }
3064 }
3065
3066 for i := len(b.Values) - 1; i >= 0; i-- {
3067 v := b.Values[i]
3068 live.remove(v.ID)
3069 if v.Op == OpPhi {
3070 continue
3071 }
3072 if opcodeTable[v.Op].call {
3073 if numCalls != nil {
3074 numCalls[b.ID]++
3075 }
3076 rematIDs = rematIDs[:0]
3077 c := live.contents()
3078 for i := range c {
3079 c[i].val += unlikelyDistance
3080 vid := c[i].key
3081 if s.values[vid].rematerializeable {
3082 rematIDs = append(rematIDs, vid)
3083 }
3084 }
3085
3086
3087
3088 for _, r := range rematIDs {
3089 live.remove(r)
3090 }
3091 }
3092 for _, a := range v.Args {
3093 if s.values[a.ID].needReg {
3094 live.set(a.ID, int32(i), v.Pos)
3095 }
3096 }
3097 }
3098
3099
3100 if loopLiveIn != nil {
3101 loop := s.loopnest.b2l[b.ID]
3102 if loop != nil && loop.header.ID == b.ID {
3103 loopLiveIn[loop] = updateLive(live, nil)
3104 }
3105 }
3106
3107
3108 for _, e := range b.Preds {
3109 p := e.b
3110 delta := branchDistance(p, b)
3111
3112
3113 t.clear()
3114 for _, e := range s.live[p.ID] {
3115 t.set(e.ID, e.dist, e.pos)
3116 }
3117 update := false
3118
3119
3120 for _, e := range live.contents() {
3121 d := e.val + delta
3122 if !t.contains(e.key) || d < t.get(e.key) {
3123 update = true
3124 t.set(e.key, d, e.pos)
3125 }
3126 }
3127
3128 if !update {
3129 continue
3130 }
3131 s.live[p.ID] = updateLive(t, s.live[p.ID])
3132 changed = true
3133 }
3134 }
3135
3136
3137
3138 if !changed {
3139 break
3140 }
3141
3142
3143
3144 if loopLiveIn != nil {
3145 break
3146 }
3147
3148
3149 if len(s.loopnest.loops) == 0 {
3150 break
3151 }
3152 }
3153 if f.pass.debug > regDebug {
3154 s.debugPrintLive("after dfs walk", f, s.live, s.desired)
3155 }
3156
3157
3158
3159 if loopLiveIn == nil {
3160 s.computeDesired()
3161 return
3162 }
3163
3164
3165
3166
3167
3168 loops := slices.Clone(s.loopnest.loops)
3169 slices.SortFunc(loops, func(a, b *loop) int {
3170 return cmp.Compare(a.depth, b.depth)
3171 })
3172
3173 loopset := f.newSparseMapPos(f.NumValues())
3174 defer f.retSparseMapPos(loopset)
3175 for _, loop := range loops {
3176 if loop.outer == nil {
3177 continue
3178 }
3179 livein := loopLiveIn[loop]
3180 loopset.clear()
3181 for _, l := range livein {
3182 loopset.set(l.ID, l.dist, l.pos)
3183 }
3184 update := false
3185 for _, l := range loopLiveIn[loop.outer] {
3186 if !loopset.contains(l.ID) {
3187 loopset.set(l.ID, l.dist, l.pos)
3188 update = true
3189 }
3190 }
3191 if update {
3192 loopLiveIn[loop] = updateLive(loopset, livein)
3193 }
3194 }
3195
3196
3197
3198 const unknownDistance = -1
3199
3200
3201
3202
3203 for _, b := range po {
3204 loop := s.loopnest.b2l[b.ID]
3205 if loop == nil {
3206 continue
3207 }
3208 headerLive := loopLiveIn[loop]
3209 loopset.clear()
3210 for _, l := range s.live[b.ID] {
3211 loopset.set(l.ID, l.dist, l.pos)
3212 }
3213 update := false
3214 for _, l := range headerLive {
3215 if !loopset.contains(l.ID) {
3216 loopset.set(l.ID, unknownDistance, src.NoXPos)
3217 update = true
3218 }
3219 }
3220 if update {
3221 s.live[b.ID] = updateLive(loopset, s.live[b.ID])
3222 }
3223 }
3224 if f.pass.debug > regDebug {
3225 s.debugPrintLive("after live loop prop", f, s.live, s.desired)
3226 }
3227
3228
3229
3230
3231 unfinishedBlocks := f.Cache.allocBlockSlice(len(po))
3232 defer f.Cache.freeBlockSlice(unfinishedBlocks)
3233 copy(unfinishedBlocks, po)
3234
3235 for len(unfinishedBlocks) > 0 {
3236 n := 0
3237 for _, b := range unfinishedBlocks {
3238 live.clear()
3239 unfinishedValues := 0
3240 for _, l := range s.live[b.ID] {
3241 if l.dist == unknownDistance {
3242 unfinishedValues++
3243 }
3244 live.set(l.ID, l.dist, l.pos)
3245 }
3246 update := false
3247 for _, e := range b.Succs {
3248 succ := e.b
3249 for _, l := range s.live[succ.ID] {
3250 if !live.contains(l.ID) || l.dist == unknownDistance {
3251 continue
3252 }
3253 dist := int32(len(succ.Values)) + l.dist + branchDistance(b, succ)
3254 dist += numCalls[succ.ID] * unlikelyDistance
3255 val := live.get(l.ID)
3256 switch {
3257 case val == unknownDistance:
3258 unfinishedValues--
3259 fallthrough
3260 case dist < val:
3261 update = true
3262 live.set(l.ID, dist, l.pos)
3263 }
3264 }
3265 }
3266 if update {
3267 s.live[b.ID] = updateLive(live, s.live[b.ID])
3268 }
3269 if unfinishedValues > 0 {
3270 unfinishedBlocks[n] = b
3271 n++
3272 }
3273 }
3274 unfinishedBlocks = unfinishedBlocks[:n]
3275 }
3276
3277
3278
3279 for _, b := range f.Blocks {
3280 slices.SortFunc(s.live[b.ID], func(a, b liveInfo) int {
3281 if a.dist != b.dist {
3282 return cmp.Compare(a.dist, b.dist)
3283 }
3284 return cmp.Compare(a.ID, b.ID)
3285 })
3286 }
3287
3288 s.computeDesired()
3289
3290 if f.pass.debug > regDebug {
3291 s.debugPrintLive("final", f, s.live, s.desired)
3292 }
3293 }
3294
3295
3296
3297
3298 func (s *regAllocState) computeDesired() {
3299
3300
3301
3302 var desired desiredState
3303 f := s.f
3304 po := f.postorder()
3305 maxPreds := 0
3306 for _, b := range f.Blocks {
3307 maxPreds = max(maxPreds, len(b.Preds))
3308 }
3309
3310 phiPrefs := make([]desiredState, maxPreds)
3311 for {
3312 changed := false
3313 for _, b := range po {
3314 desired.copy(&s.desired[b.ID])
3315 for i := range b.Preds {
3316 phiPrefs[i].reset()
3317 }
3318 var headerLoop *loop
3319 if l := s.loopnest.b2l[b.ID]; l != nil && l.header == b {
3320 headerLoop = l
3321 }
3322
3323 i := len(b.Values) - 1
3324 for ; i >= 0; i-- {
3325 v := b.Values[i]
3326 if v.Op == OpPhi {
3327 break
3328 }
3329 prefs := desired.remove(v.ID)
3330 regspec := s.regspec(v)
3331
3332 desired.clobber(regspec.clobbers)
3333
3334 for _, j := range regspec.inputs {
3335 if countRegs(j.regs) != 1 {
3336 continue
3337 }
3338 desired.clobber(j.regs)
3339 desired.add(v.Args[j.idx].ID, s.pickReg(j.regs))
3340 }
3341
3342 if opcodeTable[v.Op].resultInArg0 || v.Op == OpAMD64ADDQconst || v.Op == OpAMD64ADDLconst || v.Op == OpSelect0 {
3343
3344
3345
3346
3347
3348 if opcodeTable[v.Op].commutative {
3349 desired.addList(v.Args[1].ID, prefs)
3350 }
3351 desired.addList(v.Args[0].ID, prefs)
3352 }
3353 }
3354 for ; i >= 0; i-- {
3355 v := b.Values[i]
3356 prefs := desired.remove(v.ID)
3357 if prefs[0] == noRegister {
3358 continue
3359 }
3360
3361
3362 for _, r := range prefs {
3363 if r != noRegister {
3364 desired.avoid = desired.avoid.minus(regMaskAt(r))
3365 }
3366 }
3367
3368 for pidx, a := range v.Args {
3369 if headerLoop != nil && s.loopnest.b2l[b.Preds[pidx].b.ID] == headerLoop {
3370
3371
3372 continue
3373 }
3374 phiPrefs[pidx].addList(a.ID, prefs)
3375 }
3376 }
3377 for pidx, e := range b.Preds {
3378 p := e.b
3379 changed = s.desired[p.ID].merge(&desired) || changed
3380 changed = s.desired[p.ID].merge(&phiPrefs[pidx]) || changed
3381 }
3382 }
3383 if !changed || (!s.loopnest.hasIrreducible && len(s.loopnest.loops) == 0) {
3384 break
3385 }
3386 }
3387 }
3388
3389
3390 func updateLive(t *sparseMapPos, live []liveInfo) []liveInfo {
3391 live = live[:0]
3392 if cap(live) < t.size() {
3393 live = make([]liveInfo, 0, t.size())
3394 }
3395 for _, e := range t.contents() {
3396 live = append(live, liveInfo{e.key, e.val, e.pos})
3397 }
3398 return live
3399 }
3400
3401
3402
3403
3404 func branchDistance(b *Block, s *Block) int32 {
3405 if len(b.Succs) == 2 {
3406 if b.Succs[0].b == s && b.Likely == BranchLikely ||
3407 b.Succs[1].b == s && b.Likely == BranchUnlikely {
3408 return likelyDistance
3409 }
3410 if b.Succs[0].b == s && b.Likely == BranchUnlikely ||
3411 b.Succs[1].b == s && b.Likely == BranchLikely {
3412 return unlikelyDistance
3413 }
3414 }
3415
3416
3417 return normalDistance
3418 }
3419
3420 func (s *regAllocState) debugPrintLive(stage string, f *Func, live [][]liveInfo, desired []desiredState) {
3421 fmt.Printf("%s: live values at end of each block: %s\n", stage, f.Name)
3422 for _, b := range f.Blocks {
3423 s.debugPrintLiveBlock(b, live[b.ID], &desired[b.ID])
3424 }
3425 }
3426
3427 func (s *regAllocState) debugPrintLiveBlock(b *Block, live []liveInfo, desired *desiredState) {
3428 fmt.Printf(" %s:", b)
3429 slices.SortFunc(live, func(a, b liveInfo) int {
3430 return cmp.Compare(a.ID, b.ID)
3431 })
3432 for _, x := range live {
3433 fmt.Printf(" v%d(%d)", x.ID, x.dist)
3434 for _, e := range desired.entries {
3435 if e.ID != x.ID {
3436 continue
3437 }
3438 fmt.Printf("[")
3439 first := true
3440 for _, r := range e.regs {
3441 if r == noRegister {
3442 continue
3443 }
3444 if !first {
3445 fmt.Printf(",")
3446 }
3447 fmt.Print(&s.registers[r])
3448 first = false
3449 }
3450 fmt.Printf("]")
3451 }
3452 }
3453 if avoid := desired.avoid; !avoid.empty() {
3454 fmt.Printf(" avoid=%v", s.RegMaskString(avoid))
3455 }
3456 fmt.Println()
3457 }
3458
3459
3460 type desiredState struct {
3461
3462
3463 entries []desiredStateEntry
3464
3465
3466
3467
3468 avoid regMask
3469 }
3470 type desiredStateEntry struct {
3471
3472 ID ID
3473
3474
3475
3476
3477
3478 regs [4]register
3479 }
3480
3481
3482 func (d *desiredState) get(vid ID) [4]register {
3483 for _, e := range d.entries {
3484 if e.ID == vid {
3485 return e.regs
3486 }
3487 }
3488 return [4]register{noRegister, noRegister, noRegister, noRegister}
3489 }
3490
3491
3492 func (d *desiredState) add(vid ID, r register) {
3493 d.avoid = d.avoid.addReg(r)
3494 for i := range d.entries {
3495 e := &d.entries[i]
3496 if e.ID != vid {
3497 continue
3498 }
3499 if e.regs[0] == r {
3500
3501 return
3502 }
3503 for j := 1; j < len(e.regs); j++ {
3504 if e.regs[j] == r {
3505
3506 copy(e.regs[1:], e.regs[:j])
3507 e.regs[0] = r
3508 return
3509 }
3510 }
3511 copy(e.regs[1:], e.regs[:])
3512 e.regs[0] = r
3513 return
3514 }
3515 d.entries = append(d.entries, desiredStateEntry{vid, [4]register{r, noRegister, noRegister, noRegister}})
3516 }
3517
3518 func (d *desiredState) addList(vid ID, regs [4]register) {
3519
3520 for i := len(regs) - 1; i >= 0; i-- {
3521 r := regs[i]
3522 if r != noRegister {
3523 d.add(vid, r)
3524 }
3525 }
3526 }
3527
3528
3529 func (d *desiredState) clobber(m regMask) {
3530 for i := 0; i < len(d.entries); {
3531 e := &d.entries[i]
3532 j := 0
3533 for _, r := range e.regs {
3534 if r != noRegister && !m.hasReg(r) {
3535 e.regs[j] = r
3536 j++
3537 }
3538 }
3539 if j == 0 {
3540
3541 d.entries[i] = d.entries[len(d.entries)-1]
3542 d.entries = d.entries[:len(d.entries)-1]
3543 continue
3544 }
3545 for ; j < len(e.regs); j++ {
3546 e.regs[j] = noRegister
3547 }
3548 i++
3549 }
3550 d.avoid = d.avoid.minus(m)
3551 }
3552
3553
3554 func (d *desiredState) reset() {
3555 d.entries = d.entries[:0]
3556 d.avoid = regMask{}
3557 }
3558
3559
3560 func (d *desiredState) copy(x *desiredState) {
3561 d.entries = append(d.entries[:0], x.entries...)
3562 d.avoid = x.avoid
3563 }
3564
3565
3566 func (d *desiredState) remove(vid ID) [4]register {
3567 for i := range d.entries {
3568 if d.entries[i].ID == vid {
3569 regs := d.entries[i].regs
3570 d.entries[i] = d.entries[len(d.entries)-1]
3571 d.entries = d.entries[:len(d.entries)-1]
3572 return regs
3573 }
3574 }
3575 return [4]register{noRegister, noRegister, noRegister, noRegister}
3576 }
3577
3578
3579
3580 func (d *desiredState) merge(x *desiredState) bool {
3581 oldAvoid := d.avoid
3582 d.avoid = d.avoid.union(x.avoid)
3583
3584
3585 for _, e := range x.entries {
3586 d.addList(e.ID, e.regs)
3587 }
3588 return oldAvoid != d.avoid
3589 }
3590
3591
3592 func (loopnest *loopnest) computeUnavoidableCalls() {
3593 f := loopnest.f
3594
3595 hasCall := f.Cache.allocBoolSlice(f.NumBlocks())
3596 defer f.Cache.freeBoolSlice(hasCall)
3597 for _, b := range f.Blocks {
3598 if b.containsCall() {
3599 hasCall[b.ID] = true
3600 }
3601 }
3602 found := f.Cache.allocSparseSet(f.NumBlocks())
3603 defer f.Cache.freeSparseSet(found)
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613 loopLoop:
3614 for _, l := range loopnest.loops {
3615 found.clear()
3616 tovisit := make([]*Block, 0, 8)
3617 tovisit = append(tovisit, l.header)
3618 for len(tovisit) > 0 {
3619 cur := tovisit[len(tovisit)-1]
3620 tovisit = tovisit[:len(tovisit)-1]
3621 if hasCall[cur.ID] {
3622 continue
3623 }
3624 for _, s := range cur.Succs {
3625 nb := s.Block()
3626 if nb == l.header {
3627
3628 continue loopLoop
3629 }
3630 if found.contains(nb.ID) {
3631
3632 continue
3633 }
3634 nl := loopnest.b2l[nb.ID]
3635 if nl == nil || (nl.depth <= l.depth && nl != l) {
3636
3637 continue
3638 }
3639 tovisit = append(tovisit, nb)
3640 found.add(nb.ID)
3641 }
3642 }
3643
3644 l.containsUnavoidableCall = true
3645 }
3646 }
3647
3648 func (b *Block) containsCall() bool {
3649 if b.Kind == block.BlockDefer {
3650 return true
3651 }
3652 for _, v := range b.Values {
3653 if opcodeTable[v.Op].call {
3654 return true
3655 }
3656 }
3657 return false
3658 }
3659
View as plain text