1
2
3
4
5 package ssacompile
6
7 import (
8 "slices"
9
10 "cmd/compile/internal/ssa"
11 "cmd/compile/internal/ssa/block"
12 )
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 func loopRotate(f *ssa.Func) {
32 loopnest := f.Loopnest()
33 if loopnest.HasIrreducible {
34 return
35 }
36 if len(loopnest.Loops) == 0 {
37 return
38 }
39
40 idToIdx := f.Cache.AllocIntSlice(f.NumBlocks())
41 defer f.Cache.FreeIntSlice(idToIdx)
42 for i, b := range f.Blocks {
43 idToIdx[b.ID] = i
44 }
45
46
47 move := map[ssa.ID]struct{}{}
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 after := map[ssa.ID][]*ssa.Block{}
82
83
84 tops := map[ssa.ID]*ssa.Block{}
85
86
87
88 loopOrder := f.Cache.AllocIntSlice(len(loopnest.Loops))
89 for i := range loopOrder {
90 loopOrder[i] = i
91 }
92 defer f.Cache.FreeIntSlice(loopOrder)
93 slices.SortFunc(loopOrder, func(i, j int) int {
94 di := loopnest.Loops[i].Depth
95 dj := loopnest.Loops[j].Depth
96 switch {
97 case di > dj:
98 return -1
99 case di < dj:
100 return 1
101 default:
102 return 0
103 }
104 })
105
106
107 for _, loopIdx := range loopOrder {
108 loop := loopnest.Loops[loopIdx]
109 b := loop.Header
110 var p *ssa.Block
111 for _, e := range b.Preds {
112 if e.B.Kind != block.BlockPlain {
113 continue
114 }
115 if loopnest.B2L[e.B.ID] != loop {
116 continue
117 }
118 p = e.B
119 }
120 if p == nil {
121 continue
122 }
123 tops[loop.Header.ID] = p
124 p.Hotness |= ssa.HotInitial
125 if f.IsPgoHot {
126 p.Hotness |= ssa.HotPgo
127 }
128
129 if p == b {
130 continue
131 }
132 p.Hotness |= ssa.HotNotFlowIn
133
134
135 after[p.ID] = []*ssa.Block{b}
136 for {
137 nextIdx := idToIdx[b.ID] + 1
138 if nextIdx >= len(f.Blocks) {
139 break
140 }
141 nextb := f.Blocks[nextIdx]
142 if nextb == p {
143 break
144 }
145 if bloop := loopnest.B2L[nextb.ID]; bloop != nil {
146 if bloop == loop || bloop.Outer == loop && tops[bloop.Header.ID] == nextb {
147 after[p.ID] = append(after[p.ID], nextb)
148 }
149 }
150 b = nextb
151 }
152
153 f.Blocks[idToIdx[loop.Header.ID]] = p
154 f.Blocks[idToIdx[p.ID]] = loop.Header
155 idToIdx[loop.Header.ID], idToIdx[p.ID] = idToIdx[p.ID], idToIdx[loop.Header.ID]
156
157
158 for _, b := range after[p.ID] {
159 move[b.ID] = struct{}{}
160 }
161 }
162
163
164
165
166
167 j := 0
168
169
170
171 oldOrder := f.Cache.AllocBlockSlice(len(f.Blocks))
172 defer f.Cache.FreeBlockSlice(oldOrder)
173 copy(oldOrder, f.Blocks)
174 var moveBlocks func(bs []*ssa.Block)
175 moveBlocks = func(blocks []*ssa.Block) {
176 for _, a := range blocks {
177 f.Blocks[j] = a
178 j++
179 if nextBlocks, ok := after[a.ID]; ok {
180 moveBlocks(nextBlocks)
181 }
182 }
183 }
184 for _, b := range oldOrder {
185 if _, ok := move[b.ID]; ok {
186 continue
187 }
188 f.Blocks[j] = b
189 j++
190 moveBlocks(after[b.ID])
191 }
192 if j != len(oldOrder) {
193 f.Fatalf("bad reordering in looprotate")
194 }
195 }
196
View as plain text