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
18#include "optimizer/optimizations/cleanup.h"
19
20namespace panda::compiler {
21class CleanupTest : public GraphTest {
22};
23
24TEST_F(CleanupTest, Simple)
25{
26    GRAPH(GetGraph())
27    {
28        BASIC_BLOCK(2, 3) {}
29        BASIC_BLOCK(3, -1)
30        {
31            INST(0, Opcode::ReturnVoid);
32        }
33    }
34
35    ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
36
37    auto graph = CreateEmptyGraph();
38    GRAPH(graph)
39    {
40        BASIC_BLOCK(3, -1)
41        {
42            INST(0, Opcode::ReturnVoid);
43        }
44    }
45    ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
46}
47
48TEST_F(CleanupTest, BothHasPhi)
49{
50    GRAPH(GetGraph())
51    {
52        PARAMETER(0, 0).s64();
53        PARAMETER(1, 1).s64();
54        BASIC_BLOCK(2, 3, 6)
55        {
56            INST(2, Opcode::If).SrcType(DataType::Type::INT64).CC(CC_LE).Inputs(0, 1);
57        }
58        BASIC_BLOCK(3, 4, 5)
59        {
60            INST(3, Opcode::If).SrcType(DataType::Type::INT64).CC(CC_EQ).Inputs(0, 1);
61        }
62        BASIC_BLOCK(4, 5)
63        {
64            INST(4, Opcode::Add).s64().Inputs(0, 1);
65        }
66        BASIC_BLOCK(5, 6)
67        {
68            INST(5, Opcode::Phi).s64().Inputs({{3, 1}, {4, 4}});
69        }
70        BASIC_BLOCK(6, -1)
71        {
72            INST(6, Opcode::Phi).s64().Inputs({{2, 0}, {5, 5}});
73            INST(7, Opcode::Return).s64().Inputs(6);
74        }
75    }
76
77    ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
78
79    auto graph = CreateEmptyGraph();
80    GRAPH(graph)
81    {
82        PARAMETER(0, 0).s64();
83        PARAMETER(1, 1).s64();
84        BASIC_BLOCK(2, 3, 6)
85        {
86            INST(2, Opcode::If).SrcType(DataType::Type::INT64).CC(CC_LE).Inputs(0, 1);
87        }
88        BASIC_BLOCK(3, 4, 6)
89        {
90            INST(3, Opcode::If).SrcType(DataType::Type::INT64).CC(CC_EQ).Inputs(0, 1);
91        }
92        BASIC_BLOCK(4, 6)
93        {
94            INST(4, Opcode::Add).s64().Inputs(0, 1);
95        }
96        BASIC_BLOCK(6, -1)
97        {
98            INST(5, Opcode::Phi).s64().Inputs({{2, 0}, {3, 1}, {4, 4}});
99            INST(6, Opcode::Return).s64().Inputs(5);
100        }
101    }
102    ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
103}
104
105TEST_F(CleanupTest, HasPhi)
106{
107    GRAPH(GetGraph())
108    {
109        PARAMETER(0, 0).s64();
110        PARAMETER(1, 1).s64();
111        BASIC_BLOCK(2, 3, 4)
112        {
113            INST(2, Opcode::If).SrcType(DataType::Type::INT64).CC(CC_LT).Inputs(0, 1);
114        }
115        BASIC_BLOCK(3, 4)
116        {
117            INST(3, Opcode::Add).s64().Inputs(0, 1);
118        }
119        BASIC_BLOCK(4, 5)
120        {
121            INST(4, Opcode::Phi).s64().Inputs({{2, 1}, {3, 3}});
122        }
123        BASIC_BLOCK(5, -1)
124        {
125            INST(6, Opcode::Return).s64().Inputs(4);
126        }
127    }
128
129    ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
130
131    auto graph = CreateEmptyGraph();
132    GRAPH(graph)
133    {
134        PARAMETER(0, 0).s64();
135        PARAMETER(1, 1).s64();
136        BASIC_BLOCK(2, 3, 5)
137        {
138            INST(2, Opcode::If).SrcType(DataType::Type::INT64).CC(CC_LT).Inputs(0, 1);
139        }
140        BASIC_BLOCK(3, 5)
141        {
142            INST(3, Opcode::Add).s64().Inputs(0, 1);
143        }
144        BASIC_BLOCK(5, -1)
145        {
146            INST(4, Opcode::Phi).s64().Inputs({{2, 1}, {3, 3}});
147            INST(6, Opcode::Return).s64().Inputs(4);
148        }
149    }
150    ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
151}
152
153TEST_F(CleanupTest, DeadPhi)
154{
155    GRAPH(GetGraph())
156    {
157        PARAMETER(0, 0).s64();
158        PARAMETER(1, 1).s64();
159        BASIC_BLOCK(2, 3, 6)
160        {
161            INST(2, Opcode::If).SrcType(DataType::Type::INT64).CC(CC_NE).Inputs(0, 1);
162        }
163        BASIC_BLOCK(3, 4, 5)
164        {
165            INST(3, Opcode::If).SrcType(DataType::Type::INT64).CC(CC_LT).Inputs(0, 1);
166        }
167        BASIC_BLOCK(4, 5) {}
168        BASIC_BLOCK(5, 6)
169        {
170            INST(4, Opcode::Phi).s64().Inputs({{3, 0}, {4, 1}});
171        }
172        BASIC_BLOCK(6, -1)
173        {
174            INST(5, Opcode::ReturnVoid);
175        }
176    }
177
178    ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
179
180    auto graph = CreateEmptyGraph();
181    GRAPH(graph)
182    {
183        BASIC_BLOCK(2, -1)
184        {
185            INST(2, Opcode::ReturnVoid);
186        }
187    }
188    ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
189}
190
191TEST_F(CleanupTest, LoopPreHeader)
192{
193    GRAPH(GetGraph())
194    {
195        PARAMETER(0, 0).s64();
196        PARAMETER(1, 1).s64();
197        BASIC_BLOCK(2, 3) {}
198        BASIC_BLOCK(3, 3, -1)
199        {
200            INST(3, Opcode::Neg).s64().Inputs(0);
201            INST(5, Opcode::Compare).b().CC(CC_LT).SrcType(DataType::Type::INT64).Inputs(1, 3);
202            INST(6, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(5);
203        }
204    }
205
206    ASSERT_EQ(&BB(2), BB(3).GetLoop()->GetPreHeader());
207    ASSERT_EQ(1U, BB(3).GetLoop()->GetBlocks().size());
208    ASSERT_EQ(3U, BB(3).GetLoop()->GetOuterLoop()->GetBlocks().size());
209
210    ASSERT_FALSE(GetGraph()->RunPass<Cleanup>());
211
212    auto graph = CreateEmptyGraph();
213    GRAPH(graph)
214    {
215        PARAMETER(0, 0).s64();
216        PARAMETER(1, 1).s64();
217        BASIC_BLOCK(2, 3) {}
218        BASIC_BLOCK(3, 3, -1)
219        {
220            INST(3, Opcode::Neg).s64().Inputs(0);
221            INST(5, Opcode::Compare).b().CC(CC_LT).SrcType(DataType::Type::INT64).Inputs(1, 3);
222            INST(6, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(5);
223        }
224    }
225    ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
226}
227
228TEST_F(CleanupTest, TwoPredecessors)
229{
230    GRAPH(GetGraph())
231    {
232        PARAMETER(0, 0).s64();
233        PARAMETER(1, 1).s64();
234        BASIC_BLOCK(2, 3, 4)
235        {
236            INST(2, Opcode::Compare).b().CC(CC_LE).SrcType(DataType::Type::INT64).Inputs(1, 0);
237            INST(3, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(2);
238        }
239        BASIC_BLOCK(3, 5)
240        {
241            INST(20, Opcode::SaveState).NoVregs();
242            INST(4, Opcode::CallStatic).v0id().InputsAutoType(20);
243        }
244        BASIC_BLOCK(4, 5)
245        {
246            INST(21, Opcode::SaveState).NoVregs();
247            INST(5, Opcode::CallStatic).v0id().InputsAutoType(21);
248        }
249        BASIC_BLOCK(5, 6) {}
250        BASIC_BLOCK(6, -1)
251        {
252            INST(6, Opcode::ReturnVoid);
253        }
254    }
255
256    ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
257
258    auto graph = CreateEmptyGraph();
259    GRAPH(graph)
260    {
261        PARAMETER(0, 0).s64();
262        PARAMETER(1, 1).s64();
263        BASIC_BLOCK(2, 3, 4)
264        {
265            INST(2, Opcode::Compare).b().CC(CC_LE).SrcType(DataType::Type::INT64).Inputs(1, 0);
266            INST(3, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(2);
267        }
268        BASIC_BLOCK(3, 6)
269        {
270            INST(20, Opcode::SaveState).NoVregs();
271            INST(4, Opcode::CallStatic).v0id().InputsAutoType(20);
272        }
273        BASIC_BLOCK(4, 6)
274        {
275            INST(21, Opcode::SaveState).NoVregs();
276            INST(5, Opcode::CallStatic).v0id().InputsAutoType(21);
277        }
278        BASIC_BLOCK(6, -1)
279        {
280            INST(6, Opcode::ReturnVoid);
281        }
282    }
283    ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
284}
285
286TEST_F(CleanupTest, TwoPredecessorsPhi)
287{
288    GRAPH(GetGraph())
289    {
290        PARAMETER(0, 0).s64();
291        PARAMETER(1, 1).s64();
292        BASIC_BLOCK(2, 3, 7)
293        {
294            INST(2, Opcode::Compare).b().CC(CC_LE).SrcType(DataType::Type::INT64).Inputs(1, 0);
295            INST(3, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(2);
296        }
297        BASIC_BLOCK(3, 4, 5)
298        {
299            INST(4, Opcode::Add).s64().Inputs(0, 1);
300            INST(5, Opcode::Compare).b().CC(CC_LE).SrcType(DataType::Type::INT64).Inputs(1, 0);
301            INST(6, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(5);
302        }
303        BASIC_BLOCK(4, 6)
304        {
305            INST(20, Opcode::SaveState).NoVregs();
306            INST(7, Opcode::CallStatic).v0id().InputsAutoType(20);
307        }
308        BASIC_BLOCK(5, 6)
309        {
310            INST(21, Opcode::SaveState).NoVregs();
311            INST(8, Opcode::CallStatic).v0id().InputsAutoType(21);
312        }
313        BASIC_BLOCK(6, 7) {}
314        BASIC_BLOCK(7, -1)
315        {
316            INST(9, Opcode::Phi).s64().Inputs({{2, 1}, {6, 4}});
317            INST(10, Opcode::Return).s64().Inputs(9);
318        }
319    }
320
321    ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
322
323    auto graph = CreateEmptyGraph();
324    GRAPH(graph)
325    {
326        PARAMETER(0, 0).s64();
327        PARAMETER(1, 1).s64();
328        BASIC_BLOCK(2, 3, 7)
329        {
330            INST(2, Opcode::Compare).b().CC(CC_LE).SrcType(DataType::Type::INT64).Inputs(1, 0);
331            INST(3, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(2);
332        }
333        BASIC_BLOCK(3, 4, 5)
334        {
335            INST(4, Opcode::Add).s64().Inputs(0, 1);
336            INST(5, Opcode::Compare).b().CC(CC_LE).SrcType(DataType::Type::INT64).Inputs(1, 0);
337            INST(6, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(5);
338        }
339        BASIC_BLOCK(4, 7)
340        {
341            INST(20, Opcode::SaveState).NoVregs();
342            INST(7, Opcode::CallStatic).v0id().InputsAutoType(20);
343        }
344        BASIC_BLOCK(5, 7)
345        {
346            INST(21, Opcode::SaveState).NoVregs();
347            INST(8, Opcode::CallStatic).v0id().InputsAutoType(21);
348        }
349        BASIC_BLOCK(7, -1)
350        {
351            INST(9, Opcode::Phi).s64().Inputs({{2, 1}, {4, 4}, {5, 4}});
352            INST(10, Opcode::Return).s64().Inputs(9);
353        }
354    }
355    ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
356}
357
358TEST_F(CleanupTest, TriangleNoPhi)
359{
360    GRAPH(GetGraph())
361    {
362        PARAMETER(0, 0).s64();
363        PARAMETER(1, 1).s64();
364        BASIC_BLOCK(2, 3, 4)
365        {
366            INST(2, Opcode::Compare).b().CC(CC_LT).SrcType(DataType::Type::INT64).Inputs(1, 0);
367            INST(3, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(2);
368        }
369        BASIC_BLOCK(3, 4) {}
370        BASIC_BLOCK(4, -1)
371        {
372            INST(4, Opcode::ReturnVoid);
373        }
374    }
375
376    ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
377
378    auto graph = CreateEmptyGraph();
379    GRAPH(graph)
380    {
381        BASIC_BLOCK(4, -1)
382        {
383            INST(4, Opcode::ReturnVoid);
384        }
385    }
386    ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
387}
388
389TEST_F(CleanupTest, DiamondSamePhi)
390{
391    GRAPH(GetGraph())
392    {
393        PARAMETER(0, 0).s64();
394        PARAMETER(1, 1).s64();
395        BASIC_BLOCK(2, 3, 4)
396        {
397            INST(2, Opcode::Compare).b().CC(CC_LT).SrcType(DataType::Type::INT64).Inputs(1, 0);
398            INST(3, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(2);
399        }
400        BASIC_BLOCK(3, 5) {}
401        BASIC_BLOCK(4, 5) {}
402        BASIC_BLOCK(5, -1)
403        {
404            INST(4, Opcode::Phi).s64().Inputs({{3, 1}, {4, 1}});
405            INST(5, Opcode::Return).s64().Inputs(4);
406        }
407    }
408
409    ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
410
411    auto graph = CreateEmptyGraph();
412    GRAPH(graph)
413    {
414        PARAMETER(1, 1).s64();
415        BASIC_BLOCK(5, -1)
416        {
417            INST(5, Opcode::Return).s64().Inputs(1);
418        }
419    }
420    ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
421}
422
423TEST_F(CleanupTest, JointTriangle)
424{
425    GRAPH(GetGraph())
426    {
427        PARAMETER(0, 0).s64();
428        PARAMETER(1, 1).s64();
429        BASIC_BLOCK(2, 3, 5)
430        {
431            INST(2, Opcode::Compare).b().CC(CC_LE).SrcType(DataType::Type::INT64).Inputs(1, 0);
432            INST(3, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(2);
433        }
434        BASIC_BLOCK(3, 4, 5)
435        {
436            INST(4, Opcode::Compare).b().CC(CC_LE).SrcType(DataType::Type::INT64).Inputs(1, 0);
437            INST(5, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(4);
438        }
439        BASIC_BLOCK(4, 5) {}
440        BASIC_BLOCK(5, -1)
441        {
442            INST(6, Opcode::Phi).s64().Inputs({{2, 1}, {3, 0}, {4, 0}});
443            INST(7, Opcode::Return).s64().Inputs(6);
444        }
445    }
446
447    ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
448
449    auto graph = CreateEmptyGraph();
450    GRAPH(graph)
451    {
452        PARAMETER(0, 0).s64();
453        PARAMETER(1, 1).s64();
454        BASIC_BLOCK(2, 3, 5)
455        {
456            INST(2, Opcode::Compare).b().CC(CC_LE).SrcType(DataType::Type::INT64).Inputs(1, 0);
457            INST(3, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(2);
458        }
459        BASIC_BLOCK(3, 5) {}
460        BASIC_BLOCK(5, -1)
461        {
462            INST(6, Opcode::Phi).s64().Inputs({{2, 1}, {3, 0}});
463            INST(7, Opcode::Return).s64().Inputs(6);
464        }
465    }
466    ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
467}
468
469TEST_F(CleanupTest, TriangleProhibited)
470{
471    GRAPH(GetGraph())
472    {
473        PARAMETER(0, 0).s64();
474        PARAMETER(1, 1).s64();
475        BASIC_BLOCK(2, 3, 4)
476        {
477            INST(2, Opcode::Compare).b().CC(CC_LT).SrcType(DataType::Type::INT64).Inputs(1, 0);
478            INST(3, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(2);
479        }
480        BASIC_BLOCK(3, 4) {}
481        BASIC_BLOCK(4, -1)
482        {
483            INST(4, Opcode::Phi).s64().Inputs({{2, 1}, {3, 0}});
484            INST(5, Opcode::Return).s64().Inputs(4);
485        }
486    }
487
488    ASSERT_FALSE(GetGraph()->RunPass<Cleanup>());
489
490    auto graph = CreateEmptyGraph();
491    GRAPH(graph)
492    {
493        PARAMETER(0, 0).s64();
494        PARAMETER(1, 1).s64();
495        BASIC_BLOCK(2, 3, 4)
496        {
497            INST(2, Opcode::Compare).b().CC(CC_LT).SrcType(DataType::Type::INT64).Inputs(1, 0);
498            INST(3, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(2);
499        }
500        BASIC_BLOCK(3, 4) {}
501        BASIC_BLOCK(4, -1)
502        {
503            INST(4, Opcode::Phi).s64().Inputs({{2, 1}, {3, 0}});
504            INST(5, Opcode::Return).s64().Inputs(4);
505        }
506    }
507    ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
508}
509
510TEST_F(CleanupTest, InfiniteLoop)
511{
512    GRAPH(GetGraph())
513    {
514        PARAMETER(0, 0).s64();
515        PARAMETER(1, 1).s64();
516        BASIC_BLOCK(2, 3, 4)
517        {
518            INST(2, Opcode::Compare).b().CC(CC_LT).SrcType(DataType::Type::INT64).Inputs(1, 0);
519            INST(3, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(2);
520        }
521        BASIC_BLOCK(3, 3) {}
522        BASIC_BLOCK(4, -1)
523        {
524            INST(4, Opcode::ReturnVoid);
525        }
526    }
527
528    ASSERT_FALSE(GetGraph()->RunPass<Cleanup>());
529
530    auto graph = CreateEmptyGraph();
531    GRAPH(graph)
532    {
533        PARAMETER(0, 0).s64();
534        PARAMETER(1, 1).s64();
535        BASIC_BLOCK(2, 3, 4)
536        {
537            INST(2, Opcode::Compare).b().CC(CC_LT).SrcType(DataType::Type::INT64).Inputs(1, 0);
538            INST(3, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(2);
539        }
540        BASIC_BLOCK(3, 3) {}
541        BASIC_BLOCK(4, -1)
542        {
543            INST(4, Opcode::ReturnVoid);
544        }
545    }
546    ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
547}
548
549TEST_F(CleanupTest, JointDiamond)
550{
551    GRAPH(GetGraph())
552    {
553        PARAMETER(0, 0).u64();
554        PARAMETER(1, 1).u64();
555        BASIC_BLOCK(2, 3, 6)
556        {
557            INST(2, Opcode::If).SrcType(DataType::UINT64).CC(CC_GE).Inputs(0, 1);
558        }
559        BASIC_BLOCK(3, 4, 5)
560        {
561            INST(3, Opcode::Mul).u64().Inputs(0, 0);
562            INST(4, Opcode::Mul).u64().Inputs(1, 1);
563            INST(5, Opcode::If).SrcType(DataType::UINT64).CC(CC_GT).Inputs(4, 1);
564        }
565        BASIC_BLOCK(4, 7) {}
566        BASIC_BLOCK(5, 7) {}
567        BASIC_BLOCK(6, 7)
568        {
569            INST(20, Opcode::SaveState).NoVregs();
570            INST(6, Opcode::CallStatic).v0id().InputsAutoType(20);
571        }
572        BASIC_BLOCK(7, -1)
573        {
574            INST(7, Opcode::Phi).u64().Inputs({{6, 0}, {4, 3}, {5, 3}});
575            INST(8, Opcode::Return).u64().Inputs(7);
576        }
577    }
578
579    ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
580
581    auto graph = CreateEmptyGraph();
582    GRAPH(graph)
583    {
584        PARAMETER(0, 0).u64();
585        PARAMETER(1, 1).u64();
586        BASIC_BLOCK(2, 3, 6)
587        {
588            INST(2, Opcode::If).SrcType(DataType::UINT64).CC(CC_GE).Inputs(0, 1);
589        }
590        BASIC_BLOCK(3, 7)
591        {
592            INST(3, Opcode::Mul).u64().Inputs(0, 0);
593        }
594        BASIC_BLOCK(6, 7)
595        {
596            INST(20, Opcode::SaveState).NoVregs();
597            INST(6, Opcode::CallStatic).v0id().InputsAutoType(20);
598        }
599        BASIC_BLOCK(7, -1)
600        {
601            INST(7, Opcode::Phi).u64().Inputs({{6, 0}, {3, 3}});
602            INST(8, Opcode::Return).u64().Inputs(7);
603        }
604    }
605    ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
606}
607
608TEST_F(CleanupTest, JoinLoopBackEdgeWithMultiPreds)
609{
610    GRAPH(GetGraph())
611    {
612        PARAMETER(0, 0).u64();
613        PARAMETER(1, 1).u64();
614        PARAMETER(2, 2).u64();
615        BASIC_BLOCK(2, 3, 7)
616        {
617            INST(4, Opcode::Phi).u64().Inputs(0, 9);
618            INST(5, Opcode::If).SrcType(DataType::UINT64).CC(CC_LE).Inputs(4, 1);
619        }
620        BASIC_BLOCK(3, 4, 5)
621        {
622            INST(6, Opcode::If).SrcType(DataType::UINT64).CC(CC_LE).Inputs(4, 2);
623        }
624        BASIC_BLOCK(4, 6)
625        {
626            INST(7, Opcode::Mul).u64().Inputs(4, 1);
627        }
628        BASIC_BLOCK(5, 6)
629        {
630            INST(8, Opcode::Mul).u64().Inputs(4, 2);
631        }
632        BASIC_BLOCK(6, 2)
633        {
634            INST(9, Opcode::Phi).u64().Inputs(7, 8);
635            // loop back-edge
636        }
637        BASIC_BLOCK(7, -1)
638        {
639            INST(11, Opcode::Return).u64().Inputs(4);
640        }
641    }
642
643    ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
644    ASSERT_TRUE(GetGraph()->GetAnalysis<LoopAnalyzer>().IsValid());
645
646    auto loop = BB(2).GetLoop();
647    ASSERT_EQ(loop->GetHeader(), &BB(2));
648    ASSERT_EQ(loop->GetBackEdges().size(), 2);
649    ASSERT_TRUE(loop->HasBackEdge(&BB(4)));
650    ASSERT_TRUE(loop->HasBackEdge(&BB(5)));
651}
652
653TEST_F(CleanupTest, DiamondBecomeEmpty)
654{
655    GRAPH(GetGraph())
656    {
657        PARAMETER(0, 0).b();
658        BASIC_BLOCK(2, 3, 4)
659        {
660            INST(1, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(0);
661        }
662        BASIC_BLOCK(3, 5) {}
663        BASIC_BLOCK(4, 5) {}
664        BASIC_BLOCK(5, -1)
665        {
666            INST(2, Opcode::ReturnVoid);
667        }
668    }
669
670    ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
671
672    auto graph = CreateEmptyGraph();
673    GRAPH(graph)
674    {
675        BASIC_BLOCK(5, -1)
676        {
677            INST(2, Opcode::ReturnVoid);
678        }
679    }
680    ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
681}
682
683TEST_F(CleanupTest, CarefulDCE)
684{
685    GRAPH(GetGraph())
686    {
687        BASIC_BLOCK(2, 3, 4)
688        {
689            INST(20, Opcode::SaveState).NoVregs();
690            INST(0, Opcode::CallStatic).b().InputsAutoType(20);
691            INST(1, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(0);
692        }
693        BASIC_BLOCK(3, 4) {}
694        BASIC_BLOCK(4, -1)
695        {
696            INST(2, Opcode::ReturnVoid);
697        }
698    }
699
700    ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
701
702    auto graph = CreateEmptyGraph();
703    GRAPH(graph)
704    {
705        BASIC_BLOCK(2, -1)
706        {
707            INST(20, Opcode::SaveState).NoVregs();
708            INST(0, Opcode::CallStatic).b().InputsAutoType(20);
709            INST(1, Opcode::ReturnVoid);
710        }
711    }
712    ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
713}
714
715TEST_F(CleanupTest, CarefulDCE2)
716{
717    GRAPH(GetGraph())
718    {
719        PARAMETER(0, 0).u64();
720        PARAMETER(1, 1).u64();
721        BASIC_BLOCK(2, 3, 40)
722        {
723            INST(2, Opcode::If).SrcType(DataType::UINT64).CC(CC_GT).Inputs(0, 1);
724        }
725        BASIC_BLOCK(40, 5) {}
726        BASIC_BLOCK(3, 5) {}
727        BASIC_BLOCK(5, 6, 7)
728        {
729            INST(3, Opcode::Phi).u64().Inputs({{40, 0}, {3, 1}});
730            INST(4, Opcode::IfImm).SrcType(DataType::UINT64).CC(CC_NE).Imm(0).Inputs(3);
731        }
732        BASIC_BLOCK(6, 7) {}
733        BASIC_BLOCK(7, -1)
734        {
735            INST(5, Opcode::ReturnVoid);
736        }
737    }
738
739    ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
740
741    auto graph = CreateEmptyGraph();
742    GRAPH(graph)
743    {
744        BASIC_BLOCK(2, -1)
745        {
746            INST(0, Opcode::ReturnVoid);
747        }
748    }
749    ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
750}
751
752TEST_F(CleanupTest, Delete)
753{
754    GRAPH(GetGraph())
755    {
756        CONSTANT(0, 12);
757        CONSTANT(1, 13);
758
759        BASIC_BLOCK(2, -1)
760        {
761            INST(2, Opcode::Neg).u64().Inputs(1);
762            INST(3, Opcode::Add).u64().Inputs(0, 2);
763            INST(4, Opcode::Return).u64().Inputs(2);
764        }
765    }
766
767    // Delete Insts 0 and 3
768    ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
769
770    ASSERT_TRUE(CheckInputs(INS(2), {1}));
771    ASSERT_TRUE(CheckInputs(INS(4), {2}));
772
773    ASSERT_TRUE(CheckUsers(INS(1), {2}));
774    ASSERT_TRUE(CheckUsers(INS(2), {4}));
775    ASSERT_TRUE(CheckUsers(INS(4), {}));
776}
777
778TEST_F(CleanupTest, NotRemoved)
779{
780    GRAPH(GetGraph())
781    {
782        CONSTANT(0, 11);
783        CONSTANT(1, 12);
784        CONSTANT(2, 13);
785
786        BASIC_BLOCK(2, -1)
787        {
788            INST(3, Opcode::Add).u64().Inputs(0, 1);
789            INST(4, Opcode::Neg).u64().Inputs(3);
790            INST(5, Opcode::Sub).u64().Inputs(4, 2);
791            INST(6, Opcode::Return).u64().Inputs(5);
792        }
793    }
794
795    ASSERT_FALSE(GetGraph()->RunPass<Cleanup>());
796
797    ASSERT_TRUE(CheckInputs(INS(3), {0, 1}));
798    ASSERT_TRUE(CheckInputs(INS(4), {3}));
799    ASSERT_TRUE(CheckInputs(INS(5), {4, 2}));
800    ASSERT_TRUE(CheckInputs(INS(6), {5}));
801
802    ASSERT_TRUE(CheckUsers(INS(0), {3}));
803    ASSERT_TRUE(CheckUsers(INS(1), {3}));
804    ASSERT_TRUE(CheckUsers(INS(2), {5}));
805    ASSERT_TRUE(CheckUsers(INS(3), {4}));
806    ASSERT_TRUE(CheckUsers(INS(4), {5}));
807    ASSERT_TRUE(CheckUsers(INS(5), {6}));
808}
809
810TEST_F(CleanupTest, Loop)
811{
812    GRAPH(GetGraph())
813    {
814        CONSTANT(0, 0);
815        CONSTANT(1, 1);
816        BASIC_BLOCK(2, 3)
817        {
818            INST(2, Opcode::Phi).u64().Inputs(0, 5);
819            INST(3, Opcode::Phi).u64().Inputs(1, 6);
820        }
821        BASIC_BLOCK(3, 4, 5)
822        {
823            INST(4, Opcode::Add).u64().Inputs(2, 3);
824            INST(11, Opcode::Compare).b().SrcType(DataType::Type::INT64).Inputs(0, 1);
825            INST(12, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(11);
826        }
827        BASIC_BLOCK(4, 2)
828        {
829            INST(5, Opcode::Neg).u64().Inputs(3);
830            INST(6, Opcode::Neg).u64().Inputs(4);
831            // Must be removed
832            INST(7, Opcode::Add).u64().Inputs(5, 6);
833        }
834        BASIC_BLOCK(5, -1)
835        {
836            // Unused instruction
837            INST(8, Opcode::Neg).u64().Inputs(4);
838            INST(9, Opcode::Return).u64().Inputs(4);
839        }
840    }
841
842    // Delete Insts 7 and 8
843    ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
844
845    ASSERT_TRUE(CheckInputs(INS(2), {0, 5}));
846    ASSERT_TRUE(CheckInputs(INS(3), {1, 6}));
847    ASSERT_TRUE(CheckInputs(INS(4), {2, 3}));
848    ASSERT_TRUE(CheckInputs(INS(5), {3}));
849    ASSERT_TRUE(CheckInputs(INS(6), {4}));
850    ASSERT_TRUE(CheckInputs(INS(9), {4}));
851
852    ASSERT_TRUE(CheckUsers(INS(0), {2, 11}));
853    ASSERT_TRUE(CheckUsers(INS(1), {3, 11}));
854    ASSERT_TRUE(CheckUsers(INS(2), {4}));
855    ASSERT_TRUE(CheckUsers(INS(3), {4, 5}));
856    ASSERT_TRUE(CheckUsers(INS(4), {6, 9}));
857    ASSERT_TRUE(CheckUsers(INS(5), {2}));
858    ASSERT_TRUE(CheckUsers(INS(6), {3}));
859}
860
861TEST_F(CleanupTest, Loop1)
862{
863    GRAPH(GetGraph())
864    {
865        CONSTANT(0, 0);
866        CONSTANT(1, 1);
867
868        BASIC_BLOCK(2, 2, 3)
869        {
870            // Unused instructions
871            INST(2, Opcode::Phi).u64().Inputs(1, 3);
872            INST(3, Opcode::Add).u64().Inputs(2, 1);
873            INST(6, Opcode::Compare).b().SrcType(DataType::Type::INT64).Inputs(0, 0);
874            INST(7, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(6);
875        }
876        BASIC_BLOCK(3, -1)
877        {
878            // Unused instruction
879            INST(4, Opcode::Neg).u64().Inputs(0);
880            INST(5, Opcode::Return).u64().Inputs(4);
881        }
882    }
883
884    // Delete Insts 1, 2 and 3
885    ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
886
887    ASSERT_EQ(INS(0).GetNext(), nullptr);
888    ASSERT_FALSE(BB(2).IsEmpty());
889}
890
891/*
892 * Test Graph:
893 *                        [0]
894 *                         |
895 *                         v
896 *                /-------[2]-------\
897 *                |                 |
898 *                v                 v
899 *               [3]               [4]
900 *             /     \           /     \
901 *            v       \         /       |
902 *  [8]<---->[7]       \->[5]<-/        |
903 *            |             |           |
904 *            |             \--->[6]<---/
905 *            |                   |
906 *            \---------->[9]<----/
907 *                         |
908 *                         v
909 *                        [1]
910 */
911
912TEST_F(CleanupTest, PhiInputs1)
913{
914    GRAPH(GetGraph())
915    {
916        CONSTANT(0, 0);
917        CONSTANT(18, 2);
918        CONSTANT(1, 1);
919        BASIC_BLOCK(2, 3, 4)
920        {
921            INST(2, Opcode::Compare).b().SrcType(DataType::Type::INT64).Inputs(18, 1);
922            INST(3, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(2);
923        }
924        BASIC_BLOCK(3, 7, 5)
925        {
926            INST(4, Opcode::Compare).b().SrcType(DataType::Type::INT64).Inputs(18, 1);
927            INST(5, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(4);
928        }
929        BASIC_BLOCK(4, 5, 6)
930        {
931            INST(6, Opcode::Compare).b().SrcType(DataType::Type::INT64).Inputs(18, 1);
932            INST(7, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(6);
933        }
934
935        BASIC_BLOCK(5, 6)
936        {
937            INST(8, Opcode::Phi).u64().Inputs({{4, 0}, {3, 0}});
938        }
939        BASIC_BLOCK(6, 9)
940        {
941            INST(10, Opcode::Phi).u64().Inputs({{4, 0}, {5, 8}});
942        }
943        BASIC_BLOCK(7, 8, 9)
944        {
945            INST(12, Opcode::Phi).u64().Inputs({{8, 12}, {3, 0}});
946            INST(13, Opcode::Compare).b().SrcType(DataType::Type::INT64).Inputs(18, 1);
947            INST(14, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(13);
948        }
949        BASIC_BLOCK(8, 7) {}
950        BASIC_BLOCK(9, -1)
951        {
952            INST(16, Opcode::Phi).u64().Inputs({{6, 10}, {7, 12}});
953            INST(17, Opcode::Return).u64().Inputs(16);
954        }
955    }
956
957    // Delete all phi instructions
958    ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
959
960    ASSERT_TRUE(CheckInputs(INS(17), {0}));
961    ASSERT_TRUE(CheckUsers(INS(0), {17}));
962}
963
964/*
965 * Test Graph:
966 *                                   [0]
967 *                                    |
968 *                                    v
969 *                         /---------[2]---------\
970 *                         |                     |
971 *                         v                     v
972 *                        [3]                   [4]
973 *                         |                     |
974 *                         \-------->[5]<--------/
975 *                                    |
976 *                                    |->[6]<----\
977 *                                    |   |      |
978 *                                    |   v      |
979 *                                    \->[7]-----/
980 *                                        |
981 *                                        v
982 *                                       [8]
983 *                                        |
984 *                                        v
985 *                                       [1]
986 */
987
988TEST_F(CleanupTest, PhiInputs2)
989{
990    GRAPH(GetGraph())
991    {
992        CONSTANT(0, 0);
993        CONSTANT(1, 1);
994        CONSTANT(6, 2);
995        CONSTANT(7, 3);
996        BASIC_BLOCK(2, 3, 4)
997        {
998            INST(8, Opcode::Compare).b().SrcType(DataType::Type::INT64).Inputs(6, 7);
999            INST(9, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(8);
1000        }
1001        BASIC_BLOCK(3, 5) {}
1002        BASIC_BLOCK(4, 5) {}
1003        BASIC_BLOCK(5, 6, 7)
1004        {
1005            INST(2, Opcode::Phi).u64().Inputs(0, 1);
1006            INST(12, Opcode::Compare).b().SrcType(DataType::Type::INT64).Inputs(6, 7);
1007            INST(13, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(12);
1008        }
1009        BASIC_BLOCK(6, 7)
1010        {
1011            INST(3, Opcode::Phi).u64().Inputs({{7, 4}, {5, 2}});
1012        }
1013        BASIC_BLOCK(7, 6, 8)
1014        {
1015            INST(4, Opcode::Phi).u64().Inputs({{6, 3}, {5, 2}});
1016            INST(15, Opcode::Compare).b().SrcType(DataType::Type::INT64).Inputs(6, 7);
1017            INST(16, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(15);
1018        }
1019        BASIC_BLOCK(8, -1)
1020        {
1021            INST(5, Opcode::Return).u64().Inputs(4);
1022        }
1023    }
1024
1025    // Delete 3 and 4 phi (replace with v2p in return)
1026    ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
1027
1028    ASSERT_TRUE(CheckInputs(INS(2), {0, 1}));
1029    ASSERT_TRUE(CheckInputs(INS(5), {2}));
1030
1031    ASSERT_TRUE(CheckUsers(INS(0), {2}));
1032    ASSERT_TRUE(CheckUsers(INS(1), {2}));
1033    ASSERT_TRUE(CheckUsers(INS(2), {5}));
1034
1035    auto graph = CreateEmptyGraph();
1036    GRAPH(graph)
1037    {
1038        CONSTANT(0, 0);
1039        CONSTANT(1, 1);
1040        CONSTANT(6, 2);
1041        CONSTANT(7, 3);
1042        BASIC_BLOCK(2, 5, 4)
1043        {
1044            INST(8, Opcode::Compare).b().SrcType(DataType::Type::INT64).Inputs(6, 7);
1045            INST(9, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(8);
1046        }
1047        BASIC_BLOCK(4, 5) {}
1048        BASIC_BLOCK(5, 7)
1049        {
1050            INST(2, Opcode::Phi).u64().Inputs(0, 1);
1051        }
1052        BASIC_BLOCK(7, 7, 8)
1053        {
1054            INST(15, Opcode::Compare).b().SrcType(DataType::Type::INT64).Inputs(6, 7);
1055            INST(16, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(15);
1056        }
1057        BASIC_BLOCK(8, -1)
1058        {
1059            INST(5, Opcode::Return).u64().Inputs(2);
1060        }
1061    }
1062    ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
1063}
1064
1065TEST_F(CleanupTest, NullPtr)
1066{
1067    GRAPH(GetGraph())
1068    {
1069        CONSTANT(0, 0);
1070        CONSTANT(1, nullptr);
1071
1072        BASIC_BLOCK(2, -1)
1073        {
1074            INST(2, Opcode::Return).u64().Inputs(0);
1075        }
1076    }
1077
1078    ASSERT_TRUE(GetGraph()->HasNullPtrInst());
1079    // Delete NullPtr
1080    ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
1081    ASSERT_FALSE(GetGraph()->HasNullPtrInst());
1082}
1083
1084TEST_F(CleanupTest, JustReturnLeft)
1085{
1086    GRAPH(GetGraph())
1087    {
1088        PARAMETER(0, 0).u64();
1089        CONSTANT(1, 1);
1090        CONSTANT(2, 2);
1091        CONSTANT(3, 3);
1092        CONSTANT(4, 4);
1093        BASIC_BLOCK(2, 3, 4)
1094        {
1095            INST(5, Opcode::Add).u64().Inputs(1, 4);
1096            INST(6, Opcode::Add).u64().Inputs(2, 3);
1097            INST(7, Opcode::Compare).b().Inputs(0, 3);
1098            INST(8, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(7);
1099        }
1100        BASIC_BLOCK(3, 4) {}
1101        BASIC_BLOCK(4, -1)
1102        {
1103            INST(9, Opcode::Phi).u64().Inputs({{2, 6}, {3, 5}});
1104            INST(10, Opcode::Return).u64().Inputs(0);
1105        }
1106    }
1107
1108    ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
1109
1110    auto graph = CreateEmptyGraph();
1111    GRAPH(graph)
1112    {
1113        PARAMETER(0, 0).u64();
1114        BASIC_BLOCK(2, -1)
1115        {
1116            INST(10, Opcode::Return).u64().Inputs(0);
1117        }
1118    }
1119    ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
1120}
1121
1122TEST_F(CleanupTest, RemovingPhiFromTheSameBlock)
1123{
1124    auto graph = CreateEmptyGraph();
1125    GRAPH(graph)
1126    {
1127        PARAMETER(0, 0).u64();
1128        PARAMETER(1, 1).u64();
1129        CONSTANT(2, 1);
1130        BASIC_BLOCK(2, 2, 3)
1131        {
1132            INST(5, Opcode::Phi).u64().Inputs(1, 6);
1133            INST(6, Opcode::Phi).u64().Inputs(0, 6);
1134            INST(7, Opcode::Phi).u64().Inputs(0, 8);
1135            INST(8, Opcode::Add).u64().Inputs(7, 2);
1136            INST(9, Opcode::Compare).b().CC(CC_NE).Inputs(8, 1);
1137            INST(10, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(9);
1138        }
1139        BASIC_BLOCK(3, -1)
1140        {
1141            INST(11, Opcode::Add).u64().Inputs(5, 6);
1142            INST(12, Opcode::Return).u64().Inputs(11);
1143        }
1144    }
1145    ASSERT_TRUE(graph->RunPass<Cleanup>());
1146}
1147
1148TEST_F(CleanupTest, CallDiscardReturnValue)
1149{
1150    GRAPH(GetGraph())
1151    {
1152        BASIC_BLOCK(2, -1)
1153        {
1154            INST(20, Opcode::SaveState).NoVregs();
1155            INST(0, Opcode::CallStatic).s32().InputsAutoType(20);
1156            INST(1, Opcode::ReturnVoid).v0id();
1157        }
1158    }
1159    ASSERT_FALSE(INS(0).HasUsers());
1160    ASSERT_FALSE(GetGraph()->RunPass<Cleanup>());
1161    ASSERT_TRUE(INS(0).GetOpcode() == Opcode::CallStatic);
1162}
1163
1164TEST_F(CleanupTest, CallReturnVoid)
1165{
1166    GRAPH(GetGraph())
1167    {
1168        BASIC_BLOCK(2, -1)
1169        {
1170            INST(20, Opcode::SaveState).NoVregs();
1171            INST(0, Opcode::CallStatic).v0id().InputsAutoType(20);
1172            INST(1, Opcode::ReturnVoid).v0id();
1173        }
1174    }
1175    ASSERT_FALSE(INS(0).HasUsers());
1176    ASSERT_FALSE(GetGraph()->RunPass<Cleanup>());
1177    ASSERT_TRUE(INS(0).GetOpcode() == Opcode::CallStatic);
1178}
1179
1180TEST_F(CleanupTest, StoreObject)
1181{
1182    GRAPH(GetGraph())
1183    {
1184        PARAMETER(0, 0).ref();
1185        PARAMETER(1, 1).s32();
1186
1187        BASIC_BLOCK(2, -1)
1188        {
1189            INST(2, Opcode::SaveState).Inputs(0, 1, 1).SrcVregs({0, 1, 2});
1190            INST(3, Opcode::NullCheck).ref().Inputs(0, 2);
1191            INST(4, Opcode::StoreObject).s32().Inputs(3, 1);
1192            INST(5, Opcode::ReturnVoid).v0id();
1193        }
1194    }
1195    ASSERT_FALSE(INS(4).HasUsers());
1196    ASSERT_FALSE(GetGraph()->RunPass<Cleanup>());
1197    ASSERT_TRUE(INS(4).GetOpcode() == Opcode::StoreObject);
1198}
1199
1200TEST_F(CleanupTest, OneBlock)
1201{
1202    GRAPH(GetGraph())
1203    {
1204        BASIC_BLOCK(2, -1)
1205        {
1206            INST(0, Opcode::ReturnVoid);
1207        }
1208    }
1209
1210    ASSERT_FALSE(GetGraph()->RunPass<Cleanup>());
1211
1212    auto graph = CreateEmptyGraph();
1213    GRAPH(graph)
1214    {
1215        BASIC_BLOCK(2, -1)
1216        {
1217            INST(0, Opcode::ReturnVoid);
1218        }
1219    }
1220    ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
1221}
1222
1223TEST_F(CleanupTest, TwoBlocks)
1224{
1225    GRAPH(GetGraph())
1226    {
1227        CONSTANT(0, 12);
1228        CONSTANT(1, 13);
1229
1230        BASIC_BLOCK(2, 3)
1231        {
1232            INST(2, Opcode::Neg).u64().Inputs(1);
1233            INST(3, Opcode::Add).u64().Inputs(0, 2);
1234        }
1235
1236        BASIC_BLOCK(3, -1)
1237        {
1238            INST(4, Opcode::Add).u64().Inputs(2, 3);
1239            INST(5, Opcode::Return).u64().Inputs(4);
1240        }
1241    }
1242
1243    ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
1244
1245    auto graph = CreateEmptyGraph();
1246    GRAPH(graph)
1247    {
1248        CONSTANT(0, 12);
1249        CONSTANT(1, 13);
1250
1251        BASIC_BLOCK(2, -1)
1252        {
1253            INST(2, Opcode::Neg).u64().Inputs(1);
1254            INST(3, Opcode::Add).u64().Inputs(0, 2);
1255            INST(4, Opcode::Add).u64().Inputs(2, 3);
1256            INST(5, Opcode::Return).u64().Inputs(4);
1257        }
1258    }
1259    ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
1260}
1261
1262TEST_F(CleanupTest, SameBlockPhiTwice)
1263{
1264    GRAPH(GetGraph())
1265    {
1266        CONSTANT(0, 12).s64();
1267        CONSTANT(1, 13).s64();
1268
1269        BASIC_BLOCK(2, 3, 4)
1270        {
1271            INST(2, Opcode::Compare).b().CC(CC_LT).SrcType(DataType::Type::INT64).Inputs(0, 1);
1272            INST(3, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(2);
1273        }
1274
1275        BASIC_BLOCK(3, 5)
1276        {
1277            INST(4, Opcode::Neg).u64().Inputs(0);
1278            INST(5, Opcode::Neg).u64().Inputs(1);
1279        }
1280
1281        BASIC_BLOCK(4, 5)
1282        {
1283            INST(7, Opcode::Neg).u64().Inputs(1);
1284            INST(8, Opcode::Neg).u64().Inputs(0);
1285        }
1286
1287        BASIC_BLOCK(5, 6)
1288        {
1289            INST(10, Opcode::Phi).u64().Inputs({{3, 4}, {4, 7}, {6, 15}});
1290            INST(11, Opcode::Phi).u64().Inputs({{3, 5}, {4, 8}, {6, 16}});
1291            INST(12, Opcode::Neg).u64().Inputs(10);
1292            INST(13, Opcode::Add).u64().Inputs(10, 11);
1293        }
1294
1295        BASIC_BLOCK(6, 5, -1)
1296        {
1297            INST(15, Opcode::Add).u64().Inputs(0, 1);
1298            INST(16, Opcode::Neg).u64().Inputs(0);
1299            INST(17, Opcode::Compare).b().CC(CC_LT).SrcType(DataType::Type::INT64).Inputs(1, 0);
1300            INST(18, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(17);
1301        }
1302    }
1303
1304    ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
1305
1306    auto graph = CreateEmptyGraph();
1307    GRAPH(graph)
1308    {
1309        CONSTANT(0, 12).s64();
1310        CONSTANT(1, 13).s64();
1311
1312        BASIC_BLOCK(7, 6) {}
1313
1314        BASIC_BLOCK(6, 6, -1)
1315        {
1316            INST(17, Opcode::Compare).b().CC(CC_LT).SrcType(DataType::Type::INT64).Inputs(1, 0);
1317            INST(18, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(17);
1318        }
1319    }
1320    ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
1321}
1322
1323TEST_F(CleanupTest, TwoBlocksLoop)
1324{
1325    GRAPH(GetGraph())
1326    {
1327        CONSTANT(0, 12).s64();
1328        CONSTANT(1, 13).s64();
1329
1330        BASIC_BLOCK(2, 3, 4)
1331        {
1332            INST(2, Opcode::Compare).b().CC(CC_LT).SrcType(DataType::Type::INT64).Inputs(0, 1);
1333            INST(3, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(2);
1334        }
1335
1336        BASIC_BLOCK(3, 5)
1337        {
1338            INST(4, Opcode::Neg).u64().Inputs(0);
1339            INST(5, Opcode::Neg).u64().Inputs(1);
1340        }
1341
1342        BASIC_BLOCK(4, 5)
1343        {
1344            INST(7, Opcode::Neg).u64().Inputs(1);
1345            INST(8, Opcode::Neg).u64().Inputs(0);
1346        }
1347
1348        BASIC_BLOCK(5, 6)
1349        {
1350            INST(10, Opcode::Phi).u64().Inputs({{3, 4}, {4, 7}, {6, 15}});
1351            INST(11, Opcode::Phi).u64().Inputs({{3, 5}, {4, 8}, {6, 16}});
1352            INST(12, Opcode::Neg).u64().Inputs(10);
1353            INST(13, Opcode::Add).u64().Inputs(10, 11);
1354        }
1355
1356        BASIC_BLOCK(6, 5, -1)
1357        {
1358            INST(15, Opcode::Add).u64().Inputs(12, 13);
1359            INST(16, Opcode::Neg).u64().Inputs(12);
1360            INST(17, Opcode::Compare).b().CC(CC_LT).SrcType(DataType::Type::UINT64).Inputs(15, 16);
1361            INST(18, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(17);
1362        }
1363    }
1364
1365    ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
1366
1367    auto graph = CreateEmptyGraph();
1368    GRAPH(graph)
1369    {
1370        CONSTANT(0, 12).s64();
1371        CONSTANT(1, 13).s64();
1372
1373        BASIC_BLOCK(2, 3, 4)
1374        {
1375            INST(2, Opcode::Compare).b().CC(CC_LT).SrcType(DataType::Type::INT64).Inputs(0, 1);
1376            INST(3, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(2);
1377        }
1378
1379        BASIC_BLOCK(3, 7)
1380        {
1381            INST(4, Opcode::Neg).u64().Inputs(0);
1382            INST(5, Opcode::Neg).u64().Inputs(1);
1383        }
1384
1385        BASIC_BLOCK(4, 7)
1386        {
1387            INST(7, Opcode::Neg).u64().Inputs(1);
1388            INST(8, Opcode::Neg).u64().Inputs(0);
1389        }
1390
1391        BASIC_BLOCK(7, 5)
1392        {
1393            INST(19, Opcode::Phi).u64().Inputs({{3, 4}, {4, 7}});
1394            INST(20, Opcode::Phi).u64().Inputs({{3, 5}, {4, 8}});
1395        }
1396
1397        BASIC_BLOCK(5, 5, -1)
1398        {
1399            INST(10, Opcode::Phi).u64().Inputs({{7, 19}, {5, 15}});
1400            INST(11, Opcode::Phi).u64().Inputs({{7, 20}, {5, 16}});
1401            INST(12, Opcode::Neg).u64().Inputs(10);
1402            INST(13, Opcode::Add).u64().Inputs(10, 11);
1403            INST(15, Opcode::Add).u64().Inputs(12, 13);
1404            INST(16, Opcode::Neg).u64().Inputs(12);
1405            INST(17, Opcode::Compare).b().CC(CC_LT).SrcType(DataType::Type::UINT64).Inputs(15, 16);
1406            INST(18, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(17);
1407        }
1408    }
1409    ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
1410}
1411
1412TEST_F(CleanupTest, TwoLoopsPreHeader)
1413{
1414    GRAPH(GetGraph())
1415    {
1416        CONSTANT(0, 12).s64();
1417        CONSTANT(1, 13).s64();
1418        PARAMETER(8, 0).b();
1419
1420        BASIC_BLOCK(2, 3)
1421        {
1422            INST(2, Opcode::Neg).u64().Inputs(0);
1423        }
1424
1425        BASIC_BLOCK(3, 4, 5)
1426        {
1427            INST(4, Opcode::Neg).u64().Inputs(0);
1428            INST(9, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(8);
1429        }
1430
1431        BASIC_BLOCK(4, 4, -1)
1432        {
1433            INST(6, Opcode::Compare).b().CC(CC_LT).SrcType(DataType::Type::UINT64).Inputs(2, 1);
1434            INST(7, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(6);
1435        }
1436
1437        BASIC_BLOCK(5, 5, -1)
1438        {
1439            INST(10, Opcode::Compare).b().CC(CC_GT).SrcType(DataType::Type::UINT64).Inputs(4, 2);
1440            INST(11, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(10);
1441        }
1442    }
1443
1444    ASSERT_EQ(&BB(3), BB(4).GetLoop()->GetPreHeader());
1445    ASSERT_EQ(&BB(3), BB(5).GetLoop()->GetPreHeader());
1446    ASSERT_EQ(1U, BB(4).GetLoop()->GetBlocks().size());
1447    ASSERT_EQ(1U, BB(5).GetLoop()->GetBlocks().size());
1448    ASSERT_EQ(4U, BB(4).GetLoop()->GetOuterLoop()->GetBlocks().size());
1449    ASSERT_EQ(4U, BB(5).GetLoop()->GetOuterLoop()->GetBlocks().size());
1450
1451    ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
1452
1453    auto graph = CreateEmptyGraph();
1454    GRAPH(graph)
1455    {
1456        CONSTANT(0, 12).s64();
1457        CONSTANT(1, 13).s64();
1458        PARAMETER(8, 0).b();
1459
1460        BASIC_BLOCK(2, 4, 5)
1461        {
1462            INST(2, Opcode::Neg).u64().Inputs(0);
1463            INST(4, Opcode::Neg).u64().Inputs(0);
1464            INST(9, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(8);
1465        }
1466
1467        BASIC_BLOCK(4, 4, -1)
1468        {
1469            INST(6, Opcode::Compare).b().CC(CC_LT).SrcType(DataType::Type::UINT64).Inputs(2, 1);
1470            INST(7, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(6);
1471        }
1472
1473        BASIC_BLOCK(5, 5, -1)
1474        {
1475            INST(10, Opcode::Compare).b().CC(CC_GT).SrcType(DataType::Type::UINT64).Inputs(4, 2);
1476            INST(11, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(10);
1477        }
1478    }
1479    ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
1480
1481    EXPECT_EQ(&BB(2), BB(4).GetLoop()->GetPreHeader());
1482    EXPECT_EQ(&BB(2), BB(5).GetLoop()->GetPreHeader());
1483    EXPECT_EQ(1U, BB(4).GetLoop()->GetBlocks().size());
1484    EXPECT_EQ(1U, BB(5).GetLoop()->GetBlocks().size());
1485    EXPECT_EQ(3U, BB(4).GetLoop()->GetOuterLoop()->GetBlocks().size());
1486    EXPECT_EQ(3U, BB(5).GetLoop()->GetOuterLoop()->GetBlocks().size());
1487}
1488
1489TEST_F(CleanupTest, LoopBackEdge)
1490{
1491    GRAPH(GetGraph())
1492    {
1493        CONSTANT(0, 12).s64();
1494        CONSTANT(1, 13).s64();
1495
1496        BASIC_BLOCK(2, 3)
1497        {
1498            INST(2, Opcode::Neg).u64().Inputs(0);
1499        }
1500
1501        BASIC_BLOCK(3, 2, -1)
1502        {
1503            INST(4, Opcode::Compare).b().CC(CC_LT).SrcType(DataType::Type::UINT64).Inputs(1, 2);
1504            INST(5, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(4);
1505        }
1506    }
1507
1508    ASSERT_TRUE(BB(3).GetLoop()->HasBackEdge(&BB(3)));
1509    ASSERT_EQ(2U, BB(3).GetLoop()->GetBlocks().size());
1510
1511    ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
1512
1513    auto graph = CreateEmptyGraph();
1514    GRAPH(graph)
1515    {
1516        CONSTANT(0, 12).s64();
1517        CONSTANT(1, 13).s64();
1518
1519        BASIC_BLOCK(2, 2, -1)
1520        {
1521            INST(2, Opcode::Neg).u64().Inputs(0);
1522            INST(4, Opcode::Compare).b().CC(CC_LT).SrcType(DataType::Type::UINT64).Inputs(1, 2);
1523            INST(5, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(4);
1524        }
1525    }
1526    ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
1527
1528    EXPECT_TRUE(BB(2).GetLoop()->HasBackEdge(&BB(2)));
1529    EXPECT_EQ(1U, BB(2).GetLoop()->GetBlocks().size());
1530}
1531
1532TEST_F(CleanupTest, LoopMiddleBlock)
1533{
1534    GRAPH(GetGraph())
1535    {
1536        CONSTANT(0, 12).s64();
1537        CONSTANT(1, 13).s64();
1538
1539        BASIC_BLOCK(2, 3)
1540        {
1541            INST(2, Opcode::Neg).u64().Inputs(0);
1542        }
1543
1544        BASIC_BLOCK(3, 4)
1545        {
1546            INST(4, Opcode::Neg).u64().Inputs(1);
1547        }
1548
1549        BASIC_BLOCK(4, 2, -1)
1550        {
1551            INST(6, Opcode::Compare).b().CC(CC_LT).SrcType(DataType::Type::UINT64).Inputs(2, 4);
1552            INST(7, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(6);
1553        }
1554    }
1555
1556    ASSERT_EQ(3U, BB(2).GetLoop()->GetBlocks().size());
1557    ASSERT_EQ(3U, BB(2).GetLoop()->GetOuterLoop()->GetBlocks().size());
1558
1559    ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
1560
1561    auto graph = CreateEmptyGraph();
1562    GRAPH(graph)
1563    {
1564        CONSTANT(0, 12).s64();
1565        CONSTANT(1, 13).s64();
1566
1567        BASIC_BLOCK(2, 2, -1)
1568        {
1569            INST(2, Opcode::Neg).u64().Inputs(0);
1570            INST(4, Opcode::Neg).u64().Inputs(1);
1571            INST(6, Opcode::Compare).b().CC(CC_LT).SrcType(DataType::Type::UINT64).Inputs(2, 4);
1572            INST(7, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(6);
1573        }
1574    }
1575    ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
1576
1577    EXPECT_EQ(1U, BB(2).GetLoop()->GetBlocks().size());
1578    EXPECT_EQ(3U, BB(2).GetLoop()->GetOuterLoop()->GetBlocks().size());
1579}
1580
1581TEST_F(CleanupTest, ThreeBlocks)
1582{
1583    GRAPH(GetGraph())
1584    {
1585        CONSTANT(0, 12);
1586        CONSTANT(1, 13);
1587
1588        BASIC_BLOCK(2, 3)
1589        {
1590            INST(2, Opcode::Neg).u64().Inputs(1);
1591            INST(3, Opcode::Add).u64().Inputs(0, 2);
1592        }
1593
1594        BASIC_BLOCK(3, 4)
1595        {
1596            INST(4, Opcode::Neg).u64().Inputs(0);
1597            INST(5, Opcode::Add).u64().Inputs(1, 4);
1598        }
1599
1600        BASIC_BLOCK(4, -1)
1601        {
1602            INST(6, Opcode::Add).u64().Inputs(3, 5);
1603            INST(7, Opcode::Return).u64().Inputs(6);
1604        }
1605    }
1606
1607    ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
1608
1609    auto graph = CreateEmptyGraph();
1610    GRAPH(graph)
1611    {
1612        CONSTANT(0, 12);
1613        CONSTANT(1, 13);
1614
1615        BASIC_BLOCK(2, -1)
1616        {
1617            INST(2, Opcode::Neg).u64().Inputs(1);
1618            INST(3, Opcode::Add).u64().Inputs(0, 2);
1619            INST(4, Opcode::Neg).u64().Inputs(0);
1620            INST(5, Opcode::Add).u64().Inputs(1, 4);
1621            INST(6, Opcode::Add).u64().Inputs(3, 5);
1622            INST(7, Opcode::Return).u64().Inputs(6);
1623        }
1624    }
1625    ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
1626}
1627
1628TEST_F(CleanupTest, TwoBlocksAndPhi)
1629{
1630    GRAPH(GetGraph())
1631    {
1632        CONSTANT(0, 12).s64();
1633        CONSTANT(1, 13).s64();
1634
1635        BASIC_BLOCK(2, 3, 4)
1636        {
1637            INST(2, Opcode::Compare).b().CC(CC_LT).SrcType(DataType::Type::INT64).Inputs(0, 1);
1638            INST(3, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(2);
1639        }
1640
1641        BASIC_BLOCK(3, 5)
1642        {
1643            INST(4, Opcode::Neg).u64().Inputs(0);
1644            INST(5, Opcode::Neg).u64().Inputs(1);
1645        }
1646
1647        BASIC_BLOCK(4, 5)
1648        {
1649            INST(7, Opcode::Neg).u64().Inputs(1);
1650            INST(8, Opcode::Neg).u64().Inputs(0);
1651        }
1652
1653        BASIC_BLOCK(5, 6)
1654        {
1655            INST(10, Opcode::Phi).u64().Inputs({{3, 4}, {4, 7}});
1656            INST(11, Opcode::Phi).u64().Inputs({{3, 5}, {4, 8}});
1657            INST(12, Opcode::Neg).u64().Inputs(10);
1658            INST(13, Opcode::Add).u64().Inputs(10, 11);
1659        }
1660
1661        BASIC_BLOCK(6, 7, 8)
1662        {
1663            INST(15, Opcode::Add).u64().Inputs(12, 13);
1664            INST(16, Opcode::Neg).u64().Inputs(12);
1665            INST(17, Opcode::Compare).b().CC(CC_LT).SrcType(DataType::Type::UINT64).Inputs(16, 15);
1666            INST(18, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(17);
1667        }
1668
1669        BASIC_BLOCK(7, 8)
1670        {
1671            INST(19, Opcode::Add).u64().Inputs(0, 1);
1672        }
1673
1674        BASIC_BLOCK(8, -1)
1675        {
1676            INST(21, Opcode::Phi).u64().Inputs({{6, 16}, {7, 19}});
1677            INST(22, Opcode::Add).u64().Inputs(21, 1);
1678            INST(23, Opcode::Return).u64().Inputs(22);
1679        }
1680    }
1681
1682    ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
1683
1684    auto graph = CreateEmptyGraph();
1685    GRAPH(graph)
1686    {
1687        CONSTANT(0, 12).s64();
1688        CONSTANT(1, 13).s64();
1689
1690        BASIC_BLOCK(2, 3, 4)
1691        {
1692            INST(2, Opcode::Compare).b().CC(CC_LT).SrcType(DataType::Type::INT64).Inputs(0, 1);
1693            INST(3, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(2);
1694        }
1695
1696        BASIC_BLOCK(3, 5)
1697        {
1698            INST(4, Opcode::Neg).u64().Inputs(0);
1699            INST(5, Opcode::Neg).u64().Inputs(1);
1700        }
1701
1702        BASIC_BLOCK(4, 5)
1703        {
1704            INST(7, Opcode::Neg).u64().Inputs(1);
1705            INST(8, Opcode::Neg).u64().Inputs(0);
1706        }
1707
1708        BASIC_BLOCK(5, 7, 8)
1709        {
1710            INST(10, Opcode::Phi).u64().Inputs({{3, 4}, {4, 7}});
1711            INST(11, Opcode::Phi).u64().Inputs({{3, 5}, {4, 8}});
1712            INST(12, Opcode::Neg).u64().Inputs(10);
1713            INST(13, Opcode::Add).u64().Inputs(10, 11);
1714            INST(15, Opcode::Add).u64().Inputs(12, 13);
1715            INST(16, Opcode::Neg).u64().Inputs(12);
1716            INST(17, Opcode::Compare).b().CC(CC_LT).SrcType(DataType::Type::UINT64).Inputs(16, 15);
1717            INST(18, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0).Inputs(17);
1718        }
1719
1720        BASIC_BLOCK(7, 8)
1721        {
1722            INST(19, Opcode::Add).u64().Inputs(0, 1);
1723        }
1724
1725        BASIC_BLOCK(8, -1)
1726        {
1727            INST(21, Opcode::Phi).u64().Inputs(16, 19);
1728            INST(22, Opcode::Add).u64().Inputs(21, 1);
1729            INST(23, Opcode::Return).u64().Inputs(22);
1730        }
1731    }
1732    ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
1733}
1734}  // namespace panda::compiler
1735