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