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