...
1
2
3
4
5 package ssa
6
7
8
9
10
11
12
13 import (
14 "fmt"
15 "os"
16 )
17
18
19
20 const debugBlockOpt = false
21
22
23 func markReachable(b *BasicBlock) {
24 b.Index = -1
25 for _, succ := range b.Succs {
26 if succ.Index == 0 {
27 markReachable(succ)
28 }
29 }
30 }
31
32
33
34 func deleteUnreachableBlocks(f *Function) {
35 const white, black = 0, -1
36
37 for _, b := range f.Blocks {
38 b.Index = white
39 }
40 markReachable(f.Blocks[0])
41 if f.Recover != nil {
42 markReachable(f.Recover)
43 }
44 for i, b := range f.Blocks {
45 if b.Index == white {
46 for _, c := range b.Succs {
47 if c.Index == black {
48 c.removePred(b)
49 }
50 }
51 if debugBlockOpt {
52 fmt.Fprintln(os.Stderr, "unreachable", b)
53 }
54 f.Blocks[i] = nil
55 }
56 }
57 f.removeNilBlocks()
58 }
59
60
61
62
63 func jumpThreading(f *Function, b *BasicBlock) bool {
64 if b.Index == 0 {
65 return false
66 }
67 if b.Instrs == nil {
68 return false
69 }
70 if _, ok := b.Instrs[0].(*Jump); !ok {
71 return false
72 }
73 c := b.Succs[0]
74 if c == b {
75 return false
76 }
77 if c.hasPhi() {
78 return false
79 }
80 for j, a := range b.Preds {
81 a.replaceSucc(b, c)
82
83
84 if len(a.Succs) == 2 && a.Succs[0] == c && a.Succs[1] == c {
85 jump := new(Jump)
86 jump.setBlock(a)
87 a.Instrs[len(a.Instrs)-1] = jump
88 a.Succs = a.Succs[:1]
89 c.removePred(b)
90 } else {
91 if j == 0 {
92 c.replacePred(b, a)
93 } else {
94 c.Preds = append(c.Preds, a)
95 }
96 }
97
98 if debugBlockOpt {
99 fmt.Fprintln(os.Stderr, "jumpThreading", a, b, c)
100 }
101 }
102 f.Blocks[b.Index] = nil
103 return true
104 }
105
106
107
108
109 func fuseBlocks(f *Function, a *BasicBlock) bool {
110 if len(a.Succs) != 1 {
111 return false
112 }
113 b := a.Succs[0]
114 if len(b.Preds) != 1 {
115 return false
116 }
117
118
119
120
121 if b.hasPhi() {
122 return false
123 }
124
125
126 a.Instrs = append(a.Instrs[:len(a.Instrs)-1], b.Instrs...)
127 for _, instr := range b.Instrs {
128 instr.setBlock(a)
129 }
130
131
132 a.Succs = append(a.succs2[:0], b.Succs...)
133
134
135 for _, c := range b.Succs {
136 c.replacePred(b, a)
137 }
138
139 if debugBlockOpt {
140 fmt.Fprintln(os.Stderr, "fuseBlocks", a, b)
141 }
142
143 f.Blocks[b.Index] = nil
144 return true
145 }
146
147
148
149
150 func optimizeBlocks(f *Function) {
151 deleteUnreachableBlocks(f)
152
153
154 changed := true
155 for changed {
156 changed = false
157
158 if debugBlockOpt {
159 f.WriteTo(os.Stderr)
160 mustSanityCheck(f, nil)
161 }
162
163 for _, b := range f.Blocks {
164
165
166 if b == nil {
167 continue
168 }
169
170
171 if fuseBlocks(f, b) {
172 changed = true
173 }
174
175
176 if jumpThreading(f, b) {
177 changed = true
178 continue
179 }
180 }
181 }
182 f.removeNilBlocks()
183 }
184
View as plain text