1
2
3
4
5 package ssa
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 import (
21 "bytes"
22 "fmt"
23 "math/big"
24 "os"
25 "sort"
26 )
27
28
29
30
31
32 func (b *BasicBlock) Idom() *BasicBlock { return b.dom.idom }
33
34
35
36 func (b *BasicBlock) Dominees() []*BasicBlock { return b.dom.children }
37
38
39 func (b *BasicBlock) Dominates(c *BasicBlock) bool {
40 return b.dom.pre <= c.dom.pre && c.dom.post <= b.dom.post
41 }
42
43
44
45 func (f *Function) DomPreorder() []*BasicBlock {
46 slice := append([]*BasicBlock(nil), f.Blocks...)
47 sort.Slice(slice, func(i, j int) bool {
48 return slice[i].dom.pre < slice[j].dom.pre
49 })
50 return slice
51 }
52
53
54
55
56 func (f *Function) DomPostorder() []*BasicBlock {
57 slice := append([]*BasicBlock(nil), f.Blocks...)
58 sort.Slice(slice, func(i, j int) bool {
59 return slice[i].dom.post < slice[j].dom.post
60 })
61 return slice
62 }
63
64
65 type domInfo struct {
66 idom *BasicBlock
67 children []*BasicBlock
68 pre, post int32
69 }
70
71
72
73 type ltState struct {
74
75 sdom []*BasicBlock
76 parent []*BasicBlock
77 ancestor []*BasicBlock
78 }
79
80
81 func (lt *ltState) dfs(v *BasicBlock, i int32, preorder []*BasicBlock) int32 {
82 preorder[i] = v
83 v.dom.pre = i
84 i++
85 lt.sdom[v.Index] = v
86 lt.link(nil, v)
87 for _, w := range v.Succs {
88 if lt.sdom[w.Index] == nil {
89 lt.parent[w.Index] = v
90 i = lt.dfs(w, i, preorder)
91 }
92 }
93 return i
94 }
95
96
97 func (lt *ltState) eval(v *BasicBlock) *BasicBlock {
98
99 u := v
100 for ; lt.ancestor[v.Index] != nil; v = lt.ancestor[v.Index] {
101 if lt.sdom[v.Index].dom.pre < lt.sdom[u.Index].dom.pre {
102 u = v
103 }
104 }
105 return u
106 }
107
108
109 func (lt *ltState) link(v, w *BasicBlock) {
110 lt.ancestor[w.Index] = v
111 }
112
113
114
115 func buildDomTree(f *Function) {
116
117
118
119
120 for _, b := range f.Blocks {
121 b.dom = domInfo{}
122 }
123
124 n := len(f.Blocks)
125
126
127 space := make([]*BasicBlock, 5*n)
128 lt := ltState{
129 sdom: space[0:n],
130 parent: space[n : 2*n],
131 ancestor: space[2*n : 3*n],
132 }
133
134
135 preorder := space[3*n : 4*n]
136 root := f.Blocks[0]
137 prenum := lt.dfs(root, 0, preorder)
138 recover := f.Recover
139 if recover != nil {
140 lt.dfs(recover, prenum, preorder)
141 }
142
143 buckets := space[4*n : 5*n]
144 copy(buckets, preorder)
145
146
147 for i := int32(n) - 1; i > 0; i-- {
148 w := preorder[i]
149
150
151 for v := buckets[i]; v != w; v = buckets[v.dom.pre] {
152 u := lt.eval(v)
153 if lt.sdom[u.Index].dom.pre < i {
154 v.dom.idom = u
155 } else {
156 v.dom.idom = w
157 }
158 }
159
160
161 lt.sdom[w.Index] = lt.parent[w.Index]
162 for _, v := range w.Preds {
163 u := lt.eval(v)
164 if lt.sdom[u.Index].dom.pre < lt.sdom[w.Index].dom.pre {
165 lt.sdom[w.Index] = lt.sdom[u.Index]
166 }
167 }
168
169 lt.link(lt.parent[w.Index], w)
170
171 if lt.parent[w.Index] == lt.sdom[w.Index] {
172 w.dom.idom = lt.parent[w.Index]
173 } else {
174 buckets[i] = buckets[lt.sdom[w.Index].dom.pre]
175 buckets[lt.sdom[w.Index].dom.pre] = w
176 }
177 }
178
179
180 for v := buckets[0]; v != root; v = buckets[v.dom.pre] {
181 v.dom.idom = root
182 }
183
184
185
186 for _, w := range preorder[1:] {
187 if w == root || w == recover {
188 w.dom.idom = nil
189 } else {
190 if w.dom.idom != lt.sdom[w.Index] {
191 w.dom.idom = w.dom.idom.dom.idom
192 }
193
194 w.dom.idom.dom.children = append(w.dom.idom.dom.children, w)
195 }
196 }
197
198 pre, post := numberDomTree(root, 0, 0)
199 if recover != nil {
200 numberDomTree(recover, pre, post)
201 }
202
203
204
205
206 if f.Prog.mode&SanityCheckFunctions != 0 {
207 sanityCheckDomTree(f)
208 }
209 }
210
211
212
213
214 func numberDomTree(v *BasicBlock, pre, post int32) (int32, int32) {
215 v.dom.pre = pre
216 pre++
217 for _, child := range v.dom.children {
218 pre, post = numberDomTree(child, pre, post)
219 }
220 v.dom.post = post
221 post++
222 return pre, post
223 }
224
225
226
227
228
229
230
231 func sanityCheckDomTree(f *Function) {
232 n := len(f.Blocks)
233
234
235
236 D := make([]big.Int, n)
237
238 one := big.NewInt(1)
239
240
241 var all big.Int
242 all.Set(one).Lsh(&all, uint(n)).Sub(&all, one)
243
244
245 for i, b := range f.Blocks {
246 if i == 0 || b == f.Recover {
247
248 D[i].SetBit(&D[0], 0, 1)
249 } else {
250
251
252 D[i].Set(&all)
253 }
254 }
255
256
257 for changed := true; changed; {
258 changed = false
259 for i, b := range f.Blocks {
260 if i == 0 || b == f.Recover {
261 continue
262 }
263
264 var x big.Int
265 x.Set(&all)
266 for _, pred := range b.Preds {
267 x.And(&x, &D[pred.Index])
268 }
269 x.SetBit(&x, i, 1)
270 if D[i].Cmp(&x) != 0 {
271 D[i].Set(&x)
272 changed = true
273 }
274 }
275 }
276
277
278
279 ok := true
280 for i := 0; i < n; i++ {
281 for j := 0; j < n; j++ {
282 b, c := f.Blocks[i], f.Blocks[j]
283 if c == f.Recover {
284 continue
285 }
286 actual := b.Dominates(c)
287 expected := D[j].Bit(i) == 1
288 if actual != expected {
289 fmt.Fprintf(os.Stderr, "dominates(%s, %s)==%t, want %t\n", b, c, actual, expected)
290 ok = false
291 }
292 }
293 }
294
295 preorder := f.DomPreorder()
296 for _, b := range f.Blocks {
297 if got := preorder[b.dom.pre]; got != b {
298 fmt.Fprintf(os.Stderr, "preorder[%d]==%s, want %s\n", b.dom.pre, got, b)
299 ok = false
300 }
301 }
302
303 if !ok {
304 panic("sanityCheckDomTree failed for " + f.String())
305 }
306
307 }
308
309
310
311
312 func printDomTreeText(buf *bytes.Buffer, v *BasicBlock, indent int) {
313 fmt.Fprintf(buf, "%*s%s\n", 4*indent, "", v)
314 for _, child := range v.dom.children {
315 printDomTreeText(buf, child, indent+1)
316 }
317 }
318
319
320
321 func printDomTreeDot(buf *bytes.Buffer, f *Function) {
322 fmt.Fprintln(buf, "//", f)
323 fmt.Fprintln(buf, "digraph domtree {")
324 for i, b := range f.Blocks {
325 v := b.dom
326 fmt.Fprintf(buf, "\tn%d [label=\"%s (%d, %d)\",shape=\"rectangle\"];\n", v.pre, b, v.pre, v.post)
327
328
329
330
331 if i != 0 {
332 fmt.Fprintf(buf, "\tn%d -> n%d [style=\"solid\",weight=100];\n", v.idom.dom.pre, v.pre)
333 }
334
335 for _, pred := range b.Preds {
336 fmt.Fprintf(buf, "\tn%d -> n%d [style=\"dotted\",weight=0];\n", pred.dom.pre, v.pre)
337 }
338 }
339 fmt.Fprintln(buf, "}")
340 }
341
View as plain text