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