1 /**
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "unit_test.h"
17 #include "optimizer/optimizations/if_conversion.h"
18
19 namespace panda::compiler {
20 class IfConversionTest : public GraphTest {
21 #ifndef NDEBUG
22 public:
IfConversionTest()23 IfConversionTest()
24 {
25 // GraphChecker hack: LowLevel instructions may appear only after Lowering pass:
26 GetGraph()->SetLowLevelInstructionsEnabled();
27 }
28 #endif
29 };
30
31 /*
32 * Test Graph:
33 * [entry}
34 * |
35 * /---[2]---\
36 * | |
37 * [3] |
38 * | |
39 * \---[4]---/
40 * |
41 * [exit]
42 */
TEST_F(IfConversionTest,TriangleTrueImm)43 TEST_F(IfConversionTest, TriangleTrueImm)
44 {
45 GRAPH(GetGraph())
46 {
47 PARAMETER(0, 0).u64();
48 CONSTANT(1, 10);
49 CONSTANT(2, 2);
50 BASIC_BLOCK(2, 3, 4)
51 {
52 INST(3, Opcode::Compare).b().CC(CC_B).Inputs(0, 1);
53 INST(4, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(3);
54 }
55 BASIC_BLOCK(3, 4)
56 {
57 INST(5, Opcode::Mul).u64().Inputs(0, 2);
58 }
59 BASIC_BLOCK(4, -1)
60 {
61 INST(6, Opcode::Phi).u64().Inputs({{2, 0}, {3, 5}});
62 INST(7, Opcode::Return).u64().Inputs(6);
63 }
64 }
65
66 GetGraph()->RunPass<IfConversion>();
67
68 auto graph = CreateEmptyGraph();
69 GRAPH(graph)
70 {
71 PARAMETER(0, 0).u64();
72 CONSTANT(1, 10);
73 CONSTANT(2, 2);
74 BASIC_BLOCK(2, -1)
75 {
76 INST(3, Opcode::Compare).b().CC(CC_B).Inputs(0, 1);
77 INST(5, Opcode::Mul).u64().Inputs(0, 2);
78 INST(4, Opcode::SelectImm).u64().SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(5, 0, 3);
79 INST(7, Opcode::Return).u64().Inputs(4);
80 }
81 }
82 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
83 }
84
TEST_F(IfConversionTest,TriangleTrue)85 TEST_F(IfConversionTest, TriangleTrue)
86 {
87 GRAPH(GetGraph())
88 {
89 PARAMETER(0, 0).u64();
90 CONSTANT(1, 10);
91 CONSTANT(2, 2);
92 BASIC_BLOCK(2, 3, 4)
93 {
94 INST(3, Opcode::If).SrcType(DataType::UINT64).CC(CC_NE).Inputs(0, 1);
95 }
96 BASIC_BLOCK(3, 4)
97 {
98 INST(4, Opcode::Mul).u64().Inputs(0, 2);
99 }
100 BASIC_BLOCK(4, -1)
101 {
102 INST(5, Opcode::Phi).u64().Inputs({{2, 0}, {3, 4}});
103 INST(6, Opcode::Return).u64().Inputs(5);
104 }
105 }
106
107 GetGraph()->RunPass<IfConversion>();
108
109 auto graph = CreateEmptyGraph();
110 GRAPH(graph)
111 {
112 PARAMETER(0, 0).u64();
113 CONSTANT(1, 10);
114 CONSTANT(2, 2);
115 BASIC_BLOCK(2, -1)
116 {
117 INST(4, Opcode::Mul).u64().Inputs(0, 2);
118 INST(3, Opcode::Select).u64().SrcType(DataType::UINT64).CC(CC_NE).Inputs(4, 0, 0, 1);
119 INST(6, Opcode::Return).u64().Inputs(3);
120 }
121 }
122 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
123 }
124
125 /*
126 * Test Graph:
127 * [entry}
128 * |
129 * /---[2]---\
130 * | |
131 * | [3]
132 * | |
133 * \---[4]---/
134 * |
135 * [exit]
136 */
TEST_F(IfConversionTest,TriangleFalseImm)137 TEST_F(IfConversionTest, TriangleFalseImm)
138 {
139 GRAPH(GetGraph())
140 {
141 PARAMETER(0, 0).u64();
142 CONSTANT(1, 10);
143 CONSTANT(2, 2);
144 BASIC_BLOCK(2, 4, 3)
145 {
146 INST(3, Opcode::Compare).b().CC(CC_AE).Inputs(0, 1);
147 INST(4, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(3);
148 }
149 BASIC_BLOCK(3, 4)
150 {
151 INST(5, Opcode::Mul).u64().Inputs(0, 2);
152 }
153 BASIC_BLOCK(4, -1)
154 {
155 INST(6, Opcode::Phi).u64().Inputs({{2, 0}, {3, 5}});
156 INST(7, Opcode::Return).u64().Inputs(6);
157 }
158 }
159
160 GetGraph()->RunPass<IfConversion>();
161
162 auto graph = CreateEmptyGraph();
163 GRAPH(graph)
164 {
165 PARAMETER(0, 0).u64();
166 CONSTANT(1, 10);
167 CONSTANT(2, 2);
168 BASIC_BLOCK(2, -1)
169 {
170 INST(3, Opcode::Compare).b().CC(CC_AE).Inputs(0, 1);
171 INST(5, Opcode::Mul).u64().Inputs(0, 2);
172 INST(4, Opcode::SelectImm).u64().SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(0, 5, 3);
173 INST(7, Opcode::Return).u64().Inputs(4);
174 }
175 }
176 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
177 }
178
TEST_F(IfConversionTest,TriangleFalse)179 TEST_F(IfConversionTest, TriangleFalse)
180 {
181 GRAPH(GetGraph())
182 {
183 PARAMETER(0, 0).u64();
184 CONSTANT(1, 10);
185 CONSTANT(2, 2);
186 BASIC_BLOCK(2, 4, 3)
187 {
188 INST(3, Opcode::If).SrcType(DataType::UINT64).CC(CC_LT).Inputs(0, 1);
189 }
190 BASIC_BLOCK(3, 4)
191 {
192 INST(4, Opcode::Mul).u64().Inputs(0, 2);
193 }
194 BASIC_BLOCK(4, -1)
195 {
196 INST(5, Opcode::Phi).u64().Inputs({{2, 0}, {3, 4}});
197 INST(6, Opcode::Return).u64().Inputs(5);
198 }
199 }
200
201 GetGraph()->RunPass<IfConversion>();
202
203 auto graph = CreateEmptyGraph();
204 GRAPH(graph)
205 {
206 PARAMETER(0, 0).u64();
207 CONSTANT(1, 10);
208 CONSTANT(2, 2);
209 BASIC_BLOCK(2, -1)
210 {
211 INST(4, Opcode::Mul).u64().Inputs(0, 2);
212 INST(3, Opcode::Select).u64().SrcType(DataType::UINT64).CC(CC_LT).Inputs(0, 4, 0, 1);
213 INST(6, Opcode::Return).u64().Inputs(3);
214 }
215 }
216 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
217 }
218
219 /*
220 * Test Graph:
221 * [entry}
222 * |
223 * /---[2]---\
224 * | |
225 * /--[3]--\ |
226 * | | |
227 * [4] | |
228 * | | |
229 * \------[5]----/
230 * |
231 * [exit]
232 */
TEST_F(IfConversionTest,JointTriangleImm)233 TEST_F(IfConversionTest, JointTriangleImm)
234 {
235 GRAPH(GetGraph())
236 {
237 PARAMETER(0, 0).u64();
238 CONSTANT(1, 10);
239 CONSTANT(2, 2);
240 BASIC_BLOCK(2, 3, 5)
241 {
242 INST(3, Opcode::Compare).b().Inputs(0, 1);
243 INST(4, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(3);
244 }
245 BASIC_BLOCK(3, 4, 5)
246 {
247 INST(5, Opcode::Mul).u64().Inputs(0, 2);
248 INST(6, Opcode::Compare).b().Inputs(5, 1);
249 INST(7, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(6);
250 }
251 BASIC_BLOCK(4, 5)
252 {
253 INST(8, Opcode::Mul).u64().Inputs(5, 2);
254 }
255 BASIC_BLOCK(5, -1)
256 {
257 INST(9, Opcode::Phi).u64().Inputs({{2, 0}, {3, 5}, {4, 8}});
258 INST(10, Opcode::Return).u64().Inputs(9);
259 }
260 }
261
262 GetGraph()->RunPass<IfConversion>();
263
264 auto graph = CreateEmptyGraph();
265 GRAPH(graph)
266 {
267 PARAMETER(0, 0).u64();
268 CONSTANT(1, 10);
269 CONSTANT(2, 2);
270 BASIC_BLOCK(2, 3, 5)
271 {
272 INST(3, Opcode::Compare).b().Inputs(0, 1);
273 INST(4, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(3);
274 }
275 BASIC_BLOCK(3, 5)
276 {
277 INST(5, Opcode::Mul).u64().Inputs(0, 2);
278 INST(6, Opcode::Compare).b().Inputs(5, 1);
279 INST(8, Opcode::Mul).u64().Inputs(5, 2);
280 INST(7, Opcode::SelectImm).u64().SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(8, 5, 6);
281 }
282 BASIC_BLOCK(5, -1)
283 {
284 INST(9, Opcode::Phi).u64().Inputs({{2, 0}, {3, 7}});
285 INST(10, Opcode::Return).u64().Inputs(9);
286 }
287 }
288 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
289 }
290
TEST_F(IfConversionTest,TriangleTwice)291 TEST_F(IfConversionTest, TriangleTwice)
292 {
293 GRAPH(GetGraph())
294 {
295 PARAMETER(0, 0).u64();
296 PARAMETER(1, 1).u64();
297 PARAMETER(2, 2).u64();
298 BASIC_BLOCK(2, 3, 5)
299 {
300 INST(3, Opcode::Mul).u64().Inputs(0, 1);
301 INST(4, Opcode::If).SrcType(DataType::UINT64).CC(CC_NE).Inputs(3, 1);
302 }
303 BASIC_BLOCK(3, 4, 5)
304 {
305 INST(5, Opcode::If).SrcType(DataType::UINT64).CC(CC_NE).Inputs(3, 2);
306 }
307 BASIC_BLOCK(4, 5)
308 {
309 INST(6, Opcode::Mul).u64().Inputs(3, 2);
310 }
311 BASIC_BLOCK(5, -1)
312 {
313 INST(7, Opcode::Phi).u64().Inputs({{2, 0}, {3, 3}, {4, 6}});
314 INST(8, Opcode::Return).u64().Inputs(7);
315 }
316 }
317
318 GetGraph()->RunPass<IfConversion>();
319
320 auto graph = CreateEmptyGraph();
321 GRAPH(graph)
322 {
323 PARAMETER(0, 0).u64();
324 PARAMETER(1, 1).u64();
325 PARAMETER(2, 2).u64();
326 BASIC_BLOCK(2, -1)
327 {
328 INST(3, Opcode::Mul).u64().Inputs(0, 1);
329 INST(6, Opcode::Mul).u64().Inputs(3, 2);
330 INST(5, Opcode::Select).u64().SrcType(DataType::UINT64).CC(CC_NE).Inputs(6, 3, 3, 2);
331 INST(4, Opcode::Select).u64().SrcType(DataType::UINT64).CC(CC_NE).Inputs(5, 0, 3, 1);
332 INST(8, Opcode::Return).u64().Inputs(4);
333 }
334 }
335 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
336 }
337
TEST_F(IfConversionTest,JointTriangleWithTrickFloatPhi)338 TEST_F(IfConversionTest, JointTriangleWithTrickFloatPhi)
339 {
340 GRAPH(GetGraph())
341 {
342 PARAMETER(0, 0).u64();
343 PARAMETER(1, 1).f64();
344 CONSTANT(2, 10);
345 BASIC_BLOCK(2, 3, 5)
346 {
347 INST(3, Opcode::If).SrcType(DataType::UINT64).CC(CC_NE).Inputs(0, 2);
348 }
349 BASIC_BLOCK(3, 4, 5)
350 {
351 INST(4, Opcode::Mul).f64().Inputs(1, 1);
352 INST(5, Opcode::Mul).u64().Inputs(0, 2);
353 INST(6, Opcode::If).SrcType(DataType::UINT64).CC(CC_NE).Inputs(5, 2);
354 }
355 BASIC_BLOCK(4, 5)
356 {
357 INST(7, Opcode::Mul).u64().Inputs(5, 2);
358 }
359 BASIC_BLOCK(5, -1)
360 {
361 INST(8, Opcode::Phi).u64().Inputs({{2, 0}, {3, 5}, {4, 7}});
362 INST(9, Opcode::Phi).f64().Inputs({{2, 1}, {3, 4}, {4, 4}});
363 INST(10, Opcode::Mul).f64().Inputs(9, 9);
364 INST(20, Opcode::SaveState).NoVregs();
365 INST(11, Opcode::CallStatic).u64().InputsAutoType(8, 10, 20);
366 INST(12, Opcode::Return).u64().Inputs(11);
367 }
368 }
369
370 GetGraph()->RunPass<IfConversion>();
371 auto graph = CreateEmptyGraph();
372 GRAPH(graph)
373 {
374 PARAMETER(0, 0).u64();
375 PARAMETER(1, 1).f64();
376 CONSTANT(2, 10);
377 BASIC_BLOCK(2, 3, 5)
378 {
379 INST(3, Opcode::If).SrcType(DataType::UINT64).CC(CC_NE).Inputs(0, 2);
380 }
381 BASIC_BLOCK(3, 5)
382 {
383 INST(4, Opcode::Mul).f64().Inputs(1, 1);
384 INST(5, Opcode::Mul).u64().Inputs(0, 2);
385 INST(7, Opcode::Mul).u64().Inputs(5, 2);
386 INST(6, Opcode::Select).u64().SrcType(DataType::UINT64).CC(CC_NE).Inputs(7, 5, 5, 2);
387 }
388 BASIC_BLOCK(5, -1)
389 {
390 INST(8, Opcode::Phi).u64().Inputs({{2, 0}, {3, 6}});
391 INST(9, Opcode::Phi).f64().Inputs({{2, 1}, {3, 4}});
392 INST(10, Opcode::Mul).f64().Inputs(9, 9);
393 INST(20, Opcode::SaveState).NoVregs();
394 INST(11, Opcode::CallStatic).u64().InputsAutoType(8, 10, 20);
395 INST(12, Opcode::Return).u64().Inputs(11);
396 }
397 }
398 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
399 }
400
401 /*
402 * Test Graph:
403 * [entry}
404 * |
405 * /---[2]---\
406 * | |
407 * [3] [4]
408 * | |
409 * \---[5]---/
410 * |
411 * [exit]
412 */
TEST_F(IfConversionTest,DiamondImm)413 TEST_F(IfConversionTest, DiamondImm)
414 {
415 GRAPH(GetGraph())
416 {
417 PARAMETER(0, 0).u32();
418 PARAMETER(1, 1).u32();
419 CONSTANT(2, 0);
420 BASIC_BLOCK(2, 3, 4)
421 {
422 INST(3, Opcode::Compare).b().Inputs(1, 2);
423 INST(4, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(3);
424 }
425 BASIC_BLOCK(4, 5)
426 {
427 INST(5, Opcode::Add).u32().Inputs(0, 1);
428 }
429 BASIC_BLOCK(3, 5)
430 {
431 INST(7, Opcode::Sub).u32().Inputs(0, 1);
432 }
433 BASIC_BLOCK(5, -1)
434 {
435 INST(8, Opcode::Phi).u32().Inputs({{4, 5}, {3, 7}});
436 INST(9, Opcode::Return).u32().Inputs(8);
437 }
438 }
439
440 GetGraph()->RunPass<IfConversion>();
441
442 auto graph = CreateEmptyGraph();
443 GRAPH(graph)
444 {
445 PARAMETER(0, 0).u32();
446 PARAMETER(1, 1).u32();
447 CONSTANT(2, 0);
448 BASIC_BLOCK(2, -1)
449 {
450 INST(3, Opcode::Compare).b().Inputs(1, 2);
451 INST(7, Opcode::Sub).u32().Inputs(0, 1);
452 INST(5, Opcode::Add).u32().Inputs(0, 1);
453 INST(4, Opcode::SelectImm).u32().SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(7, 5, 3);
454 INST(9, Opcode::Return).u32().Inputs(4);
455 }
456 }
457 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
458 }
459
460 /*
461 * Test Graph:
462 * [entry}
463 * |
464 * /---[2]---\
465 * | |
466 * /--[3]--\ |
467 * | | |
468 * [4] [5] |
469 * | | |
470 * \------[6]----/
471 * |
472 * [exit]
473 */
TEST_F(IfConversionTest,JointDiamondImm)474 TEST_F(IfConversionTest, JointDiamondImm)
475 {
476 GRAPH(GetGraph())
477 {
478 PARAMETER(0, 0).u64();
479 PARAMETER(1, 1).u64();
480 BASIC_BLOCK(2, 3, 6)
481 {
482 INST(2, Opcode::Compare).b().Inputs(0, 1);
483 INST(3, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(2);
484 }
485 BASIC_BLOCK(3, 4, 5)
486 {
487 INST(4, Opcode::Mul).u64().Inputs(0, 0);
488 INST(5, Opcode::Compare).b().Inputs(4, 1);
489 INST(6, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(5);
490 }
491 BASIC_BLOCK(4, 6)
492 {
493 INST(7, Opcode::Mul).u64().Inputs(4, 1);
494 }
495 BASIC_BLOCK(5, 6)
496 {
497 INST(8, Opcode::Mul).u64().Inputs(4, 0);
498 }
499 BASIC_BLOCK(6, -1)
500 {
501 INST(9, Opcode::Phi).u64().Inputs({{2, 0}, {4, 7}, {5, 8}});
502 INST(10, Opcode::Return).u64().Inputs(9);
503 }
504 }
505
506 GetGraph()->RunPass<IfConversion>();
507
508 auto graph = CreateEmptyGraph();
509 GRAPH(graph)
510 {
511 PARAMETER(0, 0).u64();
512 PARAMETER(1, 1).u64();
513 BASIC_BLOCK(2, 3, 6)
514 {
515 INST(2, Opcode::Compare).b().Inputs(0, 1);
516 INST(3, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(2);
517 }
518 BASIC_BLOCK(3, 6)
519 {
520 INST(4, Opcode::Mul).u64().Inputs(0, 0);
521 INST(5, Opcode::Compare).b().Inputs(4, 1);
522 INST(7, Opcode::Mul).u64().Inputs(4, 1);
523 INST(8, Opcode::Mul).u64().Inputs(4, 0);
524 INST(6, Opcode::SelectImm).u64().SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(7, 8, 5);
525 }
526 BASIC_BLOCK(6, -1)
527 {
528 INST(9, Opcode::Phi).u64().Inputs({{2, 0}, {3, 6}});
529 INST(10, Opcode::Return).u64().Inputs(9);
530 }
531 }
532 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
533 }
534
TEST_F(IfConversionTest,JointDiamond)535 TEST_F(IfConversionTest, JointDiamond)
536 {
537 GRAPH(GetGraph())
538 {
539 PARAMETER(0, 0).u64();
540 PARAMETER(1, 1).u64();
541 BASIC_BLOCK(2, 3, 6)
542 {
543 INST(2, Opcode::If).SrcType(DataType::UINT64).CC(CC_GE).Inputs(0, 1);
544 }
545 BASIC_BLOCK(3, 4, 5)
546 {
547 INST(3, Opcode::Mul).u64().Inputs(0, 0);
548 INST(4, Opcode::If).SrcType(DataType::UINT64).CC(CC_GT).Inputs(3, 1);
549 }
550 BASIC_BLOCK(4, 6)
551 {
552 INST(5, Opcode::Mul).u64().Inputs(3, 1);
553 }
554 BASIC_BLOCK(5, 6)
555 {
556 INST(6, Opcode::Mul).u64().Inputs(3, 0);
557 }
558 BASIC_BLOCK(6, -1)
559 {
560 INST(7, Opcode::Phi).u64().Inputs({{2, 0}, {4, 5}, {5, 6}});
561 INST(8, Opcode::Return).u64().Inputs(7);
562 }
563 }
564
565 GetGraph()->RunPass<IfConversion>();
566
567 auto graph = CreateEmptyGraph();
568 GRAPH(graph)
569 {
570 PARAMETER(0, 0).u64();
571 PARAMETER(1, 1).u64();
572 BASIC_BLOCK(2, 3, 6)
573 {
574 INST(2, Opcode::If).SrcType(DataType::UINT64).CC(CC_GE).Inputs(0, 1);
575 }
576 BASIC_BLOCK(3, 6)
577 {
578 INST(3, Opcode::Mul).u64().Inputs(0, 0);
579 INST(5, Opcode::Mul).u64().Inputs(3, 1);
580 INST(6, Opcode::Mul).u64().Inputs(3, 0);
581 INST(4, Opcode::Select).u64().SrcType(DataType::UINT64).CC(CC_GT).Inputs(5, 6, 3, 1);
582 }
583 BASIC_BLOCK(6, -1)
584 {
585 INST(7, Opcode::Phi).u64().Inputs({{2, 0}, {3, 4}});
586 INST(8, Opcode::Return).u64().Inputs(7);
587 }
588 }
589 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
590 }
591
TEST_F(IfConversionTest,JointDiamondWithDroppedSelect)592 TEST_F(IfConversionTest, JointDiamondWithDroppedSelect)
593 {
594 GRAPH(GetGraph())
595 {
596 PARAMETER(0, 0).u64();
597 PARAMETER(1, 1).u64();
598 BASIC_BLOCK(2, 3, 6)
599 {
600 INST(2, Opcode::If).SrcType(DataType::UINT64).CC(CC_GE).Inputs(0, 1);
601 }
602 BASIC_BLOCK(3, 4, 5)
603 {
604 INST(3, Opcode::Mul).u64().Inputs(0, 0);
605 INST(4, Opcode::If).SrcType(DataType::UINT64).CC(CC_GT).Inputs(3, 1);
606 }
607 BASIC_BLOCK(4, 6)
608 {
609 INST(5, Opcode::Mul).u64().Inputs(3, 1);
610 }
611 BASIC_BLOCK(5, 6)
612 {
613 INST(6, Opcode::Mul).u64().Inputs(3, 0);
614 }
615 BASIC_BLOCK(6, -1)
616 {
617 INST(7, Opcode::Phi).u64().Inputs({{2, 0}, {4, 5}, {5, 6}});
618 INST(8, Opcode::Phi).u64().Inputs({{2, 0}, {4, 3}, {5, 3}});
619 INST(9, Opcode::Add).u64().Inputs(7, 8);
620 INST(10, Opcode::Return).u64().Inputs(9);
621 }
622 }
623
624 GetGraph()->RunPass<IfConversion>();
625
626 auto graph = CreateEmptyGraph();
627 GRAPH(graph)
628 {
629 PARAMETER(0, 0).u64();
630 PARAMETER(1, 1).u64();
631 BASIC_BLOCK(2, 3, 6)
632 {
633 INST(2, Opcode::If).SrcType(DataType::UINT64).CC(CC_GE).Inputs(0, 1);
634 }
635 BASIC_BLOCK(3, 6)
636 {
637 INST(3, Opcode::Mul).u64().Inputs(0, 0);
638 INST(5, Opcode::Mul).u64().Inputs(3, 1);
639 INST(6, Opcode::Mul).u64().Inputs(3, 0);
640 INST(4, Opcode::Select).u64().SrcType(DataType::UINT64).CC(CC_GT).Inputs(5, 6, 3, 1);
641 // Second Select not needed
642 }
643 BASIC_BLOCK(6, -1)
644 {
645 INST(7, Opcode::Phi).u64().Inputs({{2, 0}, {3, 4}});
646 INST(8, Opcode::Phi).u64().Inputs({{2, 0}, {3, 3}});
647 INST(9, Opcode::Add).u64().Inputs(7, 8);
648 INST(10, Opcode::Return).u64().Inputs(9);
649 }
650 }
651 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
652 }
653
TEST_F(IfConversionTest,JointDiamondRunTwice)654 TEST_F(IfConversionTest, JointDiamondRunTwice)
655 {
656 GRAPH(GetGraph())
657 {
658 PARAMETER(0, 0).u64();
659 PARAMETER(1, 1).u64();
660 BASIC_BLOCK(2, 3, 6)
661 {
662 INST(2, Opcode::If).SrcType(DataType::UINT64).CC(CC_GE).Inputs(0, 1);
663 }
664 BASIC_BLOCK(3, 4, 5)
665 {
666 INST(3, Opcode::Mul).u64().Inputs(0, 0);
667 INST(4, Opcode::Mul).u64().Inputs(1, 1);
668 INST(5, Opcode::If).SrcType(DataType::UINT64).CC(CC_GT).Inputs(4, 1);
669 }
670 BASIC_BLOCK(4, 6) {}
671 BASIC_BLOCK(5, 6) {}
672 BASIC_BLOCK(6, -1)
673 {
674 INST(6, Opcode::Phi).u64().Inputs({{2, 0}, {4, 3}, {5, 3}});
675 INST(7, Opcode::Return).u64().Inputs(6);
676 }
677 }
678
679 ASSERT_TRUE(GetGraph()->RunPass<IfConversion>());
680 ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
681
682 auto graph = CreateEmptyGraph();
683 GRAPH(graph)
684 {
685 PARAMETER(0, 0).u64();
686 PARAMETER(1, 1).u64();
687 BASIC_BLOCK(2, -1)
688 {
689 INST(3, Opcode::Mul).u64().Inputs(0, 0);
690 INST(2, Opcode::Select).u64().SrcType(DataType::UINT64).CC(CC_GE).Inputs(3, 0, 0, 1);
691 INST(7, Opcode::Return).u64().Inputs(2);
692 }
693 }
694 ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
695 }
696
697 /*
698 * No conversion allowed cases below.
699 */
TEST_F(IfConversionTest,TriangleWithCall)700 TEST_F(IfConversionTest, TriangleWithCall)
701 {
702 GRAPH(GetGraph())
703 {
704 PARAMETER(0, 0).u64();
705 CONSTANT(1, 10);
706 CONSTANT(2, 2);
707 BASIC_BLOCK(2, 3, 4)
708 {
709 INST(3, Opcode::Compare).b().Inputs(0, 1);
710 INST(4, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(3);
711 }
712 BASIC_BLOCK(3, 4)
713 {
714 INST(20, Opcode::SaveState).NoVregs();
715 INST(5, Opcode::CallStatic).u64().InputsAutoType(0, 2, 20);
716 }
717 BASIC_BLOCK(4, -1)
718 {
719 INST(6, Opcode::Phi).u64().Inputs({{2, 0}, {3, 5}});
720 INST(7, Opcode::Return).u64().Inputs(6);
721 }
722 }
723
724 ASSERT_FALSE(GetGraph()->RunPass<IfConversion>());
725 }
726
TEST_F(IfConversionTest,DiamondThreeOperations)727 TEST_F(IfConversionTest, DiamondThreeOperations)
728 {
729 GRAPH(GetGraph())
730 {
731 PARAMETER(0, 0).u32();
732 PARAMETER(1, 1).u32();
733 CONSTANT(2, 42);
734 CONSTANT(3, 0);
735 BASIC_BLOCK(2, 3, 4)
736 {
737 INST(4, Opcode::Compare).b().Inputs(1, 3);
738 INST(5, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(4);
739 }
740 BASIC_BLOCK(4, 5)
741 {
742 INST(6, Opcode::Add).u32().Inputs(0, 1);
743 }
744 BASIC_BLOCK(3, 5)
745 {
746 INST(7, Opcode::Add).u32().Inputs(0, 2);
747 INST(8, Opcode::Sub).u32().Inputs(7, 1);
748 }
749 BASIC_BLOCK(5, -1)
750 {
751 INST(9, Opcode::Phi).u32().Inputs({{4, 6}, {3, 8}});
752 INST(10, Opcode::Return).u32().Inputs(9);
753 }
754 }
755
756 ASSERT_FALSE(GetGraph()->RunPass<IfConversion>());
757 }
758
TEST_F(IfConversionTest,DiamondThreePhis)759 TEST_F(IfConversionTest, DiamondThreePhis)
760 {
761 GRAPH(GetGraph())
762 {
763 PARAMETER(0, 0).u32();
764 PARAMETER(1, 1).u32();
765 CONSTANT(2, 42);
766 CONSTANT(3, 0);
767 BASIC_BLOCK(2, 3, 4)
768 {
769 INST(6, Opcode::Add).u32().Inputs(0, 1);
770 INST(7, Opcode::Add).u32().Inputs(0, 2);
771 INST(8, Opcode::Sub).u32().Inputs(7, 1);
772 INST(4, Opcode::Compare).b().Inputs(1, 3);
773 INST(5, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(4);
774 }
775 BASIC_BLOCK(4, 5) {}
776 BASIC_BLOCK(3, 5) {}
777 BASIC_BLOCK(5, -1)
778 {
779 INST(9, Opcode::Phi).u32().Inputs({{4, 6}, {3, 8}});
780 INST(10, Opcode::Phi).u32().Inputs({{4, 6}, {3, 7}});
781 INST(11, Opcode::Phi).u32().Inputs({{4, 7}, {3, 8}});
782 INST(12, Opcode::Add).u32().Inputs(9, 10);
783 INST(13, Opcode::Add).u32().Inputs(11, 12);
784 INST(14, Opcode::Return).u32().Inputs(13);
785 }
786 }
787
788 ASSERT_FALSE(GetGraph()->RunPass<IfConversion>());
789 }
790
TEST_F(IfConversionTest,TriangleFloat)791 TEST_F(IfConversionTest, TriangleFloat)
792 {
793 GRAPH(GetGraph())
794 {
795 PARAMETER(0, 0).f64();
796 PARAMETER(1, 1).f64();
797 PARAMETER(2, 2).f64();
798 BASIC_BLOCK(2, 3, 4)
799 {
800 INST(3, Opcode::Cmp).s32().SrcType(DataType::FLOAT64).Inputs(0, 1);
801 INST(4, Opcode::IfImm).SrcType(DataType::INT32).CC(CC_NE).Imm(0).Inputs(3);
802 }
803 BASIC_BLOCK(3, 4)
804 {
805 INST(5, Opcode::Mul).f64().Inputs(0, 2);
806 }
807 BASIC_BLOCK(4, -1)
808 {
809 INST(6, Opcode::Phi).f64().Inputs({{2, 0}, {3, 5}});
810 INST(7, Opcode::Return).f64().Inputs(6);
811 }
812 }
813
814 ASSERT_FALSE(GetGraph()->RunPass<IfConversion>());
815 }
816
TEST_F(IfConversionTest,TrianglePhiFloat)817 TEST_F(IfConversionTest, TrianglePhiFloat)
818 {
819 GRAPH(GetGraph())
820 {
821 PARAMETER(0, 0).f64();
822 PARAMETER(1, 1).f64();
823 PARAMETER(2, 2).f64();
824 BASIC_BLOCK(2, 3, 4)
825 {
826 INST(5, Opcode::Mul).f64().Inputs(0, 2);
827 INST(3, Opcode::Cmp).s32().SrcType(DataType::FLOAT64).Inputs(0, 1);
828 INST(4, Opcode::IfImm).SrcType(DataType::INT32).CC(CC_NE).Imm(0).Inputs(3);
829 }
830 BASIC_BLOCK(3, 4) {} // Instructions 5 moved up manually
831 BASIC_BLOCK(4, -1)
832 {
833 INST(6, Opcode::Phi).f64().Inputs({{2, 0}, {3, 5}});
834 INST(7, Opcode::Return).f64().Inputs(6);
835 }
836 }
837
838 ASSERT_FALSE(GetGraph()->RunPass<IfConversion>());
839 }
840 } // namespace panda::compiler
841