1
2
3
4
5 package ssa
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 func phiopt(f *Func) {
27 sdom := f.Sdom()
28 for _, b := range f.Blocks {
29 if len(b.Preds) != 2 || len(b.Values) == 0 {
30
31 continue
32 }
33
34 pb0, b0 := b, b.Preds[0].b
35 for len(b0.Succs) == 1 && len(b0.Preds) == 1 {
36 pb0, b0 = b0, b0.Preds[0].b
37 }
38 if b0.Kind != BlockIf {
39 continue
40 }
41 pb1, b1 := b, b.Preds[1].b
42 for len(b1.Succs) == 1 && len(b1.Preds) == 1 {
43 pb1, b1 = b1, b1.Preds[0].b
44 }
45 if b1 != b0 {
46 continue
47 }
48
49
50 var reverse int
51 if b0.Succs[0].b == pb0 && b0.Succs[1].b == pb1 {
52 reverse = 0
53 } else if b0.Succs[0].b == pb1 && b0.Succs[1].b == pb0 {
54 reverse = 1
55 } else {
56 b.Fatalf("invalid predecessors\n")
57 }
58
59 for _, v := range b.Values {
60 if v.Op != OpPhi {
61 continue
62 }
63
64
65 if v.Type.IsInteger() {
66 phioptint(v, b0, reverse)
67 }
68
69 if !v.Type.IsBoolean() {
70 continue
71 }
72
73
74
75
76
77 if v.Args[0].Op == OpConstBool && v.Args[1].Op == OpConstBool {
78 if v.Args[reverse].AuxInt != v.Args[1-reverse].AuxInt {
79 ops := [2]Op{OpNot, OpCopy}
80 v.reset(ops[v.Args[reverse].AuxInt])
81 v.AddArg(b0.Controls[0])
82 if f.pass.debug > 0 {
83 f.Warnl(b.Pos, "converted OpPhi to %v", v.Op)
84 }
85 continue
86 }
87 }
88
89
90
91
92
93
94 if v.Args[reverse].Op == OpConstBool && v.Args[reverse].AuxInt == 1 {
95 if tmp := v.Args[1-reverse]; sdom.IsAncestorEq(tmp.Block, b) {
96 v.reset(OpOrB)
97 v.SetArgs2(b0.Controls[0], tmp)
98 if f.pass.debug > 0 {
99 f.Warnl(b.Pos, "converted OpPhi to %v", v.Op)
100 }
101 continue
102 }
103 }
104
105
106
107
108
109
110 if v.Args[1-reverse].Op == OpConstBool && v.Args[1-reverse].AuxInt == 0 {
111 if tmp := v.Args[reverse]; sdom.IsAncestorEq(tmp.Block, b) {
112 v.reset(OpAndB)
113 v.SetArgs2(b0.Controls[0], tmp)
114 if f.pass.debug > 0 {
115 f.Warnl(b.Pos, "converted OpPhi to %v", v.Op)
116 }
117 continue
118 }
119 }
120 }
121 }
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165 var lca *lcaRange
166 for _, b := range f.Blocks {
167 if len(b.Preds) != 2 || len(b.Values) == 0 {
168
169 continue
170 }
171
172 for _, v := range b.Values {
173
174
175 if v.Op != OpPhi {
176 continue
177 }
178 if v.Args[0].Op != OpConstBool || v.Args[1].Op != OpConstBool {
179 continue
180 }
181 if v.Args[0].AuxInt == v.Args[1].AuxInt {
182 continue
183 }
184
185 pb0 := b.Preds[0].b
186 pb1 := b.Preds[1].b
187 if pb0.Kind == BlockIf && pb0 == sdom.Parent(b) {
188
189
190
191
192
193
194
195
196
197 ei := b.Preds[0].i
198 sb1 := pb0.Succs[1-ei].b
199 if sdom.IsAncestorEq(sb1, pb1) {
200 convertPhi(pb0, v, ei)
201 break
202 }
203 } else if pb1.Kind == BlockIf && pb1 == sdom.Parent(b) {
204
205
206
207
208
209
210
211
212
213 ei := b.Preds[1].i
214 sb0 := pb1.Succs[1-ei].b
215 if sdom.IsAncestorEq(sb0, pb0) {
216 convertPhi(pb1, v, 1-ei)
217 break
218 }
219 } else {
220
221
222
223
224
225
226
227
228
229 if lca == nil {
230 lca = makeLCArange(f)
231 }
232 b0 := lca.find(pb0, pb1)
233 if b0.Kind != BlockIf {
234 break
235 }
236 sb0 := b0.Succs[0].b
237 sb1 := b0.Succs[1].b
238 var reverse int
239 if sdom.IsAncestorEq(sb0, pb0) && sdom.IsAncestorEq(sb1, pb1) {
240 reverse = 0
241 } else if sdom.IsAncestorEq(sb1, pb0) && sdom.IsAncestorEq(sb0, pb1) {
242 reverse = 1
243 } else {
244 break
245 }
246 if len(sb0.Preds) != 1 || len(sb1.Preds) != 1 {
247
248
249
250
251 break
252 }
253 convertPhi(b0, v, reverse)
254 }
255 }
256 }
257 }
258
259 func phioptint(v *Value, b0 *Block, reverse int) {
260 a0 := v.Args[0]
261 a1 := v.Args[1]
262 if a0.Op != a1.Op {
263 return
264 }
265
266 switch a0.Op {
267 case OpConst8, OpConst16, OpConst32, OpConst64:
268 default:
269 return
270 }
271
272 negate := false
273 switch {
274 case a0.AuxInt == 0 && a1.AuxInt == 1:
275 negate = true
276 case a0.AuxInt == 1 && a1.AuxInt == 0:
277 default:
278 return
279 }
280
281 if reverse == 1 {
282 negate = !negate
283 }
284
285 a := b0.Controls[0]
286 if negate {
287 a = v.Block.NewValue1(v.Pos, OpNot, a.Type, a)
288 }
289 v.AddArg(a)
290
291 cvt := v.Block.NewValue1(v.Pos, OpCvtBoolToUint8, v.Block.Func.Config.Types.UInt8, a)
292 switch v.Type.Size() {
293 case 1:
294 v.reset(OpCopy)
295 case 2:
296 v.reset(OpZeroExt8to16)
297 case 4:
298 v.reset(OpZeroExt8to32)
299 case 8:
300 v.reset(OpZeroExt8to64)
301 default:
302 v.Fatalf("bad int size %d", v.Type.Size())
303 }
304 v.AddArg(cvt)
305
306 f := b0.Func
307 if f.pass.debug > 0 {
308 f.Warnl(v.Block.Pos, "converted OpPhi bool -> int%d", v.Type.Size()*8)
309 }
310 }
311
312
313
314
315 func convertPhi(b *Block, v *Value, reverse int) {
316 f := b.Func
317 ops := [2]Op{OpNot, OpCopy}
318 v.reset(ops[v.Args[reverse].AuxInt])
319 v.AddArg(b.Controls[0])
320 if f.pass.debug > 0 {
321 f.Warnl(b.Pos, "converted OpPhi to %v", v.Op)
322 }
323 }
324
View as plain text