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