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 loopOrder := f.Cache.allocIntSlice(len(loopnest.loops))
86 for i := range loopOrder {
87 loopOrder[i] = i
88 }
89 defer f.Cache.freeIntSlice(loopOrder)
90 slices.SortFunc(loopOrder, func(i, j int) int {
91 di := loopnest.loops[i].depth
92 dj := loopnest.loops[j].depth
93 switch {
94 case di > dj:
95 return -1
96 case di < dj:
97 return 1
98 default:
99 return 0
100 }
101 })
102
103
104 for _, loopIdx := range loopOrder {
105 loop := loopnest.loops[loopIdx]
106 b := loop.header
107 var p *Block
108 for _, e := range b.Preds {
109 if e.b.Kind != BlockPlain {
110 continue
111 }
112 if loopnest.b2l[e.b.ID] != loop {
113 continue
114 }
115 p = e.b
116 }
117 if p == nil {
118 continue
119 }
120 tops[loop.header.ID] = p
121 p.Hotness |= HotInitial
122 if f.IsPgoHot {
123 p.Hotness |= HotPgo
124 }
125
126 if p == b {
127 continue
128 }
129 p.Hotness |= HotNotFlowIn
130
131
132 after[p.ID] = []*Block{b}
133 for {
134 nextIdx := idToIdx[b.ID] + 1
135 if nextIdx >= len(f.Blocks) {
136 break
137 }
138 nextb := f.Blocks[nextIdx]
139 if nextb == p {
140 break
141 }
142 if bloop := loopnest.b2l[nextb.ID]; bloop != nil {
143 if bloop == loop || bloop.outer == loop && tops[bloop.header.ID] == nextb {
144 after[p.ID] = append(after[p.ID], nextb)
145 }
146 }
147 b = nextb
148 }
149
150 f.Blocks[idToIdx[loop.header.ID]] = p
151 f.Blocks[idToIdx[p.ID]] = loop.header
152 idToIdx[loop.header.ID], idToIdx[p.ID] = idToIdx[p.ID], idToIdx[loop.header.ID]
153
154
155 for _, b := range after[p.ID] {
156 move[b.ID] = struct{}{}
157 }
158 }
159
160
161
162
163
164 j := 0
165
166
167
168 oldOrder := f.Cache.allocBlockSlice(len(f.Blocks))
169 defer f.Cache.freeBlockSlice(oldOrder)
170 copy(oldOrder, f.Blocks)
171 var moveBlocks func(bs []*Block)
172 moveBlocks = func(blocks []*Block) {
173 for _, a := range blocks {
174 f.Blocks[j] = a
175 j++
176 if nextBlocks, ok := after[a.ID]; ok {
177 moveBlocks(nextBlocks)
178 }
179 }
180 }
181 for _, b := range oldOrder {
182 if _, ok := move[b.ID]; ok {
183 continue
184 }
185 f.Blocks[j] = b
186 j++
187 moveBlocks(after[b.ID])
188 }
189 if j != len(oldOrder) {
190 f.Fatalf("bad reordering in looprotate")
191 }
192 }
193
View as plain text