Source file src/pkg/cmd/compile/internal/ssa/dom.go
1
2
3
4
5 package ssa
6
7
8 type markKind uint8
9
10 const (
11 notFound markKind = 0
12 notExplored markKind = 1
13 explored markKind = 2
14 done markKind = 3
15 )
16
17
18
19
20
21
22 func postorder(f *Func) []*Block {
23 return postorderWithNumbering(f, nil)
24 }
25
26 type blockAndIndex struct {
27 b *Block
28 index int
29 }
30
31
32
33 func postorderWithNumbering(f *Func, ponums []int32) []*Block {
34 mark := make([]markKind, f.NumBlocks())
35
36
37 order := make([]*Block, 0, len(f.Blocks))
38
39
40
41
42 s := make([]blockAndIndex, 0, 32)
43 s = append(s, blockAndIndex{b: f.Entry})
44 mark[f.Entry.ID] = explored
45 for len(s) > 0 {
46 tos := len(s) - 1
47 x := s[tos]
48 b := x.b
49 i := x.index
50 if i < len(b.Succs) {
51 s[tos].index++
52 bb := b.Succs[i].Block()
53 if mark[bb.ID] == notFound {
54 mark[bb.ID] = explored
55 s = append(s, blockAndIndex{b: bb})
56 }
57 } else {
58 s = s[:tos]
59 if len(ponums) > 0 {
60 ponums[b.ID] = int32(len(order))
61 }
62 order = append(order, b)
63 }
64 }
65 return order
66 }
67
68 type linkedBlocks func(*Block) []Edge
69
70 const nscratchslices = 7
71
72
73
74
75 const minscratchblocks = 512
76
77 func (cache *Cache) scratchBlocksForDom(maxBlockID int) (a, b, c, d, e, f, g []ID) {
78 tot := maxBlockID * nscratchslices
79 scratch := cache.domblockstore
80 if len(scratch) < tot {
81
82
83 req := (tot * 3) >> 1
84 if req < nscratchslices*minscratchblocks {
85 req = nscratchslices * minscratchblocks
86 }
87 scratch = make([]ID, req)
88 cache.domblockstore = scratch
89 } else {
90
91 scratch = scratch[0:tot]
92 for i := range scratch {
93 scratch[i] = 0
94 }
95 }
96
97 a = scratch[0*maxBlockID : 1*maxBlockID]
98 b = scratch[1*maxBlockID : 2*maxBlockID]
99 c = scratch[2*maxBlockID : 3*maxBlockID]
100 d = scratch[3*maxBlockID : 4*maxBlockID]
101 e = scratch[4*maxBlockID : 5*maxBlockID]
102 f = scratch[5*maxBlockID : 6*maxBlockID]
103 g = scratch[6*maxBlockID : 7*maxBlockID]
104
105 return
106 }
107
108 func dominators(f *Func) []*Block {
109 preds := func(b *Block) []Edge { return b.Preds }
110 succs := func(b *Block) []Edge { return b.Succs }
111
112
113
114 return f.dominatorsLTOrig(f.Entry, preds, succs)
115 }
116
117
118
119
120 func (f *Func) dominatorsLTOrig(entry *Block, predFn linkedBlocks, succFn linkedBlocks) []*Block {
121
122
123 maxBlockID := entry.Func.NumBlocks()
124 semi, vertex, label, parent, ancestor, bucketHead, bucketLink := f.Cache.scratchBlocksForDom(maxBlockID)
125
126
127
128
129 fromID := make([]*Block, maxBlockID)
130 for _, v := range f.Blocks {
131 fromID[v.ID] = v
132 }
133 idom := make([]*Block, maxBlockID)
134
135
136
137 n := f.dfsOrig(entry, succFn, semi, vertex, label, parent)
138
139 for i := n; i >= 2; i-- {
140 w := vertex[i]
141
142
143 for _, e := range predFn(fromID[w]) {
144 v := e.b
145 if semi[v.ID] == 0 {
146
147
148 continue
149 }
150 u := evalOrig(v.ID, ancestor, semi, label)
151 if semi[u] < semi[w] {
152 semi[w] = semi[u]
153 }
154 }
155
156
157
158
159 vsw := vertex[semi[w]]
160 bucketLink[w] = bucketHead[vsw]
161 bucketHead[vsw] = w
162
163 linkOrig(parent[w], w, ancestor)
164
165
166 for v := bucketHead[parent[w]]; v != 0; v = bucketLink[v] {
167 u := evalOrig(v, ancestor, semi, label)
168 if semi[u] < semi[v] {
169 idom[v] = fromID[u]
170 } else {
171 idom[v] = fromID[parent[w]]
172 }
173 }
174 }
175
176 for i := ID(2); i <= n; i++ {
177 w := vertex[i]
178 if idom[w].ID != vertex[semi[w]] {
179 idom[w] = idom[idom[w].ID]
180 }
181 }
182
183 return idom
184 }
185
186
187
188
189
190 func (f *Func) dfsOrig(entry *Block, succFn linkedBlocks, semi, vertex, label, parent []ID) ID {
191 n := ID(0)
192 s := make([]*Block, 0, 256)
193 s = append(s, entry)
194
195 for len(s) > 0 {
196 v := s[len(s)-1]
197 s = s[:len(s)-1]
198
199
200 if semi[v.ID] != 0 {
201 continue
202 }
203 n++
204 semi[v.ID] = n
205 vertex[n] = v.ID
206 label[v.ID] = v.ID
207
208 for _, e := range succFn(v) {
209 w := e.b
210
211 if semi[w.ID] == 0 {
212
213 s = append(s, w)
214 parent[w.ID] = v.ID
215 }
216 }
217 }
218 return n
219 }
220
221
222 func compressOrig(v ID, ancestor, semi, label []ID) {
223 if ancestor[ancestor[v]] != 0 {
224 compressOrig(ancestor[v], ancestor, semi, label)
225 if semi[label[ancestor[v]]] < semi[label[v]] {
226 label[v] = label[ancestor[v]]
227 }
228 ancestor[v] = ancestor[ancestor[v]]
229 }
230 }
231
232
233 func evalOrig(v ID, ancestor, semi, label []ID) ID {
234 if ancestor[v] == 0 {
235 return v
236 }
237 compressOrig(v, ancestor, semi, label)
238 return label[v]
239 }
240
241 func linkOrig(v, w ID, ancestor []ID) {
242 ancestor[w] = v
243 }
244
245
246
247
248 func dominatorsSimple(f *Func) []*Block {
249
250
251 idom := make([]*Block, f.NumBlocks())
252
253
254 post := f.postorder()
255
256
257 postnum := make([]int, f.NumBlocks())
258 for i, b := range post {
259 postnum[b.ID] = i
260 }
261
262
263 idom[f.Entry.ID] = f.Entry
264 if postnum[f.Entry.ID] != len(post)-1 {
265 f.Fatalf("entry block %v not last in postorder", f.Entry)
266 }
267
268
269 for {
270 changed := false
271
272 for i := len(post) - 2; i >= 0; i-- {
273 b := post[i]
274 var d *Block
275 for _, e := range b.Preds {
276 p := e.b
277 if idom[p.ID] == nil {
278 continue
279 }
280 if d == nil {
281 d = p
282 continue
283 }
284 d = intersect(d, p, postnum, idom)
285 }
286 if d != idom[b.ID] {
287 idom[b.ID] = d
288 changed = true
289 }
290 }
291 if !changed {
292 break
293 }
294 }
295
296 idom[f.Entry.ID] = nil
297 return idom
298 }
299
300
301
302 func intersect(b, c *Block, postnum []int, idom []*Block) *Block {
303
304
305 for b != c {
306 if postnum[b.ID] < postnum[c.ID] {
307 b = idom[b.ID]
308 } else {
309 c = idom[c.ID]
310 }
311 }
312 return b
313 }
314
View as plain text