• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2025 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 "libpandabase/utils/utils.h"
17 #include "macros.h"
18 #include "unit_test.h"
19 #include "optimizer/ir/graph_cloner.h"
20 #include "optimizer/optimizations/peepholes.h"
21 #include "optimizer/optimizations/branch_elimination.h"
22 #include "optimizer/optimizations/lowering.h"
23 #include "optimizer/optimizations/cleanup.h"
24 
25 namespace ark::compiler {
26 class PeepholesTest : public CommonTest {
27 public:
PeepholesTest()28     PeepholesTest()
29         : graph_(CreateGraphStartEndBlocks()),
30           defaultCompilerSafePointsRequireRegMap_(g_options.IsCompilerSafePointsRequireRegMap())
31     {
32     }
33 
~PeepholesTest()34     ~PeepholesTest() override
35     {
36         g_options.SetCompilerSafePointsRequireRegMap(defaultCompilerSafePointsRequireRegMap_);
37     }
38 
39     NO_COPY_SEMANTIC(PeepholesTest);
40     NO_MOVE_SEMANTIC(PeepholesTest);
41 
GetGraph()42     Graph *GetGraph()
43     {
44         return graph_;
45     }
46 
CheckCompare(DataType::Type paramType,ConditionCode origCc,ConditionCode cc)47     void CheckCompare(DataType::Type paramType, ConditionCode origCc, ConditionCode cc)
48     {
49         auto graph1 = CreateEmptyGraph();
50         GRAPH(graph1)
51         {
52             CONSTANT(0U, 0U);
53             PARAMETER(1U, 0U);
54             INS(1U).SetType(paramType);
55             PARAMETER(2U, 1U);
56             INS(2U).SetType(paramType);
57             BASIC_BLOCK(2U, 1U)
58             {
59                 INST(3U, Opcode::Cmp).s32().Inputs(1U, 2U);
60                 INST(4U, Opcode::Compare).b().CC(origCc).Inputs(3U, 0U);
61                 INST(5U, Opcode::Return).b().Inputs(4U);
62             }
63         }
64         graph1->RunPass<Peepholes>();
65         GraphChecker(graph1).Check();
66 
67         auto graph2 = CreateEmptyGraph();
68         GRAPH(graph2)
69         {
70             CONSTANT(0U, 0U);
71             PARAMETER(1U, 0U);
72             INS(1U).SetType(paramType);
73             PARAMETER(2U, 1U);
74             INS(2U).SetType(paramType);
75             BASIC_BLOCK(2U, 1U)
76             {
77                 INST(3U, Opcode::Cmp).s32().Inputs(1U, 2U);
78                 INST(4U, Opcode::Compare).b().CC(cc).Inputs(1U, 2U);
79                 INST(5U, Opcode::Return).b().Inputs(4U);
80             }
81         }
82         ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
83     }
84 
CheckCompare(ConditionCode cc,int64_t cst,std::optional<uint64_t> expCst,bool expInv)85     void CheckCompare(ConditionCode cc, int64_t cst, std::optional<uint64_t> expCst, bool expInv)
86     {
87         auto graph = CreateEmptyGraph();
88         GRAPH(graph)
89         {
90             CONSTANT(0U, cst);
91             PARAMETER(1U, 0U).b();
92             BASIC_BLOCK(2U, 3U, 4U)
93             {
94                 INST(3U, Opcode::Compare).b().CC(cc).Inputs(1U, 0U);
95                 INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
96             }
97             BASIC_BLOCK(3U, -1L)
98             {
99                 INST(5U, Opcode::ReturnVoid);
100             }
101             BASIC_BLOCK(4U, -1L)
102             {
103                 INST(6U, Opcode::ReturnVoid);
104             }
105         }
106         graph->RunPass<Peepholes>();
107         GraphChecker(graph).Check();
108 
109         EXPECT_FALSE(INS(3U).HasUsers());
110         if (expCst.has_value()) {
111             auto inst = INS(4U).GetInput(0U).GetInst();
112             EXPECT_EQ(inst->GetOpcode(), Opcode::Constant);
113             EXPECT_EQ(inst->CastToConstant()->GetIntValue(), *expCst);
114         } else {
115             EXPECT_EQ(INS(4U).GetInput(0U).GetInst(), &INS(1U));
116         }
117         EXPECT_EQ(INS(4U).CastToIfImm()->GetImm(), 0U);
118         EXPECT_EQ(INS(4U).CastToIfImm()->GetCc() == CC_EQ, expInv);
119     }
120 
CheckCast(DataType::Type srcType,DataType::Type tgtType,bool applied)121     void CheckCast(DataType::Type srcType, DataType::Type tgtType, bool applied)
122     {
123         if (srcType == DataType::REFERENCE || tgtType == DataType::REFERENCE) {
124             return;
125         }
126         auto graph1 = CreateEmptyGraph();
127         GRAPH(graph1)
128         {
129             PARAMETER(0U, 0U);
130             INS(0U).SetType(srcType);
131             BASIC_BLOCK(2U, 1U)
132             {
133                 INST(1U, Opcode::Cast).SrcType(srcType).Inputs(0U);
134                 INS(1U).SetType(tgtType);
135                 INST(2U, Opcode::Return).Inputs(1U);
136                 INS(2U).SetType(tgtType);
137             }
138         }
139         auto graph2 = CreateEmptyGraph();
140         if (applied) {
141             GRAPH(graph2)
142             {
143                 PARAMETER(0U, 0U);
144                 INS(0U).SetType(srcType);
145                 BASIC_BLOCK(2U, 1U)
146                 {
147                     INST(1U, Opcode::Cast).SrcType(srcType).Inputs(0U);
148                     INS(1U).SetType(tgtType);
149                     INST(2U, Opcode::Return).Inputs(0U);
150                     INS(2U).SetType(srcType);
151                 }
152             }
153         } else {
154             GRAPH(graph2)
155             {
156                 PARAMETER(0U, 0U);
157                 INS(0U).SetType(srcType);
158                 BASIC_BLOCK(2U, 1U)
159                 {
160                     INST(1U, Opcode::Cast).SrcType(srcType).Inputs(0U);
161                     INS(1U).SetType(tgtType);
162                     INST(2U, Opcode::Return).Inputs(1U);
163                     INS(2U).SetType(tgtType);
164                 }
165             }
166         }
167         ASSERT_EQ(graph1->RunPass<Peepholes>(), applied);
168         ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
169     }
170 
BuildCheckCastResJoined(DataType::Type srcType,DataType::Type mdlType,DataType::Type tgtType)171     Graph *BuildCheckCastResJoined(DataType::Type srcType, DataType::Type mdlType, DataType::Type tgtType)
172     {
173         auto graph = CreateEmptyGraph();
174         GRAPH(graph)
175         {
176             PARAMETER(0U, 0U);
177             INS(0U).SetType(srcType);
178             BASIC_BLOCK(2U, 1U)
179             {
180                 INST(1U, Opcode::Cast).SrcType(srcType).Inputs(0U);
181                 INS(1U).SetType(mdlType);
182                 INST(2U, Opcode::Cast).SrcType(srcType).Inputs(0U);
183                 INS(2U).SetType(tgtType);
184                 INST(3U, Opcode::Return).Inputs(2U);
185                 INS(3U).SetType(tgtType);
186             }
187         }
188         return graph;
189     }
190 
BuildCheckCastResNotJoined(DataType::Type srcType,DataType::Type mdlType,DataType::Type tgtType)191     Graph *BuildCheckCastResNotJoined(DataType::Type srcType, DataType::Type mdlType, DataType::Type tgtType)
192     {
193         auto graph = CreateEmptyGraph();
194         GRAPH(graph)
195         {
196             PARAMETER(0U, 0U);
197             INS(0U).SetType(srcType);
198             BASIC_BLOCK(2U, 1U)
199             {
200                 INST(1U, Opcode::Cast).SrcType(srcType).Inputs(0U);
201                 INS(1U).SetType(mdlType);
202                 INST(2U, Opcode::Cast).SrcType(mdlType).Inputs(1U);
203                 INS(2U).SetType(tgtType);
204                 INST(3U, Opcode::Return).Inputs(0U);
205                 INS(3U).SetType(srcType);
206             }
207         }
208         return graph;
209     }
210 
CheckCast(DataType::Type srcType,DataType::Type mdlType,DataType::Type tgtType,bool applied,bool joinCast)211     void CheckCast(DataType::Type srcType, DataType::Type mdlType, DataType::Type tgtType, bool applied, bool joinCast)
212     {
213         if (srcType == DataType::REFERENCE || tgtType == DataType::REFERENCE || mdlType == DataType::REFERENCE) {
214             return;
215         }
216         auto graph1 = CreateEmptyGraph();
217         GRAPH(graph1)
218         {
219             PARAMETER(0U, 0U);
220             INS(0U).SetType(srcType);
221             BASIC_BLOCK(2U, 1U)
222             {
223                 INST(1U, Opcode::Cast).SrcType(srcType).Inputs(0U);
224                 INS(1U).SetType(mdlType);
225                 INST(2U, Opcode::Cast).SrcType(mdlType).Inputs(1U);
226                 INS(2U).SetType(tgtType);
227                 INST(3U, Opcode::Return).Inputs(2U);
228                 INS(3U).SetType(tgtType);
229             }
230         }
231         Graph *graph2;
232         if (applied && joinCast) {
233             graph2 = BuildCheckCastResJoined(srcType, mdlType, tgtType);
234         } else if (applied) {
235             graph2 = BuildCheckCastResNotJoined(srcType, mdlType, tgtType);
236         } else {
237             graph2 = GraphCloner(graph1, GetAllocator(), GetLocalAllocator()).CloneGraph();
238         }
239         ASSERT_EQ(graph1->RunPass<Peepholes>(), applied);
240         ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
241     }
242 
CheckCast(int i,int j,int k)243     void CheckCast(int i, int j, int k)
244     {
245         if (i == j || j == k) {
246             return;
247         }
248         auto srcType = static_cast<DataType::Type>(i);
249         auto mdlType = static_cast<DataType::Type>(j);
250         auto tgtType = static_cast<DataType::Type>(k);
251         auto joinCast = DataType::GetTypeSize(srcType, GetArch()) > DataType::GetTypeSize(mdlType, GetArch()) &&
252                         DataType::GetTypeSize(mdlType, GetArch()) > DataType::GetTypeSize(tgtType, GetArch());
253         CheckCast(srcType, mdlType, tgtType,
254                   (srcType == tgtType &&
255                    DataType::GetTypeSize(mdlType, GetArch()) > DataType::GetTypeSize(tgtType, GetArch())) ||
256                       joinCast,
257                   joinCast);
258     }
259 
CheckCompareFoldIntoTest(uint64_t constant,ConditionCode cc,bool success,ConditionCode expectedCc=CC_EQ)260     void CheckCompareFoldIntoTest(uint64_t constant, ConditionCode cc, bool success, ConditionCode expectedCc = CC_EQ)
261     {
262         auto graph = CreateEmptyGraph();
263         GRAPH(graph)
264         {
265             PARAMETER(0U, 0U).u64();
266             PARAMETER(1U, 1U).u64();
267             CONSTANT(2U, constant);
268 
269             BASIC_BLOCK(2U, -1L)
270             {
271                 INST(3U, Opcode::And).u64().Inputs(0U, 1U);
272                 INST(4U, Opcode::Compare).b().CC(cc).Inputs(3U, 2U);
273                 INST(5U, Opcode::Return).b().Inputs(4U);
274             }
275         }
276 
277         ASSERT_EQ(graph->RunPass<Peepholes>(), success);
278         if (!success) {
279             return;
280         }
281 
282         graph->RunPass<Cleanup>();
283 
284         auto expectedGraph = CreateEmptyGraph();
285         GRAPH(expectedGraph)
286         {
287             PARAMETER(0U, 0U).u64();
288             PARAMETER(1U, 1U).u64();
289 
290             BASIC_BLOCK(2U, -1L)
291             {
292                 INST(4U, Opcode::Compare).b().CC(expectedCc).Inputs(0U, 1U);
293                 INST(5U, Opcode::Return).b().Inputs(4U);
294             }
295         }
296 
297         ASSERT_TRUE(GraphComparator().Compare(graph, expectedGraph));
298     }
299 
CheckIfAndZeroFoldIntoIfTest(uint64_t constant,ConditionCode cc,bool success,ConditionCode expectedCc=CC_EQ)300     void CheckIfAndZeroFoldIntoIfTest(uint64_t constant, ConditionCode cc, bool success,
301                                       ConditionCode expectedCc = CC_EQ)
302     {
303         auto graph = CreateEmptyGraph();
304         GRAPH(graph)
305         {
306             PARAMETER(0U, 0U).u64();
307             PARAMETER(1U, 1U).u64();
308             CONSTANT(2U, constant);
309             CONSTANT(3U, -1L);
310             CONSTANT(4U, -2L);
311 
312             BASIC_BLOCK(2U, 3U, 4U)
313             {
314                 INST(5U, Opcode::And).u64().Inputs(0U, 1U);
315                 INST(6U, Opcode::If).SrcType(DataType::UINT64).CC(cc).Inputs(5U, 2U);
316             }
317 
318             BASIC_BLOCK(3U, 4U) {}
319 
320             BASIC_BLOCK(4U, -1L)
321             {
322                 INST(7U, Opcode::Phi).s64().Inputs(3U, 4U);
323                 INST(8U, Opcode::Return).s64().Inputs(7U);
324             }
325         }
326 
327         ASSERT_EQ(graph->RunPass<Peepholes>(), success);
328         if (!success) {
329             return;
330         }
331 
332         graph->RunPass<Cleanup>();
333 
334         auto expectedGraph = CreateEmptyGraph();
335         GRAPH(expectedGraph)
336         {
337             PARAMETER(0U, 0U).u64();
338             PARAMETER(1U, 1U).u64();
339             CONSTANT(3U, -1L);
340             CONSTANT(4U, -2L);
341 
342             BASIC_BLOCK(2U, 3U, 4U)
343             {
344                 INST(6U, Opcode::If).SrcType(DataType::UINT64).CC(expectedCc).Inputs(0U, 1U);
345             }
346 
347             BASIC_BLOCK(3U, 4U) {}
348 
349             BASIC_BLOCK(4U, -1L)
350             {
351                 INST(7U, Opcode::Phi).s64().Inputs(3U, 4U);
352                 INST(8U, Opcode::Return).s64().Inputs(7U);
353             }
354         }
355 
356         ASSERT_TRUE(GraphComparator().Compare(graph, expectedGraph));
357     }
358 
CheckCompareLenArrayWithZeroTest(int64_t constant,ConditionCode cc,std::optional<bool> expectedValue,bool swap=false)359     void CheckCompareLenArrayWithZeroTest(int64_t constant, ConditionCode cc, std::optional<bool> expectedValue,
360                                           bool swap = false)
361     {
362         auto graph = CreateEmptyGraph();
363         GRAPH(graph)
364         {
365             PARAMETER(0U, 0U).ref();
366             CONSTANT(1U, constant);
367             BASIC_BLOCK(2U, -1L)
368             {
369                 INST(3U, Opcode::LenArray).s32().Inputs(0U);
370                 if (swap) {
371                     INST(4U, Opcode::Compare).b().CC(cc).Inputs(1U, 3U);
372                 } else {
373                     INST(4U, Opcode::Compare).b().CC(cc).Inputs(3U, 1U);
374                 }
375                 INST(5U, Opcode::Return).b().Inputs(4U);
376             }
377         }
378 
379         ASSERT_EQ(graph->RunPass<Peepholes>(), expectedValue.has_value());
380         if (!expectedValue.has_value()) {
381             return;
382         }
383 
384         graph->RunPass<Cleanup>();
385 
386         auto expectedGraph = CreateEmptyGraph();
387         GRAPH(expectedGraph)
388         {
389             CONSTANT(1U, *expectedValue);
390             BASIC_BLOCK(2U, -1L)
391             {
392                 INST(2U, Opcode::Return).b().Inputs(1U);
393             }
394         }
395 
396         ASSERT_TRUE(GraphComparator().Compare(graph, expectedGraph));
397     }
398 
399     void CastTest2Addition1MainLoop(int i, int j);
400 
401 private:
402     Graph *graph_ {nullptr};
403 
404 private:
405     bool defaultCompilerSafePointsRequireRegMap_;
406 };
407 
408 // NOLINTBEGIN(readability-magic-numbers)
TEST_F(PeepholesTest,TestAnd1)409 TEST_F(PeepholesTest, TestAnd1)
410 {
411     // case 1:
412     // 0.i64 Const ...
413     // 1.i64 AND v0, v5
414     // ===>
415     // 0.i64 Const 25
416     // 1.i64 AND v5, v0
417     GRAPH(GetGraph())
418     {
419         PARAMETER(0U, 1U).u64();
420         CONSTANT(1U, 2U);
421         BASIC_BLOCK(2U, -1L)
422         {
423             INST(2U, Opcode::And).u64().Inputs(1U, 0U);
424             INST(3U, Opcode::Return).u64().Inputs(2U);
425         }
426     }
427     GetGraph()->RunPass<Peepholes>();
428     GraphChecker(GetGraph()).Check();
429     ASSERT_EQ(INS(2U).GetInput(0U).GetInst(), &INS(0U));
430     ASSERT_EQ(INS(2U).GetInput(1U).GetInst(), &INS(1U));
431     ASSERT_EQ(INS(1U).GetUsers().Front().GetIndex(), 1U);
432     ASSERT_EQ(INS(0U).GetUsers().Front().GetIndex(), 0U);
433 }
434 
TEST_F(PeepholesTest,TestAnd2)435 TEST_F(PeepholesTest, TestAnd2)
436 {
437     // case 2:
438     // 0.i64 Const 0xFFF..FF
439     // 1.i64 AND v5, v0
440     // 2.i64 INS which use v1
441     // ===>
442     // 0.i64 Const 0xFFF..FF
443     // 1.i64 AND v5, v0
444     // 2.i64 INS which use v5
445     GRAPH(GetGraph())
446     {
447         PARAMETER(0U, 1U).u64();
448         CONSTANT(1U, -1L);
449         BASIC_BLOCK(2U, -1L)
450         {
451             INST(2U, Opcode::And).u64().Inputs(0U, 1U);
452             INST(3U, Opcode::Return).u64().Inputs(2U);
453         }
454     }
455     GetGraph()->RunPass<Peepholes>();
456     GraphChecker(GetGraph()).Check();
457     ASSERT_EQ(INS(3U).GetInput(0U).GetInst(), &INS(0U));
458 }
459 
TEST_F(PeepholesTest,TestAnd2Addition)460 TEST_F(PeepholesTest, TestAnd2Addition)
461 {
462     // Case 1 + Case 2
463     GRAPH(GetGraph())
464     {
465         PARAMETER(0U, 1U).u64();
466         CONSTANT(1U, -1L);
467         BASIC_BLOCK(2U, -1L)
468         {
469             INST(2U, Opcode::And).u64().Inputs(1U, 0U);
470             INST(3U, Opcode::Return).u64().Inputs(2U);
471         }
472     }
473     GetGraph()->RunPass<Peepholes>();
474     GraphChecker(GetGraph()).Check();
475     ASSERT_EQ(INS(3U).GetInput(0U).GetInst(), &INS(0U));
476     ASSERT_EQ(INS(1U).GetUsers().Front().GetIndex(), 1U);
477     ASSERT_EQ(INS(0U).GetUsers().Front().GetIndex(), 0U);
478 }
479 
TEST_F(PeepholesTest,TestAnd3)480 TEST_F(PeepholesTest, TestAnd3)
481 {
482     // case 3:
483     // 1.i64 AND v5, v5
484     // 2.i64 INS which use v1
485     // ===>
486     // 1.i64 AND v5, v5
487     // 2.i64 INS which use v5
488     GRAPH(GetGraph())
489     {
490         PARAMETER(0U, 1U).u64();
491         BASIC_BLOCK(2U, -1L)
492         {
493             INST(2U, Opcode::And).u64().Inputs(0U, 0U);
494             INST(3U, Opcode::Return).u64().Inputs(2U);
495         }
496     }
497     GetGraph()->RunPass<Peepholes>();
498     GraphChecker(GetGraph()).Check();
499     ASSERT_EQ(INS(3U).GetInput(0U).GetInst(), &INS(0U));
500 }
501 
TEST_F(PeepholesTest,TestAnd3Addition)502 TEST_F(PeepholesTest, TestAnd3Addition)
503 {
504     // case 3:
505     // but input's type not equal with and-inst's type
506     GRAPH(GetGraph())
507     {
508         PARAMETER(0U, 1U).s32();
509         BASIC_BLOCK(2U, -1L)
510         {
511             INST(2U, Opcode::And).s16().Inputs(0U, 0U);
512             INST(3U, Opcode::Return).s32().Inputs(2U);
513         }
514     }
515     GetGraph()->RunPass<Peepholes>();
516     GraphChecker(GetGraph()).Check();
517     ASSERT_EQ(INS(3U).GetInput(0U).GetInst(), &INS(2U));
518 }
519 
TEST_F(PeepholesTest,TestAnd4)520 TEST_F(PeepholesTest, TestAnd4)
521 {
522     // case 4: De Morgan rules
523     // 2.i64 not v0 -> {4}
524     // 3.i64 not v1 -> {4}
525     // 4.i64 AND v2, v3
526     // ===>
527     // 5.i64 OR v0, v1
528     // 6.i64 not v5
529     GRAPH(GetGraph())
530     {
531         PARAMETER(0U, 1U).u64();
532         PARAMETER(1U, 2U).u64();
533         BASIC_BLOCK(2U, -1L)
534         {
535             INST(2U, Opcode::Not).u64().Inputs(0U);
536             INST(3U, Opcode::Not).u64().Inputs(1U);
537             INST(4U, Opcode::And).u64().Inputs(2U, 3U);
538             INST(5U, Opcode::Return).u64().Inputs(4U);
539         }
540     }
541     GetGraph()->RunPass<Peepholes>();
542     GraphChecker(GetGraph()).Check();
543     auto notInst = INS(5U).GetInput(0U).GetInst();
544     ASSERT_EQ(notInst->GetOpcode(), Opcode::Not);
545     auto orInst = notInst->GetInput(0U).GetInst();
546     ASSERT_EQ(orInst->GetOpcode(), Opcode::Or);
547     ASSERT_EQ(orInst->GetInput(0U).GetInst(), &INS(0U));
548     ASSERT_EQ(orInst->GetInput(1U).GetInst(), &INS(1U));
549 }
550 
TEST_F(PeepholesTest,TestAnd4Addition)551 TEST_F(PeepholesTest, TestAnd4Addition)
552 {
553     // Case 4, but NOT-inst have more than 1 user
554     GRAPH(GetGraph())
555     {
556         PARAMETER(0U, 1U).u64();
557         PARAMETER(1U, 2U).u64();
558         BASIC_BLOCK(2U, -1L)
559         {
560             INST(2U, Opcode::Not).u64().Inputs(0U);
561             INST(3U, Opcode::Not).u64().Inputs(1U);
562             INST(4U, Opcode::And).u64().Inputs(2U, 3U);
563             INST(5U, Opcode::Not).u64().Inputs(2U);
564             INST(6U, Opcode::Not).u64().Inputs(3U);
565             INST(20U, Opcode::SaveState).NoVregs();
566             INST(7U, Opcode::CallStatic).u64().InputsAutoType(4U, 5U, 6U, 20U);
567             INST(8U, Opcode::Return).u64().Inputs(7U);
568         }
569     }
570     GetGraph()->RunPass<Peepholes>();
571     GraphChecker(GetGraph()).Check();
572     auto andInst = INS(7U).GetInput(0U).GetInst();
573     ASSERT_EQ(andInst->GetOpcode(), Opcode::And);
574 }
575 
TEST_F(PeepholesTest,TestOr1)576 TEST_F(PeepholesTest, TestOr1)
577 {
578     // case 1:
579     // 0.i64 Const ...
580     // 1.i64 Or v0, v5
581     // ===>
582     // 0.i64 Const 25
583     // 1.i64 Or v5, v0
584     GRAPH(GetGraph())
585     {
586         PARAMETER(0U, 1U).u64();
587         CONSTANT(1U, 2U);
588         BASIC_BLOCK(2U, -1L)
589         {
590             INST(2U, Opcode::Or).u64().Inputs(1U, 0U);
591             INST(3U, Opcode::Return).u64().Inputs(2U);
592         }
593     }
594     GetGraph()->RunPass<Peepholes>();
595     GraphChecker(GetGraph()).Check();
596     ASSERT_EQ(INS(2U).GetInput(0U).GetInst(), &INS(0U));
597     ASSERT_EQ(INS(2U).GetInput(1U).GetInst(), &INS(1U));
598     ASSERT_EQ(INS(1U).GetUsers().Front().GetIndex(), 1U);
599     ASSERT_EQ(INS(0U).GetUsers().Front().GetIndex(), 0U);
600 }
601 
TEST_F(PeepholesTest,TestOr2)602 TEST_F(PeepholesTest, TestOr2)
603 {
604     // case 2:
605     // 0.i64 Const 0x000..00
606     // 1.i64 OR v5, v0
607     // 2.i64 INS which use v1
608     // ===>
609     // 0.i64 Const 0x000..00
610     // 1.i64 OR v5, v0
611     // 2.i64 INS which use v5
612     GRAPH(GetGraph())
613     {
614         PARAMETER(0U, 1U).u64();
615         CONSTANT(1U, 0U);
616         BASIC_BLOCK(2U, -1L)
617         {
618             INST(2U, Opcode::Or).u64().Inputs(1U, 0U);
619             INST(3U, Opcode::Return).u64().Inputs(2U);
620         }
621     }
622     GetGraph()->RunPass<Peepholes>();
623     GraphChecker(GetGraph()).Check();
624     ASSERT_EQ(INS(3U).GetInput(0U).GetInst(), &INS(0U));
625 }
626 
TEST_F(PeepholesTest,AddConstantTest1)627 TEST_F(PeepholesTest, AddConstantTest1)
628 {
629     GRAPH(GetGraph())
630     {
631         PARAMETER(0U, 0U).u64();
632         PARAMETER(1U, 1U).u64();
633         CONSTANT(2U, 1U);
634         CONSTANT(3U, 0U);
635 
636         BASIC_BLOCK(2U, -1L)
637         {
638             INST(4U, Opcode::Add).u64().Inputs(2U, 0U);
639             INST(5U, Opcode::Add).u64().Inputs(3U, 1U);
640             INST(20U, Opcode::SaveState).NoVregs();
641             INST(6U, Opcode::CallStatic).u64().InputsAutoType(4U, 5U, 20U);
642             INST(7U, Opcode::Return).u64().Inputs(6U);
643         }
644     }
645     GetGraph()->RunPass<Peepholes>();
646     ASSERT_TRUE(CheckInputs(INS(4U), {0U, 2U}));
647     ASSERT_TRUE(CheckInputs(INS(5U), {1U, 3U}));
648     ASSERT_TRUE(CheckInputs(INS(6U), {4U, 1U, 20U}));
649 
650     ASSERT_TRUE(CheckUsers(INS(0U), {4U}));
651     ASSERT_TRUE(CheckUsers(INS(2U), {4U}));
652     ASSERT_TRUE(CheckUsers(INS(3U), {5U}));
653     ASSERT_TRUE(INS(5U).GetUsers().Empty());
654 }
655 
TEST_F(PeepholesTest,AddConstantTest2)656 TEST_F(PeepholesTest, AddConstantTest2)
657 {
658     GRAPH(GetGraph())
659     {
660         PARAMETER(0U, 0U).u64();
661         CONSTANT(1U, 5U);
662         CONSTANT(2U, 6U);
663 
664         BASIC_BLOCK(2U, -1L)
665         {
666             INST(3U, Opcode::Add).u64().Inputs(0U, 1U);
667             INST(4U, Opcode::Sub).u64().Inputs(0U, 1U);
668 
669             INST(5U, Opcode::Add).u64().Inputs(2U, 3U);
670             INST(6U, Opcode::Add).u64().Inputs(2U, 4U);
671             INST(20U, Opcode::SaveState).NoVregs();
672             INST(7U, Opcode::CallStatic).u64().InputsAutoType(5U, 6U, 20U);
673             INST(8U, Opcode::Return).u64().Inputs(7U);
674         }
675     }
676     GetGraph()->RunPass<Peepholes>();
677 
678     auto const3 = INS(2U).GetNext();
679     ASSERT_TRUE(const3 != nullptr);
680     auto const4 = const3->GetNext();
681     ASSERT_TRUE(const4 != nullptr && const4->GetNext() == nullptr);
682 
683     ASSERT_TRUE(INS(5U).GetInput(0U) == &INS(0U) && INS(5U).GetInput(1U) == const3);
684     ASSERT_TRUE(INS(6U).GetInput(0U) == &INS(0U) && INS(6U).GetInput(1U) == const4);
685 
686     ASSERT_TRUE(CheckUsers(INS(0U), {3U, 4U, 5U, 6U}));
687     ASSERT_TRUE(CheckUsers(INS(1U), {3U, 4U}));
688     ASSERT_TRUE(CheckUsers(*const3, {5U}));
689     ASSERT_TRUE(CheckUsers(*const4, {6U}));
690     ASSERT_TRUE(INS(2U).GetUsers().Empty());
691 }
692 
TEST_F(PeepholesTest,AddConstantTest3)693 TEST_F(PeepholesTest, AddConstantTest3)
694 {
695     GRAPH(GetGraph())
696     {
697         PARAMETER(0U, 0U).u32();
698         CONSTANT(1U, 5U);
699         CONSTANT(2U, 6U);
700 
701         BASIC_BLOCK(2U, -1L)
702         {
703             INST(3U, Opcode::Add).u16().Inputs(0U, 1U);
704             INST(4U, Opcode::Sub).u16().Inputs(0U, 1U);
705 
706             INST(5U, Opcode::Add).u32().Inputs(2U, 3U);
707             INST(6U, Opcode::Add).u32().Inputs(2U, 4U);
708             INST(20U, Opcode::SaveState).NoVregs();
709             INST(7U, Opcode::CallStatic).u64().InputsAutoType(5U, 6U, 20U);
710             INST(8U, Opcode::Return).u64().Inputs(7U);
711         }
712     }
713     GetGraph()->RunPass<Peepholes>();
714 
715     ASSERT_TRUE(INS(2U).GetNext() == nullptr);
716 
717     ASSERT_TRUE(CheckInputs(INS(3U), {0U, 1U}));
718     ASSERT_TRUE(CheckInputs(INS(4U), {0U, 1U}));
719     ASSERT_TRUE(CheckInputs(INS(5U), {3U, 2U}));
720     ASSERT_TRUE(CheckInputs(INS(6U), {4U, 2U}));
721 
722     ASSERT_TRUE(CheckUsers(INS(0U), {3U, 4U}));
723     ASSERT_TRUE(CheckUsers(INS(1U), {3U, 4U}));
724     ASSERT_TRUE(CheckUsers(INS(2U), {5U, 6U}));
725     ASSERT_TRUE(CheckUsers(INS(3U), {5U}));
726     ASSERT_TRUE(CheckUsers(INS(4U), {6U}));
727 }
728 
TEST_F(PeepholesTest,AddNegTest1)729 TEST_F(PeepholesTest, AddNegTest1)
730 {
731     GRAPH(GetGraph())
732     {
733         PARAMETER(0U, 0U).u64();
734         PARAMETER(1U, 1U).u64();
735 
736         BASIC_BLOCK(2U, -1L)
737         {
738             INST(2U, Opcode::Neg).u64().Inputs(0U);
739             INST(3U, Opcode::Neg).u64().Inputs(1U);
740 
741             INST(4U, Opcode::Add).u64().Inputs(2U, 3U);
742             INST(5U, Opcode::Return).u64().Inputs(4U);
743         }
744     }
745     GetGraph()->RunPass<Peepholes>();
746 
747     auto newNeg = INS(4U).GetNext();
748 
749     ASSERT_TRUE(CheckUsers(INS(0U), {2U, 4U}));
750     ASSERT_TRUE(CheckUsers(INS(1U), {3U, 4U}));
751     ASSERT_TRUE(INS(2U).GetUsers().Empty());
752     ASSERT_TRUE(INS(3U).GetUsers().Empty());
753 
754     ASSERT(CheckInputs(INS(4U), {0U, 1U}));
755 
756     auto user = INS(4U).GetUsers().begin();
757     ASSERT_TRUE(user->GetInst() == newNeg);
758     ASSERT_FALSE(++user != INS(4U).GetUsers().end());
759 
760     ASSERT_TRUE(newNeg->GetInput(0U) == &INS(4U));
761     ASSERT_TRUE(CheckUsers(*newNeg, {5U}));
762 
763     ASSERT_TRUE(INS(5U).GetInput(0U) == newNeg);
764 }
765 
TEST_F(PeepholesTest,AddNegTest2)766 TEST_F(PeepholesTest, AddNegTest2)
767 {
768     GRAPH(GetGraph())
769     {
770         PARAMETER(0U, 0U).u64();
771         PARAMETER(1U, 1U).u64();
772 
773         BASIC_BLOCK(2U, -1L)
774         {
775             INST(2U, Opcode::Neg).u64().Inputs(0U);
776             INST(3U, Opcode::Neg).u64().Inputs(1U);
777 
778             INST(4U, Opcode::Add).u64().Inputs(2U, 3U);
779             INST(20U, Opcode::SaveState).NoVregs();
780             INST(6U, Opcode::CallStatic).u64().InputsAutoType(2U, 4U, 20U);
781             INST(5U, Opcode::Return).u64().Inputs(6U);
782         }
783     }
784     GetGraph()->RunPass<Peepholes>();
785 
786     ASSERT_TRUE(CheckUsers(INS(0U), {2U}));
787     ASSERT_TRUE(CheckUsers(INS(1U), {3U}));
788 
789     ASSERT_TRUE(CheckInputs(INS(2U), {0U}));
790     ASSERT_TRUE(CheckUsers(INS(2U), {4U, 6U}));
791     ASSERT_TRUE(CheckInputs(INS(3U), {1U}));
792     ASSERT_TRUE(CheckUsers(INS(3U), {4U}));
793 
794     ASSERT_TRUE(CheckInputs(INS(4U), {2U, 3U}));
795 }
796 
TEST_F(PeepholesTest,AddNegTest3)797 TEST_F(PeepholesTest, AddNegTest3)
798 {
799     GRAPH(GetGraph())
800     {
801         PARAMETER(0U, 0U).u64();
802         PARAMETER(1U, 1U).u64();
803         CONSTANT(8U, 1U);
804         CONSTANT(9U, 2U);
805 
806         BASIC_BLOCK(2U, -1L)
807         {
808             INST(2U, Opcode::Neg).u64().Inputs(0U);
809             INST(3U, Opcode::Neg).u64().Inputs(1U);
810 
811             INST(4U, Opcode::Add).u64().Inputs(2U, 8U);
812             INST(5U, Opcode::Add).u64().Inputs(3U, 9U);
813 
814             INST(6U, Opcode::Add).u64().Inputs(2U, 3U);
815             INST(20U, Opcode::SaveState).NoVregs();
816             INST(10U, Opcode::CallStatic).u64().InputsAutoType(4U, 5U, 6U, 20U);
817             INST(7U, Opcode::Return).u64().Inputs(10U);
818         }
819     }
820     GetGraph()->RunPass<Peepholes>();
821     ASSERT_TRUE(CheckUsers(INS(0U), {2U}));
822     ASSERT_TRUE(CheckUsers(INS(1U), {3U}));
823     ASSERT_TRUE(CheckUsers(INS(2U), {4U, 6U}));
824     ASSERT_TRUE(CheckUsers(INS(3U), {5U, 6U}));
825 
826     ASSERT(CheckInputs(INS(4U), {2U, 8U}));
827     ASSERT(CheckInputs(INS(5U), {3U, 9U}));
828 
829     ASSERT_TRUE(CheckInputs(INS(6U), {2U, 3U}));
830     ASSERT_TRUE(CheckUsers(INS(6U), {10U}));
831     ASSERT_TRUE(INS(6U).GetNext()->GetNext() == &INS(10U));
832 
833     ASSERT_TRUE(CheckInputs(INS(7U), {10U}));
834 }
835 
TEST_F(PeepholesTest,AddNegTest4)836 TEST_F(PeepholesTest, AddNegTest4)
837 {
838     GRAPH(GetGraph())
839     {
840         PARAMETER(0U, 0U).u64();
841         PARAMETER(1U, 1U).u64();
842 
843         BASIC_BLOCK(2U, -1L)
844         {
845             INST(2U, Opcode::Neg).u64().Inputs(0U);
846             INST(3U, Opcode::Neg).u64().Inputs(1U);
847 
848             INST(4U, Opcode::Add).u64().Inputs(0U, 3U);
849             INST(5U, Opcode::Add).u64().Inputs(2U, 1U);
850             INST(20U, Opcode::SaveState).NoVregs();
851             INST(7U, Opcode::CallStatic).u64().InputsAutoType(4U, 5U, 20U);
852             INST(6U, Opcode::Return).u64().Inputs(7U);
853         }
854     }
855     GetGraph()->RunPass<Peepholes>();
856 
857     ASSERT_TRUE(CheckUsers(INS(0U), {2U, 4U, 5U}));
858     ASSERT_TRUE(CheckUsers(INS(1U), {3U, 4U, 5U}));
859 
860     ASSERT_TRUE(INS(2U).GetUsers().Empty());
861     ASSERT_TRUE(INS(3U).GetUsers().Empty());
862 
863     ASSERT_TRUE(CheckInputs(INS(4U), {0U, 1U}));
864     ASSERT_TRUE(INS(4U).GetOpcode() == Opcode::Sub);
865 
866     ASSERT_TRUE(CheckInputs(INS(5U), {1U, 0U}));
867     ASSERT_TRUE(INS(5U).GetOpcode() == Opcode::Sub);
868 }
869 
TEST_F(PeepholesTest,AddNegConstOne)870 TEST_F(PeepholesTest, AddNegConstOne)
871 {
872     GRAPH(GetGraph())
873     {
874         CONSTANT(0U, 1U);
875         BASIC_BLOCK(2U, -1L)
876         {
877             INST(1U, Opcode::SaveState).NoVregs();
878             INST(2U, Opcode::CallStatic).b().InputsAutoType(1U);
879             INST(3U, Opcode::Neg).s32().Inputs(2U);
880             INST(4U, Opcode::Add).s32().Inputs(3U, 0U);
881             INST(5U, Opcode::Return).s32().Inputs(4U);
882         }
883     }
884 
885     auto graph = CreateEmptyGraph();
886     GRAPH(graph)
887     {
888         CONSTANT(6U, 0U);
889         BASIC_BLOCK(2U, -1L)
890         {
891             INST(1U, Opcode::SaveState).NoVregs();
892             INST(2U, Opcode::CallStatic).b().InputsAutoType(1U);
893             INST(7U, Opcode::Compare).s32().b().CC(ConditionCode::CC_EQ).SetType(DataType::BOOL).Inputs(2U, 6U);
894             INST(5U, Opcode::Return).s32().Inputs(7U);
895         }
896     }
897 
898     ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
899     ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
900 
901     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
902 }
903 
TEST_F(PeepholesTest,SameAddAndSubTest)904 TEST_F(PeepholesTest, SameAddAndSubTest)
905 {
906     GRAPH(GetGraph())
907     {
908         PARAMETER(0U, 0U).u64();
909         PARAMETER(1U, 1U).u64();
910 
911         BASIC_BLOCK(2U, -1L)
912         {
913             INST(2U, Opcode::Sub).u64().Inputs(0U, 1U);
914             INST(3U, Opcode::Add).u64().Inputs(2U, 1U);
915             INST(4U, Opcode::Add).u64().Inputs(1U, 2U);
916             INST(5U, Opcode::Add).u64().Inputs(3U, 4U);
917 
918             INST(6U, Opcode::Add).u32().Inputs(1U, 2U);
919             INST(7U, Opcode::Add).u32().Inputs(2U, 1U);
920             INST(8U, Opcode::Add).u32().Inputs(6U, 7U);
921             INST(20U, Opcode::SaveState).NoVregs();
922             INST(10U, Opcode::CallStatic).u64().InputsAutoType(5U, 8U, 20U);
923             INST(9U, Opcode::Return).u64().Inputs(10U);
924         }
925     }
926     GetGraph()->RunPass<Peepholes>();
927 
928     ASSERT_TRUE(INS(3U).GetUsers().Empty());
929     ASSERT_TRUE(INS(4U).GetUsers().Empty());
930     ASSERT_TRUE(CheckInputs(INS(5U), {0U, 0U}));
931 
932     ASSERT_TRUE(CheckInputs(INS(6U), {1U, 2U}));
933     ASSERT_TRUE(CheckInputs(INS(7U), {2U, 1U}));
934     ASSERT_TRUE(CheckInputs(INS(8U), {6U, 7U}));
935 }
936 
937 // (a - b) + (c + b) -> a + c
TEST_F(PeepholesTest,AddSubAndAddSameOperandTest1)938 TEST_F(PeepholesTest, AddSubAndAddSameOperandTest1)
939 {
940     GRAPH(GetGraph())
941     {
942         PARAMETER(0U, 0U).u64();
943         PARAMETER(1U, 1U).u64();
944         PARAMETER(2U, 2U).u64();
945 
946         BASIC_BLOCK(2U, -1L)
947         {
948             INST(3U, Opcode::Sub).u64().Inputs(0U, 1U);
949             INST(4U, Opcode::Add).u64().Inputs(2U, 1U);
950             INST(5U, Opcode::Add).u64().Inputs(3U, 4U);
951             INST(6U, Opcode::Return).u64().Inputs(5U);
952         }
953     }
954     GetGraph()->RunPass<Peepholes>();
955     ASSERT_EQ(INS(5U).GetOpcode(), Opcode::Add);
956     ASSERT_TRUE(CheckInputs(INS(5U), {0U, 2U}));
957 }
958 
959 // (a - b) + (b + c) -> a + c
TEST_F(PeepholesTest,AddSubAndAddSameOperandTest2)960 TEST_F(PeepholesTest, AddSubAndAddSameOperandTest2)
961 {
962     GRAPH(GetGraph())
963     {
964         PARAMETER(0U, 0U).u64();
965         PARAMETER(1U, 1U).u64();
966         PARAMETER(2U, 2U).u64();
967 
968         BASIC_BLOCK(2U, -1L)
969         {
970             INST(3U, Opcode::Sub).u64().Inputs(0U, 1U);
971             INST(4U, Opcode::Add).u64().Inputs(1U, 2U);
972             INST(5U, Opcode::Add).u64().Inputs(3U, 4U);
973             INST(6U, Opcode::Return).u64().Inputs(5U);
974         }
975     }
976     GetGraph()->RunPass<Peepholes>();
977     ASSERT_EQ(INS(5U).GetOpcode(), Opcode::Add);
978     ASSERT_TRUE(CheckInputs(INS(5U), {0U, 2U}));
979 }
980 
981 // (a + b) + (c - b) -> c + a
TEST_F(PeepholesTest,AddAddAndSubSameOperandTest1)982 TEST_F(PeepholesTest, AddAddAndSubSameOperandTest1)
983 {
984     GRAPH(GetGraph())
985     {
986         PARAMETER(0U, 0U).u64();
987         PARAMETER(1U, 1U).u64();
988         PARAMETER(2U, 2U).u64();
989 
990         BASIC_BLOCK(2U, -1L)
991         {
992             INST(3U, Opcode::Sub).u64().Inputs(2U, 1U);
993             INST(4U, Opcode::Add).u64().Inputs(0U, 1U);
994             INST(5U, Opcode::Add).u64().Inputs(4U, 3U);
995             INST(6U, Opcode::Return).u64().Inputs(5U);
996         }
997     }
998     GetGraph()->RunPass<Peepholes>();
999     ASSERT_EQ(INS(5U).GetOpcode(), Opcode::Add);
1000     ASSERT_TRUE(CheckInputs(INS(5U), {2U, 0U}));
1001 }
1002 
1003 // (b + a) + (c - b) -> c + a
TEST_F(PeepholesTest,AddAddAndSubSameOperandTest2)1004 TEST_F(PeepholesTest, AddAddAndSubSameOperandTest2)
1005 {
1006     GRAPH(GetGraph())
1007     {
1008         PARAMETER(0U, 0U).u64();
1009         PARAMETER(1U, 1U).u64();
1010         PARAMETER(2U, 2U).u64();
1011 
1012         BASIC_BLOCK(2U, -1L)
1013         {
1014             INST(3U, Opcode::Sub).u64().Inputs(2U, 1U);
1015             INST(4U, Opcode::Add).u64().Inputs(1U, 0U);
1016             INST(5U, Opcode::Add).u64().Inputs(4U, 3U);
1017             INST(6U, Opcode::Return).u64().Inputs(5U);
1018         }
1019     }
1020     GetGraph()->RunPass<Peepholes>();
1021     ASSERT_EQ(INS(5U).GetOpcode(), Opcode::Add);
1022     ASSERT_TRUE(CheckInputs(INS(5U), {2U, 0U}));
1023 }
1024 
1025 // (a - b) + (b - c) -> a - c
TEST_F(PeepholesTest,AddSubAndSubSameOperandTest1)1026 TEST_F(PeepholesTest, AddSubAndSubSameOperandTest1)
1027 {
1028     GRAPH(GetGraph())
1029     {
1030         PARAMETER(0U, 0U).u64();
1031         PARAMETER(1U, 1U).u64();
1032         PARAMETER(2U, 2U).u64();
1033 
1034         BASIC_BLOCK(2U, -1L)
1035         {
1036             INST(3U, Opcode::Sub).u64().Inputs(0U, 1U);
1037             INST(4U, Opcode::Sub).u64().Inputs(1U, 2U);
1038             INST(5U, Opcode::Add).u64().Inputs(3U, 4U);
1039             INST(6U, Opcode::Return).u64().Inputs(5U);
1040         }
1041     }
1042     GetGraph()->RunPass<Peepholes>();
1043     ASSERT_EQ(INS(5U).GetOpcode(), Opcode::Sub);
1044     ASSERT_TRUE(CheckInputs(INS(5U), {0U, 2U}));
1045 }
1046 
1047 // (a - b) + (c - a) -> c - b
TEST_F(PeepholesTest,AddSubAndSubSameOperandTest2)1048 TEST_F(PeepholesTest, AddSubAndSubSameOperandTest2)
1049 {
1050     GRAPH(GetGraph())
1051     {
1052         PARAMETER(0U, 0U).u64();
1053         PARAMETER(1U, 1U).u64();
1054         PARAMETER(2U, 2U).u64();
1055 
1056         BASIC_BLOCK(2U, -1L)
1057         {
1058             INST(3U, Opcode::Sub).u64().Inputs(0U, 1U);
1059             INST(4U, Opcode::Sub).u64().Inputs(2U, 0U);
1060             INST(5U, Opcode::Add).u64().Inputs(3U, 4U);
1061             INST(6U, Opcode::Return).u64().Inputs(5U);
1062         }
1063     }
1064     GetGraph()->RunPass<Peepholes>();
1065     ASSERT_EQ(INS(5U).GetOpcode(), Opcode::Sub);
1066     ASSERT_TRUE(CheckInputs(INS(5U), {2U, 1U}));
1067 }
1068 
1069 // a + (0 - b) -> a - b
TEST_F(PeepholesTest,AddSubLeftZeroOperandTest1)1070 TEST_F(PeepholesTest, AddSubLeftZeroOperandTest1)
1071 {
1072     GRAPH(GetGraph())
1073     {
1074         PARAMETER(0U, 0U).u64();
1075         CONSTANT(1U, 0U);
1076         PARAMETER(2U, 1U).u64();
1077 
1078         BASIC_BLOCK(2U, -1L)
1079         {
1080             INST(3U, Opcode::Sub).u64().Inputs(1U, 2U);
1081             INST(4U, Opcode::Add).u64().Inputs(0U, 3U);
1082             INST(5U, Opcode::Return).u64().Inputs(4U);
1083         }
1084     }
1085     GetGraph()->RunPass<Peepholes>();
1086     ASSERT_EQ(INS(4U).GetOpcode(), Opcode::Sub);
1087     ASSERT_TRUE(CheckInputs(INS(4U), {0U, 2U}));
1088 }
1089 
1090 // (0 - a) + b -> b - a
TEST_F(PeepholesTest,AddSubLeftZeroOperandTest2)1091 TEST_F(PeepholesTest, AddSubLeftZeroOperandTest2)
1092 {
1093     GRAPH(GetGraph())
1094     {
1095         PARAMETER(0U, 0U).u64();
1096         CONSTANT(1U, 0U);
1097         PARAMETER(2U, 1U).u64();
1098 
1099         BASIC_BLOCK(2U, -1L)
1100         {
1101             INST(3U, Opcode::Sub).u64().Inputs(1U, 0U);
1102             INST(4U, Opcode::Add).u64().Inputs(3U, 2U);
1103             INST(5U, Opcode::Return).u64().Inputs(4U);
1104         }
1105     }
1106     GetGraph()->RunPass<Peepholes>();
1107     ASSERT_EQ(INS(4U).GetOpcode(), Opcode::Sub);
1108     ASSERT_TRUE(CheckInputs(INS(4U), {2U, 0U}));
1109 }
1110 
1111 // (x + a) - (x + b) -> a - b
TEST_F(PeepholesTest,SubAddSameOperandTest1)1112 TEST_F(PeepholesTest, SubAddSameOperandTest1)
1113 {
1114     GRAPH(GetGraph())
1115     {
1116         PARAMETER(0U, 0U).u64();
1117         PARAMETER(1U, 1U).u64();
1118         PARAMETER(2U, 2U).u64();
1119 
1120         BASIC_BLOCK(2U, -1L)
1121         {
1122             INST(3U, Opcode::Add).u64().Inputs(0U, 1U);
1123             INST(4U, Opcode::Add).u64().Inputs(0U, 2U);
1124             INST(5U, Opcode::Sub).u64().Inputs(3U, 4U);
1125             INST(6U, Opcode::Return).u64().Inputs(5U);
1126         }
1127     }
1128     GetGraph()->RunPass<Peepholes>();
1129     ASSERT_EQ(INS(5U).GetOpcode(), Opcode::Sub);
1130     ASSERT_TRUE(CheckInputs(INS(5U), {1U, 2U}));
1131 }
1132 
1133 // (a + x) - (x + b) -> a - b
TEST_F(PeepholesTest,SubAddSameOperandTest2)1134 TEST_F(PeepholesTest, SubAddSameOperandTest2)
1135 {
1136     GRAPH(GetGraph())
1137     {
1138         PARAMETER(0U, 0U).u64();
1139         PARAMETER(1U, 1U).u64();
1140         PARAMETER(2U, 2U).u64();
1141 
1142         BASIC_BLOCK(2U, -1L)
1143         {
1144             INST(3U, Opcode::Add).u64().Inputs(1U, 0U);
1145             INST(4U, Opcode::Add).u64().Inputs(0U, 2U);
1146             INST(5U, Opcode::Sub).u64().Inputs(3U, 4U);
1147             INST(6U, Opcode::Return).u64().Inputs(5U);
1148         }
1149     }
1150     GetGraph()->RunPass<Peepholes>();
1151     ASSERT_EQ(INS(5U).GetOpcode(), Opcode::Sub);
1152     ASSERT_TRUE(CheckInputs(INS(5U), {1U, 2U}));
1153 }
1154 
1155 // (a + x) - (b + x) -> a - b
TEST_F(PeepholesTest,SubAddSameOperandTest3)1156 TEST_F(PeepholesTest, SubAddSameOperandTest3)
1157 {
1158     GRAPH(GetGraph())
1159     {
1160         PARAMETER(0U, 0U).u64();
1161         PARAMETER(1U, 1U).u64();
1162         PARAMETER(2U, 2U).u64();
1163 
1164         BASIC_BLOCK(2U, -1L)
1165         {
1166             INST(3U, Opcode::Add).u64().Inputs(1U, 0U);
1167             INST(4U, Opcode::Add).u64().Inputs(2U, 0U);
1168             INST(5U, Opcode::Sub).u64().Inputs(3U, 4U);
1169             INST(6U, Opcode::Return).u64().Inputs(5U);
1170         }
1171     }
1172     GetGraph()->RunPass<Peepholes>();
1173     ASSERT_EQ(INS(5U).GetOpcode(), Opcode::Sub);
1174     ASSERT_TRUE(CheckInputs(INS(5U), {1U, 2U}));
1175 }
1176 
1177 // (x + a) - (b + x) -> a - b
TEST_F(PeepholesTest,SubAddSameOperandTest4)1178 TEST_F(PeepholesTest, SubAddSameOperandTest4)
1179 {
1180     GRAPH(GetGraph())
1181     {
1182         PARAMETER(0U, 0U).u64();
1183         PARAMETER(1U, 1U).u64();
1184         PARAMETER(2U, 2U).u64();
1185 
1186         BASIC_BLOCK(2U, -1L)
1187         {
1188             INST(3U, Opcode::Add).u64().Inputs(0U, 1U);
1189             INST(4U, Opcode::Add).u64().Inputs(2U, 0U);
1190             INST(5U, Opcode::Sub).u64().Inputs(3U, 4U);
1191             INST(6U, Opcode::Return).u64().Inputs(5U);
1192         }
1193     }
1194     GetGraph()->RunPass<Peepholes>();
1195     ASSERT_EQ(INS(5U).GetOpcode(), Opcode::Sub);
1196     ASSERT_TRUE(CheckInputs(INS(5U), {1U, 2U}));
1197 }
1198 
TEST_F(PeepholesTest,SubZeroConstantTest)1199 TEST_F(PeepholesTest, SubZeroConstantTest)
1200 {
1201     GRAPH(GetGraph())
1202     {
1203         PARAMETER(0U, 0U).u64();
1204         CONSTANT(3U, 0U);
1205 
1206         BASIC_BLOCK(2U, -1L)
1207         {
1208             INST(6U, Opcode::Sub).u64().Inputs(0U, 3U);
1209             INST(20U, Opcode::SaveState).NoVregs();
1210             INST(9U, Opcode::CallStatic).s32().InputsAutoType(6U, 20U);
1211             INST(10U, Opcode::Return).s32().Inputs(9U);
1212         }
1213     }
1214     GetGraph()->RunPass<Peepholes>();
1215 
1216     ASSERT_TRUE(INS(6U).GetUsers().Empty());
1217     ASSERT_TRUE(INS(9U).GetInput(0U) == &INS(0U));
1218 }
1219 
TEST_F(PeepholesTest,SubFromZeroConstantTest)1220 TEST_F(PeepholesTest, SubFromZeroConstantTest)
1221 {
1222     GRAPH(GetGraph())
1223     {
1224         PARAMETER(0U, 0U).s64();
1225         CONSTANT(1U, 0U);
1226 
1227         BASIC_BLOCK(2U, -1L)
1228         {
1229             INST(2U, Opcode::Sub).s64().Inputs(1U, 0U);
1230             INST(3U, Opcode::Return).s64().Inputs(2U);
1231         }
1232     }
1233 
1234     ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
1235     GetGraph()->RunPass<Cleanup>();
1236     auto graph = CreateEmptyGraph();
1237     GRAPH(graph)
1238     {
1239         PARAMETER(0U, 0U).s64();
1240 
1241         BASIC_BLOCK(2U, -1L)
1242         {
1243             INST(2U, Opcode::Neg).s64().Inputs(0U);
1244             INST(3U, Opcode::Return).s64().Inputs(2U);
1245         }
1246     }
1247     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
1248 }
1249 
TEST_F(PeepholesTest,SubFromZeroConstantFPTest)1250 TEST_F(PeepholesTest, SubFromZeroConstantFPTest)
1251 {
1252     GRAPH(GetGraph())
1253     {
1254         PARAMETER(0U, 0U).f64();
1255         CONSTANT(1U, 0.0);
1256 
1257         BASIC_BLOCK(2U, -1L)
1258         {
1259             INST(2U, Opcode::Sub).f64().Inputs(1U, 0U);
1260             INST(3U, Opcode::Return).f64().Inputs(2U);
1261         }
1262     }
1263 
1264     ASSERT_FALSE(GetGraph()->RunPass<Peepholes>());
1265 }
1266 
TEST_F(PeepholesTest,SubConstantTest1)1267 TEST_F(PeepholesTest, SubConstantTest1)
1268 {
1269     GRAPH(GetGraph())
1270     {
1271         PARAMETER(0U, 0U).u64();
1272         CONSTANT(1U, 5U);
1273         CONSTANT(2U, 6U);
1274 
1275         BASIC_BLOCK(2U, -1L)
1276         {
1277             INST(3U, Opcode::Add).u64().Inputs(0U, 1U);
1278             INST(4U, Opcode::Sub).u64().Inputs(0U, 1U);
1279 
1280             INST(5U, Opcode::Sub).u64().Inputs(3U, 2U);
1281             INST(6U, Opcode::Sub).u64().Inputs(4U, 2U);
1282             INST(20U, Opcode::SaveState).NoVregs();
1283             INST(8U, Opcode::CallStatic).u64().InputsAutoType(5U, 6U, 20U);
1284             INST(7U, Opcode::Return).u64().Inputs(8U);
1285         }
1286     }
1287     GetGraph()->RunPass<Peepholes>();
1288     auto const3 = static_cast<ConstantInst *>(INS(2U).GetNext());
1289     ASSERT_TRUE(const3 != nullptr);
1290     auto const4 = static_cast<ConstantInst *>(const3->GetNext());
1291     ASSERT_TRUE(const4 != nullptr && const4->GetNext() == nullptr);
1292     ASSERT_TRUE(const3->IsEqualConst(1U));
1293     ASSERT_TRUE(const4->IsEqualConst(11U));
1294 
1295     ASSERT_TRUE(INS(5U).GetInput(0U) == &INS(0U) && INS(5U).GetInput(1U) == const3);
1296     ASSERT_TRUE(INS(6U).GetInput(0U) == &INS(0U) && INS(6U).GetInput(1U) == const4);
1297 
1298     ASSERT_TRUE(CheckUsers(INS(0U), {3U, 4U, 5U, 6U}));
1299     ASSERT_TRUE(CheckUsers(INS(1U), {3U, 4U}));
1300     ASSERT_TRUE(INS(2U).GetUsers().Empty());
1301     ASSERT_TRUE(CheckUsers(*const3, {5U}));
1302     ASSERT_TRUE(CheckUsers(*const4, {6U}));
1303 }
1304 
TEST_F(PeepholesTest,SubConstantTest2)1305 TEST_F(PeepholesTest, SubConstantTest2)
1306 {
1307     GRAPH(GetGraph())
1308     {
1309         PARAMETER(0U, 0U).u64();
1310         CONSTANT(1U, 5U);
1311         CONSTANT(2U, 6U);
1312 
1313         BASIC_BLOCK(2U, -1L)
1314         {
1315             INST(3U, Opcode::Add).u64().Inputs(0U, 1U);
1316             INST(4U, Opcode::Sub).u64().Inputs(0U, 1U);
1317 
1318             INST(5U, Opcode::Sub).u32().Inputs(3U, 2U);
1319             INST(6U, Opcode::Sub).u32().Inputs(4U, 2U);
1320             INST(20U, Opcode::SaveState).NoVregs();
1321             INST(8U, Opcode::CallStatic).u64().InputsAutoType(5U, 6U, 20U);
1322             INST(7U, Opcode::Return).u64().Inputs(8U);
1323         }
1324     }
1325     GetGraph()->RunPass<Peepholes>();
1326 
1327     ASSERT_TRUE(INS(2U).GetNext() == nullptr);
1328 
1329     ASSERT_TRUE(CheckInputs(INS(3U), {0U, 1U}));
1330     ASSERT_TRUE(CheckInputs(INS(4U), {0U, 1U}));
1331     ASSERT_TRUE(CheckInputs(INS(5U), {3U, 2U}));
1332     ASSERT_TRUE(CheckInputs(INS(6U), {4U, 2U}));
1333 
1334     ASSERT_TRUE(CheckUsers(INS(0U), {3U, 4U}));
1335     ASSERT_TRUE(CheckUsers(INS(1U), {3U, 4U}));
1336     ASSERT_TRUE(CheckUsers(INS(2U), {5U, 6U}));
1337     ASSERT_TRUE(CheckUsers(INS(3U), {5U}));
1338     ASSERT_TRUE(CheckUsers(INS(4U), {6U}));
1339 }
1340 
TEST_F(PeepholesTest,SubNegTest)1341 TEST_F(PeepholesTest, SubNegTest)
1342 {
1343     GRAPH(GetGraph())
1344     {
1345         PARAMETER(0U, 0U).u64();
1346         PARAMETER(1U, 1U).u64();
1347 
1348         BASIC_BLOCK(2U, -1L)
1349         {
1350             INST(2U, Opcode::Neg).u64().Inputs(0U);
1351             INST(3U, Opcode::Neg).u64().Inputs(1U);
1352 
1353             INST(4U, Opcode::Sub).u64().Inputs(0U, 3U);
1354             INST(5U, Opcode::Sub).u64().Inputs(2U, 0U);
1355             INST(6U, Opcode::Sub).u64().Inputs(2U, 3U);
1356             INST(7U, Opcode::Sub).u64().Inputs(3U, 2U);
1357             INST(20U, Opcode::SaveState).NoVregs();
1358             INST(8U, Opcode::CallStatic).u64().InputsAutoType(4U, 5U, 6U, 7U, 20U);
1359             INST(9U, Opcode::Return).u64().Inputs(8U);
1360         }
1361     }
1362     GetGraph()->RunPass<Peepholes>();
1363 
1364     ASSERT_TRUE(CheckInputs(INS(4U), {0U, 1U}));
1365     ASSERT_TRUE(INS(4U).GetOpcode() == Opcode::Add);
1366     ASSERT_TRUE(CheckInputs(INS(5U), {2U, 0U}));
1367     ASSERT_TRUE(INS(5U).GetOpcode() == Opcode::Sub);
1368     ASSERT_TRUE(CheckInputs(INS(6U), {1U, 0U}));
1369     ASSERT_TRUE(INS(6U).GetOpcode() == Opcode::Sub);
1370     ASSERT_TRUE(CheckInputs(INS(7U), {0U, 1U}));
1371     ASSERT_TRUE(INS(7U).GetOpcode() == Opcode::Sub);
1372 }
1373 
TEST_F(PeepholesTest,SameSubAndAddTest1)1374 TEST_F(PeepholesTest, SameSubAndAddTest1)
1375 {
1376     GRAPH(GetGraph())
1377     {
1378         PARAMETER(0U, 0U).u64();
1379         PARAMETER(1U, 1U).u64();
1380 
1381         BASIC_BLOCK(2U, -1L)
1382         {
1383             INST(2U, Opcode::Add).u64().Inputs(0U, 1U);
1384 
1385             INST(4U, Opcode::Sub).u64().Inputs(2U, 0U);
1386             INST(5U, Opcode::Sub).u64().Inputs(2U, 1U);
1387             INST(6U, Opcode::Add).u64().Inputs(4U, 5U);
1388             INST(7U, Opcode::Return).u64().Inputs(6U);
1389         }
1390     }
1391     ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
1392 
1393     ASSERT_TRUE(INS(4U).GetUsers().Empty());
1394     ASSERT_TRUE(INS(5U).GetUsers().Empty());
1395     ASSERT_TRUE(CheckInputs(INS(6U), {1U, 0U}));
1396 }
1397 
TEST_F(PeepholesTest,SameSubAndAddTest2)1398 TEST_F(PeepholesTest, SameSubAndAddTest2)
1399 {
1400     GRAPH(GetGraph())
1401     {
1402         PARAMETER(0U, 0U).u64();
1403         PARAMETER(1U, 1U).u64();
1404 
1405         BASIC_BLOCK(2U, -1L)
1406         {
1407             INST(2U, Opcode::Sub).u64().Inputs(0U, 1U);
1408             INST(3U, Opcode::Sub).u64().Inputs(1U, 0U);
1409 
1410             INST(4U, Opcode::Sub).u64().Inputs(0U, 2U);
1411             INST(5U, Opcode::Sub).u64().Inputs(3U, 1U);
1412             INST(6U, Opcode::Add).u64().Inputs(4U, 5U);
1413             INST(7U, Opcode::Return).u64().Inputs(6U);
1414         }
1415     }
1416     GetGraph()->RunPass<Peepholes>();
1417 
1418     ASSERT_TRUE(INS(4U).GetUsers().Empty());
1419     ASSERT_TRUE(CheckUsers(INS(5U), {6U}));
1420     ASSERT_TRUE(CheckInputs(INS(6U), {1U, 5U}));
1421 }
1422 
TEST_F(PeepholesTest,TestOr2Addition1)1423 TEST_F(PeepholesTest, TestOr2Addition1)
1424 {
1425     // Case 1 + Case 2
1426     GRAPH(GetGraph())
1427     {
1428         PARAMETER(0U, 1U).u64();
1429         CONSTANT(1U, 0U);
1430         BASIC_BLOCK(2U, -1L)
1431         {
1432             INST(2U, Opcode::Or).u64().Inputs(0U, 1U);
1433             INST(3U, Opcode::Return).u64().Inputs(2U);
1434         }
1435     }
1436     GetGraph()->RunPass<Peepholes>();
1437     GraphChecker(GetGraph()).Check();
1438     ASSERT_EQ(INS(3U).GetInput(0U).GetInst(), &INS(0U));
1439     ASSERT_EQ(INS(1U).GetUsers().Front().GetIndex(), 1U);
1440     ASSERT_EQ(INS(0U).GetUsers().Front().GetIndex(), 0U);
1441 }
1442 
TEST_F(PeepholesTest,TestOr3)1443 TEST_F(PeepholesTest, TestOr3)
1444 {
1445     // case 3:
1446     // 1.i64 OR v5, v5
1447     // 2.i64 INS which use v1
1448     // ===>
1449     // 1.i64 OR v5, v5
1450     // 2.i64 INS which use v5
1451     GRAPH(GetGraph())
1452     {
1453         PARAMETER(0U, 1U).u64();
1454         BASIC_BLOCK(2U, -1L)
1455         {
1456             INST(2U, Opcode::Or).u64().Inputs(0U, 0U);
1457             INST(3U, Opcode::Return).u64().Inputs(2U);
1458         }
1459     }
1460     GetGraph()->RunPass<Peepholes>();
1461     GraphChecker(GetGraph()).Check();
1462     ASSERT_EQ(INS(3U).GetInput(0U).GetInst(), &INS(0U));
1463 }
1464 
TEST_F(PeepholesTest,TestOr4)1465 TEST_F(PeepholesTest, TestOr4)
1466 {
1467     // case 4: De Morgan rules
1468     // 2.i64 not v0 -> {4}
1469     // 3.i64 not v1 -> {4}
1470     // 4.i64 OR v2, v3
1471     // ===>
1472     // 5.i64 AND v0, v1
1473     // 6.i64 not v5
1474     GRAPH(GetGraph())
1475     {
1476         PARAMETER(0U, 1U).u64();
1477         PARAMETER(1U, 2U).u64();
1478         BASIC_BLOCK(2U, -1L)
1479         {
1480             INST(2U, Opcode::Not).u64().Inputs(0U);
1481             INST(3U, Opcode::Not).u64().Inputs(1U);
1482             INST(4U, Opcode::Or).u64().Inputs(2U, 3U);
1483             INST(5U, Opcode::Return).u64().Inputs(4U);
1484         }
1485     }
1486     ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
1487     GraphChecker(GetGraph()).Check();
1488     auto notInst = INS(5U).GetInput(0U).GetInst();
1489     ASSERT_EQ(notInst->GetOpcode(), Opcode::Not);
1490     auto andInst = notInst->GetInput(0U).GetInst();
1491     ASSERT_EQ(andInst->GetOpcode(), Opcode::And);
1492     ASSERT_EQ(andInst->GetInput(0U).GetInst(), &INS(0U));
1493     ASSERT_EQ(andInst->GetInput(1U).GetInst(), &INS(1U));
1494 }
1495 
TEST_F(PeepholesTest,TestOr4Addition1)1496 TEST_F(PeepholesTest, TestOr4Addition1)
1497 {
1498     // Case 4, but NOT-inst have more than 1 user
1499     GRAPH(GetGraph())
1500     {
1501         PARAMETER(0U, 1U).u64();
1502         PARAMETER(1U, 2U).u64();
1503         BASIC_BLOCK(2U, -1L)
1504         {
1505             INST(2U, Opcode::Not).u64().Inputs(0U);
1506             INST(3U, Opcode::Not).u64().Inputs(1U);
1507             INST(4U, Opcode::Or).u64().Inputs(2U, 3U);
1508             INST(5U, Opcode::Not).u64().Inputs(2U);
1509             INST(6U, Opcode::Not).u64().Inputs(3U);
1510             INST(20U, Opcode::SaveState).NoVregs();
1511             INST(8U, Opcode::CallStatic).u64().InputsAutoType(4U, 5U, 6U, 20U);
1512             INST(7U, Opcode::Return).u64().Inputs(8U);
1513         }
1514     }
1515     GetGraph()->RunPass<Peepholes>();
1516     GraphChecker(GetGraph()).Check();
1517     auto orInst = INS(8U).GetInput(0U).GetInst();
1518     ASSERT_EQ(orInst->GetOpcode(), Opcode::Or);
1519 }
1520 
TEST_F(PeepholesTest,NegTest1)1521 TEST_F(PeepholesTest, NegTest1)
1522 {
1523     GRAPH(GetGraph())
1524     {
1525         PARAMETER(0U, 0U).s64();
1526         PARAMETER(1U, 1U).s64();
1527         BASIC_BLOCK(2U, -1L)
1528         {
1529             INST(4U, Opcode::Neg).s64().Inputs(0U);
1530             INST(5U, Opcode::Neg).s64().Inputs(4U);
1531             INST(6U, Opcode::Add).s64().Inputs(1U, 5U);
1532             INST(20U, Opcode::SaveState).NoVregs();
1533             INST(11U, Opcode::CallStatic).u32().InputsAutoType(6U, 20U);
1534             INST(10U, Opcode::Return).u32().Inputs(11U);
1535         }
1536     }
1537     GetGraph()->RunPass<Peepholes>();
1538 
1539     ASSERT_TRUE(CheckInputs(INS(5U), {4U}));
1540     ASSERT_TRUE(INS(5U).GetUsers().Empty());
1541     ASSERT_TRUE(CheckInputs(INS(6U), {1U, 0U}));
1542     ASSERT_EQ(INS(6U).GetOpcode(), Opcode::Add);
1543 }
1544 
TEST_F(PeepholesTest,NegTest2)1545 TEST_F(PeepholesTest, NegTest2)
1546 {
1547     GRAPH(GetGraph())
1548     {
1549         PARAMETER(0U, 0U).s64();
1550         PARAMETER(1U, 1U).s64();
1551         BASIC_BLOCK(2U, -1L)
1552         {
1553             INST(2U, Opcode::Sub).s64().Inputs(0U, 1U);
1554             INST(3U, Opcode::Neg).s64().Inputs(2U);
1555             INST(4U, Opcode::Return).s64().Inputs(3U);
1556         }
1557     }
1558     GetGraph()->RunPass<Peepholes>();
1559 
1560     ASSERT_TRUE(INS(3U).GetUsers().Empty());
1561     ASSERT_NE(INS(3U).GetNext(), &INS(4U));
1562     auto sub = INS(3U).GetNext();
1563     ASSERT_EQ(sub->GetOpcode(), Opcode::Sub);
1564     ASSERT_EQ(sub->GetType(), INS(3U).GetType());
1565 
1566     ASSERT_EQ(sub->GetInput(0U).GetInst(), &INS(1U));
1567     ASSERT_EQ(sub->GetInput(1U).GetInst(), &INS(0U));
1568 
1569     ASSERT_EQ(INS(4U).GetInput(0U).GetInst(), sub);
1570 }
1571 
SRC_GRAPH(NegationCompare,Graph * graph)1572 SRC_GRAPH(NegationCompare, Graph *graph)
1573 {
1574     GRAPH(graph)
1575     {
1576         PARAMETER(0U, 0U).s64();
1577         PARAMETER(1U, 1U).s64();
1578         CONSTANT(5U, 0x1U);
1579         BASIC_BLOCK(2U, -1L)
1580         {
1581             INST(2U, Opcode::Compare).b().CC(CC_GT).Inputs(0U, 1U);
1582             INST(3U, Opcode::Neg).s32().Inputs(2U);
1583             INST(6U, Opcode::Add).s32().Inputs(3U, 5U);
1584             INST(4U, Opcode::Return).b().Inputs(6U);
1585         }
1586     }
1587 }
1588 
OUT_GRAPH(NegationCompare,Graph * graph)1589 OUT_GRAPH(NegationCompare, Graph *graph)
1590 {
1591     GRAPH(graph)
1592     {
1593         PARAMETER(0U, 0U).s64();
1594         PARAMETER(1U, 1U).s64();
1595         BASIC_BLOCK(2U, -1L)
1596         {
1597             INST(2U, Opcode::Compare).b().CC(CC_LE).Inputs(0U, 1U);
1598             INST(4U, Opcode::Return).b().Inputs(2U);
1599         }
1600     }
1601 }
1602 
SRC_GRAPH(NegationCompareOSR,Graph * graph)1603 SRC_GRAPH(NegationCompareOSR, Graph *graph)
1604 {
1605     GRAPH(graph)
1606     {
1607         PARAMETER(0U, 0U).s64();
1608         PARAMETER(1U, 1U).s64();
1609         CONSTANT(5U, 0x1U);
1610         BASIC_BLOCK(2U, 3U)
1611         {
1612             INST(2U, Opcode::Compare).b().CC(CC_GT).Inputs(0U, 1U);
1613             INST(3U, Opcode::Neg).s32().Inputs(2U);
1614             INST(6U, Opcode::Add).s32().Inputs(3U, 5U);
1615         }
1616         BASIC_BLOCK(3U, -1L)
1617         {
1618             INST(4U, Opcode::Return).b().Inputs(6U);
1619         }
1620     }
1621 }
1622 
OUT_GRAPH(NegationCompareOSR,Graph * graph)1623 OUT_GRAPH(NegationCompareOSR, Graph *graph)
1624 {
1625     GRAPH(graph)
1626     {
1627         PARAMETER(0U, 0U).s64();
1628         PARAMETER(1U, 1U).s64();
1629         CONSTANT(5U, 0x1U);
1630         BASIC_BLOCK(2U, 3U)
1631         {
1632             INST(2U, Opcode::Compare).b().CC(CC_LE).Inputs(0U, 1U);
1633             INST(3U, Opcode::Neg).s32().Inputs(2U);
1634             INST(6U, Opcode::Add).s32().Inputs(3U, 5U);
1635         }
1636         BASIC_BLOCK(3U, -1L)
1637         {
1638             INST(4U, Opcode::Return).b().Inputs(2U);
1639         }
1640     }
1641 }
1642 
TEST_F(PeepholesTest,NegationCompare)1643 TEST_F(PeepholesTest, NegationCompare)
1644 {
1645     src_graph::NegationCompare::CREATE(GetGraph());
1646     ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
1647     ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
1648 
1649     auto graph = CreateEmptyGraph();
1650     out_graph::NegationCompare::CREATE(graph);
1651     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
1652 
1653     // Test with OSR
1654     auto defaultGraph = CreateEmptyGraph();
1655     src_graph::NegationCompareOSR::CREATE(defaultGraph);
1656     Graph *graphOsr =
1657         GraphCloner(defaultGraph, defaultGraph->GetAllocator(), defaultGraph->GetLocalAllocator()).CloneGraph();
1658     graphOsr->SetMode(GraphMode::Osr());
1659 
1660     Graph *graphClone = GraphCloner(graphOsr, graphOsr->GetAllocator(), graphOsr->GetLocalAllocator()).CloneGraph();
1661 
1662     ASSERT_FALSE(graphOsr->RunPass<Peepholes>());
1663     ASSERT_TRUE(GraphComparator().Compare(graphOsr, graphClone));
1664 
1665     auto optimizedGraph = CreateEmptyGraph();
1666     out_graph::NegationCompareOSR::CREATE(optimizedGraph);
1667     ASSERT_TRUE(defaultGraph->RunPass<Peepholes>());
1668     ASSERT_TRUE(GraphComparator().Compare(defaultGraph, optimizedGraph));
1669 }
1670 
SRC_GRAPH(TransformNegationToCompare,Graph * graph)1671 SRC_GRAPH(TransformNegationToCompare, Graph *graph)
1672 {
1673     GRAPH(graph)
1674     {
1675         PARAMETER(0U, 0U).s64();
1676         CONSTANT(5U, 0x1U);
1677         BASIC_BLOCK(2U, 3U)
1678         {
1679             INST(1U, Opcode::SaveState).NoVregs();
1680             INST(2U, Opcode::CallStatic).b().InputsAutoType(1U);
1681             INST(3U, Opcode::Neg).s32().Inputs(2U);
1682             INST(6U, Opcode::Add).s32().Inputs(3U, 5U);
1683         }
1684         BASIC_BLOCK(3U, -1L)
1685         {
1686             INST(4U, Opcode::Return).b().Inputs(6U);
1687         }
1688     }
1689 }
1690 
OUT_GRAPH(TransformNegationToCompare,Graph * graph)1691 OUT_GRAPH(TransformNegationToCompare, Graph *graph)
1692 {
1693     GRAPH(graph)
1694     {
1695         PARAMETER(0U, 0U).s64();
1696         CONSTANT(5U, 0x1U);
1697         CONSTANT(7U, 0x0U);
1698         BASIC_BLOCK(2U, 3U)
1699         {
1700             INST(1U, Opcode::SaveState).NoVregs();
1701             INST(2U, Opcode::CallStatic).b().InputsAutoType(1U);
1702             INST(3U, Opcode::Neg).s32().Inputs(2U);
1703             INST(6U, Opcode::Add).s32().Inputs(3U, 5U);
1704             INST(8U, Opcode::Compare).b().Inputs(2U, 7U);
1705         }
1706         BASIC_BLOCK(3U, -1L)
1707         {
1708             INST(4U, Opcode::Return).b().Inputs(8U);
1709         }
1710     }
1711 }
1712 
TEST_F(PeepholesTest,TransformNegationToCompare)1713 TEST_F(PeepholesTest, TransformNegationToCompare)
1714 {
1715     // Test with OSR
1716     auto defaultGraph = CreateEmptyGraph();
1717     src_graph::TransformNegationToCompare::CREATE(defaultGraph);
1718     Graph *graphOsr =
1719         GraphCloner(defaultGraph, defaultGraph->GetAllocator(), defaultGraph->GetLocalAllocator()).CloneGraph();
1720     graphOsr->SetMode(GraphMode::Osr());
1721 
1722     Graph *graphClone = GraphCloner(graphOsr, graphOsr->GetAllocator(), graphOsr->GetLocalAllocator()).CloneGraph();
1723 
1724     ASSERT_FALSE(graphOsr->RunPass<Peepholes>());
1725     ASSERT_TRUE(GraphComparator().Compare(graphOsr, graphClone));
1726     // Test without OSR
1727     auto optimizedGraph = CreateEmptyGraph();
1728     out_graph::TransformNegationToCompare::CREATE(optimizedGraph);
1729     ASSERT_TRUE(defaultGraph->RunPass<Peepholes>());
1730     ASSERT_TRUE(GraphComparator().Compare(defaultGraph, optimizedGraph));
1731 }
1732 
TEST_F(PeepholesTest,NegCompareNotWork)1733 TEST_F(PeepholesTest, NegCompareNotWork)
1734 {
1735     GRAPH(GetGraph())
1736     {
1737         PARAMETER(0U, 0U).s64();
1738         PARAMETER(1U, 1U).s64();
1739         BASIC_BLOCK(2U, -1L)
1740         {
1741             INST(2U, Opcode::Compare).b().CC(CC_GT).Inputs(0U, 1U);
1742             INST(3U, Opcode::Neg).b().Inputs(2U);
1743             INST(5U, Opcode::Mul).b().Inputs(2U, 3U);
1744             INST(4U, Opcode::Return).b().Inputs(5U);
1745         }
1746     }
1747     Graph *graphClone =
1748         GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
1749     ASSERT_FALSE(GetGraph()->RunPass<Peepholes>());
1750     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graphClone));
1751 }
1752 
SRC_GRAPH(CompareNegation,Graph * graph)1753 SRC_GRAPH(CompareNegation, Graph *graph)
1754 {
1755     GRAPH(graph)
1756     {
1757         PARAMETER(0U, 0U).b();
1758         PARAMETER(1U, 1U).b();
1759         CONSTANT(8U, 0x1U);
1760         BASIC_BLOCK(2U, -1L)
1761         {
1762             INST(2U, Opcode::Neg).i32().Inputs(0U);
1763             INST(9U, Opcode::Add).i32().Inputs(2U, 8U);
1764             INST(4U, Opcode::Compare).b().CC(ConditionCode::CC_EQ).SrcType(DataType::BOOL).Inputs(1U, 9U);
1765             INST(7U, Opcode::Return).b().Inputs(4U);
1766         }
1767     }
1768 }
1769 
OUT_GRAPH(CompareNegation,Graph * graph)1770 OUT_GRAPH(CompareNegation, Graph *graph)
1771 {
1772     GRAPH(graph)
1773     {
1774         PARAMETER(0U, 0U).b();
1775         PARAMETER(1U, 1U).b();
1776         BASIC_BLOCK(2U, -1L)
1777         {
1778             INST(4U, Opcode::Compare).b().CC(ConditionCode::CC_NE).SrcType(DataType::BOOL).Inputs(1U, 0U);
1779             INST(7U, Opcode::Return).b().Inputs(4U);
1780         }
1781     }
1782 }
1783 
TEST_F(PeepholesTest,CompareNegation)1784 TEST_F(PeepholesTest, CompareNegation)
1785 {
1786     src_graph::CompareNegation::CREATE(GetGraph());
1787     auto graph = CreateEmptyGraph();
1788     out_graph::CompareNegation::CREATE(graph);
1789     ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
1790     ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
1791     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
1792 
1793     auto graph1 = CreateEmptyGraph();
1794     GRAPH(graph1)
1795     {
1796         PARAMETER(0U, 0U).b();
1797         PARAMETER(1U, 1U).b();
1798         CONSTANT(8U, 0x1U);
1799         BASIC_BLOCK(2U, -1L)
1800         {
1801             INST(2U, Opcode::Neg).i32().Inputs(0U);
1802             INST(9U, Opcode::Add).i32().Inputs(2U, 8U);
1803             INST(4U, Opcode::Compare).b().CC(ConditionCode::CC_EQ).SrcType(DataType::BOOL).Inputs(1U, 9U);
1804             INST(11U, Opcode::Add).i32().Inputs(4U, 9U);
1805             INST(7U, Opcode::Return).b().Inputs(11U);
1806         }
1807     }
1808     auto graph2 = CreateEmptyGraph();
1809     GRAPH(graph2)
1810     {
1811         PARAMETER(0U, 0U).b();
1812         PARAMETER(1U, 1U).b();
1813         CONSTANT(8U, 0x1U);
1814         BASIC_BLOCK(2U, -1L)
1815         {
1816             INST(2U, Opcode::Neg).i32().Inputs(0U);
1817             INST(9U, Opcode::Add).i32().Inputs(2U, 8U);
1818             INST(4U, Opcode::Compare).b().CC(ConditionCode::CC_NE).SrcType(DataType::BOOL).Inputs(1U, 0U);
1819             INST(11U, Opcode::Add).i32().Inputs(4U, 9U);
1820             INST(7U, Opcode::Return).b().Inputs(11U);
1821         }
1822     }
1823     GraphChecker(graph1).Check();
1824     ASSERT_TRUE(graph1->RunPass<Peepholes>());
1825     ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
1826 }
1827 
SRC_GRAPH(CompareNegationBoolOsr,Graph * graph)1828 SRC_GRAPH(CompareNegationBoolOsr, Graph *graph)
1829 {
1830     GRAPH(graph)
1831     {
1832         PARAMETER(1U, 1U).b();
1833         CONSTANT(3U, 0x1U);
1834         BASIC_BLOCK(2U, 3U)
1835         {
1836             INST(6U, Opcode::SaveState).NoVregs();
1837             INST(7U, Opcode::CallStatic).b().InputsAutoType(6U);
1838         }
1839         BASIC_BLOCK(3U, -1L)
1840         {
1841             INST(2U, Opcode::Neg).s32().Inputs(7U);
1842             INST(8U, Opcode::Add).s32().Inputs(2U, 3U);
1843             INST(4U, Opcode::Compare).b().CC(ConditionCode::CC_EQ).SrcType(DataType::BOOL).Inputs(8U, 1U);
1844             INST(5U, Opcode::Return).b().Inputs(4U);
1845         }
1846     }
1847 }
1848 
OUT_GRAPH(CompareNegationBoolOsr,Graph * graph)1849 OUT_GRAPH(CompareNegationBoolOsr, Graph *graph)
1850 {
1851     GRAPH(graph)
1852     {
1853         PARAMETER(1U, 1U).b();
1854         CONSTANT(3U, 0x1U);
1855         BASIC_BLOCK(2U, -1L)
1856         {
1857             INST(6U, Opcode::SaveState).NoVregs();
1858             INST(7U, Opcode::CallStatic).b().InputsAutoType(6U);
1859 
1860             INST(2U, Opcode::Neg).s32().Inputs(7U);
1861             INST(8U, Opcode::Add).s32().Inputs(2U, 3U);
1862             INST(4U, Opcode::Compare).b().CC(ConditionCode::CC_EQ).SrcType(DataType::BOOL).Inputs(8U, 1U);
1863             INST(5U, Opcode::Return).b().Inputs(4U);
1864         }
1865     }
1866 }
1867 
TEST_F(PeepholesTest,CompareNegationBoolOsr)1868 TEST_F(PeepholesTest, CompareNegationBoolOsr)
1869 {
1870     // Peephole don't work with that graph in OSR
1871     GetGraph()->SetMode(GraphMode::Osr());
1872     src_graph::CompareNegationBoolOsr::CREATE(GetGraph());
1873     ASSERT_FALSE(GetGraph()->RunPass<Peepholes>());
1874 
1875     // Work with that graph
1876     auto optimizableGraph = CreateEmptyGraph();
1877     optimizableGraph->SetMode(GraphMode::Osr());
1878     out_graph::CompareNegationBoolOsr::CREATE(optimizableGraph);
1879 
1880     auto optimizableGraphAfter = CreateEmptyGraph();
1881     optimizableGraphAfter->SetMode(GraphMode::Osr());
1882     GRAPH(optimizableGraphAfter)
1883     {
1884         PARAMETER(1U, 1U).b();
1885         BASIC_BLOCK(2U, -1L)
1886         {
1887             INST(6U, Opcode::SaveState).NoVregs();
1888             INST(7U, Opcode::CallStatic).b().InputsAutoType(6U);
1889 
1890             INST(4U, Opcode::Compare).b().CC(ConditionCode::CC_NE).SrcType(DataType::BOOL).Inputs(7U, 1U);
1891             INST(5U, Opcode::Return).b().Inputs(4U);
1892         }
1893     }
1894     ASSERT_TRUE(optimizableGraph->RunPass<Peepholes>());
1895     ASSERT_TRUE(optimizableGraph->RunPass<Cleanup>());
1896     ASSERT_TRUE(GraphComparator().Compare(optimizableGraph, optimizableGraphAfter));
1897 }
1898 
SRC_GRAPH(IfImmNegation,Graph * graph,ConditionCode code)1899 SRC_GRAPH(IfImmNegation, Graph *graph, ConditionCode code)
1900 {
1901     GRAPH(graph)
1902     {
1903         PARAMETER(0U, 0U).b();
1904         PARAMETER(1U, 1U).b();
1905         CONSTANT(8U, 0x1U);
1906         BASIC_BLOCK(2U, 3U, 4U)
1907         {
1908             INST(2U, Opcode::Neg).b().Inputs(0U);
1909             INST(9U, Opcode::Add).i32().Inputs(2U, 8U);
1910             INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).Imm(1U).CC(code).Inputs(9U);
1911         }
1912         BASIC_BLOCK(3U, -1L)
1913         {
1914             INST(6U, Opcode::Return).b().Inputs(0U);
1915         }
1916         BASIC_BLOCK(4U, -1L)
1917         {
1918             INST(7U, Opcode::Return).b().Inputs(0U);
1919         }
1920     }
1921 }
1922 
OUT_GRAPH(IfImmNegation,Graph * graph,ConditionCode code)1923 OUT_GRAPH(IfImmNegation, Graph *graph, ConditionCode code)
1924 {
1925     GRAPH(graph)
1926     {
1927         PARAMETER(0U, 0U).b();
1928         PARAMETER(1U, 1U).b();
1929         CONSTANT(8U, 0x1U);
1930         CONSTANT(10U, 0x0U);
1931         BASIC_BLOCK(2U, 3U, 4U)
1932         {
1933             INST(2U, Opcode::Neg).b().Inputs(0U);
1934             INST(9U, Opcode::Add).i32().Inputs(2U, 8U);
1935             INST(11U, Opcode::Compare).b().SrcType(DataType::BOOL).Inputs(0U, 10U);
1936             // That optimized by combination Compare + IfImm
1937             INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).Imm(1U).CC(GetInverseConditionCode(code)).Inputs(0U);
1938         }
1939         BASIC_BLOCK(3U, -1L)
1940         {
1941             INST(6U, Opcode::Return).b().Inputs(0U);
1942         }
1943         BASIC_BLOCK(4U, -1L)
1944         {
1945             INST(7U, Opcode::Return).b().Inputs(0U);
1946         }
1947     }
1948 }
1949 
TEST_F(PeepholesTest,IfImmNegation)1950 TEST_F(PeepholesTest, IfImmNegation)
1951 {
1952     // ConditionCode in IfImm with bool src maybe not only CC_EQ or CC_NE
1953     std::array<ConditionCode, 4U> codes {ConditionCode::CC_NE, ConditionCode::CC_EQ, ConditionCode::CC_GE,
1954                                          ConditionCode::CC_B};
1955     for (auto code : codes) {
1956         auto graph = CreateEmptyGraph();
1957         src_graph::IfImmNegation::CREATE(graph, code);
1958 
1959         Graph *finalGraph = nullptr;
1960         finalGraph = CreateEmptyGraph();
1961         out_graph::IfImmNegation::CREATE(finalGraph, code);
1962         ASSERT_TRUE(graph->RunPass<Peepholes>());
1963         ASSERT_TRUE(GraphComparator().Compare(graph, finalGraph));
1964     }
1965 }
1966 
SRC_GRAPH(IfImmNegationOsr,Graph * graph)1967 SRC_GRAPH(IfImmNegationOsr, Graph *graph)
1968 {
1969     GRAPH(graph)
1970     {
1971         PARAMETER(0U, 0U).b();
1972         PARAMETER(1U, 1U).b();
1973         CONSTANT(3U, 0x1U);
1974         BASIC_BLOCK(2U, 3U)
1975         {
1976             INST(6U, Opcode::SaveState).NoVregs();
1977             INST(7U, Opcode::CallStatic).b().InputsAutoType(6U);
1978         }
1979         BASIC_BLOCK(3U, 4U, 5U)
1980         {
1981             INST(2U, Opcode::Neg).s32().Inputs(7U);
1982             INST(9U, Opcode::Add).s32().Inputs(2U, 3U);
1983             INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).Imm(1U).CC(ConditionCode::CC_EQ).Inputs(9U);
1984         }
1985         BASIC_BLOCK(4U, -1L)
1986         {
1987             INST(5U, Opcode::Return).b().Inputs(0U);
1988         }
1989         BASIC_BLOCK(5U, -1L)
1990         {
1991             INST(8U, Opcode::Return).b().Inputs(0U);
1992         }
1993     }
1994 }
1995 
OUT_GRAPH(IfImmNegationOsr,Graph * graph)1996 OUT_GRAPH(IfImmNegationOsr, Graph *graph)
1997 {
1998     GRAPH(graph)
1999     {
2000         PARAMETER(0U, 0U).b();
2001         PARAMETER(1U, 1U).b();
2002         CONSTANT(3U, 0x1U);
2003         BASIC_BLOCK(2U, 4U, 5U)
2004         {
2005             INST(6U, Opcode::SaveState).NoVregs();
2006             INST(7U, Opcode::CallStatic).b().InputsAutoType(6U);
2007 
2008             INST(2U, Opcode::Neg).s32().Inputs(7U);
2009             INST(9U, Opcode::Add).s32().Inputs(2U, 3U);
2010             INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).Imm(1U).CC(ConditionCode::CC_EQ).Inputs(9U);
2011         }
2012         BASIC_BLOCK(4U, -1L)
2013         {
2014             INST(5U, Opcode::Return).b().Inputs(0U);
2015         }
2016         BASIC_BLOCK(5U, -1L)
2017         {
2018             INST(8U, Opcode::Return).b().Inputs(0U);
2019         }
2020     }
2021 }
2022 
TEST_F(PeepholesTest,IfImmNegationOsr)2023 TEST_F(PeepholesTest, IfImmNegationOsr)
2024 {
2025     // Peephole don't work with that graph in OSR
2026     GetGraph()->SetMode(GraphMode::Osr());
2027     src_graph::IfImmNegationOsr::CREATE(GetGraph());
2028     ASSERT_FALSE(GetGraph()->RunPass<Peepholes>());
2029 
2030     // Work with that graph
2031     auto optimizableGraph = CreateEmptyGraph();
2032     optimizableGraph->SetMode(GraphMode::Osr());
2033     out_graph::IfImmNegationOsr::CREATE(optimizableGraph);
2034 
2035     auto optimizableGraphAfter = CreateEmptyGraph();
2036     optimizableGraphAfter->SetMode(GraphMode::Osr());
2037     GRAPH(optimizableGraphAfter)
2038     {
2039         PARAMETER(0U, 0U).b();
2040         PARAMETER(1U, 1U).b();
2041         CONSTANT(3U, 0x1U);
2042         CONSTANT(10U, 0x0U);
2043         BASIC_BLOCK(2U, 4U, 5U)
2044         {
2045             INST(6U, Opcode::SaveState).NoVregs();
2046             INST(7U, Opcode::CallStatic).b().InputsAutoType(6U);
2047 
2048             INST(2U, Opcode::Neg).s32().Inputs(7U);
2049             INST(9U, Opcode::Add).s32().Inputs(2U, 3U);
2050             INST(11U, Opcode::Compare).b().SrcType(DataType::BOOL).Inputs(7U, 10U);
2051             INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).Imm(1U).CC(ConditionCode::CC_NE).Inputs(7U);
2052         }
2053         BASIC_BLOCK(4U, -1L)
2054         {
2055             INST(5U, Opcode::Return).b().Inputs(0U);
2056         }
2057         BASIC_BLOCK(5U, -1L)
2058         {
2059             INST(8U, Opcode::Return).b().Inputs(0U);
2060         }
2061     }
2062     ASSERT_TRUE(optimizableGraph->RunPass<Peepholes>());
2063     ASSERT_TRUE(GraphComparator().Compare(optimizableGraph, optimizableGraphAfter));
2064 }
2065 
2066 // Checking the shift with zero constant
TEST_F(PeepholesTest,ShlZeroTest)2067 TEST_F(PeepholesTest, ShlZeroTest)
2068 {
2069     GRAPH(GetGraph())
2070     {
2071         PARAMETER(0U, 0U).u64();
2072         CONSTANT(1U, 0U);
2073         CONSTANT(2U, 1U);
2074 
2075         BASIC_BLOCK(2U, -1L)
2076         {
2077             INST(3U, Opcode::Shl).u64().Inputs(0U, 1U);
2078             INST(4U, Opcode::Shl).u64().Inputs(0U, 2U);
2079 
2080             INST(5U, Opcode::Add).u64().Inputs(3U, 4U);
2081             INST(6U, Opcode::Return).u64().Inputs(5U);
2082         }
2083     }
2084     GetGraph()->RunPass<Peepholes>();
2085 
2086     ASSERT_TRUE(INS(3U).GetUsers().Empty());
2087 
2088     ASSERT_TRUE(CheckInputs(INS(5U), {0U, 4U}));
2089     ASSERT_EQ(INS(5U).GetOpcode(), Opcode::Add);
2090 }
2091 
2092 // Checking repeated shifts for constants with the same types
TEST_F(PeepholesTest,ShlRepeatConstTest1)2093 TEST_F(PeepholesTest, ShlRepeatConstTest1)
2094 {
2095     GRAPH(GetGraph())
2096     {
2097         PARAMETER(0U, 0U).u64();
2098         CONSTANT(1U, 5U);
2099         CONSTANT(2U, 6U);
2100 
2101         BASIC_BLOCK(2U, -1L)
2102         {
2103             INST(3U, Opcode::Shl).u64().Inputs(0U, 1U);
2104             INST(4U, Opcode::Shl).u64().Inputs(3U, 2U);
2105             INST(5U, Opcode::Return).u64().Inputs(4U);
2106         }
2107     }
2108     GetGraph()->RunPass<Peepholes>();
2109 
2110     ASSERT_NE(INS(2U).GetNext(), nullptr);
2111     auto const3 = static_cast<ConstantInst *>(INS(2U).GetNext());
2112     ASSERT_TRUE(const3->IsEqualConst(11U));
2113 
2114     ASSERT_TRUE(INS(3U).GetUsers().Empty());
2115     ASSERT_EQ(INS(3U).GetOpcode(), Opcode::Shl);
2116     ASSERT_TRUE(CheckUsers(INS(4U), {5U}));
2117     ASSERT_EQ(INS(4U).GetOpcode(), Opcode::Shl);
2118     ASSERT_EQ(INS(4U).GetInput(0U).GetInst(), &INS(0U));
2119     ASSERT_EQ(INS(4U).GetInput(1U).GetInst(), const3);
2120 
2121     ASSERT_TRUE(CheckInputs(INS(5U), {4U}));
2122 }
2123 
2124 // Checking repeated shifts for constants with different types
TEST_F(PeepholesTest,ShlRepeatConstTest2)2125 TEST_F(PeepholesTest, ShlRepeatConstTest2)
2126 {
2127     GRAPH(GetGraph())
2128     {
2129         PARAMETER(0U, 0U).u32();
2130         CONSTANT(1U, 5U);
2131         CONSTANT(2U, 6U);
2132 
2133         BASIC_BLOCK(2U, -1L)
2134         {
2135             INST(3U, Opcode::Shl).u16().Inputs(0U, 1U);
2136             INST(4U, Opcode::Shl).u32().Inputs(3U, 2U);
2137             INST(5U, Opcode::Return).u32().Inputs(4U);
2138         }
2139     }
2140     GetGraph()->RunPass<Peepholes>();
2141 
2142     ASSERT_EQ(INS(2U).GetNext(), nullptr);
2143 
2144     ASSERT_TRUE(CheckInputs(INS(3U), {0U, 1U}));
2145     ASSERT_TRUE(CheckUsers(INS(3U), {4U}));
2146     ASSERT_EQ(INS(3U).GetOpcode(), Opcode::Shl);
2147     ASSERT_TRUE(CheckInputs(INS(4U), {3U, 2U}));
2148     ASSERT_TRUE(CheckUsers(INS(4U), {5U}));
2149     ASSERT_EQ(INS(4U).GetOpcode(), Opcode::Shl);
2150 
2151     ASSERT_TRUE(CheckInputs(INS(5U), {4U}));
2152 }
2153 
2154 // Checking the shift for a constant greater than the type size
SRC_GRAPH(ShlBigConstTest,Graph * graph)2155 SRC_GRAPH(ShlBigConstTest, Graph *graph)
2156 {
2157     GRAPH(graph)
2158     {
2159         PARAMETER(0U, 0U).u64();
2160         PARAMETER(1U, 1U).u32();
2161         PARAMETER(2U, 2U).u16();
2162         PARAMETER(3U, 3U).u8();
2163         CONSTANT(4U, 127U);
2164 
2165         BASIC_BLOCK(2U, -1L)
2166         {
2167             INST(5U, Opcode::Shl).u64().Inputs(0U, 4U);
2168             INST(6U, Opcode::Shl).u32().Inputs(1U, 4U);
2169             INST(7U, Opcode::Shl).u16().Inputs(2U, 4U);
2170             INST(8U, Opcode::Shl).u8().Inputs(3U, 4U);
2171             INST(20U, Opcode::SaveState).NoVregs();
2172             INST(10U, Opcode::CallStatic).s64().InputsAutoType(5U, 6U, 7U, 8U, 20U);
2173             INST(9U, Opcode::Return).s64().Inputs(10U);
2174         }
2175     }
2176 }
2177 
TEST_F(PeepholesTest,ShlBigConstTest)2178 TEST_F(PeepholesTest, ShlBigConstTest)
2179 {
2180     src_graph::ShlBigConstTest::CREATE(GetGraph());
2181     GetGraph()->RunPass<Peepholes>();
2182 
2183     ASSERT_NE(INS(4U).GetNext(), nullptr);
2184     auto const64 = static_cast<ConstantInst *>(INS(4U).GetNext());
2185     ASSERT_TRUE(const64->IsEqualConst(63U));
2186 
2187     ASSERT_NE(const64->GetNext(), nullptr);
2188     auto const32 = static_cast<ConstantInst *>(const64->GetNext());
2189     ASSERT_TRUE(const32->IsEqualConst(31U));
2190 
2191     ASSERT_NE(const32->GetNext(), nullptr);
2192     auto const16 = static_cast<ConstantInst *>(const32->GetNext());
2193     ASSERT_TRUE(const16->IsEqualConst(15U));
2194 
2195     ASSERT_NE(const16->GetNext(), nullptr);
2196     auto const8 = static_cast<ConstantInst *>(const16->GetNext());
2197     ASSERT_TRUE(const8->IsEqualConst(7U));
2198 
2199     ASSERT_EQ(INS(5U).GetInput(0U).GetInst(), &INS(0U));
2200     ASSERT_EQ(INS(5U).GetInput(1U).GetInst(), const64);
2201     ASSERT_EQ(INS(5U).GetOpcode(), Opcode::Shl);
2202 
2203     ASSERT_EQ(INS(6U).GetInput(0U).GetInst(), &INS(1U));
2204     ASSERT_EQ(INS(6U).GetInput(1U).GetInst(), const32);
2205     ASSERT_EQ(INS(6U).GetOpcode(), Opcode::Shl);
2206 
2207     ASSERT_EQ(INS(7U).GetInput(0U).GetInst(), &INS(2U));
2208     ASSERT_EQ(INS(7U).GetInput(1U).GetInst(), const16);
2209     ASSERT_EQ(INS(7U).GetOpcode(), Opcode::Shl);
2210 
2211     ASSERT_EQ(INS(8U).GetInput(0U).GetInst(), &INS(3U));
2212     ASSERT_EQ(INS(8U).GetInput(1U).GetInst(), const8);
2213     ASSERT_EQ(INS(8U).GetOpcode(), Opcode::Shl);
2214 }
2215 
TEST_F(PeepholesTest,ShlPlusShrTest)2216 TEST_F(PeepholesTest, ShlPlusShrTest)
2217 {
2218     // applied
2219     GRAPH(GetGraph())
2220     {
2221         PARAMETER(0U, 0U).s32();
2222         CONSTANT(1U, 0x18U);
2223 
2224         BASIC_BLOCK(2U, -1L)
2225         {
2226             INST(2U, Opcode::Shl).s32().Inputs(0U, 1U);
2227             INST(3U, Opcode::Shr).s32().Inputs(2U, 1U);
2228             INST(4U, Opcode::Return).s32().Inputs(3U);
2229         }
2230     }
2231     ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
2232     GetGraph()->RunPass<Cleanup>();
2233     auto graph = CreateEmptyGraph();
2234     GRAPH(graph)
2235     {
2236         PARAMETER(0U, 0U).s32();
2237         CONSTANT(5U, 0xffU);
2238 
2239         BASIC_BLOCK(2U, -1L)
2240         {
2241             INST(6U, Opcode::And).s32().Inputs(0U, 5U);
2242             INST(4U, Opcode::Return).s32().Inputs(6U);
2243         }
2244     }
2245     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
2246 }
2247 
TEST_F(PeepholesTest,ShlPlusShrTest1)2248 TEST_F(PeepholesTest, ShlPlusShrTest1)
2249 {
2250     // not applied, different constants
2251     GRAPH(GetGraph())
2252     {
2253         PARAMETER(0U, 0U).s32();
2254         CONSTANT(1U, 0x18U);
2255         CONSTANT(5U, 0x10U);
2256 
2257         BASIC_BLOCK(2U, -1L)
2258         {
2259             INST(2U, Opcode::Shl).s32().Inputs(0U, 1U);
2260             INST(3U, Opcode::Shr).s32().Inputs(2U, 5U);
2261             INST(4U, Opcode::Return).s32().Inputs(3U);
2262         }
2263     }
2264     ASSERT_FALSE(GetGraph()->RunPass<Peepholes>());
2265     auto graph = CreateEmptyGraph();
2266     GRAPH(graph)
2267     {
2268         PARAMETER(0U, 0U).s32();
2269         CONSTANT(1U, 0x18U);
2270         CONSTANT(5U, 0x10U);
2271 
2272         BASIC_BLOCK(2U, -1L)
2273         {
2274             INST(2U, Opcode::Shl).s32().Inputs(0U, 1U);
2275             INST(3U, Opcode::Shr).s32().Inputs(2U, 5U);
2276             INST(4U, Opcode::Return).s32().Inputs(3U);
2277         }
2278     }
2279     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
2280 }
2281 
TEST_F(PeepholesTest,ShlPlusShrTest2)2282 TEST_F(PeepholesTest, ShlPlusShrTest2)
2283 {
2284     // not applied, same inputs but not a constant
2285     GRAPH(GetGraph())
2286     {
2287         PARAMETER(0U, 0U).s32();
2288         PARAMETER(1U, 1U).s32();
2289 
2290         BASIC_BLOCK(2U, -1L)
2291         {
2292             INST(2U, Opcode::Shl).s32().Inputs(0U, 1U);
2293             INST(3U, Opcode::Shr).s32().Inputs(2U, 1U);
2294             INST(4U, Opcode::Return).s32().Inputs(3U);
2295         }
2296     }
2297     ASSERT_FALSE(GetGraph()->RunPass<Peepholes>());
2298     auto graph = CreateEmptyGraph();
2299     GRAPH(graph)
2300     {
2301         PARAMETER(0U, 0U).s32();
2302         PARAMETER(1U, 1U).s32();
2303 
2304         BASIC_BLOCK(2U, -1L)
2305         {
2306             INST(2U, Opcode::Shl).s32().Inputs(0U, 1U);
2307             INST(3U, Opcode::Shr).s32().Inputs(2U, 1U);
2308             INST(4U, Opcode::Return).s32().Inputs(3U);
2309         }
2310     }
2311     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
2312 }
2313 
2314 // Checking the shift with zero constant
TEST_F(PeepholesTest,ShrZeroTest)2315 TEST_F(PeepholesTest, ShrZeroTest)
2316 {
2317     GRAPH(GetGraph())
2318     {
2319         PARAMETER(0U, 0U).u64();
2320         CONSTANT(1U, 0U);
2321         CONSTANT(2U, 1U);
2322 
2323         BASIC_BLOCK(2U, -1L)
2324         {
2325             INST(3U, Opcode::Shr).u64().Inputs(0U, 1U);
2326             INST(4U, Opcode::Shr).u64().Inputs(0U, 2U);
2327 
2328             INST(5U, Opcode::Add).u64().Inputs(3U, 4U);
2329             INST(6U, Opcode::Return).u64().Inputs(5U);
2330         }
2331     }
2332     GetGraph()->RunPass<Peepholes>();
2333 
2334     ASSERT_TRUE(INS(3U).GetUsers().Empty());
2335 
2336     ASSERT_TRUE(CheckInputs(INS(5U), {0U, 4U}));
2337     ASSERT_EQ(INS(5U).GetOpcode(), Opcode::Add);
2338 }
2339 
2340 // Checking repeated shifts for constants with the same types
TEST_F(PeepholesTest,ShrRepeatConstTest1)2341 TEST_F(PeepholesTest, ShrRepeatConstTest1)
2342 {
2343     GRAPH(GetGraph())
2344     {
2345         PARAMETER(0U, 0U).u64();
2346         CONSTANT(1U, 5U);
2347         CONSTANT(2U, 6U);
2348 
2349         BASIC_BLOCK(2U, -1L)
2350         {
2351             INST(3U, Opcode::Shr).u64().Inputs(0U, 1U);
2352             INST(4U, Opcode::Shr).u64().Inputs(3U, 2U);
2353             INST(5U, Opcode::Return).u64().Inputs(4U);
2354         }
2355     }
2356     GetGraph()->RunPass<Peepholes>();
2357 
2358     ASSERT_NE(INS(2U).GetNext(), nullptr);
2359     auto const3 = static_cast<ConstantInst *>(INS(2U).GetNext());
2360     ASSERT_TRUE(const3->IsEqualConst(11U));
2361 
2362     ASSERT_TRUE(INS(3U).GetUsers().Empty());
2363     ASSERT_EQ(INS(3U).GetOpcode(), Opcode::Shr);
2364     ASSERT_TRUE(CheckUsers(INS(4U), {5U}));
2365     ASSERT_EQ(INS(4U).GetOpcode(), Opcode::Shr);
2366     ASSERT_EQ(INS(4U).GetInput(0U).GetInst(), &INS(0U));
2367     ASSERT_EQ(INS(4U).GetInput(1U).GetInst(), const3);
2368 
2369     ASSERT_TRUE(CheckInputs(INS(5U), {4U}));
2370 }
2371 
2372 // Checking repeated shifts for constants with different types
TEST_F(PeepholesTest,ShrRepeatConstTest2)2373 TEST_F(PeepholesTest, ShrRepeatConstTest2)
2374 {
2375     GRAPH(GetGraph())
2376     {
2377         PARAMETER(0U, 0U).u32();
2378         CONSTANT(1U, 5U);
2379         CONSTANT(2U, 6U);
2380 
2381         BASIC_BLOCK(2U, -1L)
2382         {
2383             INST(3U, Opcode::Shr).u16().Inputs(0U, 1U);
2384             INST(4U, Opcode::Shr).u32().Inputs(3U, 2U);
2385             INST(5U, Opcode::Return).u32().Inputs(4U);
2386         }
2387     }
2388     GetGraph()->RunPass<Peepholes>();
2389 
2390     ASSERT_EQ(INS(2U).GetNext(), nullptr);
2391 
2392     ASSERT_TRUE(CheckInputs(INS(3U), {0U, 1U}));
2393     ASSERT_TRUE(CheckUsers(INS(3U), {4U}));
2394     ASSERT_EQ(INS(3U).GetOpcode(), Opcode::Shr);
2395     ASSERT_TRUE(CheckInputs(INS(4U), {3U, 2U}));
2396     ASSERT_TRUE(CheckUsers(INS(4U), {5U}));
2397     ASSERT_EQ(INS(4U).GetOpcode(), Opcode::Shr);
2398 
2399     ASSERT_TRUE(CheckInputs(INS(5U), {4U}));
2400 }
2401 
2402 // Checking the shift for a constant greater than the type size
SRC_GRAPH(ShrBigConstTest,Graph * graph)2403 SRC_GRAPH(ShrBigConstTest, Graph *graph)
2404 {
2405     GRAPH(graph)
2406     {
2407         PARAMETER(0U, 0U).u64();
2408         PARAMETER(1U, 1U).u32();
2409         PARAMETER(2U, 2U).u16();
2410         PARAMETER(3U, 3U).u8();
2411         CONSTANT(4U, 127U);
2412 
2413         BASIC_BLOCK(2U, -1L)
2414         {
2415             INST(5U, Opcode::Shr).u64().Inputs(0U, 4U);
2416             INST(6U, Opcode::Shr).u32().Inputs(1U, 4U);
2417             INST(7U, Opcode::Shr).u16().Inputs(2U, 4U);
2418             INST(8U, Opcode::Shr).u8().Inputs(3U, 4U);
2419             INST(20U, Opcode::SaveState).NoVregs();
2420             INST(9U, Opcode::CallStatic).u64().InputsAutoType(5U, 6U, 7U, 8U, 20U);
2421             INST(10U, Opcode::Return).u64().Inputs(9U);
2422         }
2423     }
2424 }
2425 
TEST_F(PeepholesTest,ShrBigConstTest)2426 TEST_F(PeepholesTest, ShrBigConstTest)
2427 {
2428     src_graph::ShrBigConstTest::CREATE(GetGraph());
2429     GetGraph()->RunPass<Peepholes>();
2430 
2431     ASSERT_NE(INS(4U).GetNext(), nullptr);
2432     auto const64 = static_cast<ConstantInst *>(INS(4U).GetNext());
2433     ASSERT_TRUE(const64->IsEqualConst(63U));
2434 
2435     ASSERT_NE(const64->GetNext(), nullptr);
2436     auto const32 = static_cast<ConstantInst *>(const64->GetNext());
2437     ASSERT_TRUE(const32->IsEqualConst(31U));
2438 
2439     ASSERT_NE(const32->GetNext(), nullptr);
2440     auto const16 = static_cast<ConstantInst *>(const32->GetNext());
2441     ASSERT_TRUE(const16->IsEqualConst(15U));
2442 
2443     ASSERT_NE(const16->GetNext(), nullptr);
2444     auto const8 = static_cast<ConstantInst *>(const16->GetNext());
2445     ASSERT_TRUE(const8->IsEqualConst(7U));
2446 
2447     ASSERT_EQ(INS(5U).GetInput(0U).GetInst(), &INS(0U));
2448     ASSERT_EQ(INS(5U).GetInput(1U).GetInst(), const64);
2449     ASSERT_EQ(INS(5U).GetOpcode(), Opcode::Shr);
2450 
2451     ASSERT_EQ(INS(6U).GetInput(0U).GetInst(), &INS(1U));
2452     ASSERT_EQ(INS(6U).GetInput(1U).GetInst(), const32);
2453     ASSERT_EQ(INS(6U).GetOpcode(), Opcode::Shr);
2454 
2455     ASSERT_EQ(INS(7U).GetInput(0U).GetInst(), &INS(2U));
2456     ASSERT_EQ(INS(7U).GetInput(1U).GetInst(), const16);
2457     ASSERT_EQ(INS(7U).GetOpcode(), Opcode::Shr);
2458 
2459     ASSERT_EQ(INS(8U).GetInput(0U).GetInst(), &INS(3U));
2460     ASSERT_EQ(INS(8U).GetInput(1U).GetInst(), const8);
2461     ASSERT_EQ(INS(8U).GetOpcode(), Opcode::Shr);
2462 }
2463 
2464 // Checking the shift with zero constant
TEST_F(PeepholesTest,AShrZeroTest)2465 TEST_F(PeepholesTest, AShrZeroTest)
2466 {
2467     GRAPH(GetGraph())
2468     {
2469         PARAMETER(0U, 0U).u64();
2470         CONSTANT(1U, 0U);
2471         CONSTANT(2U, 1U);
2472 
2473         BASIC_BLOCK(2U, -1L)
2474         {
2475             INST(3U, Opcode::AShr).u64().Inputs(0U, 1U);
2476             INST(4U, Opcode::AShr).u64().Inputs(0U, 2U);
2477 
2478             INST(5U, Opcode::Add).u64().Inputs(3U, 4U);
2479             INST(6U, Opcode::Return).u64().Inputs(5U);
2480         }
2481     }
2482     GetGraph()->RunPass<Peepholes>();
2483 
2484     ASSERT_TRUE(INS(3U).GetUsers().Empty());
2485 
2486     ASSERT_TRUE(CheckInputs(INS(5U), {0U, 4U}));
2487     ASSERT_EQ(INS(5U).GetOpcode(), Opcode::Add);
2488 }
2489 
2490 // Checking repeated shifts for constants with the same types
TEST_F(PeepholesTest,AShrRepeatConstTest1)2491 TEST_F(PeepholesTest, AShrRepeatConstTest1)
2492 {
2493     GRAPH(GetGraph())
2494     {
2495         PARAMETER(0U, 0U).u64();
2496         CONSTANT(1U, 5U);
2497         CONSTANT(2U, 6U);
2498 
2499         BASIC_BLOCK(2U, -1L)
2500         {
2501             INST(3U, Opcode::AShr).u64().Inputs(0U, 1U);
2502             INST(4U, Opcode::AShr).u64().Inputs(3U, 2U);
2503             INST(5U, Opcode::Return).u64().Inputs(4U);
2504         }
2505     }
2506     GetGraph()->RunPass<Peepholes>();
2507 
2508     ASSERT_NE(INS(2U).GetNext(), nullptr);
2509     auto const3 = static_cast<ConstantInst *>(INS(2U).GetNext());
2510     ASSERT_TRUE(const3->IsEqualConst(11U));
2511 
2512     ASSERT_TRUE(INS(3U).GetUsers().Empty());
2513     ASSERT_EQ(INS(3U).GetOpcode(), Opcode::AShr);
2514     ASSERT_TRUE(CheckUsers(INS(4U), {5U}));
2515     ASSERT_EQ(INS(4U).GetOpcode(), Opcode::AShr);
2516     ASSERT_EQ(INS(4U).GetInput(0U).GetInst(), &INS(0U));
2517     ASSERT_EQ(INS(4U).GetInput(1U).GetInst(), const3);
2518 
2519     ASSERT_TRUE(CheckInputs(INS(5U), {4U}));
2520 }
2521 
2522 // Checking repeated shifts for constants with different types
TEST_F(PeepholesTest,AShrRepeatConstTest2)2523 TEST_F(PeepholesTest, AShrRepeatConstTest2)
2524 {
2525     GRAPH(GetGraph())
2526     {
2527         PARAMETER(0U, 0U).u32();
2528         CONSTANT(1U, 5U);
2529         CONSTANT(2U, 6U);
2530 
2531         BASIC_BLOCK(2U, -1L)
2532         {
2533             INST(3U, Opcode::AShr).u16().Inputs(0U, 1U);
2534             INST(4U, Opcode::AShr).u32().Inputs(3U, 2U);
2535             INST(5U, Opcode::Return).u32().Inputs(4U);
2536         }
2537     }
2538     GetGraph()->RunPass<Peepholes>();
2539 
2540     ASSERT_EQ(INS(2U).GetNext(), nullptr);
2541 
2542     ASSERT_TRUE(CheckInputs(INS(3U), {0U, 1U}));
2543     ASSERT_TRUE(CheckUsers(INS(3U), {4U}));
2544     ASSERT_EQ(INS(3U).GetOpcode(), Opcode::AShr);
2545     ASSERT_TRUE(CheckInputs(INS(4U), {3U, 2U}));
2546     ASSERT_TRUE(CheckUsers(INS(4U), {5U}));
2547     ASSERT_EQ(INS(4U).GetOpcode(), Opcode::AShr);
2548 
2549     ASSERT_TRUE(CheckInputs(INS(5U), {4U}));
2550 }
2551 
2552 // Checking the shift for a constant greater than the type size
SRC_GRAPH(AShrBigConstTest,Graph * graph)2553 SRC_GRAPH(AShrBigConstTest, Graph *graph)
2554 {
2555     GRAPH(graph)
2556     {
2557         PARAMETER(0U, 0U).u64();
2558         PARAMETER(1U, 1U).u32();
2559         PARAMETER(2U, 2U).u16();
2560         PARAMETER(3U, 3U).u8();
2561         CONSTANT(4U, 127U);
2562 
2563         BASIC_BLOCK(2U, -1L)
2564         {
2565             INST(5U, Opcode::AShr).u64().Inputs(0U, 4U);
2566             INST(6U, Opcode::AShr).u32().Inputs(1U, 4U);
2567             INST(7U, Opcode::AShr).u16().Inputs(2U, 4U);
2568             INST(8U, Opcode::AShr).u8().Inputs(3U, 4U);
2569             INST(20U, Opcode::SaveState).NoVregs();
2570             INST(10U, Opcode::CallStatic).u64().InputsAutoType(5U, 6U, 7U, 8U, 20U);
2571             INST(9U, Opcode::Return).u64().Inputs(10U);
2572         }
2573     }
2574 }
2575 
TEST_F(PeepholesTest,AShrBigConstTest)2576 TEST_F(PeepholesTest, AShrBigConstTest)
2577 {
2578     src_graph::AShrBigConstTest::CREATE(GetGraph());
2579     GetGraph()->RunPass<Peepholes>();
2580 
2581     ASSERT_NE(INS(4U).GetNext(), nullptr);
2582     auto const64 = static_cast<ConstantInst *>(INS(4U).GetNext());
2583     ASSERT_TRUE(const64->IsEqualConst(63U));
2584 
2585     ASSERT_NE(const64->GetNext(), nullptr);
2586     auto const32 = static_cast<ConstantInst *>(const64->GetNext());
2587     ASSERT_TRUE(const32->IsEqualConst(31U));
2588 
2589     ASSERT_NE(const32->GetNext(), nullptr);
2590     auto const16 = static_cast<ConstantInst *>(const32->GetNext());
2591     ASSERT_TRUE(const16->IsEqualConst(15U));
2592 
2593     ASSERT_NE(const16->GetNext(), nullptr);
2594     auto const8 = static_cast<ConstantInst *>(const16->GetNext());
2595     ASSERT_TRUE(const8->IsEqualConst(7U));
2596 
2597     ASSERT_EQ(INS(5U).GetInput(0U).GetInst(), &INS(0U));
2598     ASSERT_EQ(INS(5U).GetInput(1U).GetInst(), const64);
2599     ASSERT_EQ(INS(5U).GetOpcode(), Opcode::AShr);
2600 
2601     ASSERT_EQ(INS(6U).GetInput(0U).GetInst(), &INS(1U));
2602     ASSERT_EQ(INS(6U).GetInput(1U).GetInst(), const32);
2603     ASSERT_EQ(INS(6U).GetOpcode(), Opcode::AShr);
2604 
2605     ASSERT_EQ(INS(7U).GetInput(0U).GetInst(), &INS(2U));
2606     ASSERT_EQ(INS(7U).GetInput(1U).GetInst(), const16);
2607     ASSERT_EQ(INS(7U).GetOpcode(), Opcode::AShr);
2608 
2609     ASSERT_EQ(INS(8U).GetInput(0U).GetInst(), &INS(3U));
2610     ASSERT_EQ(INS(8U).GetInput(1U).GetInst(), const8);
2611     ASSERT_EQ(INS(8U).GetOpcode(), Opcode::AShr);
2612 }
2613 
TEST_F(PeepholesTest,ShlPlusAShrTest1)2614 TEST_F(PeepholesTest, ShlPlusAShrTest1)
2615 {
2616     GRAPH(GetGraph())
2617     {
2618         PARAMETER(0U, 0U).s32();
2619         CONSTANT(1U, 0x18U);
2620 
2621         BASIC_BLOCK(2U, -1L)
2622         {
2623             INST(2U, Opcode::Shl).s32().Inputs(0U, 1U);
2624             INST(3U, Opcode::AShr).s32().Inputs(2U, 1U);
2625             INST(4U, Opcode::Return).s32().Inputs(3U);
2626         }
2627     }
2628     ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
2629     GetGraph()->RunPass<Cleanup>();
2630     auto graph = CreateEmptyGraph();
2631     GRAPH(graph)
2632     {
2633         PARAMETER(0U, 0U).s32();
2634 
2635         BASIC_BLOCK(2U, -1L)
2636         {
2637             INST(6U, Opcode::Cast).s8().SrcType(DataType::INT32).Inputs(0U);
2638             INST(4U, Opcode::Return).s32().Inputs(6U);
2639         }
2640     }
2641     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
2642 }
2643 
TEST_F(PeepholesTest,ShlPlusAShrTest2)2644 TEST_F(PeepholesTest, ShlPlusAShrTest2)
2645 {
2646     GRAPH(GetGraph())
2647     {
2648         PARAMETER(0U, 0U).s32();
2649         CONSTANT(1U, 0x10U);
2650 
2651         BASIC_BLOCK(2U, -1L)
2652         {
2653             INST(2U, Opcode::Shl).s32().Inputs(0U, 1U);
2654             INST(3U, Opcode::AShr).s32().Inputs(2U, 1U);
2655             INST(4U, Opcode::Return).s32().Inputs(3U);
2656         }
2657     }
2658     ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
2659     GetGraph()->RunPass<Cleanup>();
2660     auto graph = CreateEmptyGraph();
2661     GRAPH(graph)
2662     {
2663         PARAMETER(0U, 0U).s32();
2664 
2665         BASIC_BLOCK(2U, -1L)
2666         {
2667             INST(6U, Opcode::Cast).s16().SrcType(DataType::INT32).Inputs(0U);
2668             INST(4U, Opcode::Return).s32().Inputs(6U);
2669         }
2670     }
2671     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
2672 }
2673 
TEST_F(PeepholesTest,ShlPlusAShrTest3)2674 TEST_F(PeepholesTest, ShlPlusAShrTest3)
2675 {
2676     GRAPH(GetGraph())
2677     {
2678         PARAMETER(0U, 0U).s64();
2679         CONSTANT(1U, 0x8U);
2680 
2681         BASIC_BLOCK(2U, -1L)
2682         {
2683             INST(2U, Opcode::Shl).s64().Inputs(0U, 1U);
2684             INST(3U, Opcode::AShr).s64().Inputs(2U, 1U);
2685             INST(4U, Opcode::Return).s32().Inputs(3U);
2686         }
2687     }
2688     ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
2689     GetGraph()->RunPass<Cleanup>();
2690     auto graph = CreateEmptyGraph();
2691     GRAPH(graph)
2692     {
2693         PARAMETER(0U, 0U).s64();
2694 
2695         BASIC_BLOCK(2U, -1L)
2696         {
2697             INST(6U, Opcode::Cast).s32().SrcType(DataType::INT64).Inputs(0U);
2698             INST(4U, Opcode::Return).s32().Inputs(6U);
2699         }
2700     }
2701     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
2702 }
2703 
TEST_F(PeepholesTest,ShlPlusAShrTest4)2704 TEST_F(PeepholesTest, ShlPlusAShrTest4)
2705 {
2706     // not applied, different constants
2707     GRAPH(GetGraph())
2708     {
2709         PARAMETER(0U, 0U).s32();
2710         CONSTANT(1U, 0x18U);
2711         CONSTANT(5U, 0x10U);
2712 
2713         BASIC_BLOCK(2U, -1L)
2714         {
2715             INST(2U, Opcode::Shl).s32().Inputs(0U, 1U);
2716             INST(3U, Opcode::AShr).s32().Inputs(2U, 5U);
2717             INST(4U, Opcode::Return).s32().Inputs(3U);
2718         }
2719     }
2720     ASSERT_FALSE(GetGraph()->RunPass<Peepholes>());
2721     auto graph = CreateEmptyGraph();
2722     GRAPH(graph)
2723     {
2724         PARAMETER(0U, 0U).s32();
2725         CONSTANT(1U, 0x18U);
2726         CONSTANT(5U, 0x10U);
2727 
2728         BASIC_BLOCK(2U, -1L)
2729         {
2730             INST(2U, Opcode::Shl).s32().Inputs(0U, 1U);
2731             INST(3U, Opcode::AShr).s32().Inputs(2U, 5U);
2732             INST(4U, Opcode::Return).s32().Inputs(3U);
2733         }
2734     }
2735     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
2736 }
2737 
TEST_F(PeepholesTest,ShlPlusAShrTest5)2738 TEST_F(PeepholesTest, ShlPlusAShrTest5)
2739 {
2740     // not applied, same inputs but not a constant
2741     GRAPH(GetGraph())
2742     {
2743         PARAMETER(0U, 0U).s32();
2744         PARAMETER(1U, 1U).s32();
2745 
2746         BASIC_BLOCK(2U, -1L)
2747         {
2748             INST(2U, Opcode::Shl).s32().Inputs(0U, 1U);
2749             INST(3U, Opcode::Shr).s32().Inputs(2U, 1U);
2750             INST(4U, Opcode::Return).s32().Inputs(3U);
2751         }
2752     }
2753     ASSERT_FALSE(GetGraph()->RunPass<Peepholes>());
2754     auto graph = CreateEmptyGraph();
2755     GRAPH(graph)
2756     {
2757         PARAMETER(0U, 0U).s32();
2758         PARAMETER(1U, 1U).s32();
2759 
2760         BASIC_BLOCK(2U, -1L)
2761         {
2762             INST(2U, Opcode::Shl).s32().Inputs(0U, 1U);
2763             INST(3U, Opcode::Shr).s32().Inputs(2U, 1U);
2764             INST(4U, Opcode::Return).s32().Inputs(3U);
2765         }
2766     }
2767     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
2768 }
2769 
TEST_F(PeepholesTest,TestMulCase1)2770 TEST_F(PeepholesTest, TestMulCase1)
2771 {
2772     // case 1:
2773     // 0. Const 1
2774     // 1. MUL v5, v0 -> {v2, ...}
2775     // 2. INS v1
2776     // ===>
2777     // 0. Const 1
2778     // 1. MUL v5, v0
2779     // 2. INS v5
2780     GRAPH(GetGraph())
2781     {
2782         PARAMETER(0U, 0U).u64();
2783         CONSTANT(3U, 1U);
2784         BASIC_BLOCK(2U, -1L)
2785         {
2786             INST(6U, Opcode::Mul).u64().Inputs(0U, 3U);
2787             INST(12U, Opcode::Mul).u16().Inputs(0U, 3U);
2788             INST(20U, Opcode::SaveState).NoVregs();
2789             INST(21U, Opcode::CallStatic).u64().InputsAutoType(6U, 12U, 20U);
2790             INST(14U, Opcode::Return).u64().Inputs(21U);
2791         }
2792     }
2793     GetGraph()->RunPass<Peepholes>();
2794 
2795     ASSERT_EQ(INS(21U).GetInput(0U).GetInst(), &INS(0U));
2796     ASSERT_TRUE(INS(6U).GetUsers().Empty());
2797 
2798     ASSERT_EQ(INS(21U).GetInput(1U).GetInst(), &INS(0U));
2799     ASSERT_TRUE(INS(12U).GetUsers().Empty());
2800 }
2801 
TEST_F(PeepholesTest,TestMulCase2)2802 TEST_F(PeepholesTest, TestMulCase2)
2803 {
2804     // case 2:
2805     // 0. Const -1
2806     // 1. MUL v5, v0
2807     // 2. INS v1
2808     // ===>
2809     // 0. Const -1
2810     // 1. MUL v5, v0
2811     // 3. NEG v5 -> {v2, ...}
2812     // 2. INS v3
2813     GRAPH(GetGraph())
2814     {
2815         PARAMETER(0U, 0U).u64();
2816         CONSTANT(3U, -1L);
2817         BASIC_BLOCK(2U, -1L)
2818         {
2819             INST(6U, Opcode::Mul).u64().Inputs(0U, 3U);
2820             INST(20U, Opcode::SaveState).NoVregs();
2821             INST(13U, Opcode::CallStatic).u64().InputsAutoType(6U, 20U);
2822             INST(12U, Opcode::Return).u64().Inputs(13U);
2823         }
2824     }
2825     ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
2826     GetGraph()->RunPass<Cleanup>();
2827     auto graph = CreateEmptyGraph();
2828     GRAPH(graph)
2829     {
2830         PARAMETER(0U, 0U).u64();
2831         BASIC_BLOCK(2U, -1L)
2832         {
2833             INST(6U, Opcode::Neg).u64().Inputs(0U);
2834             INST(20U, Opcode::SaveState).NoVregs();
2835             INST(13U, Opcode::CallStatic).u64().InputsAutoType(6U, 20U);
2836             INST(12U, Opcode::Return).u64().Inputs(13U);
2837         }
2838     }
2839     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
2840 }
2841 
TEST_F(PeepholesTest,TestMulCase3)2842 TEST_F(PeepholesTest, TestMulCase3)
2843 {
2844     // case 3:
2845     // 0. Const 2
2846     // 1. MUL v5, v0
2847     // 2. INS v1
2848     // ===>
2849     // 0. Const -1
2850     // 1. MUL v5, v0
2851     // 3. ADD v5 , V5 -> {v2, ...}
2852     // 2. INS v3
2853     GRAPH(GetGraph())
2854     {
2855         PARAMETER(0U, 0U).u64();
2856         CONSTANT(3U, 2U);
2857         BASIC_BLOCK(2U, -1L)
2858         {
2859             INST(6U, Opcode::Mul).u64().Inputs(0U, 3U);
2860             INST(20U, Opcode::SaveState).NoVregs();
2861             INST(13U, Opcode::CallStatic).u64().InputsAutoType(6U, 20U);
2862             INST(12U, Opcode::Return).u64().Inputs(13U);
2863         }
2864     }
2865     ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
2866     GetGraph()->RunPass<Cleanup>();
2867     auto graph = CreateEmptyGraph();
2868     GRAPH(graph)
2869     {
2870         PARAMETER(0U, 0U).u64();
2871         BASIC_BLOCK(2U, -1L)
2872         {
2873             INST(6U, Opcode::Add).u64().Inputs(0U, 0U);
2874             INST(20U, Opcode::SaveState).NoVregs();
2875             INST(13U, Opcode::CallStatic).u64().InputsAutoType(6U, 20U);
2876             INST(12U, Opcode::Return).u64().Inputs(13U);
2877         }
2878     }
2879     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
2880 }
2881 
SRC_GRAPH(TestMulCase4,Graph * graph)2882 SRC_GRAPH(TestMulCase4, Graph *graph)
2883 {
2884     GRAPH(graph)
2885     {
2886         PARAMETER(0U, 0U).u64();
2887         PARAMETER(1U, 1U).s64();
2888         PARAMETER(2U, 2U).u16();
2889         PARAMETER(13U, 3U).f32();
2890         PARAMETER(14U, 4U).f64();
2891         CONSTANT(3U, 4U);
2892         CONSTANT(4U, 16U);
2893         CONSTANT(5U, 512U);
2894         CONSTANT(15U, 4.0F);
2895         CONSTANT(16U, 16.0_D);
2896         BASIC_BLOCK(2U, -1L)
2897         {
2898             INST(6U, Opcode::Mul).u64().Inputs(0U, 3U);
2899             INST(8U, Opcode::Mul).s64().Inputs(1U, 4U);
2900             INST(10U, Opcode::Mul).u16().Inputs(2U, 5U);
2901             INST(17U, Opcode::Mul).f32().Inputs(13U, 15U);
2902             INST(19U, Opcode::Mul).f64().Inputs(14U, 16U);
2903             INST(20U, Opcode::SaveState).NoVregs();
2904             INST(21U, Opcode::CallStatic).u64().InputsAutoType(6U, 8U, 10U, 17U, 19U, 20U);
2905             INST(22U, Opcode::Return).u64().Inputs(21U);
2906         }
2907     }
2908 }
2909 
OUT_GRAPH(TestMulCase4,Graph * graph)2910 OUT_GRAPH(TestMulCase4, Graph *graph)
2911 {
2912     GRAPH(graph)
2913     {
2914         PARAMETER(0U, 0U).u64();
2915         PARAMETER(1U, 1U).s64();
2916         PARAMETER(2U, 2U).u16();
2917         PARAMETER(13U, 3U).f32();
2918         PARAMETER(14U, 4U).f64();
2919         CONSTANT(3U, 4U);
2920         CONSTANT(15U, 4.0F);
2921         CONSTANT(16U, 16.0_D);
2922         CONSTANT(23U, 2U);
2923         CONSTANT(24U, 9U);
2924         BASIC_BLOCK(2U, -1L)
2925         {
2926             INST(6U, Opcode::Shl).u64().Inputs(0U, 23U);
2927             INST(8U, Opcode::Shl).s64().Inputs(1U, 3U);
2928             INST(10U, Opcode::Shl).u16().Inputs(2U, 24U);
2929             INST(17U, Opcode::Mul).f32().Inputs(13U, 15U);
2930             INST(19U, Opcode::Mul).f64().Inputs(14U, 16U);
2931             INST(20U, Opcode::SaveState).NoVregs();
2932             INST(21U, Opcode::CallStatic).u64().InputsAutoType(6U, 8U, 10U, 17U, 19U, 20U);
2933             INST(22U, Opcode::Return).u64().Inputs(21U);
2934         }
2935     }
2936 }
2937 
TEST_F(PeepholesTest,TestMulCase4)2938 TEST_F(PeepholesTest, TestMulCase4)
2939 {
2940     // case 4:
2941     // 0. Const 2^N
2942     // 1. MUL v5, v0
2943     // 2. INS v1
2944     // ===>
2945     // 0. Const -1
2946     // 1. MUL v5, v0
2947     // 3. SHL v5 , N -> {v2, ...}
2948     // 2. INS v3
2949     src_graph::TestMulCase4::CREATE(GetGraph());
2950     ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
2951     GetGraph()->RunPass<Cleanup>();
2952     auto graph = CreateEmptyGraph();
2953     out_graph::TestMulCase4::CREATE(graph);
2954     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
2955 }
2956 
TEST_F(PeepholesTest,TestDivCase1)2957 TEST_F(PeepholesTest, TestDivCase1)
2958 {
2959     // case 1:
2960     // 0. Const 1
2961     // 1. DIV v5, v0 -> {v2, ...}
2962     // 2. INS v1
2963     // ===>
2964     // 0. Const 1
2965     // 1. DIV v5, v0
2966     // 3. MOV v5 -> {v2, ...}
2967     // 2. INS v3
2968     GRAPH(GetGraph())
2969     {
2970         PARAMETER(0U, 0U).u64();
2971         CONSTANT(3U, 1U);
2972         BASIC_BLOCK(2U, -1L)
2973         {
2974             INST(6U, Opcode::Div).u64().Inputs(0U, 3U);
2975             INST(12U, Opcode::Div).u16().Inputs(0U, 3U);
2976             INST(20U, Opcode::SaveState).NoVregs();
2977             INST(21U, Opcode::CallStatic).u64().InputsAutoType(6U, 12U, 20U);
2978             INST(22U, Opcode::Return).u64().Inputs(21U);
2979         }
2980     }
2981     GetGraph()->RunPass<Peepholes>();
2982     GraphChecker(GetGraph()).Check();
2983 
2984     ASSERT_EQ(INS(21U).GetInput(0U).GetInst(), &INS(0U));
2985     ASSERT_TRUE(INS(6U).GetUsers().Empty());
2986 
2987     ASSERT_EQ(INS(21U).GetInput(1U).GetInst(), &INS(0U));
2988     ASSERT_TRUE(INS(12U).GetUsers().Empty());
2989 }
2990 
TEST_F(PeepholesTest,TestDivCase2)2991 TEST_F(PeepholesTest, TestDivCase2)
2992 {
2993     // case 2:
2994     // 0. Const -1
2995     // 1. DIV v5, v0 -> {v2, ...}
2996     // 2. INS v1
2997     // ===>
2998     // 0. Const -1
2999     // 1. DIV v5, v0
3000     // 3. NEG v5 -> {v2, ...}
3001     // 2. INS v3
3002     GRAPH(GetGraph())
3003     {
3004         PARAMETER(0U, 0U).u64();
3005         CONSTANT(3U, -1L);
3006         BASIC_BLOCK(2U, -1L)
3007         {
3008             INST(6U, Opcode::Div).u64().Inputs(0U, 3U);
3009             INST(20U, Opcode::SaveState).NoVregs();
3010             INST(21U, Opcode::CallStatic).u64().InputsAutoType(6U, 20U);
3011             INST(22U, Opcode::Return).u64().Inputs(21U);
3012         }
3013     }
3014     ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
3015     GetGraph()->RunPass<Cleanup>();
3016     auto graph = CreateEmptyGraph();
3017     GRAPH(graph)
3018     {
3019         PARAMETER(0U, 0U).u64();
3020         BASIC_BLOCK(2U, -1L)
3021         {
3022             INST(6U, Opcode::Neg).u64().Inputs(0U);
3023             INST(20U, Opcode::SaveState).NoVregs();
3024             INST(13U, Opcode::CallStatic).u64().InputsAutoType(6U, 20U);
3025             INST(12U, Opcode::Return).u64().Inputs(13U);
3026         }
3027     }
3028     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3029 }
3030 
TEST_F(PeepholesTest,TestDivCase3Unsigned)3031 TEST_F(PeepholesTest, TestDivCase3Unsigned)
3032 {
3033     for (auto type : {DataType::UINT8, DataType::UINT16, DataType::UINT32, DataType::UINT64}) {
3034         auto graph1 = CreateEmptyGraph();
3035         GRAPH(graph1)
3036         {
3037             PARAMETER(0U, 0U);
3038             INS(0U).SetType(type);
3039             CONSTANT(1U, 4U);
3040             BASIC_BLOCK(2U, -1L)
3041             {
3042                 INST(2U, Opcode::Div).Inputs(0U, 1U);
3043                 INS(2U).SetType(type);
3044                 INST(3U, Opcode::Return).Inputs(2U);
3045                 INS(3U).SetType(type);
3046             }
3047         }
3048         ASSERT_TRUE(graph1->RunPass<Peepholes>());
3049         graph1->RunPass<Cleanup>();
3050         auto graph2 = CreateEmptyGraph();
3051         GRAPH(graph2)
3052         {
3053             PARAMETER(0U, 0U);
3054             INS(0U).SetType(type);
3055             CONSTANT(1U, 2U);
3056             BASIC_BLOCK(2U, -1L)
3057             {
3058                 INST(2U, Opcode::Shr).Inputs(0U, 1U);
3059                 INS(2U).SetType(type);
3060                 INST(3U, Opcode::Return).Inputs(2U);
3061                 INS(3U).SetType(type);
3062             }
3063         }
3064         ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
3065     }
3066 }
3067 
TEST_F(PeepholesTest,TestDivCase3SignedPositive)3068 TEST_F(PeepholesTest, TestDivCase3SignedPositive)
3069 {
3070     for (auto type : {DataType::INT8, DataType::INT16, DataType::INT32, DataType::INT64}) {
3071         auto graph1 = CreateEmptyGraph();
3072         GRAPH(graph1)
3073         {
3074             PARAMETER(0U, 0U);
3075             INS(0U).SetType(type);
3076             CONSTANT(1U, 4U);
3077             BASIC_BLOCK(2U, -1L)
3078             {
3079                 INST(2U, Opcode::Div).Inputs(0U, 1U);
3080                 INS(2U).SetType(type);
3081                 INST(3U, Opcode::Return).Inputs(2U);
3082                 INS(3U).SetType(type);
3083             }
3084         }
3085 
3086         ASSERT_FALSE(graph1->RunPass<Peepholes>());
3087         graph1->RunPass<Cleanup>();
3088 
3089         auto graph2 = CreateEmptyGraph();
3090         GRAPH(graph2)
3091         {
3092             PARAMETER(0U, 0U);
3093             INS(0U).SetType(type);
3094             CONSTANT(1U, 4U);
3095             BASIC_BLOCK(2U, -1L)
3096             {
3097                 INST(2U, Opcode::Div).Inputs(0U, 1U);
3098                 INS(2U).SetType(type);
3099                 INST(3U, Opcode::Return).Inputs(2U);
3100                 INS(3U).SetType(type);
3101             }
3102         }
3103         ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
3104     }
3105 }
3106 
TEST_F(PeepholesTest,TestDivCase3SignedNegative)3107 TEST_F(PeepholesTest, TestDivCase3SignedNegative)
3108 {
3109     for (auto type : {DataType::INT8, DataType::INT16, DataType::INT32, DataType::INT64}) {
3110         auto graph1 = CreateEmptyGraph();
3111         GRAPH(graph1)
3112         {
3113             PARAMETER(0U, 0U);
3114             INS(0U).SetType(type);
3115             CONSTANT(1U, -16L);
3116             BASIC_BLOCK(2U, -1L)
3117             {
3118                 INST(2U, Opcode::Div).Inputs(0U, 1U);
3119                 INS(2U).SetType(type);
3120                 INST(3U, Opcode::Return).Inputs(2U);
3121                 INS(3U).SetType(type);
3122             }
3123         }
3124 
3125         ASSERT_FALSE(graph1->RunPass<Peepholes>());
3126         graph1->RunPass<Cleanup>();
3127 
3128         auto graph2 = CreateEmptyGraph();
3129         GRAPH(graph2)
3130         {
3131             PARAMETER(0U, 0U);
3132             INS(0U).SetType(type);
3133             CONSTANT(1U, -16L);
3134             BASIC_BLOCK(2U, -1L)
3135             {
3136                 INST(2U, Opcode::Div).Inputs(0U, 1U);
3137                 INS(2U).SetType(type);
3138                 INST(3U, Opcode::Return).Inputs(2U);
3139                 INS(3U).SetType(type);
3140             }
3141         }
3142         ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
3143     }
3144 }
3145 
TEST_F(PeepholesTest,TestLenArray1)3146 TEST_F(PeepholesTest, TestLenArray1)
3147 {
3148     // 1. .... ->{v2}
3149     // 2. NewArray v1 ->{v3,..}
3150     // 3. LenArray v2 ->{v4, v5...}
3151     // ===>
3152     // 1. .... ->{v2, v4, v5, ...}
3153     // 2. NewArray v1 ->{v3,..}
3154     // 3. LenArray v2
3155     GRAPH(GetGraph())
3156     {
3157         CONSTANT(0U, 10U);
3158         BASIC_BLOCK(2U, 1U)
3159         {
3160             INST(44U, Opcode::LoadAndInitClass).ref().Inputs().TypeId(68U);
3161             INST(1U, Opcode::NewArray).ref().Inputs(44U, 0U);
3162             INST(2U, Opcode::LenArray).s32().Inputs(1U);
3163             INST(3U, Opcode::Return).s32().Inputs(2U);
3164         }
3165     }
3166     GetGraph()->RunPass<Peepholes>();
3167     GraphChecker(GetGraph()).Check();
3168     auto cnst = INS(3U).GetInput(0U).GetInst();
3169     ASSERT_EQ(cnst->GetOpcode(), Opcode::Constant);
3170     ASSERT_TRUE(INS(2U).GetUsers().Empty());
3171 }
3172 
TEST_F(PeepholesTest,TestLenArray2)3173 TEST_F(PeepholesTest, TestLenArray2)
3174 {
3175     // 1. .... ->{v2}
3176     // 2. NewArray v1 ->{v3,..}
3177     // 3. LenArray v2 ->{v4, v5...}
3178     // ===>
3179     // 1. .... ->{v2, v4, v5, ...}
3180     // 2. NewArray v1 ->{v3,..}
3181     // 3. LenArray v2
3182     GRAPH(GetGraph())
3183     {
3184         CONSTANT(0U, 10U);
3185         BASIC_BLOCK(2U, 1U)
3186         {
3187             INST(10U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
3188             INST(1U, Opcode::NegativeCheck).s32().Inputs(0U, 10U);
3189             INST(44U, Opcode::LoadAndInitClass).ref().Inputs(10U).TypeId(68U);
3190             INST(2U, Opcode::NewArray).ref().Inputs(44U, 1U);
3191             INST(3U, Opcode::NullCheck).ref().Inputs(2U, 10U);
3192             INST(4U, Opcode::LenArray).s32().Inputs(3U);
3193             INST(5U, Opcode::Return).s32().Inputs(4U);
3194         }
3195     }
3196     GetGraph()->RunPass<Peepholes>();
3197     GraphChecker(GetGraph()).Check();
3198     auto cnst = INS(5U).GetInput(0U).GetInst();
3199     ASSERT_EQ(cnst->GetOpcode(), Opcode::Constant);
3200     ASSERT_TRUE(INS(4U).GetUsers().Empty());
3201 }
3202 
SRC_GRAPH(TestPhi1,Graph * graph)3203 SRC_GRAPH(TestPhi1, Graph *graph)
3204 {
3205     GRAPH(graph)
3206     {
3207         PARAMETER(0U, 0U).s32();
3208         PARAMETER(1U, 1U).s32();
3209         BASIC_BLOCK(2U, 3U, 4U)
3210         {
3211             INST(3U, Opcode::Compare).b().Inputs(0U, 1U);
3212             INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
3213         }
3214         BASIC_BLOCK(3U, 5U)
3215         {
3216             INST(5U, Opcode::Sub).s32().Inputs(0U, 1U);
3217         }
3218         BASIC_BLOCK(4U, 5U)
3219         {
3220             INST(7U, Opcode::Sub).s32().Inputs(1U, 0U);
3221         }
3222         BASIC_BLOCK(5U, 1U)
3223         {
3224             INST(9U, Opcode::Phi).s32().Inputs(5U, 7U);
3225             INST(10U, Opcode::Phi).s32().Inputs(5U, 7U);
3226             INST(11U, Opcode::Add).s32().Inputs(9U, 0U);
3227             INST(12U, Opcode::Add).s32().Inputs(10U, 1U);
3228             INST(13U, Opcode::Add).s32().Inputs(11U, 12U);
3229             INST(14U, Opcode::Return).s32().Inputs(13U);
3230         }
3231     }
3232 }
3233 
OUT_GRAPH(TestPhi1,Graph * graph)3234 OUT_GRAPH(TestPhi1, Graph *graph)
3235 {
3236     GRAPH(graph)
3237     {
3238         PARAMETER(0U, 0U).s32();
3239         PARAMETER(1U, 1U).s32();
3240         BASIC_BLOCK(2U, 3U, 4U)
3241         {
3242             INST(3U, Opcode::Compare).b().Inputs(0U, 1U);
3243             INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
3244         }
3245         BASIC_BLOCK(3U, 5U)
3246         {
3247             INST(5U, Opcode::Sub).s32().Inputs(0U, 1U);
3248         }
3249         BASIC_BLOCK(4U, 5U)
3250         {
3251             INST(7U, Opcode::Sub).s32().Inputs(1U, 0U);
3252         }
3253         BASIC_BLOCK(5U, 1U)
3254         {
3255             INST(9U, Opcode::Phi).s32().Inputs(5U, 7U);
3256             INST(10U, Opcode::Phi).s32().Inputs(5U, 7U);
3257             INST(11U, Opcode::Add).s32().Inputs(9U, 0U);
3258             INST(12U, Opcode::Add).s32().Inputs(9U, 1U);
3259             INST(13U, Opcode::Add).s32().Inputs(11U, 12U);
3260             INST(14U, Opcode::Return).s32().Inputs(13U);
3261         }
3262     }
3263 }
3264 
TEST_F(PeepholesTest,TestPhi1)3265 TEST_F(PeepholesTest, TestPhi1)
3266 {
3267     // Users isn't intersect
3268     // 2.type  Phi v0, v1 -> v4
3269     // 3.type  Phi v0, v1 -> v5
3270     // ===>
3271     // 2.type  Phi v0, v1 -> v4, v5
3272     // 3.type  Phi v0, v1
3273     src_graph::TestPhi1::CREATE(GetGraph());
3274     GetGraph()->RunPass<Peepholes>();
3275     auto graph = CreateEmptyGraph();
3276     out_graph::TestPhi1::CREATE(graph);
3277     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3278 }
3279 
SRC_GRAPH(PhiTestWithChecks,Graph * graph)3280 SRC_GRAPH(PhiTestWithChecks, Graph *graph)
3281 {
3282     GRAPH(graph)
3283     {
3284         PARAMETER(0U, 0U).ref();
3285         PARAMETER(1U, 1U).ref();
3286         BASIC_BLOCK(2U, 3U, 4U)
3287         {
3288             INST(3U, Opcode::Compare).b().Inputs(0U, 1U);
3289             INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
3290         }
3291         BASIC_BLOCK(3U, 5U)
3292         {
3293             INST(5U, Opcode::NullCheck).ref().Inputs(0U);
3294         }
3295         BASIC_BLOCK(4U, 5U)
3296         {
3297             INST(7U, Opcode::NullCheck).ref().Inputs(1U);
3298         }
3299         BASIC_BLOCK(5U, 1U)
3300         {
3301             INST(9U, Opcode::Phi).ref().Inputs(5U, 7U);
3302             INST(10U, Opcode::Phi).ref().Inputs(0U, 1U);
3303             INST(12U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
3304             INST(11U, Opcode::CallStatic).s32().InputsAutoType(9U, 10U, 12U);
3305             INST(14U, Opcode::Return).s32().Inputs(11U);
3306         }
3307     }
3308 }
3309 
OUT_GRAPH(PhiTestWithChecks,Graph * graph)3310 OUT_GRAPH(PhiTestWithChecks, Graph *graph)
3311 {
3312     GRAPH(graph)
3313     {
3314         PARAMETER(0U, 0U).ref();
3315         PARAMETER(1U, 1U).ref();
3316         BASIC_BLOCK(2U, 3U, 4U)
3317         {
3318             INST(3U, Opcode::Compare).b().Inputs(0U, 1U);
3319             INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
3320         }
3321         BASIC_BLOCK(3U, 5U)
3322         {
3323             INST(5U, Opcode::NullCheck).ref().Inputs(0U);
3324         }
3325         BASIC_BLOCK(4U, 5U)
3326         {
3327             INST(7U, Opcode::NullCheck).ref().Inputs(1U);
3328         }
3329         BASIC_BLOCK(5U, 1U)
3330         {
3331             INST(9U, Opcode::Phi).ref().Inputs(5U, 7U);
3332             INST(10U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
3333             INST(11U, Opcode::CallStatic).s32().InputsAutoType(9U, 9U, 10U);
3334             INST(14U, Opcode::Return).s32().Inputs(11U);
3335         }
3336     }
3337 }
3338 
TEST_F(PeepholesTest,PhiTestWithChecks)3339 TEST_F(PeepholesTest, PhiTestWithChecks)
3340 {
3341     // Users isn't intersect
3342     // 2.type  Phi v0, v1 -> v4
3343     // 3.type  Phi v0, v1 -> v5
3344     // ===>
3345     // 2.type  Phi v0, v1 -> v4, v5
3346     // 3.type  Phi v0, v1
3347     src_graph::PhiTestWithChecks::CREATE(GetGraph());
3348     ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
3349     ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
3350     auto graph = CreateEmptyGraph();
3351     out_graph::PhiTestWithChecks::CREATE(graph);
3352     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3353 }
3354 
SRC_GRAPH(TestPhi2,Graph * graph)3355 SRC_GRAPH(TestPhi2, Graph *graph)
3356 {
3357     GRAPH(graph)
3358     {
3359         PARAMETER(0U, 0U).s32();
3360         PARAMETER(1U, 1U).s32();
3361         BASIC_BLOCK(2U, 3U, 4U)
3362         {
3363             INST(3U, Opcode::Compare).b().Inputs(0U, 1U);
3364             INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
3365         }
3366         BASIC_BLOCK(3U, 5U)
3367         {
3368             INST(5U, Opcode::Sub).s32().Inputs(0U, 1U);
3369         }
3370         BASIC_BLOCK(4U, 5U)
3371         {
3372             INST(7U, Opcode::Sub).s32().Inputs(1U, 0U);
3373         }
3374         BASIC_BLOCK(5U, 1U)
3375         {
3376             INST(9U, Opcode::Phi).s32().Inputs(5U, 7U);
3377             INST(10U, Opcode::Phi).s32().Inputs(5U, 7U);
3378             INST(11U, Opcode::Add).s32().Inputs(9U, 0U);
3379             INST(12U, Opcode::Add).s32().Inputs(9U, 10U);
3380             INST(13U, Opcode::Add).s32().Inputs(10U, 1U);
3381             INST(14U, Opcode::Add).s32().Inputs(11U, 12U);
3382             INST(15U, Opcode::Add).s32().Inputs(13U, 14U);
3383             INST(20U, Opcode::SaveState).NoVregs();
3384             INST(16U, Opcode::CallStatic).v0id().InputsAutoType(9U, 10U, 15U, 20U);
3385             ;
3386             INST(17U, Opcode::Return).s32().Inputs(15U);
3387         }
3388     }
3389 }
3390 
OUT_GRAPH(TestPhi2,Graph * graph)3391 OUT_GRAPH(TestPhi2, Graph *graph)
3392 {
3393     GRAPH(graph)
3394     {
3395         PARAMETER(0U, 0U).s32();
3396         PARAMETER(1U, 1U).s32();
3397         BASIC_BLOCK(2U, 3U, 4U)
3398         {
3399             INST(3U, Opcode::Compare).b().Inputs(0U, 1U);
3400             INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
3401         }
3402         BASIC_BLOCK(3U, 5U)
3403         {
3404             INST(5U, Opcode::Sub).s32().Inputs(0U, 1U);
3405         }
3406         BASIC_BLOCK(4U, 5U)
3407         {
3408             INST(7U, Opcode::Sub).s32().Inputs(1U, 0U);
3409         }
3410         BASIC_BLOCK(5U, 1U)
3411         {
3412             INST(9U, Opcode::Phi).s32().Inputs(5U, 7U);
3413             INST(10U, Opcode::Phi).s32().Inputs(5U, 7U);
3414             INST(11U, Opcode::Add).s32().Inputs(9U, 0U);
3415             INST(12U, Opcode::Add).s32().Inputs(9U, 9U);
3416             INST(13U, Opcode::Add).s32().Inputs(9U, 1U);
3417             INST(14U, Opcode::Add).s32().Inputs(11U, 12U);
3418             INST(15U, Opcode::Add).s32().Inputs(13U, 14U);
3419             INST(20U, Opcode::SaveState).NoVregs();
3420             INST(16U, Opcode::CallStatic).v0id().InputsAutoType(9U, 9U, 15U, 20U);
3421             INST(17U, Opcode::Return).s32().Inputs(15U);
3422         }
3423     }
3424 }
3425 
TEST_F(PeepholesTest,TestPhi2)3426 TEST_F(PeepholesTest, TestPhi2)
3427 {
3428     // Users is intersect
3429     // 2.type  Phi v0, v1 -> v4, v5
3430     // 3.type  Phi v0, v1 -> v5, v6
3431     // ===>
3432     // 2.type  Phi v0, v1 -> v4, v5
3433     // 3.type  Phi v0, v1
3434     src_graph::TestPhi2::CREATE(GetGraph());
3435     GetGraph()->RunPass<Peepholes>();
3436     auto graph = CreateEmptyGraph();
3437     out_graph::TestPhi2::CREATE(graph);
3438     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3439 }
3440 
SRC_GRAPH(TestPhi3,Graph * graph)3441 SRC_GRAPH(TestPhi3, Graph *graph)
3442 {
3443     GRAPH(graph)
3444     {
3445         PARAMETER(0U, 0U).s32();
3446         PARAMETER(1U, 1U).s32();
3447         BASIC_BLOCK(2U, 3U, 4U)
3448         {
3449             INST(3U, Opcode::Compare).b().Inputs(0U, 1U);
3450             INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
3451         }
3452         BASIC_BLOCK(3U, 5U)
3453         {
3454             INST(5U, Opcode::Sub).s32().Inputs(0U, 1U);  // Phi 11
3455             INST(6U, Opcode::Add).s32().Inputs(0U, 1U);  // Phi 12
3456         }
3457         BASIC_BLOCK(4U, 5U)
3458         {
3459             INST(8U, Opcode::Sub).s32().Inputs(1U, 0U);  // Phi 11
3460             INST(9U, Opcode::Add).s32().Inputs(0U, 1U);  // Phi 12
3461         }
3462         BASIC_BLOCK(5U, 1U)
3463         {
3464             INST(11U, Opcode::Phi).s32().Inputs(5U, 8U);
3465             INST(12U, Opcode::Phi).s32().Inputs(6U, 9U);
3466             INST(13U, Opcode::Add).s32().Inputs(11U, 12U);
3467             INST(20U, Opcode::SaveState).NoVregs();
3468             INST(14U, Opcode::CallStatic).v0id().InputsAutoType(11U, 12U, 13U, 20U);
3469             INST(15U, Opcode::Return).s32().Inputs(13U);
3470         }
3471     }
3472 }
3473 
OUT_GRAPH(TestPhi3,Graph * graph)3474 OUT_GRAPH(TestPhi3, Graph *graph)
3475 {
3476     GRAPH(graph)
3477     {
3478         PARAMETER(0U, 0U).s32();
3479         PARAMETER(1U, 1U).s32();
3480         BASIC_BLOCK(2U, 3U, 4U)
3481         {
3482             INST(3U, Opcode::Compare).b().Inputs(0U, 1U);
3483             INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
3484         }
3485         BASIC_BLOCK(3U, 5U)
3486         {
3487             INST(5U, Opcode::Sub).s32().Inputs(0U, 1U);  // Phi 11
3488             INST(6U, Opcode::Add).s32().Inputs(0U, 1U);  // Phi 12
3489         }
3490         BASIC_BLOCK(4U, 5U)
3491         {
3492             INST(8U, Opcode::Sub).s32().Inputs(1U, 0U);  // Phi 11
3493             INST(9U, Opcode::Add).s32().Inputs(0U, 1U);  // Phi 12
3494         }
3495         BASIC_BLOCK(5U, 1U)
3496         {
3497             INST(11U, Opcode::Phi).s32().Inputs(5U, 8U);
3498             INST(12U, Opcode::Phi).s32().Inputs(6U, 9U);
3499             INST(13U, Opcode::Add).s32().Inputs(11U, 12U);
3500             INST(20U, Opcode::SaveState).NoVregs();
3501             INST(14U, Opcode::CallStatic).v0id().InputsAutoType(11U, 12U, 13U, 20U);
3502             INST(15U, Opcode::Return).s32().Inputs(13U);
3503         }
3504     }
3505 }
3506 
TEST_F(PeepholesTest,TestPhi3)3507 TEST_F(PeepholesTest, TestPhi3)
3508 {
3509     // Peephole rule isn't applied.
3510     // Same types, different inputs.
3511     src_graph::TestPhi3::CREATE(GetGraph());
3512     GetGraph()->RunPass<Peepholes>();
3513     auto graph = CreateEmptyGraph();
3514     out_graph::TestPhi3::CREATE(graph);
3515     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3516 }
3517 
SRC_GRAPH(TestPhi4,Graph * graph)3518 SRC_GRAPH(TestPhi4, Graph *graph)
3519 {
3520     GRAPH(graph)
3521     {
3522         PARAMETER(0U, 0U).s32();
3523         PARAMETER(1U, 1U).s32();
3524         BASIC_BLOCK(2U, 3U, 4U)
3525         {
3526             INST(3U, Opcode::Compare).b().Inputs(0U, 1U);
3527             INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
3528         }
3529         BASIC_BLOCK(3U, 5U)
3530         {
3531             INST(5U, Opcode::Sub).s32().Inputs(0U, 1U);
3532         }
3533         BASIC_BLOCK(4U, 5U)
3534         {
3535             INST(8U, Opcode::Sub).s32().Inputs(1U, 0U);
3536         }
3537         BASIC_BLOCK(5U, 1U)
3538         {
3539             INST(11U, Opcode::Phi).s16().Inputs(5U, 8U);
3540             INST(12U, Opcode::Phi).s32().Inputs(5U, 8U);
3541             INST(13U, Opcode::Add).s32().Inputs(11U, 12U);
3542             INST(20U, Opcode::SaveState).NoVregs();
3543             INST(14U, Opcode::CallStatic).v0id().InputsAutoType(11U, 12U, 13U, 20U);
3544             INST(15U, Opcode::Return).s32().Inputs(13U);
3545         }
3546     }
3547 }
3548 
OUT_GRAPH(TestPhi4,Graph * graph)3549 OUT_GRAPH(TestPhi4, Graph *graph)
3550 {
3551     GRAPH(graph)
3552     {
3553         PARAMETER(0U, 0U).s32();
3554         PARAMETER(1U, 1U).s32();
3555         BASIC_BLOCK(2U, 3U, 4U)
3556         {
3557             INST(3U, Opcode::Compare).b().Inputs(0U, 1U);
3558             INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
3559         }
3560         BASIC_BLOCK(3U, 5U)
3561         {
3562             INST(5U, Opcode::Sub).s32().Inputs(0U, 1U);
3563         }
3564         BASIC_BLOCK(4U, 5U)
3565         {
3566             INST(8U, Opcode::Sub).s32().Inputs(1U, 0U);
3567         }
3568         BASIC_BLOCK(5U, 1U)
3569         {
3570             INST(11U, Opcode::Phi).s16().Inputs(5U, 8U);
3571             INST(12U, Opcode::Phi).s32().Inputs(5U, 8U);
3572             INST(13U, Opcode::Add).s32().Inputs(11U, 12U);
3573             INST(20U, Opcode::SaveState).NoVregs();
3574             INST(14U, Opcode::CallStatic).v0id().InputsAutoType(11U, 12U, 13U, 20U);
3575             INST(15U, Opcode::Return).s32().Inputs(13U);
3576         }
3577     }
3578 }
3579 
TEST_F(PeepholesTest,TestPhi4)3580 TEST_F(PeepholesTest, TestPhi4)
3581 {
3582     // Peephole rule isn't applied.
3583     // Different types, same inputs.
3584     src_graph::TestPhi4::CREATE(GetGraph());
3585     GetGraph()->RunPass<Peepholes>();
3586     auto graph = CreateEmptyGraph();
3587     out_graph::TestPhi4::CREATE(graph);
3588     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3589 }
3590 
SRC_GRAPH(TestPhi5,Graph * graph)3591 SRC_GRAPH(TestPhi5, Graph *graph)
3592 {
3593     GRAPH(graph)
3594     {
3595         PARAMETER(0U, 0U).s32();
3596         PARAMETER(1U, 1U).s32();
3597         PARAMETER(17U, 2U).f32();
3598         PARAMETER(18U, 3U).f32();
3599         BASIC_BLOCK(2U, 3U, 4U)
3600         {
3601             INST(3U, Opcode::Compare).b().Inputs(0U, 1U);
3602             INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
3603         }
3604         BASIC_BLOCK(3U, 5U)
3605         {
3606             INST(5U, Opcode::Sub).s32().Inputs(0U, 1U);    // Phi 11
3607             INST(6U, Opcode::Add).f32().Inputs(18U, 17U);  // Phi 12
3608         }
3609         BASIC_BLOCK(4U, 5U)
3610         {
3611             INST(8U, Opcode::Sub).s32().Inputs(1U, 0U);    // Phi 11
3612             INST(9U, Opcode::Add).f32().Inputs(18U, 17U);  // Phi 12
3613         }
3614         BASIC_BLOCK(5U, 1U)
3615         {
3616             INST(11U, Opcode::Phi).s32().Inputs(5U, 8U);
3617             INST(12U, Opcode::Phi).f32().Inputs(6U, 9U);
3618             INST(13U, Opcode::Cast).f32().SrcType(DataType::INT32).Inputs(11U);
3619             INST(14U, Opcode::Add).f32().Inputs(13U, 12U);
3620             INST(20U, Opcode::SaveState).NoVregs();
3621             INST(15U, Opcode::CallStatic).v0id().InputsAutoType(11U, 12U, 13U, 14U, 20U);
3622             INST(16U, Opcode::Return).f32().Inputs(14U);
3623         }
3624     }
3625 }
3626 
OUT_GRAPH(TestPhi5,Graph * graph)3627 OUT_GRAPH(TestPhi5, Graph *graph)
3628 {
3629     GRAPH(graph)
3630     {
3631         PARAMETER(0U, 0U).s32();
3632         PARAMETER(1U, 1U).s32();
3633         PARAMETER(17U, 2U).f32();
3634         PARAMETER(18U, 3U).f32();
3635         BASIC_BLOCK(2U, 3U, 4U)
3636         {
3637             INST(3U, Opcode::Compare).b().Inputs(0U, 1U);
3638             INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
3639         }
3640         BASIC_BLOCK(3U, 5U)
3641         {
3642             INST(5U, Opcode::Sub).s32().Inputs(0U, 1U);    // Phi 11
3643             INST(6U, Opcode::Add).f32().Inputs(18U, 17U);  // Phi 12
3644         }
3645         BASIC_BLOCK(4U, 5U)
3646         {
3647             INST(8U, Opcode::Sub).s32().Inputs(1U, 0U);    // Phi 11
3648             INST(9U, Opcode::Add).f32().Inputs(18U, 17U);  // Phi 12
3649         }
3650         BASIC_BLOCK(5U, 1U)
3651         {
3652             INST(11U, Opcode::Phi).s32().Inputs(5U, 8U);
3653             INST(12U, Opcode::Phi).f32().Inputs(6U, 9U);
3654             INST(13U, Opcode::Cast).f32().SrcType(DataType::INT32).Inputs(11U);
3655             INST(14U, Opcode::Add).f32().Inputs(13U, 12U);
3656             INST(20U, Opcode::SaveState).NoVregs();
3657             INST(15U, Opcode::CallStatic).v0id().InputsAutoType(11U, 12U, 13U, 14U, 20U);
3658             INST(16U, Opcode::Return).f32().Inputs(14U);
3659         }
3660     }
3661 }
3662 
TEST_F(PeepholesTest,TestPhi5)3663 TEST_F(PeepholesTest, TestPhi5)
3664 {
3665     // Peephole rule isn't applied.
3666     // Different types, different inputs.
3667     src_graph::TestPhi5::CREATE(GetGraph());
3668     GetGraph()->RunPass<Peepholes>();
3669     auto graph = CreateEmptyGraph();
3670     out_graph::TestPhi5::CREATE(graph);
3671     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3672 }
3673 
TEST_F(PeepholesTest,MultiplePeepholeTest)3674 TEST_F(PeepholesTest, MultiplePeepholeTest)
3675 {
3676     GRAPH(GetGraph())
3677     {
3678         CONSTANT(0U, 100U);
3679         CONSTANT(1U, -46L);
3680         CONSTANT(2U, 0U);
3681         BASIC_BLOCK(2U, 3U, 4U)
3682         {
3683             INST(3U, Opcode::Compare).b().SrcType(DataType::Type::INT64).CC(CC_LT).Inputs(1U, 2U);
3684             INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
3685         }
3686         BASIC_BLOCK(3U, 5U)
3687         {
3688             INST(5U, Opcode::Sub).s32().Inputs(0U, 1U);
3689         }
3690         BASIC_BLOCK(4U, 5U)
3691         {
3692             INST(8U, Opcode::Add).s32().Inputs(0U, 1U);
3693         }
3694         BASIC_BLOCK(5U, 1U)
3695         {
3696             INST(11U, Opcode::Phi).s32().Inputs(5U, 8U);
3697             INST(16U, Opcode::Return).s32().Inputs(11U);
3698         }
3699     }
3700     GetGraph()->RunPass<Peepholes>();
3701     GetGraph()->RunPass<BranchElimination>();
3702     GetGraph()->RunPass<Cleanup>();
3703     GetGraph()->RunPass<Peepholes>();
3704 #ifndef NDEBUG
3705     GetGraph()->SetLowLevelInstructionsEnabled();
3706 #endif
3707     GetGraph()->RunPass<Lowering>();
3708     GetGraph()->RunPass<Cleanup>();
3709 
3710     auto graph = CreateEmptyGraph();
3711     GRAPH(graph)
3712     {
3713         BASIC_BLOCK(5U, 1U)
3714         {
3715             INST(16U, Opcode::ReturnI).s32().Imm(146U);
3716         }
3717     }
3718     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3719 }
3720 
TEST_F(PeepholesTest,CompareTest)3721 TEST_F(PeepholesTest, CompareTest)
3722 {
3723     // test case 2
3724     CheckCompare(DataType::UINT32, ConditionCode::CC_LT, ConditionCode::CC_B);
3725     CheckCompare(DataType::UINT32, ConditionCode::CC_LE, ConditionCode::CC_BE);
3726     CheckCompare(DataType::UINT32, ConditionCode::CC_GT, ConditionCode::CC_A);
3727     CheckCompare(DataType::UINT32, ConditionCode::CC_GE, ConditionCode::CC_AE);
3728     CheckCompare(DataType::UINT32, ConditionCode::CC_EQ, ConditionCode::CC_EQ);
3729     CheckCompare(DataType::UINT32, ConditionCode::CC_NE, ConditionCode::CC_NE);
3730 
3731     CheckCompare(DataType::INT32, ConditionCode::CC_LT, ConditionCode::CC_LT);
3732     CheckCompare(DataType::INT32, ConditionCode::CC_LE, ConditionCode::CC_LE);
3733     CheckCompare(DataType::INT32, ConditionCode::CC_GT, ConditionCode::CC_GT);
3734     CheckCompare(DataType::INT32, ConditionCode::CC_GE, ConditionCode::CC_GE);
3735     CheckCompare(DataType::INT32, ConditionCode::CC_EQ, ConditionCode::CC_EQ);
3736     CheckCompare(DataType::INT32, ConditionCode::CC_NE, ConditionCode::CC_NE);
3737 
3738     CheckCompare(DataType::INT32, ConditionCode::CC_B, ConditionCode::CC_B);
3739     CheckCompare(DataType::INT32, ConditionCode::CC_BE, ConditionCode::CC_BE);
3740     CheckCompare(DataType::INT32, ConditionCode::CC_A, ConditionCode::CC_A);
3741     CheckCompare(DataType::INT32, ConditionCode::CC_AE, ConditionCode::CC_AE);
3742 
3743     CheckCompare(DataType::UINT64, ConditionCode::CC_LT, ConditionCode::CC_B);
3744     CheckCompare(DataType::UINT64, ConditionCode::CC_LE, ConditionCode::CC_BE);
3745     CheckCompare(DataType::UINT64, ConditionCode::CC_GT, ConditionCode::CC_A);
3746     CheckCompare(DataType::UINT64, ConditionCode::CC_GE, ConditionCode::CC_AE);
3747     CheckCompare(DataType::UINT64, ConditionCode::CC_EQ, ConditionCode::CC_EQ);
3748     CheckCompare(DataType::UINT64, ConditionCode::CC_NE, ConditionCode::CC_NE);
3749 
3750     CheckCompare(DataType::INT64, ConditionCode::CC_LT, ConditionCode::CC_LT);
3751     CheckCompare(DataType::INT64, ConditionCode::CC_LE, ConditionCode::CC_LE);
3752     CheckCompare(DataType::INT64, ConditionCode::CC_GT, ConditionCode::CC_GT);
3753     CheckCompare(DataType::INT64, ConditionCode::CC_GE, ConditionCode::CC_GE);
3754     CheckCompare(DataType::INT64, ConditionCode::CC_EQ, ConditionCode::CC_EQ);
3755     CheckCompare(DataType::INT64, ConditionCode::CC_NE, ConditionCode::CC_NE);
3756 
3757     CheckCompare(DataType::INT64, ConditionCode::CC_B, ConditionCode::CC_B);
3758     CheckCompare(DataType::INT64, ConditionCode::CC_BE, ConditionCode::CC_BE);
3759     CheckCompare(DataType::INT64, ConditionCode::CC_A, ConditionCode::CC_A);
3760     CheckCompare(DataType::INT64, ConditionCode::CC_AE, ConditionCode::CC_AE);
3761 }
3762 
TEST_F(PeepholesTest,CompareTest1)3763 TEST_F(PeepholesTest, CompareTest1)
3764 {
3765     // applied case 2
3766     GRAPH(GetGraph())
3767     {
3768         CONSTANT(0U, 0U);
3769         PARAMETER(1U, 0U).u32();
3770         PARAMETER(2U, 1U).u32();
3771         BASIC_BLOCK(2U, 1U)
3772         {
3773             INST(3U, Opcode::Cmp).s32().Inputs(1U, 2U);
3774             INST(4U, Opcode::Compare).b().CC(CC_LT).Inputs(3U, 0U);
3775             INST(5U, Opcode::Return).b().Inputs(4U);
3776         }
3777     }
3778     GetGraph()->RunPass<Peepholes>();
3779     GraphChecker(GetGraph()).Check();
3780     auto graph = CreateEmptyGraph();
3781     GRAPH(graph)
3782     {
3783         CONSTANT(0U, 0U);
3784         PARAMETER(1U, 0U).u32();
3785         PARAMETER(2U, 1U).u32();
3786         BASIC_BLOCK(2U, 1U)
3787         {
3788             INST(3U, Opcode::Cmp).s32().Inputs(1U, 2U);
3789             INST(4U, Opcode::Compare).b().CC(CC_B).Inputs(1U, 2U);
3790             INST(5U, Opcode::Return).b().Inputs(4U);
3791         }
3792     }
3793     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3794 }
3795 
TEST_F(PeepholesTest,CompareTest1Addition0)3796 TEST_F(PeepholesTest, CompareTest1Addition0)
3797 {
3798     // cmp with zero and inputs are signed, compare operands are in normal order (constant is the second operand)
3799     GRAPH(GetGraph())
3800     {
3801         CONSTANT(0U, 0U);
3802         PARAMETER(1U, 1U).u32();
3803         BASIC_BLOCK(2U, 1U)
3804         {
3805             INST(2U, Opcode::Cmp).s32().Inputs(0U, 1U);
3806             INST(3U, Opcode::Compare).b().CC(CC_LT).Inputs(2U, 0U);
3807             INST(4U, Opcode::Return).b().Inputs(3U);
3808         }
3809     }
3810     GetGraph()->RunPass<Peepholes>();
3811     GraphChecker(GetGraph()).Check();
3812     auto graph = CreateEmptyGraph();
3813     GRAPH(graph)
3814     {
3815         CONSTANT(0U, 0U);
3816         PARAMETER(1U, 1U).u32();
3817         BASIC_BLOCK(2U, 1U)
3818         {
3819             INST(2U, Opcode::Cmp).s32().Inputs(0U, 1U);
3820             INST(3U, Opcode::Compare).b().CC(CC_B).Inputs(0U, 1U);
3821             INST(4U, Opcode::Return).b().Inputs(3U);
3822         }
3823     }
3824     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3825 }
3826 
TEST_F(PeepholesTest,CompareTest1Addition1)3827 TEST_F(PeepholesTest, CompareTest1Addition1)
3828 {
3829     // cmp inputs are unsigned, compare operands are in reverse order (constant is the first operand)
3830     GRAPH(GetGraph())
3831     {
3832         CONSTANT(0U, 0U);
3833         PARAMETER(1U, 0U).u32();
3834         PARAMETER(2U, 1U).u32();
3835         BASIC_BLOCK(2U, 1U)
3836         {
3837             INST(3U, Opcode::Cmp).s32().Inputs(1U, 2U);
3838             INST(4U, Opcode::Compare).b().CC(CC_LT).Inputs(0U, 3U);
3839             INST(5U, Opcode::Return).b().Inputs(4U);
3840         }
3841     }
3842     GetGraph()->RunPass<Peepholes>();
3843     GraphChecker(GetGraph()).Check();
3844     auto graph = CreateEmptyGraph();
3845     GRAPH(graph)
3846     {
3847         CONSTANT(0U, 0U);
3848         PARAMETER(1U, 0U).u32();
3849         PARAMETER(2U, 1U).u32();
3850         BASIC_BLOCK(2U, 1U)
3851         {
3852             INST(3U, Opcode::Cmp).s32().Inputs(1U, 2U);
3853             INST(4U, Opcode::Compare).b().CC(CC_A).Inputs(1U, 2U);
3854             INST(5U, Opcode::Return).b().Inputs(4U);
3855         }
3856     }
3857     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3858 }
3859 
TEST_F(PeepholesTest,CompareTest1Addition2)3860 TEST_F(PeepholesTest, CompareTest1Addition2)
3861 {
3862     // cmp inputs are signed and compare operands are in normal order
3863     GRAPH(GetGraph())
3864     {
3865         CONSTANT(0U, 0U);
3866         PARAMETER(1U, 0U).s32();
3867         PARAMETER(2U, 1U).s32();
3868         BASIC_BLOCK(2U, 1U)
3869         {
3870             INST(3U, Opcode::Cmp).s32().Inputs(1U, 2U);
3871             INST(4U, Opcode::Compare).b().CC(CC_LT).Inputs(3U, 0U);
3872             INST(5U, Opcode::Return).b().Inputs(4U);
3873         }
3874     }
3875     GetGraph()->RunPass<Peepholes>();
3876     GraphChecker(GetGraph()).Check();
3877     auto graph = CreateEmptyGraph();
3878     GRAPH(graph)
3879     {
3880         CONSTANT(0U, 0U);
3881         PARAMETER(1U, 0U).s32();
3882         PARAMETER(2U, 1U).s32();
3883         BASIC_BLOCK(2U, 1U)
3884         {
3885             INST(3U, Opcode::Cmp).s32().Inputs(1U, 2U);
3886             INST(4U, Opcode::Compare).b().CC(CC_LT).Inputs(1U, 2U);
3887             INST(5U, Opcode::Return).b().Inputs(4U);
3888         }
3889     }
3890     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3891 }
3892 
TEST_F(PeepholesTest,CompareTest1Addition3)3893 TEST_F(PeepholesTest, CompareTest1Addition3)
3894 {
3895     // cmp inputs are signed and compare operands are in reverse order
3896     GRAPH(GetGraph())
3897     {
3898         CONSTANT(0U, 0U);
3899         PARAMETER(1U, 0U).s32();
3900         PARAMETER(2U, 1U).s32();
3901         BASIC_BLOCK(2U, 1U)
3902         {
3903             INST(3U, Opcode::Cmp).s32().Inputs(1U, 2U);
3904             INST(4U, Opcode::Compare).b().CC(CC_LT).Inputs(0U, 3U);
3905             INST(5U, Opcode::Return).b().Inputs(4U);
3906         }
3907     }
3908     GetGraph()->RunPass<Peepholes>();
3909     GraphChecker(GetGraph()).Check();
3910     auto graph = CreateEmptyGraph();
3911     GRAPH(graph)
3912     {
3913         CONSTANT(0U, 0U);
3914         PARAMETER(1U, 0U).s32();
3915         PARAMETER(2U, 1U).s32();
3916         BASIC_BLOCK(2U, 1U)
3917         {
3918             INST(3U, Opcode::Cmp).s32().Inputs(1U, 2U);
3919             INST(4U, Opcode::Compare).b().CC(CC_GT).Inputs(1U, 2U);
3920             INST(5U, Opcode::Return).b().Inputs(4U);
3921         }
3922     }
3923     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3924 }
3925 
TEST_F(PeepholesTest,CompareTest2)3926 TEST_F(PeepholesTest, CompareTest2)
3927 {
3928     // not applied, Compare with non zero constant
3929     GRAPH(GetGraph())
3930     {
3931         CONSTANT(0U, 1U);
3932         PARAMETER(1U, 0U).s32();
3933         PARAMETER(2U, 1U).s32();
3934         BASIC_BLOCK(2U, 1U)
3935         {
3936             INST(3U, Opcode::Cmp).s32().Inputs(1U, 2U);
3937             INST(4U, Opcode::Compare).b().CC(CC_LT).Inputs(3U, 0U);
3938             INST(5U, Opcode::Return).b().Inputs(4U);
3939         }
3940     }
3941     GetGraph()->RunPass<Peepholes>();
3942     GraphChecker(GetGraph()).Check();
3943     auto graph = CreateEmptyGraph();
3944     GRAPH(graph)
3945     {
3946         CONSTANT(0U, 1U);
3947         PARAMETER(1U, 0U).s32();
3948         PARAMETER(2U, 1U).s32();
3949         BASIC_BLOCK(2U, 1U)
3950         {
3951             INST(3U, Opcode::Cmp).s32().Inputs(1U, 2U);
3952             INST(4U, Opcode::Compare).b().CC(CC_LT).Inputs(3U, 0U);
3953             INST(5U, Opcode::Return).b().Inputs(4U);
3954         }
3955     }
3956     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3957 }
3958 
TEST_F(PeepholesTest,CompareTest3)3959 TEST_F(PeepholesTest, CompareTest3)
3960 {
3961     // not applied, cmp have more than 1 users.
3962     GRAPH(GetGraph())
3963     {
3964         CONSTANT(0U, 1U);
3965         PARAMETER(1U, 0U).s32();
3966         PARAMETER(2U, 1U).s32();
3967         BASIC_BLOCK(2U, 3U, 4U)
3968         {
3969             INST(3U, Opcode::Cmp).s32().Inputs(1U, 2U);
3970             INST(4U, Opcode::Compare).b().CC(CC_LT).Inputs(3U, 0U);
3971             INST(5U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(4U);
3972         }
3973         BASIC_BLOCK(3U, 1U)
3974         {
3975             INST(6U, Opcode::Return).s32().Inputs(3U);
3976         }
3977         BASIC_BLOCK(4U, 1U)
3978         {
3979             INST(7U, Opcode::Return).s32().Inputs(3U);
3980         }
3981     }
3982     GetGraph()->RunPass<Peepholes>();
3983     GraphChecker(GetGraph()).Check();
3984     auto graph = CreateEmptyGraph();
3985     GRAPH(graph)
3986     {
3987         CONSTANT(0U, 1U);
3988         PARAMETER(1U, 0U).s32();
3989         PARAMETER(2U, 1U).s32();
3990         BASIC_BLOCK(2U, 3U, 4U)
3991         {
3992             INST(3U, Opcode::Cmp).s32().Inputs(1U, 2U);
3993             INST(4U, Opcode::Compare).b().CC(CC_LT).Inputs(3U, 0U);
3994             INST(5U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(4U);
3995         }
3996         BASIC_BLOCK(3U, 1U)
3997         {
3998             INST(6U, Opcode::Return).s32().Inputs(3U);
3999         }
4000         BASIC_BLOCK(4U, 1U)
4001         {
4002             INST(7U, Opcode::Return).s32().Inputs(3U);
4003         }
4004     }
4005     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
4006 }
4007 
CompareBoolWithConst(ConditionCode cc,bool input,int cst)4008 static bool CompareBoolWithConst(ConditionCode cc, bool input, int cst)
4009 {
4010     switch (cc) {
4011         case CC_EQ:
4012             return static_cast<int>(input) == cst;
4013         case CC_NE:
4014             return static_cast<int>(input) != cst;
4015         case CC_LT:
4016             return static_cast<int>(input) < cst;
4017         case CC_LE:
4018             return static_cast<int>(input) <= cst;
4019         case CC_GT:
4020             return static_cast<int>(input) > cst;
4021         case CC_GE:
4022             return static_cast<int>(input) >= cst;
4023         case CC_B:
4024             return static_cast<uint64_t>(input) < static_cast<uint64_t>(cst);
4025         case CC_BE:
4026             return static_cast<uint64_t>(input) <= static_cast<uint64_t>(cst);
4027         case CC_A:
4028             return static_cast<uint64_t>(input) > static_cast<uint64_t>(cst);
4029         case CC_AE:
4030             return static_cast<uint64_t>(input) >= static_cast<uint64_t>(cst);
4031         default:
4032             UNREACHABLE();
4033     }
4034 }
4035 
TEST_F(PeepholesTest,CompareTest4)4036 TEST_F(PeepholesTest, CompareTest4)
4037 {
4038     for (auto cc : {CC_EQ, CC_NE, CC_LT, CC_LE, CC_GT, CC_GE, CC_B, CC_BE, CC_A, CC_AE}) {
4039         for (auto cst : {-2L, -1L, 0L, 1L, 2L}) {
4040             auto inputTrue = CompareBoolWithConst(cc, true, cst);
4041             auto inputFalse = CompareBoolWithConst(cc, false, cst);
4042             if (inputTrue && inputFalse) {
4043                 CheckCompare(cc, cst, {1U}, false);
4044             } else if (!inputTrue && !inputFalse) {
4045                 CheckCompare(cc, cst, {0U}, false);
4046             } else if (inputTrue && !inputFalse) {
4047                 CheckCompare(cc, cst, std::nullopt, false);
4048             } else {
4049                 CheckCompare(cc, cst, std::nullopt, true);
4050             }
4051         }
4052     }
4053 }
4054 
TEST_F(PeepholesTest,CompareTestCmpWithZero1)4055 TEST_F(PeepholesTest, CompareTestCmpWithZero1)
4056 {
4057     GRAPH(GetGraph())
4058     {
4059         CONSTANT(0U, 0U);
4060         PARAMETER(1U, 1U).s32();
4061         PARAMETER(2U, 10U).s32();
4062         BASIC_BLOCK(2U, 1U)
4063         {
4064             INST(3U, Opcode::Cast).f64().SrcType(DataType::INT32).Inputs(1U);
4065             INST(4U, Opcode::Cast).f64().SrcType(DataType::INT32).Inputs(2U);
4066             INST(5U, Opcode::Cmp).s32().Inputs(3U, 4U);
4067             INST(6U, Opcode::Compare).b().CC(CC_LT).Inputs(5U, 0U);
4068             INST(7U, Opcode::Return).b().Inputs(6U);
4069         }
4070     }
4071     GetGraph()->RunPass<Peepholes>();
4072     GetGraph()->RunPass<Cleanup>();
4073     GraphChecker(GetGraph()).Check();
4074     auto graph = CreateEmptyGraph();
4075     GRAPH(graph)
4076     {
4077         PARAMETER(1U, 1U).s32();
4078         PARAMETER(2U, 10U).s32();
4079         BASIC_BLOCK(2U, 1U)
4080         {
4081             INST(6U, Opcode::Compare).b().CC(CC_LT).Inputs(1U, 2U);
4082             INST(7U, Opcode::Return).b().Inputs(6U);
4083         }
4084     }
4085     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
4086 }
4087 
TEST_F(PeepholesTest,CompareTestCmpWithZero2)4088 TEST_F(PeepholesTest, CompareTestCmpWithZero2)
4089 {
4090     GRAPH(GetGraph())
4091     {
4092         CONSTANT(0U, 0U);
4093         CONSTANT(1U, 10.0F);
4094         PARAMETER(2U, 1U).s32();
4095         BASIC_BLOCK(2U, 1U)
4096         {
4097             INST(3U, Opcode::Cast).f32().SrcType(DataType::INT32).Inputs(2U);
4098             INST(4U, Opcode::Cmp).s32().Inputs(3U, 1U);
4099             INST(5U, Opcode::Compare).b().CC(CC_LT).Inputs(4U, 0U);
4100             INST(6U, Opcode::Return).b().Inputs(5U);
4101         }
4102     }
4103     GetGraph()->RunPass<Peepholes>();
4104     GetGraph()->RunPass<Cleanup>();
4105     GraphChecker(GetGraph()).Check();
4106     auto graph = CreateEmptyGraph();
4107     GRAPH(graph)
4108     {
4109         PARAMETER(2U, 1U).s32();
4110         CONSTANT(7U, 10U);
4111         BASIC_BLOCK(2U, 1U)
4112         {
4113             INST(5U, Opcode::Compare).b().CC(CC_LT).Inputs(2U, 7U);
4114             INST(6U, Opcode::Return).b().Inputs(5U);
4115         }
4116     }
4117     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
4118 }
4119 
TEST_F(PeepholesTest,CompareTestCmpMultipleUsers)4120 TEST_F(PeepholesTest, CompareTestCmpMultipleUsers)
4121 {
4122     GRAPH(GetGraph())
4123     {
4124         CONSTANT(0U, 0U);
4125         PARAMETER(1U, 0U).s32();
4126         PARAMETER(2U, 1U).s32();
4127         BASIC_BLOCK(2U, 1U)
4128         {
4129             INST(3U, Opcode::Cmp).s32().Inputs(1U, 2U);
4130             INST(4U, Opcode::Compare).b().CC(CC_LT).Inputs(3U, 0U);
4131             INST(5U, Opcode::Add).i32().Inputs(3U, 4U);
4132             INST(6U, Opcode::Return).b().Inputs(5U);
4133         }
4134     }
4135     GetGraph()->RunPass<Peepholes>();
4136     GraphChecker(GetGraph()).Check();
4137     auto graph = CreateEmptyGraph();
4138     GRAPH(graph)
4139     {
4140         CONSTANT(0U, 0U);
4141         PARAMETER(1U, 0U).s32();
4142         PARAMETER(2U, 1U).s32();
4143         BASIC_BLOCK(2U, 1U)
4144         {
4145             INST(3U, Opcode::Cmp).s32().Inputs(1U, 2U);
4146             INST(4U, Opcode::Compare).b().CC(CC_LT).Inputs(1U, 2U);
4147             INST(5U, Opcode::Add).i32().Inputs(3U, 4U);
4148             INST(6U, Opcode::Return).b().Inputs(5U);
4149         }
4150     }
4151     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
4152 }
4153 
4154 // cast case 1
TEST_F(PeepholesTest,CastTest1)4155 TEST_F(PeepholesTest, CastTest1)
4156 {
4157     for (int i = 1; i < DataType::ANY; ++i) {
4158         for (int j = 1; j < DataType::ANY; ++j) {
4159             if ((i == DataType::FLOAT32 || i == DataType::FLOAT64) && j >= DataType::BOOL && j <= DataType::INT16) {
4160                 continue;
4161             }
4162             CheckCast(static_cast<DataType::Type>(i), static_cast<DataType::Type>(j), i == j);
4163         }
4164     }
4165 }
4166 
CastTest2Addition1MainLoop(int i,int j)4167 void PeepholesTest::CastTest2Addition1MainLoop(int i, int j)
4168 {
4169     for (int k = 1; k < DataType::LAST - 5L; ++k) {
4170         if ((i == DataType::FLOAT32 || i == DataType::FLOAT64) && j >= DataType::BOOL && j <= DataType::INT16) {
4171             continue;
4172         }
4173         CheckCast(i, j, k);
4174     }
4175 }
4176 
4177 // cast case 2
TEST_F(PeepholesTest,CastTest2Addition1)4178 TEST_F(PeepholesTest, CastTest2Addition1)
4179 {
4180     for (int i = 1; i < DataType::LAST - 5L; ++i) {
4181         for (int j = 1; j < DataType::LAST - 5L; ++j) {
4182             CastTest2Addition1MainLoop(i, j);
4183         }
4184     }
4185 }
4186 // cast case 2
TEST_F(PeepholesTest,CastTest2Addition2)4187 TEST_F(PeepholesTest, CastTest2Addition2)
4188 {
4189     for (int i = DataType::LAST - 5L; i < DataType::ANY; ++i) {
4190         for (int j = DataType::LAST - 5L; j < DataType::ANY; ++j) {
4191             for (int k = DataType::LAST - 5L; k < DataType::ANY; ++k) {
4192                 CheckCast(i, j, k);
4193             }
4194         }
4195     }
4196 }
4197 
4198 // cast case 1, several casts
TEST_F(PeepholesTest,CastTest3)4199 TEST_F(PeepholesTest, CastTest3)
4200 {
4201     GRAPH(GetGraph())
4202     {
4203         PARAMETER(0U, 0U).s32();
4204         BASIC_BLOCK(2U, 1U)
4205         {
4206             INST(1U, Opcode::Cast).s32().SrcType(DataType::INT32).Inputs(0U);
4207             INST(2U, Opcode::Cast).s32().SrcType(DataType::INT32).Inputs(1U);
4208             INST(3U, Opcode::Cast).s32().SrcType(DataType::INT32).Inputs(2U);
4209             INST(4U, Opcode::Cast).s32().SrcType(DataType::INT32).Inputs(3U);
4210             INST(5U, Opcode::Return).s32().Inputs(4U);
4211         }
4212     }
4213     auto graph = CreateEmptyGraph();
4214     GRAPH(graph)
4215     {
4216         PARAMETER(0U, 0U).s32();
4217         BASIC_BLOCK(2U, 1U)
4218         {
4219             INST(1U, Opcode::Cast).s32().SrcType(DataType::INT32).Inputs(0U);
4220             INST(2U, Opcode::Cast).s32().SrcType(DataType::INT32).Inputs(0U);
4221             INST(3U, Opcode::Cast).s32().SrcType(DataType::INT32).Inputs(0U);
4222             INST(4U, Opcode::Cast).s32().SrcType(DataType::INT32).Inputs(0U);
4223             INST(5U, Opcode::Return).s32().Inputs(0U);
4224         }
4225     }
4226     ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
4227     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
4228 }
4229 
4230 // Casts from float32/64 to int8/16 don't support.
4231 // cast case 2, several casts
TEST_F(PeepholesTest,DISABLED_CastTest4)4232 TEST_F(PeepholesTest, DISABLED_CastTest4)
4233 {
4234     GRAPH(GetGraph())
4235     {
4236         PARAMETER(0U, 0U).s16();
4237         BASIC_BLOCK(2U, 1U)
4238         {
4239             INST(1U, Opcode::Cast).f32().SrcType(DataType::INT16).Inputs(0U);
4240             INST(2U, Opcode::Cast).s16().SrcType(DataType::FLOAT32).Inputs(1U);
4241             INST(3U, Opcode::Cast).f64().SrcType(DataType::INT16).Inputs(2U);
4242             INST(4U, Opcode::Cast).s16().SrcType(DataType::FLOAT64).Inputs(3U);
4243             INST(5U, Opcode::Return).s16().Inputs(4U);
4244         }
4245     }
4246     auto graph = CreateEmptyGraph();
4247     GRAPH(graph)
4248     {
4249         PARAMETER(0U, 0U).s16();
4250         BASIC_BLOCK(2U, 1U)
4251         {
4252             INST(1U, Opcode::Cast).f32().SrcType(DataType::INT16).Inputs(0U);
4253             INST(2U, Opcode::Cast).s16().SrcType(DataType::FLOAT32).Inputs(1U);
4254             INST(3U, Opcode::Cast).f64().SrcType(DataType::INT16).Inputs(0U);
4255             INST(4U, Opcode::Cast).s16().SrcType(DataType::FLOAT64).Inputs(3U);
4256             INST(5U, Opcode::Return).s16().Inputs(0U);
4257         }
4258     }
4259     ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
4260     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
4261 }
4262 
4263 // cast case 3
TEST_F(PeepholesTest,CastTest5)4264 TEST_F(PeepholesTest, CastTest5)
4265 {
4266     GRAPH(GetGraph())
4267     {
4268         PARAMETER(0U, 0U).s32();
4269         CONSTANT(1U, 0x18U);
4270 
4271         BASIC_BLOCK(2U, -1L)
4272         {
4273             INST(2U, Opcode::Shl).s32().Inputs(0U, 1U);
4274             INST(3U, Opcode::Shr).s32().Inputs(2U, 1U);
4275             INST(4U, Opcode::Shl).s32().Inputs(3U, 1U);
4276             INST(5U, Opcode::AShr).s32().Inputs(4U, 1U);
4277             INST(6U, Opcode::Return).s32().Inputs(5U);
4278         }
4279     }
4280     ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
4281     auto graph = CreateEmptyGraph();
4282     GRAPH(graph)
4283     {
4284         PARAMETER(0U, 0U).s32();
4285         CONSTANT(1U, 0x18U);
4286         CONSTANT(7U, 0xffU);
4287 
4288         BASIC_BLOCK(2U, -1L)
4289         {
4290             INST(2U, Opcode::Shl).s32().Inputs(0U, 1U);
4291             INST(3U, Opcode::Shr).s32().Inputs(2U, 1U);
4292             INST(8U, Opcode::And).s32().Inputs(0U, 7U);
4293 
4294             INST(4U, Opcode::Shl).s32().Inputs(8U, 1U);
4295             INST(5U, Opcode::AShr).s32().Inputs(4U, 1U);
4296             INST(9U, Opcode::Cast).s8().SrcType(DataType::INT32).Inputs(0U);
4297 
4298             INST(6U, Opcode::Return).s32().Inputs(9U);
4299         }
4300     }
4301     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
4302 }
4303 
TEST_F(PeepholesTest,TrySwapInputsTest)4304 TEST_F(PeepholesTest, TrySwapInputsTest)
4305 {
4306     for (Opcode opc : {Opcode::Add, Opcode::And, Opcode::Or, Opcode::Xor, Opcode::Min, Opcode::Max, Opcode::Mul}) {
4307         auto graph1 = CreateEmptyGraph();
4308         GRAPH(graph1)
4309         {
4310             PARAMETER(0U, 0U).s32();
4311             CONSTANT(1U, 23U);
4312             BASIC_BLOCK(2U, 1U)
4313             {
4314                 INST(2U, opc).s32().Inputs(1U, 0U);
4315                 INST(3U, Opcode::Return).s32().Inputs(2U);
4316             }
4317         }
4318         ASSERT_TRUE(graph1->RunPass<Peepholes>());
4319         auto graph2 = CreateEmptyGraph();
4320         GRAPH(graph2)
4321         {
4322             PARAMETER(0U, 0U).s32();
4323             CONSTANT(1U, 23U);
4324             BASIC_BLOCK(2U, 1U)
4325             {
4326                 INST(2U, opc).s32().Inputs(0U, 1U);
4327                 INST(3U, Opcode::Return).s32().Inputs(2U);
4328             }
4329         }
4330         ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
4331     }
4332 }
4333 
TEST_F(PeepholesTest,ReplaceXorWithNot)4334 TEST_F(PeepholesTest, ReplaceXorWithNot)
4335 {
4336     GRAPH(GetGraph())
4337     {
4338         PARAMETER(0U, 0U).s32();
4339         CONSTANT(1U, -1L);
4340 
4341         BASIC_BLOCK(2U, -1L)
4342         {
4343             INST(2U, Opcode::Xor).s32().Inputs(0U, 1U);
4344             INST(3U, Opcode::Xor).s32().Inputs(1U, 0U);
4345             INST(4U, Opcode::Add).s32().Inputs(2U, 3U);
4346             INST(5U, Opcode::Return).s32().Inputs(4U);
4347         }
4348     }
4349     ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
4350     ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
4351     auto graph = CreateEmptyGraph();
4352     GRAPH(graph)
4353     {
4354         PARAMETER(0U, 0U).s32();
4355 
4356         BASIC_BLOCK(2U, -1L)
4357         {
4358             INST(1U, Opcode::Not).s32().Inputs(0U);
4359             INST(2U, Opcode::Not).s32().Inputs(0U);
4360             INST(3U, Opcode::Add).s32().Inputs(1U, 2U);
4361             INST(4U, Opcode::Return).s32().Inputs(3U);
4362         }
4363     }
4364     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
4365 }
4366 
TEST_F(PeepholesTest,XorWithZero)4367 TEST_F(PeepholesTest, XorWithZero)
4368 {
4369     GRAPH(GetGraph())
4370     {
4371         PARAMETER(0U, 0U).s32();
4372         CONSTANT(1U, 0U);
4373 
4374         BASIC_BLOCK(2U, -1L)
4375         {
4376             INST(2U, Opcode::Xor).s32().Inputs(0U, 1U);
4377             INST(3U, Opcode::Xor).s32().Inputs(1U, 0U);
4378             INST(4U, Opcode::Add).s32().Inputs(2U, 3U);
4379             INST(5U, Opcode::Return).s32().Inputs(4U);
4380         }
4381     }
4382     ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
4383     ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
4384     auto graph = CreateEmptyGraph();
4385     GRAPH(graph)
4386     {
4387         PARAMETER(0U, 0U).s32();
4388 
4389         BASIC_BLOCK(2U, -1L)
4390         {
4391             INST(3U, Opcode::Add).s32().Inputs(0U, 0U);
4392             INST(4U, Opcode::Return).s32().Inputs(3U);
4393         }
4394     }
4395     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
4396 }
4397 
SRC_GRAPH(CleanupTrigger,Graph * graph)4398 SRC_GRAPH(CleanupTrigger, Graph *graph)
4399 {
4400     GRAPH(graph)
4401     {
4402         PARAMETER(0U, 0U).u64();
4403         CONSTANT(1U, 1U);
4404         CONSTANT(2U, 2U);
4405         CONSTANT(3U, 3U);
4406         CONSTANT(4U, 4U);
4407         BASIC_BLOCK(2U, 3U, 4U)
4408         {
4409             INST(5U, Opcode::Add).u64().Inputs(1U, 4U);
4410             INST(6U, Opcode::Add).u64().Inputs(2U, 3U);
4411             INST(7U, Opcode::Compare).b().Inputs(0U, 3U);
4412             INST(8U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(7U);
4413         }
4414         BASIC_BLOCK(3U, 4U) {}
4415         BASIC_BLOCK(4U, -1L)
4416         {
4417             INST(9U, Opcode::Phi).u64().Inputs({{2U, 6U}, {3U, 5U}});
4418             INST(10U, Opcode::Return).u64().Inputs(9U);
4419         }
4420     }
4421 }
4422 
OUT_GRAPH(CleanupTrigger,Graph * graph)4423 OUT_GRAPH(CleanupTrigger, Graph *graph)
4424 {
4425     GRAPH(graph)
4426     {
4427         PARAMETER(0U, 0U).u64();
4428         CONSTANT(1U, 1U);
4429         CONSTANT(2U, 2U);
4430         CONSTANT(3U, 3U);
4431         CONSTANT(4U, 4U);
4432         CONSTANT(11U, 5U);
4433         BASIC_BLOCK(2U, 3U, 4U)
4434         {
4435             INST(5U, Opcode::Add).u64().Inputs(1U, 4U);
4436             INST(6U, Opcode::Add).u64().Inputs(2U, 3U);
4437             INST(7U, Opcode::Compare).b().Inputs(0U, 3U);
4438             INST(8U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(7U);
4439         }
4440         BASIC_BLOCK(3U, 4U) {}
4441         BASIC_BLOCK(4U, -1L)
4442         {
4443             INST(9U, Opcode::Phi).u64().Inputs({{2U, 11U}, {3U, 11U}});
4444             INST(10U, Opcode::Return).u64().Inputs(9U);
4445         }
4446     }
4447 }
4448 
TEST_F(PeepholesTest,CleanupTrigger)4449 TEST_F(PeepholesTest, CleanupTrigger)
4450 {
4451     src_graph::CleanupTrigger::CREATE(GetGraph());
4452 
4453     GraphChecker(GetGraph()).Check();
4454     ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
4455 
4456     auto graph = CreateEmptyGraph();
4457     out_graph::CleanupTrigger::CREATE(graph);
4458     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
4459 }
4460 
TEST_F(PeepholesTest,TestAbsUnsigned)4461 TEST_F(PeepholesTest, TestAbsUnsigned)
4462 {
4463     GRAPH(GetGraph())
4464     {
4465         PARAMETER(0U, 1U).u64();
4466         BASIC_BLOCK(2U, -1L)
4467         {
4468             INST(2U, Opcode::Abs).u64().Inputs(0U);
4469             INST(3U, Opcode::Return).u64().Inputs(2U);
4470         }
4471     }
4472     ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
4473     GraphChecker(GetGraph()).Check();
4474     ASSERT_EQ(INS(3U).GetInput(0U).GetInst(), &INS(0U));
4475 }
4476 
TEST_F(PeepholesTest,SafePoint)4477 TEST_F(PeepholesTest, SafePoint)
4478 {
4479     GRAPH(GetGraph())
4480     {
4481         PARAMETER(0U, 1U).u64();
4482         PARAMETER(1U, 2U).s32();
4483         PARAMETER(2U, 3U).f64();
4484         PARAMETER(3U, 4U).ref();
4485         BASIC_BLOCK(2U, -1L)
4486         {
4487             INST(4U, Opcode::SafePoint).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
4488             INST(5U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
4489             INST(6U, Opcode::CallStatic).u64().InputsAutoType(0U, 1U, 2U, 3U, 5U);
4490             INST(7U, Opcode::Return).u64().Inputs(6U);
4491         }
4492     }
4493     Graph *graphEt = CreateEmptyGraph();
4494     GRAPH(graphEt)
4495     {
4496         PARAMETER(0U, 1U).u64();
4497         PARAMETER(1U, 2U).s32();
4498         PARAMETER(2U, 3U).f64();
4499         PARAMETER(3U, 4U).ref();
4500         BASIC_BLOCK(2U, -1L)
4501         {
4502             INST(4U, Opcode::SafePoint).Inputs(3U).SrcVregs({3U});
4503             INST(5U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
4504             INST(6U, Opcode::CallStatic).u64().InputsAutoType(0U, 1U, 2U, 3U, 5U);
4505             INST(7U, Opcode::Return).u64().Inputs(6U);
4506         }
4507     }
4508 
4509     ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
4510     GraphChecker(GetGraph()).Check();
4511     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graphEt));
4512 }
4513 
TEST_F(PeepholesTest,SafePointWithRegMap)4514 TEST_F(PeepholesTest, SafePointWithRegMap)
4515 {
4516     g_options.SetCompilerSafePointsRequireRegMap(true);
4517 
4518     GRAPH(GetGraph())
4519     {
4520         PARAMETER(0U, 1U).u64();
4521         PARAMETER(1U, 2U).s32();
4522         PARAMETER(2U, 3U).f64();
4523         PARAMETER(3U, 4U).ref();
4524         BASIC_BLOCK(2U, -1L)
4525         {
4526             INST(4U, Opcode::SafePoint).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
4527             INST(5U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
4528             INST(6U, Opcode::CallStatic).u64().InputsAutoType(0U, 1U, 2U, 3U, 5U);
4529             INST(7U, Opcode::Return).u64().Inputs(6U);
4530         }
4531     }
4532     Graph *graphEt = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
4533     ASSERT_FALSE(GetGraph()->RunPass<Peepholes>());
4534     GraphChecker(GetGraph()).Check();
4535     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graphEt));
4536 }
4537 
SRC_GRAPH(ShlShlAddAdd,Graph * graph)4538 SRC_GRAPH(ShlShlAddAdd, Graph *graph)
4539 {
4540     GRAPH(graph)
4541     {
4542         PARAMETER(0U, 0U).i64();
4543         PARAMETER(1U, 1U).i64();
4544         CONSTANT(2U, 16U);
4545         CONSTANT(3U, 17U);
4546         BASIC_BLOCK(2U, -1L)
4547         {
4548             INST(4U, Opcode::Shl).i64().Inputs(0U, 2U);
4549             INST(5U, Opcode::Shl).i64().Inputs(0U, 3U);
4550             INST(6U, Opcode::Add).i64().Inputs(4U, 5U);
4551             INST(7U, Opcode::Add).i64().Inputs(1U, 6U);
4552             INST(8U, Opcode::Return).i64().Inputs(7U);
4553         }
4554     }
4555 }
4556 
OUT_GRAPH(ShlShlAddAdd,Graph * graph)4557 OUT_GRAPH(ShlShlAddAdd, Graph *graph)
4558 {
4559     GRAPH(graph)
4560     {
4561         PARAMETER(0U, 0U).i64();
4562         PARAMETER(1U, 1U).i64();
4563         CONSTANT(2U, 16U);
4564         CONSTANT(3U, 17U);
4565         BASIC_BLOCK(2U, -1L)
4566         {
4567             INST(4U, Opcode::Shl).i64().Inputs(0U, 2U);
4568             INST(5U, Opcode::Shl).i64().Inputs(0U, 3U);
4569             INST(6U, Opcode::Add).i64().Inputs(1U, 4U);
4570             INST(7U, Opcode::Add).i64().Inputs(6U, 5U);
4571             INST(8U, Opcode::Return).i64().Inputs(7U);
4572         }
4573     }
4574 }
4575 
SRC_GRAPH(ShlShlAddAdd1,Graph * graph)4576 SRC_GRAPH(ShlShlAddAdd1, Graph *graph)
4577 {
4578     GRAPH(graph)
4579     {
4580         PARAMETER(0U, 0U).i64();
4581         PARAMETER(1U, 1U).i64();
4582         CONSTANT(2U, 16U);
4583         CONSTANT(3U, 17U);
4584         BASIC_BLOCK(2U, -1L)
4585         {
4586             // shl4 !HasSingleUser()
4587             INST(4U, Opcode::Shl).i64().Inputs(0U, 2U);
4588             INST(5U, Opcode::Shl).i64().Inputs(0U, 3U);
4589             INST(6U, Opcode::Add).i64().Inputs(4U, 5U);
4590             INST(7U, Opcode::Add).i64().Inputs(1U, 6U);
4591             INST(8U, Opcode::Add).i64().Inputs(4U, 7U);
4592             INST(9U, Opcode::Return).i64().Inputs(8U);
4593         }
4594     }
4595 }
4596 
SRC_GRAPH(ShlShlAddAdd2,Graph * graph)4597 SRC_GRAPH(ShlShlAddAdd2, Graph *graph)
4598 {
4599     GRAPH(graph)
4600     {
4601         PARAMETER(0U, 0U).i64();
4602         PARAMETER(1U, 1U).i64();
4603         CONSTANT(2U, 16U);
4604         CONSTANT(3U, 17U);
4605         BASIC_BLOCK(2U, -1L)
4606         {
4607             // shl5 !HasSingleUser()
4608             INST(4U, Opcode::Shl).i64().Inputs(0U, 2U);
4609             INST(5U, Opcode::Shl).i64().Inputs(0U, 3U);
4610             INST(6U, Opcode::Add).i64().Inputs(4U, 5U);
4611             INST(7U, Opcode::Add).i64().Inputs(1U, 6U);
4612             INST(8U, Opcode::Add).i64().Inputs(5U, 7U);
4613             INST(9U, Opcode::Return).i64().Inputs(8U);
4614         }
4615     }
4616 }
4617 
SRC_GRAPH(ShlShlAddAdd3,Graph * graph)4618 SRC_GRAPH(ShlShlAddAdd3, Graph *graph)
4619 {
4620     GRAPH(graph)
4621     {
4622         PARAMETER(0U, 0U).i64();
4623         PARAMETER(1U, 1U).i64();
4624         CONSTANT(2U, 16U);
4625         CONSTANT(3U, 17U);
4626         BASIC_BLOCK(2U, -1L)
4627         {
4628             // add6 !HasSingleUser()
4629             INST(4U, Opcode::Shl).i64().Inputs(0U, 2U);
4630             INST(5U, Opcode::Shl).i64().Inputs(0U, 3U);
4631             INST(6U, Opcode::Add).i64().Inputs(4U, 5U);
4632             INST(7U, Opcode::Add).i64().Inputs(1U, 6U);
4633             INST(8U, Opcode::Add).i64().Inputs(0U, 6U);
4634             INST(9U, Opcode::Return).i64().Inputs(8U);
4635         }
4636     }
4637 }
4638 
SRC_GRAPH(ShlShlAddAdd4,Graph * graph)4639 SRC_GRAPH(ShlShlAddAdd4, Graph *graph)
4640 {
4641     GRAPH(graph)
4642     {
4643         PARAMETER(0U, 0U).i64();
4644         PARAMETER(1U, 1U).i64();
4645         CONSTANT(2U, 16U);
4646         CONSTANT(3U, 17U);
4647         BASIC_BLOCK(2U, -1L)
4648         {
4649             // shl4 and shl5 have different input(0).
4650             INST(4U, Opcode::Shl).i64().Inputs(0U, 2U);
4651             INST(5U, Opcode::Shl).i64().Inputs(1U, 3U);
4652             INST(6U, Opcode::Add).i64().Inputs(4U, 5U);
4653             INST(7U, Opcode::Add).i64().Inputs(1U, 6U);
4654             INST(8U, Opcode::Return).i64().Inputs(7U);
4655         }
4656     }
4657 }
4658 
SRC_GRAPH(ShlShlAddAdd5,Graph * graph)4659 SRC_GRAPH(ShlShlAddAdd5, Graph *graph)
4660 {
4661     GRAPH(graph)
4662     {
4663         PARAMETER(0U, 0U).i64();
4664         PARAMETER(1U, 1U).i64();
4665         PARAMETER(2U, 2U).i64();
4666         CONSTANT(3U, 17U);
4667         BASIC_BLOCK(2U, -1L)
4668         {
4669             // shl4->GetInput(1) is not constant.
4670             INST(4U, Opcode::Shl).i64().Inputs(0U, 2U);
4671             INST(5U, Opcode::Shl).i64().Inputs(1U, 3U);
4672             INST(6U, Opcode::Add).i64().Inputs(4U, 5U);
4673             INST(7U, Opcode::Add).i64().Inputs(1U, 6U);
4674             INST(8U, Opcode::Return).i64().Inputs(7U);
4675         }
4676     }
4677 }
4678 
SRC_GRAPH(ShlShlAddAdd6,Graph * graph)4679 SRC_GRAPH(ShlShlAddAdd6, Graph *graph)
4680 {
4681     GRAPH(graph)
4682     {
4683         PARAMETER(0U, 0U).i64();
4684         PARAMETER(1U, 1U).i64();
4685         CONSTANT(2U, 16U);
4686         PARAMETER(3U, 2U).i64();
4687         BASIC_BLOCK(2U, -1L)
4688         {
4689             // shl5->GetInput(1) is not constant.
4690             INST(4U, Opcode::Shl).i64().Inputs(0U, 2U);
4691             INST(5U, Opcode::Shl).i64().Inputs(1U, 3U);
4692             INST(6U, Opcode::Add).i64().Inputs(4U, 5U);
4693             INST(7U, Opcode::Add).i64().Inputs(1U, 6U);
4694             INST(8U, Opcode::Return).i64().Inputs(7U);
4695         }
4696     }
4697 }
4698 
SRC_GRAPH(ShlShlAddAdd7,Graph * graph)4699 SRC_GRAPH(ShlShlAddAdd7, Graph *graph)
4700 {
4701     GRAPH(graph)
4702     {
4703         PARAMETER(0U, 0U).i64();
4704         PARAMETER(1U, 1U).i64();
4705         CONSTANT(2U, 16U);
4706         CONSTANT(3U, 17U);
4707         BASIC_BLOCK(2U, 3U)
4708         {
4709             INST(20U, Opcode::Shl).i64().Inputs(0U, 2U);
4710             INST(21U, Opcode::Shl).i64().Inputs(0U, 3U);
4711             INST(22U, Opcode::Add).i64().Inputs(20U, 21U);
4712         }
4713         BASIC_BLOCK(3U, 4U)
4714         {
4715             INST(30U, Opcode::Add).i64().Inputs(0U, 1U);
4716         }
4717         BASIC_BLOCK(4U, -1L)
4718         {
4719             // add40: input(0) does not dominate input(1)
4720             INST(40U, Opcode::Add).i64().Inputs(30U, 22U);
4721             INST(41U, Opcode::Return).i64().Inputs(40U);
4722         }
4723     }
4724 }
4725 
TEST_F(PeepholesTest,ShlShlAddAdd)4726 TEST_F(PeepholesTest, ShlShlAddAdd)
4727 {
4728     src_graph::ShlShlAddAdd::CREATE(GetGraph());
4729     Graph *graphPeepholed = CreateEmptyGraph();
4730     out_graph::ShlShlAddAdd::CREATE(graphPeepholed);
4731 
4732     ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
4733     ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
4734     GraphChecker(GetGraph()).Check();
4735     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graphPeepholed));
4736 
4737     // Not optimizable cases
4738     Graph *graphNotOptimizable = CreateEmptyGraph();
4739     src_graph::ShlShlAddAdd1::CREATE(graphNotOptimizable);
4740     ASSERT_FALSE(graphNotOptimizable->RunPass<Peepholes>());
4741 
4742     graphNotOptimizable = CreateEmptyGraph();
4743     src_graph::ShlShlAddAdd2::CREATE(graphNotOptimizable);
4744     ASSERT_FALSE(graphNotOptimizable->RunPass<Peepholes>());
4745 
4746     graphNotOptimizable = CreateEmptyGraph();
4747     src_graph::ShlShlAddAdd3::CREATE(graphNotOptimizable);
4748     ASSERT_FALSE(graphNotOptimizable->RunPass<Peepholes>());
4749 
4750     graphNotOptimizable = CreateEmptyGraph();
4751     src_graph::ShlShlAddAdd4::CREATE(graphNotOptimizable);
4752     ASSERT_FALSE(graphNotOptimizable->RunPass<Peepholes>());
4753 
4754     graphNotOptimizable = CreateEmptyGraph();
4755     src_graph::ShlShlAddAdd5::CREATE(graphNotOptimizable);
4756     ASSERT_FALSE(graphNotOptimizable->RunPass<Peepholes>());
4757 
4758     graphNotOptimizable = CreateEmptyGraph();
4759     src_graph::ShlShlAddAdd6::CREATE(graphNotOptimizable);
4760     ASSERT_FALSE(graphNotOptimizable->RunPass<Peepholes>());
4761 
4762     graphNotOptimizable = CreateEmptyGraph();
4763     src_graph::ShlShlAddAdd7::CREATE(graphNotOptimizable);
4764     ASSERT_FALSE(graphNotOptimizable->RunPass<Peepholes>());
4765 }
4766 
TEST_F(PeepholesTest,ShlShlAddSub)4767 TEST_F(PeepholesTest, ShlShlAddSub)
4768 {
4769     GRAPH(GetGraph())
4770     {
4771         PARAMETER(0U, 0U).i64();
4772         PARAMETER(1U, 1U).i64();
4773         CONSTANT(2U, 16U);
4774         CONSTANT(3U, 17U);
4775         BASIC_BLOCK(2U, -1L)
4776         {
4777             INST(4U, Opcode::Shl).i64().Inputs(0U, 2U);
4778             INST(5U, Opcode::Shl).i64().Inputs(0U, 3U);
4779             INST(6U, Opcode::Add).i64().Inputs(4U, 5U);
4780             INST(7U, Opcode::Sub).i64().Inputs(1U, 6U);
4781             INST(8U, Opcode::Return).i64().Inputs(7U);
4782         }
4783     }
4784     Graph *graphPeepholed = CreateEmptyGraph();
4785     GRAPH(graphPeepholed)
4786     {
4787         PARAMETER(0U, 0U).i64();
4788         PARAMETER(1U, 1U).i64();
4789         CONSTANT(2U, 16U);
4790         CONSTANT(3U, 17U);
4791         BASIC_BLOCK(2U, -1L)
4792         {
4793             INST(4U, Opcode::Shl).i64().Inputs(0U, 2U);
4794             INST(5U, Opcode::Shl).i64().Inputs(0U, 3U);
4795             INST(6U, Opcode::Sub).i64().Inputs(1U, 4U);
4796             INST(7U, Opcode::Sub).i64().Inputs(6U, 5U);
4797             INST(8U, Opcode::Return).i64().Inputs(7U);
4798         }
4799     }
4800 
4801     ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
4802     ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
4803     GraphChecker(GetGraph()).Check();
4804     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graphPeepholed));
4805 }
4806 
TEST_F(PeepholesTest,ShlShlSubAdd)4807 TEST_F(PeepholesTest, ShlShlSubAdd)
4808 {
4809     GRAPH(GetGraph())
4810     {
4811         PARAMETER(0U, 0U).i64();
4812         PARAMETER(1U, 1U).i64();
4813         CONSTANT(2U, 16U);
4814         CONSTANT(3U, 17U);
4815         BASIC_BLOCK(2U, -1L)
4816         {
4817             INST(4U, Opcode::Shl).i64().Inputs(0U, 2U);
4818             INST(5U, Opcode::Shl).i64().Inputs(0U, 3U);
4819             INST(6U, Opcode::Sub).i64().Inputs(4U, 5U);
4820             INST(7U, Opcode::Add).i64().Inputs(1U, 6U);
4821             INST(8U, Opcode::Return).i64().Inputs(7U);
4822         }
4823     }
4824     Graph *graphPeepholed = CreateEmptyGraph();
4825     GRAPH(graphPeepholed)
4826     {
4827         PARAMETER(0U, 0U).i64();
4828         PARAMETER(1U, 1U).i64();
4829         CONSTANT(2U, 16U);
4830         CONSTANT(3U, 17U);
4831         BASIC_BLOCK(2U, -1L)
4832         {
4833             INST(4U, Opcode::Shl).i64().Inputs(0U, 2U);
4834             INST(5U, Opcode::Shl).i64().Inputs(0U, 3U);
4835             INST(6U, Opcode::Add).i64().Inputs(1U, 4U);
4836             INST(7U, Opcode::Sub).i64().Inputs(6U, 5U);
4837             INST(8U, Opcode::Return).i64().Inputs(7U);
4838         }
4839     }
4840 
4841     ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
4842     ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
4843     GraphChecker(GetGraph()).Check();
4844     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graphPeepholed));
4845 }
4846 
TEST_F(PeepholesTest,ShlShlSubSub)4847 TEST_F(PeepholesTest, ShlShlSubSub)
4848 {
4849     GRAPH(GetGraph())
4850     {
4851         PARAMETER(0U, 0U).i64();
4852         PARAMETER(1U, 1U).i64();
4853         CONSTANT(2U, 16U);
4854         CONSTANT(3U, 17U);
4855         BASIC_BLOCK(2U, -1L)
4856         {
4857             INST(4U, Opcode::Shl).i64().Inputs(0U, 2U);
4858             INST(5U, Opcode::Shl).i64().Inputs(0U, 3U);
4859             INST(6U, Opcode::Sub).i64().Inputs(4U, 5U);
4860             INST(7U, Opcode::Sub).i64().Inputs(1U, 6U);
4861             INST(8U, Opcode::Return).i64().Inputs(7U);
4862         }
4863     }
4864     Graph *graphPeepholed = CreateEmptyGraph();
4865     GRAPH(graphPeepholed)
4866     {
4867         PARAMETER(0U, 0U).i64();
4868         PARAMETER(1U, 1U).i64();
4869         CONSTANT(2U, 16U);
4870         CONSTANT(3U, 17U);
4871         BASIC_BLOCK(2U, -1L)
4872         {
4873             INST(4U, Opcode::Shl).i64().Inputs(0U, 2U);
4874             INST(5U, Opcode::Shl).i64().Inputs(0U, 3U);
4875             INST(6U, Opcode::Sub).i64().Inputs(1U, 4U);
4876             INST(7U, Opcode::Add).i64().Inputs(6U, 5U);
4877             INST(8U, Opcode::Return).i64().Inputs(7U);
4878         }
4879     }
4880 
4881     ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
4882     ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
4883     GraphChecker(GetGraph()).Check();
4884     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graphPeepholed));
4885 }
4886 
TEST_F(PeepholesTest,CompareAndWithZero)4887 TEST_F(PeepholesTest, CompareAndWithZero)
4888 {
4889     CheckCompareFoldIntoTest(0U, CC_EQ, true, CC_TST_EQ);
4890     CheckCompareFoldIntoTest(0U, CC_NE, true, CC_TST_NE);
4891 
4892     CheckCompareFoldIntoTest(1U, CC_EQ, false);
4893     CheckCompareFoldIntoTest(2U, CC_NE, false);
4894 
4895     // check comparision with zero for all CCs except CC_EQ and CC_NE
4896     for (int cc = CC_LT; cc <= CC_LAST; ++cc) {
4897         CheckCompareFoldIntoTest(0U, static_cast<ConditionCode>(cc), false);
4898     }
4899 }
4900 
TEST_F(PeepholesTest,IfAndComparedWithZero)4901 TEST_F(PeepholesTest, IfAndComparedWithZero)
4902 {
4903     CheckIfAndZeroFoldIntoIfTest(0U, CC_EQ, true, CC_TST_EQ);
4904     CheckIfAndZeroFoldIntoIfTest(0U, CC_NE, true, CC_TST_NE);
4905 
4906     CheckIfAndZeroFoldIntoIfTest(1U, CC_EQ, false);
4907     CheckIfAndZeroFoldIntoIfTest(2U, CC_NE, false);
4908 
4909     // check comparision with zero for all CCs except CC_EQ and CC_NE
4910     for (int cc = CC_LT; cc <= CC_LAST; ++cc) {
4911         CheckCompareFoldIntoTest(0U, static_cast<ConditionCode>(cc), false);
4912     }
4913 }
4914 
TEST_F(PeepholesTest,CompareLenArrayWithZero)4915 TEST_F(PeepholesTest, CompareLenArrayWithZero)
4916 {
4917     CheckCompareLenArrayWithZeroTest(0U, CC_GE, true);
4918     CheckCompareLenArrayWithZeroTest(0U, CC_LT, false);
4919     CheckCompareLenArrayWithZeroTest(0U, CC_LE, std::nullopt);
4920     CheckCompareLenArrayWithZeroTest(1U, CC_GE, std::nullopt);
4921     CheckCompareLenArrayWithZeroTest(1U, CC_LT, std::nullopt);
4922 }
4923 
TEST_F(PeepholesTest,CompareLenArrayWithZeroSwapped)4924 TEST_F(PeepholesTest, CompareLenArrayWithZeroSwapped)
4925 {
4926     CheckCompareLenArrayWithZeroTest(0U, CC_LE, true, true);
4927     CheckCompareLenArrayWithZeroTest(0U, CC_GT, false, true);
4928     CheckCompareLenArrayWithZeroTest(0U, CC_GE, std::nullopt, true);
4929     CheckCompareLenArrayWithZeroTest(1U, CC_LE, std::nullopt, true);
4930     CheckCompareLenArrayWithZeroTest(1U, CC_GT, std::nullopt, true);
4931 }
4932 
TEST_F(PeepholesTest,TestEqualInputs)4933 TEST_F(PeepholesTest, TestEqualInputs)
4934 {
4935     GRAPH(GetGraph())
4936     {
4937         PARAMETER(0U, 0U).u64();
4938 
4939         BASIC_BLOCK(2U, -1L)
4940         {
4941             INST(1U, Opcode::Compare).b().CC(CC_TST_EQ).Inputs(0U, 0U);
4942             INST(2U, Opcode::Compare).b().CC(CC_TST_NE).Inputs(0U, 0U);
4943             INST(3U, Opcode::SaveState).NoVregs();
4944             INST(4U, Opcode::CallStatic).b().InputsAutoType(1U, 2U, 3U);
4945             INST(5U, Opcode::ReturnVoid);
4946         }
4947     }
4948     Graph *graphPeepholed = CreateEmptyGraph();
4949     GRAPH(graphPeepholed)
4950     {
4951         PARAMETER(0U, 0U).u64();
4952         CONSTANT(1U, 0U).s64();
4953 
4954         BASIC_BLOCK(2U, -1L)
4955         {
4956             INST(2U, Opcode::Compare).b().CC(CC_EQ).Inputs(0U, 1U);
4957             INST(3U, Opcode::Compare).b().CC(CC_NE).Inputs(0U, 1U);
4958             INST(4U, Opcode::SaveState).NoVregs();
4959             INST(5U, Opcode::CallStatic).b().InputsAutoType(2U, 3U, 4U);
4960             INST(6U, Opcode::ReturnVoid);
4961         }
4962     }
4963 
4964     ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
4965     GraphChecker(GetGraph()).Check();
4966     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graphPeepholed));
4967 }
4968 
SRC_GRAPH(AndWithCast,Graph * graph)4969 SRC_GRAPH(AndWithCast, Graph *graph)
4970 {
4971     GRAPH(graph)
4972     {
4973         PARAMETER(0U, 0U).i64();
4974         PARAMETER(1U, 1U).i32();
4975         CONSTANT(2U, 0xFFFFFFFFU);
4976         CONSTANT(3U, 0xFFFFU);
4977         CONSTANT(4U, 0xFFU);
4978         CONSTANT(5U, 0xF7U);
4979 
4980         BASIC_BLOCK(2U, -1L)
4981         {
4982             INST(10U, Opcode::And).i32().Inputs(1U, 2U);
4983             INST(11U, Opcode::And).i32().Inputs(1U, 3U);
4984             INST(12U, Opcode::And).i32().Inputs(1U, 4U);
4985             INST(13U, Opcode::And).i32().Inputs(1U, 5U);
4986 
4987             INST(22U, Opcode::Cast).i16().SrcType(DataType::INT32).Inputs(10U);
4988             INST(23U, Opcode::Cast).i16().SrcType(DataType::INT32).Inputs(11U);
4989             INST(24U, Opcode::Cast).i16().SrcType(DataType::INT32).Inputs(12U);
4990             INST(25U, Opcode::Cast).i16().SrcType(DataType::INT32).Inputs(13U);
4991 
4992             INST(26U, Opcode::Cast).u16().SrcType(DataType::INT32).Inputs(10U);
4993             INST(27U, Opcode::Cast).u16().SrcType(DataType::INT32).Inputs(11U);
4994             INST(28U, Opcode::Cast).u16().SrcType(DataType::INT32).Inputs(12U);
4995             INST(29U, Opcode::Cast).u16().SrcType(DataType::INT32).Inputs(13U);
4996 
4997             INST(30U, Opcode::Cast).i8().SrcType(DataType::INT32).Inputs(10U);
4998             INST(31U, Opcode::Cast).i8().SrcType(DataType::INT32).Inputs(11U);
4999             INST(32U, Opcode::Cast).i8().SrcType(DataType::INT32).Inputs(12U);
5000             INST(33U, Opcode::Cast).i8().SrcType(DataType::INT32).Inputs(13U);
5001 
5002             INST(34U, Opcode::Cast).u8().SrcType(DataType::INT32).Inputs(10U);
5003             INST(35U, Opcode::Cast).u8().SrcType(DataType::INT32).Inputs(11U);
5004             INST(36U, Opcode::Cast).u8().SrcType(DataType::INT32).Inputs(12U);
5005             INST(37U, Opcode::Cast).u8().SrcType(DataType::INT32).Inputs(13U);
5006 
5007             INST(38U, Opcode::ReturnVoid).v0id();
5008         }
5009     }
5010 }
5011 
OUT_GRAPH(AndWithCast,Graph * graph)5012 OUT_GRAPH(AndWithCast, Graph *graph)
5013 {
5014     GRAPH(graph)
5015     {
5016         PARAMETER(0U, 0U).i64();
5017         PARAMETER(1U, 1U).i32();
5018         CONSTANT(2U, 0xFFFFFFFFU);
5019         CONSTANT(3U, 0xFFFFU);
5020         CONSTANT(4U, 0xFFU);
5021         CONSTANT(5U, 0xF7U);
5022 
5023         BASIC_BLOCK(2U, -1L)
5024         {
5025             INST(10U, Opcode::And).i32().Inputs(1U, 2U);
5026             INST(11U, Opcode::And).i32().Inputs(1U, 3U);
5027             INST(12U, Opcode::And).i32().Inputs(1U, 4U);
5028             INST(13U, Opcode::And).i32().Inputs(1U, 5U);
5029 
5030             INST(22U, Opcode::Cast).i16().SrcType(DataType::INT32).Inputs(1U);
5031             INST(23U, Opcode::Cast).i16().SrcType(DataType::INT32).Inputs(1U);
5032             INST(24U, Opcode::Cast).i16().SrcType(DataType::INT32).Inputs(12U);
5033             INST(25U, Opcode::Cast).i16().SrcType(DataType::INT32).Inputs(13U);
5034 
5035             INST(26U, Opcode::Cast).u16().SrcType(DataType::INT32).Inputs(1U);
5036             INST(27U, Opcode::Cast).u16().SrcType(DataType::INT32).Inputs(1U);
5037             INST(28U, Opcode::Cast).u16().SrcType(DataType::INT32).Inputs(12U);
5038             INST(29U, Opcode::Cast).u16().SrcType(DataType::INT32).Inputs(13U);
5039 
5040             INST(30U, Opcode::Cast).i8().SrcType(DataType::INT32).Inputs(1U);
5041             INST(31U, Opcode::Cast).i8().SrcType(DataType::INT32).Inputs(1U);
5042             INST(32U, Opcode::Cast).i8().SrcType(DataType::INT32).Inputs(1U);
5043             INST(33U, Opcode::Cast).i8().SrcType(DataType::INT32).Inputs(13U);
5044 
5045             INST(34U, Opcode::Cast).u8().SrcType(DataType::INT32).Inputs(1U);
5046             INST(35U, Opcode::Cast).u8().SrcType(DataType::INT32).Inputs(1U);
5047             INST(36U, Opcode::Cast).u8().SrcType(DataType::INT32).Inputs(1U);
5048             INST(37U, Opcode::Cast).u8().SrcType(DataType::INT32).Inputs(13U);
5049 
5050             INST(38U, Opcode::ReturnVoid).v0id();
5051         }
5052     }
5053 }
5054 
TEST_F(PeepholesTest,AndWithCast)5055 TEST_F(PeepholesTest, AndWithCast)
5056 {
5057     auto graph = CreateEmptyGraph();
5058     src_graph::AndWithCast::CREATE(graph);
5059 
5060     auto graphExpected = CreateEmptyGraph();
5061     out_graph::AndWithCast::CREATE(graphExpected);
5062     ASSERT_TRUE(graph->RunPass<Peepholes>());
5063     ASSERT_TRUE(GraphComparator().Compare(graph, graphExpected));
5064 }
5065 
SRC_GRAPH(AndWithStore,Graph * graph)5066 SRC_GRAPH(AndWithStore, Graph *graph)
5067 {
5068     GRAPH(graph)
5069     {
5070         PARAMETER(0U, 0U).ptr();
5071         PARAMETER(1U, 1U).u64();
5072         CONSTANT(2U, 0xFFFFFFFFU);
5073         CONSTANT(3U, 0xFFFFU);
5074         CONSTANT(4U, 0xFFU);
5075         CONSTANT(5U, 0xF7U);
5076 
5077         BASIC_BLOCK(2U, -1L)
5078         {
5079             INST(6U, Opcode::And).i32().Inputs(1U, 2U);
5080             INST(7U, Opcode::And).i32().Inputs(1U, 3U);
5081             INST(8U, Opcode::And).i32().Inputs(1U, 4U);
5082             INST(9U, Opcode::And).i32().Inputs(1U, 5U);
5083 
5084             INST(10U, Opcode::Store).i32().Inputs(0U, 1U, 6U);
5085             INST(11U, Opcode::Store).i32().Inputs(0U, 1U, 7U);
5086             INST(12U, Opcode::Store).i32().Inputs(0U, 1U, 8U);
5087             INST(13U, Opcode::Store).i32().Inputs(0U, 1U, 9U);
5088 
5089             INST(14U, Opcode::Store).u32().Inputs(0U, 1U, 6U);
5090             INST(15U, Opcode::Store).u32().Inputs(0U, 1U, 7U);
5091             INST(16U, Opcode::Store).u32().Inputs(0U, 1U, 8U);
5092             INST(17U, Opcode::Store).u32().Inputs(0U, 1U, 9U);
5093 
5094             INST(18U, Opcode::Store).i16().Inputs(0U, 1U, 6U);
5095             INST(19U, Opcode::Store).i16().Inputs(0U, 1U, 7U);
5096             INST(20U, Opcode::Store).i16().Inputs(0U, 1U, 8U);
5097             INST(21U, Opcode::Store).i16().Inputs(0U, 1U, 9U);
5098 
5099             INST(22U, Opcode::Store).u16().Inputs(0U, 1U, 6U);
5100             INST(23U, Opcode::Store).u16().Inputs(0U, 1U, 7U);
5101             INST(24U, Opcode::Store).u16().Inputs(0U, 1U, 8U);
5102             INST(25U, Opcode::Store).u16().Inputs(0U, 1U, 9U);
5103 
5104             INST(26U, Opcode::Store).i8().Inputs(0U, 1U, 6U);
5105             INST(27U, Opcode::Store).i8().Inputs(0U, 1U, 7U);
5106             INST(28U, Opcode::Store).i8().Inputs(0U, 1U, 8U);
5107             INST(29U, Opcode::Store).i8().Inputs(0U, 1U, 9U);
5108 
5109             INST(30U, Opcode::Store).u8().Inputs(0U, 1U, 6U);
5110             INST(31U, Opcode::Store).u8().Inputs(0U, 1U, 7U);
5111             INST(32U, Opcode::Store).u8().Inputs(0U, 1U, 8U);
5112             INST(33U, Opcode::Store).u8().Inputs(0U, 1U, 9U);
5113 
5114             INST(34U, Opcode::ReturnVoid).v0id();
5115         }
5116     }
5117 }
5118 
OUT_GRAPH(AndWithStore,Graph * graph)5119 OUT_GRAPH(AndWithStore, Graph *graph)
5120 {
5121     GRAPH(graph)
5122     {
5123         PARAMETER(0U, 0U).ptr();
5124         PARAMETER(1U, 1U).u64();
5125         CONSTANT(2U, 0xFFFFFFFFU);
5126         CONSTANT(3U, 0xFFFFU);
5127         CONSTANT(4U, 0xFFU);
5128         CONSTANT(5U, 0xF7U);
5129 
5130         BASIC_BLOCK(2U, -1L)
5131         {
5132             INST(6U, Opcode::And).i32().Inputs(1U, 2U);
5133             INST(7U, Opcode::And).i32().Inputs(1U, 3U);
5134             INST(8U, Opcode::And).i32().Inputs(1U, 4U);
5135             INST(9U, Opcode::And).i32().Inputs(1U, 5U);
5136 
5137             INST(10U, Opcode::Store).i32().Inputs(0U, 1U, 1U);
5138             INST(11U, Opcode::Store).i32().Inputs(0U, 1U, 7U);
5139             INST(12U, Opcode::Store).i32().Inputs(0U, 1U, 8U);
5140             INST(13U, Opcode::Store).i32().Inputs(0U, 1U, 9U);
5141 
5142             INST(14U, Opcode::Store).u32().Inputs(0U, 1U, 1U);
5143             INST(15U, Opcode::Store).u32().Inputs(0U, 1U, 7U);
5144             INST(16U, Opcode::Store).u32().Inputs(0U, 1U, 8U);
5145             INST(17U, Opcode::Store).u32().Inputs(0U, 1U, 9U);
5146 
5147             INST(18U, Opcode::Store).i16().Inputs(0U, 1U, 1U);
5148             INST(19U, Opcode::Store).i16().Inputs(0U, 1U, 1U);
5149             INST(20U, Opcode::Store).i16().Inputs(0U, 1U, 8U);
5150             INST(21U, Opcode::Store).i16().Inputs(0U, 1U, 9U);
5151 
5152             INST(22U, Opcode::Store).u16().Inputs(0U, 1U, 1U);
5153             INST(23U, Opcode::Store).u16().Inputs(0U, 1U, 1U);
5154             INST(24U, Opcode::Store).u16().Inputs(0U, 1U, 8U);
5155             INST(25U, Opcode::Store).u16().Inputs(0U, 1U, 9U);
5156 
5157             INST(26U, Opcode::Store).i8().Inputs(0U, 1U, 1U);
5158             INST(27U, Opcode::Store).i8().Inputs(0U, 1U, 1U);
5159             INST(28U, Opcode::Store).i8().Inputs(0U, 1U, 1U);
5160             INST(29U, Opcode::Store).i8().Inputs(0U, 1U, 9U);
5161 
5162             INST(30U, Opcode::Store).u8().Inputs(0U, 1U, 1U);
5163             INST(31U, Opcode::Store).u8().Inputs(0U, 1U, 1U);
5164             INST(32U, Opcode::Store).u8().Inputs(0U, 1U, 1U);
5165             INST(33U, Opcode::Store).u8().Inputs(0U, 1U, 9U);
5166 
5167             INST(34U, Opcode::ReturnVoid).v0id();
5168         }
5169     }
5170 }
5171 
TEST_F(PeepholesTest,AndWithStore)5172 TEST_F(PeepholesTest, AndWithStore)
5173 {
5174     auto graph = CreateEmptyGraph();
5175     src_graph::AndWithStore::CREATE(graph);
5176     auto graphExpected = CreateEmptyGraph();
5177     out_graph::AndWithStore::CREATE(graphExpected);
5178     ASSERT_TRUE(graph->RunPass<Peepholes>());
5179     ASSERT_TRUE(GraphComparator().Compare(graph, graphExpected));
5180 }
5181 
SRC_GRAPH(CastWithStore,Graph * graph)5182 SRC_GRAPH(CastWithStore, Graph *graph)
5183 {
5184     GRAPH(graph)
5185     {
5186         PARAMETER(0U, 0U).ptr();
5187         PARAMETER(1U, 1U).i64();
5188         PARAMETER(2U, 2U).i32();
5189 
5190         BASIC_BLOCK(2U, -1L)
5191         {
5192             INST(6U, Opcode::Cast).i32().SrcType(DataType::INT64).Inputs(1U);
5193             INST(7U, Opcode::Cast).i16().SrcType(DataType::INT32).Inputs(2U);
5194             INST(8U, Opcode::Cast).i8().SrcType(DataType::INT32).Inputs(2U);
5195 
5196             INST(9U, Opcode::Store).i32().Inputs(0U, 1U, 6U);
5197             INST(10U, Opcode::Store).i32().Inputs(0U, 1U, 7U);
5198             INST(11U, Opcode::Store).i32().Inputs(0U, 1U, 8U);
5199 
5200             INST(12U, Opcode::Store).u32().Inputs(0U, 1U, 6U);
5201             INST(13U, Opcode::Store).u32().Inputs(0U, 1U, 7U);
5202             INST(14U, Opcode::Store).u32().Inputs(0U, 1U, 8U);
5203 
5204             INST(15U, Opcode::Store).i16().Inputs(0U, 1U, 6U);
5205             INST(16U, Opcode::Store).i16().Inputs(0U, 1U, 7U);
5206             INST(17U, Opcode::Store).i16().Inputs(0U, 1U, 8U);
5207 
5208             INST(18U, Opcode::Store).u16().Inputs(0U, 1U, 6U);
5209             INST(19U, Opcode::Store).u16().Inputs(0U, 1U, 7U);
5210             INST(20U, Opcode::Store).u16().Inputs(0U, 1U, 8U);
5211 
5212             INST(21U, Opcode::Store).i8().Inputs(0U, 1U, 6U);
5213             INST(22U, Opcode::Store).i8().Inputs(0U, 1U, 7U);
5214             INST(23U, Opcode::Store).i8().Inputs(0U, 1U, 8U);
5215 
5216             INST(24U, Opcode::Store).u8().Inputs(0U, 1U, 6U);
5217             INST(25U, Opcode::Store).u8().Inputs(0U, 1U, 7U);
5218             INST(26U, Opcode::Store).u8().Inputs(0U, 1U, 8U);
5219 
5220             INST(27U, Opcode::ReturnVoid).v0id();
5221         }
5222     }
5223 }
5224 
OUT_GRAPH(CastWithStore,Graph * graph)5225 OUT_GRAPH(CastWithStore, Graph *graph)
5226 {
5227     GRAPH(graph)
5228     {
5229         PARAMETER(0U, 0U).ptr();
5230         PARAMETER(1U, 1U).i64();
5231         PARAMETER(2U, 2U).i32();
5232 
5233         BASIC_BLOCK(2U, -1L)
5234         {
5235             INST(6U, Opcode::Cast).i32().SrcType(DataType::INT64).Inputs(1U);
5236             INST(7U, Opcode::Cast).i16().SrcType(DataType::INT32).Inputs(2U);
5237             INST(8U, Opcode::Cast).i8().SrcType(DataType::INT32).Inputs(2U);
5238 
5239             INST(9U, Opcode::Store).i32().Inputs(0U, 1U, 1U);
5240             INST(10U, Opcode::Store).i32().Inputs(0U, 1U, 7U);
5241             INST(11U, Opcode::Store).i32().Inputs(0U, 1U, 8U);
5242 
5243             INST(12U, Opcode::Store).u32().Inputs(0U, 1U, 1U);
5244             INST(13U, Opcode::Store).u32().Inputs(0U, 1U, 7U);
5245             INST(14U, Opcode::Store).u32().Inputs(0U, 1U, 8U);
5246 
5247             INST(15U, Opcode::Store).i16().Inputs(0U, 1U, 1U);
5248             INST(16U, Opcode::Store).i16().Inputs(0U, 1U, 2U);
5249             INST(17U, Opcode::Store).i16().Inputs(0U, 1U, 8U);
5250 
5251             INST(18U, Opcode::Store).u16().Inputs(0U, 1U, 1U);
5252             INST(19U, Opcode::Store).u16().Inputs(0U, 1U, 2U);
5253             INST(20U, Opcode::Store).u16().Inputs(0U, 1U, 8U);
5254 
5255             INST(21U, Opcode::Store).i8().Inputs(0U, 1U, 1U);
5256             INST(22U, Opcode::Store).i8().Inputs(0U, 1U, 2U);
5257             INST(23U, Opcode::Store).i8().Inputs(0U, 1U, 2U);
5258 
5259             INST(24U, Opcode::Store).u8().Inputs(0U, 1U, 1U);
5260             INST(25U, Opcode::Store).u8().Inputs(0U, 1U, 2U);
5261             INST(26U, Opcode::Store).u8().Inputs(0U, 1U, 2U);
5262 
5263             INST(27U, Opcode::ReturnVoid).v0id();
5264         }
5265     }
5266 }
5267 
TEST_F(PeepholesTest,CastWithStore)5268 TEST_F(PeepholesTest, CastWithStore)
5269 {
5270     auto graph = CreateEmptyGraph();
5271     src_graph::CastWithStore::CREATE(graph);
5272     auto graphExpected = CreateEmptyGraph();
5273     out_graph::CastWithStore::CREATE(graphExpected);
5274     ASSERT_TRUE(graph->RunPass<Peepholes>());
5275     ASSERT_TRUE(GraphComparator().Compare(graph, graphExpected));
5276 }
5277 
TEST_F(PeepholesTest,CastWithStoreSignMismatch)5278 TEST_F(PeepholesTest, CastWithStoreSignMismatch)
5279 {
5280     auto graph = CreateEmptyGraph();
5281     GRAPH(graph)
5282     {
5283         PARAMETER(0U, 0U).ptr();
5284         PARAMETER(1U, 1U).i64();
5285         PARAMETER(2U, 2U).u8();
5286 
5287         BASIC_BLOCK(2U, -1L)
5288         {
5289             INST(3U, Opcode::Cast).i32().SrcType(DataType::INT8).Inputs(2U);
5290             INST(4U, Opcode::Store).i32().Inputs(0U, 1U, 3U);
5291             INST(5U, Opcode::ReturnVoid).v0id();
5292         }
5293     }
5294 #ifndef NDEBUG
5295     ASSERT_DEATH(graph->RunPass<Peepholes>(), "");
5296 #else
5297     ASSERT_FALSE(graph->RunPass<Peepholes>());
5298 #endif
5299 }
5300 
TEST_F(PeepholesTest,CastWithStoreTypeMismatch)5301 TEST_F(PeepholesTest, CastWithStoreTypeMismatch)
5302 {
5303     auto graph = CreateEmptyGraph();
5304     GRAPH(graph)
5305     {
5306         PARAMETER(0U, 0U).ptr();
5307         PARAMETER(1U, 1U).i64();
5308         PARAMETER(2U, 2U).i16();
5309 
5310         BASIC_BLOCK(2U, -1L)
5311         {
5312             INST(3U, Opcode::Cast).i32().SrcType(DataType::INT8).Inputs(2U);
5313             INST(4U, Opcode::Store).i32().Inputs(0U, 1U, 3U);
5314             INST(5U, Opcode::ReturnVoid).v0id();
5315         }
5316     }
5317 #ifndef NDEBUG
5318     ASSERT_DEATH(graph->RunPass<Peepholes>(), "");
5319 #else
5320     ASSERT_FALSE(graph->RunPass<Peepholes>());
5321 #endif
5322 }
5323 
TEST_F(PeepholesTest,CastI64ToU16)5324 TEST_F(PeepholesTest, CastI64ToU16)
5325 {
5326     auto graph = CreateEmptyGraph();
5327     GRAPH(graph)
5328     {
5329         PARAMETER(0U, 0U).i64();
5330         CONSTANT(2U, 0xFFFFU);
5331 
5332         BASIC_BLOCK(2U, -1L)
5333         {
5334             INST(3U, Opcode::Cast).i32().SrcType(DataType::INT64).Inputs(0U);
5335             INST(4U, Opcode::And).i32().Inputs(3U, 2U);
5336             INST(5U, Opcode::Return).i32().Inputs(4U);
5337         }
5338     }
5339 
5340     auto graphExpected = CreateEmptyGraph();
5341     GRAPH(graphExpected)
5342     {
5343         PARAMETER(0U, 0U).i64();
5344 
5345         BASIC_BLOCK(2U, -1L)
5346         {
5347             INST(6U, Opcode::Cast).u16().SrcType(DataType::INT64).Inputs(0U);
5348             INST(5U, Opcode::Return).i32().Inputs(6U);
5349         }
5350     }
5351     ASSERT_TRUE(graph->RunPass<Peepholes>());
5352     graph->RunPass<Cleanup>();
5353     ASSERT_TRUE(GraphComparator().Compare(graph, graphExpected));
5354 }
5355 
TEST_F(PeepholesTest,CastI8ToU16)5356 TEST_F(PeepholesTest, CastI8ToU16)
5357 {
5358     auto graph = CreateEmptyGraph();
5359     GRAPH(graph)
5360     {
5361         PARAMETER(0U, 0U).i8();
5362         CONSTANT(2U, 0xFFFFU);
5363 
5364         BASIC_BLOCK(2U, -1L)
5365         {
5366             INST(3U, Opcode::Cast).i32().SrcType(DataType::INT8).Inputs(0U);
5367             INST(4U, Opcode::And).i32().Inputs(3U, 2U);
5368             INST(5U, Opcode::Return).i32().Inputs(4U);
5369         }
5370     }
5371 
5372     auto graphExpected = CreateEmptyGraph();
5373     GRAPH(graphExpected)
5374     {
5375         PARAMETER(0U, 0U).i8();
5376 
5377         BASIC_BLOCK(2U, -1L)
5378         {
5379             INST(6U, Opcode::Cast).u16().SrcType(DataType::INT8).Inputs(0U);
5380             INST(5U, Opcode::Return).i32().Inputs(6U);
5381         }
5382     }
5383     ASSERT_TRUE(graph->RunPass<Peepholes>());
5384     graph->RunPass<Cleanup>();
5385     ASSERT_TRUE(GraphComparator().Compare(graph, graphExpected));
5386 }
5387 
TEST_F(PeepholesTest,CastI64ToB)5388 TEST_F(PeepholesTest, CastI64ToB)
5389 {
5390     auto graph = CreateEmptyGraph();
5391     GRAPH(graph)
5392     {
5393         PARAMETER(0U, 0U).i64();
5394 
5395         BASIC_BLOCK(2U, -1L)
5396         {
5397             INST(1U, Opcode::Cast).i32().SrcType(DataType::INT64).Inputs(0U);
5398             INST(2U, Opcode::Cast).b().SrcType(DataType::INT32).Inputs(1U);
5399             INST(3U, Opcode::Return).b().Inputs(2U);
5400         }
5401     }
5402 
5403     auto graphExpected = CreateEmptyGraph();
5404     GRAPH(graphExpected)
5405     {
5406         PARAMETER(0U, 0U).i64();
5407 
5408         BASIC_BLOCK(2U, -1L)
5409         {
5410             INST(2U, Opcode::Cast).b().SrcType(DataType::INT64).Inputs(0U);
5411             INST(3U, Opcode::Return).b().Inputs(2U);
5412         }
5413     }
5414     ASSERT_TRUE(graph->RunPass<Peepholes>());
5415     graph->RunPass<Cleanup>();
5416     ASSERT_TRUE(GraphComparator().Compare(graph, graphExpected));
5417 }
5418 
TEST_F(PeepholesTest,CastI64ToBSignMismatch)5419 TEST_F(PeepholesTest, CastI64ToBSignMismatch)
5420 {
5421     auto graph = CreateEmptyGraph();
5422     GRAPH(graph)
5423     {
5424         PARAMETER(0U, 0U).i64();
5425 
5426         BASIC_BLOCK(2U, -1L)
5427         {
5428             INST(1U, Opcode::Cast).i32().SrcType(DataType::INT64).Inputs(0U);
5429             INST(2U, Opcode::Cast).b().SrcType(DataType::UINT32).Inputs(1U);
5430             INST(3U, Opcode::Return).b().Inputs(2U);
5431         }
5432     }
5433 
5434 #ifndef NDEBUG
5435     ASSERT_DEATH(graph->RunPass<Peepholes>(), "");
5436 #else
5437     ASSERT_FALSE(graph->RunPass<Peepholes>());
5438 #endif
5439 }
5440 
TEST_F(PeepholesTest,CastI64ToBTypeMismatch)5441 TEST_F(PeepholesTest, CastI64ToBTypeMismatch)
5442 {
5443     auto graph = CreateEmptyGraph();
5444     GRAPH(graph)
5445     {
5446         PARAMETER(0U, 0U).i64();
5447 
5448         BASIC_BLOCK(2U, -1L)
5449         {
5450             INST(1U, Opcode::Cast).i32().SrcType(DataType::INT64).Inputs(0U);
5451             INST(2U, Opcode::Cast).b().SrcType(DataType::INT16).Inputs(1U);
5452             INST(3U, Opcode::Return).b().Inputs(2U);
5453         }
5454     }
5455 
5456 #ifndef NDEBUG
5457     ASSERT_DEATH(graph->RunPass<Peepholes>(), "");
5458 #else
5459     ASSERT_FALSE(graph->RunPass<Peepholes>());
5460 #endif
5461 }
5462 
TEST_F(PeepholesTest,ConstCombineAdd)5463 TEST_F(PeepholesTest, ConstCombineAdd)
5464 {
5465     auto graph1 = CreateEmptyGraph();
5466     GRAPH(graph1)
5467     {
5468         PARAMETER(0U, 0U).i64();
5469         CONSTANT(1U, 3U);
5470         CONSTANT(2U, 7U);
5471         BASIC_BLOCK(2U, 1U)
5472         {
5473             INST(3U, Opcode::Add).s64().Inputs(0U, 1U);
5474             INST(4U, Opcode::Add).s64().Inputs(3U, 2U);
5475             INST(5U, Opcode::Return).s64().Inputs(4U);
5476         }
5477     }
5478     auto graph2 = CreateEmptyGraph();
5479     GRAPH(graph2)
5480     {
5481         PARAMETER(0U, 0U).i64();
5482         CONSTANT(6U, 10U);
5483         BASIC_BLOCK(2U, 1U)
5484         {
5485             INST(4U, Opcode::Add).s64().Inputs(0U, 6U);
5486             INST(5U, Opcode::Return).s64().Inputs(4U);
5487         }
5488     }
5489     ASSERT_TRUE(graph1->RunPass<Peepholes>());
5490     graph1->RunPass<Cleanup>();
5491     ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
5492 }
5493 
TEST_F(PeepholesTest,ConstCombineAddSub)5494 TEST_F(PeepholesTest, ConstCombineAddSub)
5495 {
5496     auto graph1 = CreateEmptyGraph();
5497     GRAPH(graph1)
5498     {
5499         PARAMETER(0U, 0U).i64();
5500         CONSTANT(1U, 3U);
5501         CONSTANT(2U, 7U);
5502         BASIC_BLOCK(2U, 1U)
5503         {
5504             INST(3U, Opcode::Sub).s64().Inputs(0U, 1U);
5505             INST(4U, Opcode::Add).s64().Inputs(3U, 2U);
5506             INST(5U, Opcode::Return).s64().Inputs(4U);
5507         }
5508     }
5509     auto graph2 = CreateEmptyGraph();
5510     GRAPH(graph2)
5511     {
5512         PARAMETER(0U, 0U).i64();
5513         CONSTANT(6U, 4U);
5514         BASIC_BLOCK(2U, 1U)
5515         {
5516             INST(4U, Opcode::Add).s64().Inputs(0U, 6U);
5517             INST(5U, Opcode::Return).s64().Inputs(4U);
5518         }
5519     }
5520     ASSERT_TRUE(graph1->RunPass<Peepholes>());
5521     graph1->RunPass<Cleanup>();
5522     ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
5523 }
5524 
TEST_F(PeepholesTest,ConstCombineSubAdd)5525 TEST_F(PeepholesTest, ConstCombineSubAdd)
5526 {
5527     auto graph1 = CreateEmptyGraph();
5528     GRAPH(graph1)
5529     {
5530         PARAMETER(0U, 0U).i64();
5531         CONSTANT(1U, 3U);
5532         CONSTANT(2U, 7U);
5533         BASIC_BLOCK(2U, 1U)
5534         {
5535             INST(3U, Opcode::Add).s64().Inputs(0U, 1U);
5536             INST(4U, Opcode::Sub).s64().Inputs(3U, 2U);
5537             INST(5U, Opcode::Return).s64().Inputs(4U);
5538         }
5539     }
5540     auto graph2 = CreateEmptyGraph();
5541     GRAPH(graph2)
5542     {
5543         PARAMETER(0U, 0U).i64();
5544         CONSTANT(6U, 4U);
5545         BASIC_BLOCK(2U, 1U)
5546         {
5547             INST(4U, Opcode::Sub).s64().Inputs(0U, 6U);
5548             INST(5U, Opcode::Return).s64().Inputs(4U);
5549         }
5550     }
5551     ASSERT_TRUE(graph1->RunPass<Peepholes>());
5552     graph1->RunPass<Cleanup>();
5553     ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
5554 }
5555 
TEST_F(PeepholesTest,ConstCombineShift)5556 TEST_F(PeepholesTest, ConstCombineShift)
5557 {
5558     for (auto opcode : {Opcode::Shr, Opcode::Shl, Opcode::AShr}) {
5559         for (auto shift : {7U, 71U}) {
5560             auto graph1 = CreateEmptyGraph();
5561             GRAPH(graph1)
5562             {
5563                 PARAMETER(0U, 0U).i64();
5564                 CONSTANT(1U, 3U);
5565                 CONSTANT(2U, shift);
5566                 BASIC_BLOCK(2U, 1U)
5567                 {
5568                     INST(3U, opcode).s64().Inputs(0U, 1U);
5569                     INST(4U, opcode).s64().Inputs(3U, 2U);
5570                     INST(5U, Opcode::Return).s64().Inputs(4U);
5571                 }
5572             }
5573             auto graph2 = CreateEmptyGraph();
5574             GRAPH(graph2)
5575             {
5576                 PARAMETER(0U, 0U).i64();
5577                 CONSTANT(6U, 10U);
5578                 BASIC_BLOCK(2U, 1U)
5579                 {
5580                     INST(4U, opcode).s64().Inputs(0U, 6U);
5581                     INST(5U, Opcode::Return).s64().Inputs(4U);
5582                 }
5583             }
5584             ASSERT_TRUE(graph1->RunPass<Peepholes>());
5585             graph1->RunPass<Cleanup>();
5586             ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
5587         }
5588     }
5589 }
5590 
TEST_F(PeepholesTest,ConstCombineShiftAlwaysZero)5591 TEST_F(PeepholesTest, ConstCombineShiftAlwaysZero)
5592 {
5593     for (auto opcode : {Opcode::Shr, Opcode::Shl}) {
5594         auto graph1 = CreateEmptyGraph();
5595         GRAPH(graph1)
5596         {
5597             PARAMETER(0U, 0U).i64();
5598             CONSTANT(1U, 31U);
5599             CONSTANT(2U, 33U);
5600             BASIC_BLOCK(2U, 1U)
5601             {
5602                 INST(3U, opcode).s64().Inputs(0U, 1U);
5603                 INST(4U, opcode).s64().Inputs(3U, 2U);
5604                 INST(5U, Opcode::Return).s64().Inputs(4U);
5605             }
5606         }
5607         auto graph2 = CreateEmptyGraph();
5608         GRAPH(graph2)
5609         {
5610             CONSTANT(6U, 0U);
5611             BASIC_BLOCK(2U, 1U)
5612             {
5613                 INST(5U, Opcode::Return).s64().Inputs(6U);
5614             }
5615         }
5616         ASSERT_TRUE(graph1->RunPass<Peepholes>());
5617         graph1->RunPass<Cleanup>();
5618         ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
5619     }
5620 }
5621 
TEST_F(PeepholesTest,ConstCombineAShrMax)5622 TEST_F(PeepholesTest, ConstCombineAShrMax)
5623 {
5624     auto graph1 = CreateEmptyGraph();
5625     GRAPH(graph1)
5626     {
5627         PARAMETER(0U, 0U).i64();
5628         CONSTANT(1U, 31U);
5629         CONSTANT(2U, 33U);
5630         BASIC_BLOCK(2U, 1U)
5631         {
5632             INST(3U, Opcode::AShr).s64().Inputs(0U, 1U);
5633             INST(4U, Opcode::AShr).s64().Inputs(3U, 2U);
5634             INST(5U, Opcode::Return).s64().Inputs(4U);
5635         }
5636     }
5637     auto graph2 = CreateEmptyGraph();
5638     GRAPH(graph2)
5639     {
5640         PARAMETER(0U, 0U).i64();
5641         CONSTANT(6U, 63U);
5642         BASIC_BLOCK(2U, 1U)
5643         {
5644             INST(4U, Opcode::AShr).s64().Inputs(0U, 6U);
5645             INST(5U, Opcode::Return).s64().Inputs(4U);
5646         }
5647     }
5648     ASSERT_TRUE(graph1->RunPass<Peepholes>());
5649     graph1->RunPass<Cleanup>();
5650     ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
5651 }
5652 
TEST_F(PeepholesTest,ConstCombineMul)5653 TEST_F(PeepholesTest, ConstCombineMul)
5654 {
5655     auto graph1 = CreateEmptyGraph();
5656     GRAPH(graph1)
5657     {
5658         PARAMETER(0U, 0U).i64();
5659         CONSTANT(1U, 3U);
5660         CONSTANT(2U, 7U);
5661         BASIC_BLOCK(2U, 1U)
5662         {
5663             INST(3U, Opcode::Mul).s64().Inputs(0U, 1U);
5664             INST(4U, Opcode::Mul).s64().Inputs(3U, 2U);
5665             INST(5U, Opcode::Return).s64().Inputs(4U);
5666         }
5667     }
5668     auto graph2 = CreateEmptyGraph();
5669     GRAPH(graph2)
5670     {
5671         PARAMETER(0U, 0U).i64();
5672         CONSTANT(6U, 21U);
5673         BASIC_BLOCK(2U, 1U)
5674         {
5675             INST(4U, Opcode::Mul).s64().Inputs(0U, 6U);
5676             INST(5U, Opcode::Return).s64().Inputs(4U);
5677         }
5678     }
5679     ASSERT_TRUE(graph1->RunPass<Peepholes>());
5680     graph1->RunPass<Cleanup>();
5681     ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
5682 }
5683 
SRC_GRAPH(ConditionalAssignment,Graph * graph,bool inverse)5684 SRC_GRAPH(ConditionalAssignment, Graph *graph, bool inverse)
5685 {
5686     GRAPH(graph)
5687     {
5688         PARAMETER(0U, 0U).b();
5689         CONSTANT(2U, 0x0U).s64();
5690         CONSTANT(4U, 0x1U).s32();
5691         CONSTANT(5U, 0x0U).s32();
5692 
5693         BASIC_BLOCK(2U, 3U, 4U)
5694         {
5695             INST(1U, Opcode::Compare).b().SrcType(DataType::BOOL).CC(CC_NE).Inputs(0U, 2U);
5696             INST(3U, Opcode::IfImm).SrcType(compiler::DataType::BOOL).CC(inverse ? CC_NE : CC_EQ).Imm(0U).Inputs(1U);
5697         }
5698 
5699         BASIC_BLOCK(4U, 3U) {}
5700 
5701         BASIC_BLOCK(3U, -1L)
5702         {
5703             INST(6U, Opcode::Phi).b().Inputs(5U, 4U);
5704             INST(7U, Opcode::Return).b().Inputs(6U);
5705         }
5706     }
5707 }
5708 
OUT_GRAPH(ConditionalAssignment,Graph * graph)5709 OUT_GRAPH(ConditionalAssignment, Graph *graph)
5710 {
5711     GRAPH(graph)
5712     {
5713         PARAMETER(0U, 0U).b();
5714 
5715         BASIC_BLOCK(2U, -1L)
5716         {
5717             INST(7U, Opcode::Return).b().Inputs(0U);
5718         }
5719     }
5720 }
5721 
OUT_GRAPH(ConditionalAssignmentInverse,Graph * graph)5722 OUT_GRAPH(ConditionalAssignmentInverse, Graph *graph)
5723 {
5724     GRAPH(graph)
5725     {
5726         PARAMETER(0U, 0U).b();
5727 
5728         BASIC_BLOCK(2U, -1L)
5729         {
5730             INST(10U, Opcode::XorI).b().Inputs(0U).Imm(1U);
5731             INST(7U, Opcode::Return).b().Inputs(10U);
5732         }
5733     }
5734 }
5735 
TEST_F(PeepholesTest,ConditionalAssignment)5736 TEST_F(PeepholesTest, ConditionalAssignment)
5737 {
5738     for (auto inverse : {true, false}) {
5739         auto graph = CreateEmptyBytecodeGraph();
5740         src_graph::ConditionalAssignment::CREATE(graph, inverse);
5741 
5742 #ifndef NDEBUG
5743         graph->SetLowLevelInstructionsEnabled();
5744 #endif
5745 
5746         EXPECT_TRUE(graph->RunPass<Peepholes>());
5747         EXPECT_TRUE(graph->RunPass<Cleanup>());
5748         EXPECT_TRUE(graph->RunPass<Lowering>());
5749         graph->RunPass<Cleanup>();
5750 
5751         auto expected = CreateEmptyBytecodeGraph();
5752         if (inverse) {
5753             out_graph::ConditionalAssignmentInverse::CREATE(expected);
5754         } else {
5755             out_graph::ConditionalAssignment::CREATE(expected);
5756         }
5757         EXPECT_TRUE(GraphComparator().Compare(graph, expected));
5758     }
5759 }
5760 
SRC_GRAPH(ConditionalAssignmentPreserveIf,Graph * graph,bool inverse)5761 SRC_GRAPH(ConditionalAssignmentPreserveIf, Graph *graph, bool inverse)
5762 {
5763     GRAPH(graph)
5764     {
5765         PARAMETER(0U, 0U).u64();
5766         CONSTANT(4U, 1U);
5767         CONSTANT(5U, 0U);
5768 
5769         BASIC_BLOCK(2U, 3U, 4U)
5770         {
5771             INST(1U, Opcode::Compare).b().SrcType(DataType::UINT64).CC(CC_GT).Inputs(0U, 4U);
5772             INST(3U, Opcode::IfImm).SrcType(compiler::DataType::BOOL).CC(inverse ? CC_NE : CC_EQ).Imm(0U).Inputs(1U);
5773         }
5774 
5775         BASIC_BLOCK(4U, 3U)
5776         {
5777             INST(8U, Opcode::SaveState).NoVregs();
5778             INST(9U, Opcode::CallStatic).u64().InputsAutoType(8U);
5779         }
5780 
5781         BASIC_BLOCK(3U, -1L)
5782         {
5783             INST(6U, Opcode::Phi).b().Inputs(5U, 4U);
5784             INST(7U, Opcode::Return).b().Inputs(6U);
5785         }
5786     }
5787 }
5788 
OUT_GRAPH(ConditionalAssignmentPreserveIf,Graph * expected,bool inverse)5789 OUT_GRAPH(ConditionalAssignmentPreserveIf, Graph *expected, bool inverse)
5790 {
5791     GRAPH(expected)
5792     {
5793         PARAMETER(0U, 0U).u64();
5794         CONSTANT(4U, 1U);
5795         if (inverse) {
5796             CONSTANT(5U, 0U);
5797         }
5798 
5799         BASIC_BLOCK(2U, 3U, 4U)
5800         {
5801             INST(1U, Opcode::Compare).b().SrcType(DataType::UINT64).CC(CC_GT).Inputs(0U, 4U);
5802             INST(3U, Opcode::IfImm).SrcType(compiler::DataType::BOOL).CC(inverse ? CC_NE : CC_EQ).Imm(0U).Inputs(1U);
5803         }
5804 
5805         BASIC_BLOCK(4U, 3U)
5806         {
5807             INST(8U, Opcode::SaveState).NoVregs();
5808             INST(9U, Opcode::CallStatic).u64().InputsAutoType(8U);
5809         }
5810 
5811         BASIC_BLOCK(3U, -1L)
5812         {
5813             if (inverse) {
5814                 INST(11U, Opcode::Compare).b().CC(ConditionCode::CC_EQ).SetType(DataType::BOOL).Inputs(1U, 5U);
5815                 INST(7U, Opcode::Return).b().Inputs(11U);
5816             } else {
5817                 INST(7U, Opcode::Return).b().Inputs(1U);
5818             }
5819         }
5820     }
5821 }
5822 
TEST_F(PeepholesTest,ConditionalAssignmentPreserveIf)5823 TEST_F(PeepholesTest, ConditionalAssignmentPreserveIf)
5824 {
5825     for (auto inverse : {true, false}) {
5826         auto graph = CreateEmptyGraph();
5827         src_graph::ConditionalAssignmentPreserveIf::CREATE(graph, inverse);
5828 
5829         ASSERT_TRUE(graph->RunPass<Peepholes>());
5830         ASSERT_TRUE(graph->RunPass<Cleanup>());
5831 
5832         auto expected = CreateEmptyGraph();
5833         out_graph::ConditionalAssignmentPreserveIf::CREATE(expected, inverse);
5834 
5835         EXPECT_TRUE(GraphComparator().Compare(graph, expected));
5836     }
5837 }
5838 
TEST_F(PeepholesTest,ConditionalAssignmentBytecodeCompare)5839 TEST_F(PeepholesTest, ConditionalAssignmentBytecodeCompare)
5840 {
5841     // In case of bytecode optimizer we can not generate Compare instruction,
5842     // the optimization isn't applied
5843     auto graph = CreateEmptyBytecodeGraph();
5844     GRAPH(graph)
5845     {
5846         PARAMETER(0U, 0U).s32();
5847         CONSTANT(1U, 0x0U).s32();
5848         CONSTANT(2U, 0x1U).s32();
5849 
5850         BASIC_BLOCK(2U, 3U, 4U)
5851         {
5852             INST(3U, Opcode::Compare).b().SrcType(DataType::INT32).CC(CC_GT).Inputs(0U, 2U);
5853             INST(4U, Opcode::IfImm).SrcType(compiler::DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
5854         }
5855 
5856         BASIC_BLOCK(4U, 3U) {}
5857 
5858         BASIC_BLOCK(3U, -1L)
5859         {
5860             INST(5U, Opcode::Phi).b().Inputs(1U, 2U);
5861             INST(6U, Opcode::Return).b().Inputs(5U);
5862         }
5863     }
5864 
5865     ASSERT_FALSE(graph->RunPass<Peepholes>());
5866 }
5867 
TEST_F(PeepholesTest,ConditionalAssignmentWrongConstants)5868 TEST_F(PeepholesTest, ConditionalAssignmentWrongConstants)
5869 {
5870     // Constants are the same or not equal to 0 and 1
5871     for (auto constant : {0U, 2U}) {
5872         auto graph = CreateEmptyGraph();
5873         GRAPH(graph)
5874         {
5875             PARAMETER(0U, 0U).s32();
5876             CONSTANT(1U, 0U).s32();
5877             CONSTANT(2U, constant).s32();
5878 
5879             BASIC_BLOCK(2U, 3U, 4U)
5880             {
5881                 INST(3U, Opcode::Compare).b().SrcType(DataType::INT32).CC(CC_GT).Inputs(0U, 2U);
5882                 INST(4U, Opcode::IfImm).SrcType(compiler::DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
5883             }
5884 
5885             BASIC_BLOCK(4U, 3U) {}
5886 
5887             BASIC_BLOCK(3U, -1L)
5888             {
5889                 INST(5U, Opcode::Phi).b().Inputs(1U, 2U);
5890                 INST(6U, Opcode::Return).b().Inputs(5U);
5891             }
5892         }
5893 
5894         EXPECT_FALSE(graph->RunPass<Peepholes>());
5895     }
5896 }
5897 
SRC_GRAPH(ConditionalAssignmentsTwoBranches,Graph * graph,bool inverse)5898 SRC_GRAPH(ConditionalAssignmentsTwoBranches, Graph *graph, bool inverse)
5899 {
5900     GRAPH(graph)
5901     {
5902         PARAMETER(0U, 0U).b();
5903         CONSTANT(2U, 0x0U).s64();
5904         CONSTANT(4U, 0x1U).s32();
5905         CONSTANT(5U, 0x0U).s32();
5906 
5907         BASIC_BLOCK(2U, 4U, 5U)
5908         {
5909             INST(1U, Opcode::Compare).b().SrcType(DataType::BOOL).CC(CC_NE).Inputs(0U, 2U);
5910             INST(3U, Opcode::IfImm).SrcType(compiler::DataType::BOOL).CC(inverse ? CC_NE : CC_EQ).Imm(0U).Inputs(1U);
5911         }
5912 
5913         BASIC_BLOCK(4U, 6U) {}
5914         BASIC_BLOCK(6U, 3U) {}
5915 
5916         BASIC_BLOCK(5U, 3U) {}
5917 
5918         BASIC_BLOCK(3U, -1L)
5919         {
5920             INST(6U, Opcode::Phi).b().Inputs(4U, 5U);
5921             INST(7U, Opcode::Return).b().Inputs(6U);
5922         }
5923     }
5924 }
5925 
TEST_F(PeepholesTest,ConditionalAssignmentsTwoBranches)5926 TEST_F(PeepholesTest, ConditionalAssignmentsTwoBranches)
5927 {
5928     for (auto inverse : {true, false}) {
5929         auto graph = CreateEmptyBytecodeGraph();
5930         src_graph::ConditionalAssignmentsTwoBranches::CREATE(graph, inverse);
5931 
5932 #ifndef NDEBUG
5933         graph->SetLowLevelInstructionsEnabled();
5934 #endif
5935 
5936         EXPECT_TRUE(graph->RunPass<Peepholes>());
5937         EXPECT_TRUE(graph->RunPass<Cleanup>());
5938         EXPECT_TRUE(graph->RunPass<Lowering>());
5939         graph->RunPass<Cleanup>();
5940 
5941         auto expected = CreateEmptyBytecodeGraph();
5942         if (!inverse) {
5943             GRAPH(expected)
5944             {
5945                 PARAMETER(0U, 0U).b();
5946 
5947                 BASIC_BLOCK(2U, -1L)
5948                 {
5949                     INST(10U, Opcode::XorI).b().Inputs(0U).Imm(1U);
5950                     INST(7U, Opcode::Return).b().Inputs(10U);
5951                 }
5952             }
5953         } else {
5954             GRAPH(expected)
5955             {
5956                 PARAMETER(0U, 0U).b();
5957 
5958                 BASIC_BLOCK(2U, -1L)
5959                 {
5960                     INST(7U, Opcode::Return).b().Inputs(0U);
5961                 }
5962             }
5963         }
5964         EXPECT_TRUE(GraphComparator().Compare(graph, expected));
5965     }
5966 }
5967 
5968 /* We cannot replace Phi because its value may come from both branches of If
5969  *   [entry]
5970  *      |
5971  *      v
5972  *     [2]--->[4]
5973  *      |      |
5974  *      v      v
5975  *     [3]--->[5]
5976  *      |      |
5977  *      v      |
5978  *     [6]<----/
5979  *      |
5980  *      v
5981  *    [exit]
5982  */
TEST_F(PeepholesTest,ConditionalAssignmentMixedBranches)5983 TEST_F(PeepholesTest, ConditionalAssignmentMixedBranches)
5984 {
5985     GRAPH(GetGraph())
5986     {
5987         PARAMETER(0U, 0U).u64();
5988         CONSTANT(1U, 0U);
5989         CONSTANT(2U, 1U);
5990 
5991         BASIC_BLOCK(2U, 3U, 4U)
5992         {
5993             INST(4U, Opcode::Compare).b().SrcType(DataType::UINT64).CC(CC_NE).Inputs(0U, 1U);
5994             INST(5U, Opcode::IfImm).SrcType(compiler::DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(4U);
5995         }
5996 
5997         BASIC_BLOCK(3U, 5U, 6U)
5998         {
5999             INST(6U, Opcode::Compare).b().SrcType(DataType::UINT64).CC(CC_NE).Inputs(0U, 2U);
6000             INST(7U, Opcode::IfImm).SrcType(compiler::DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(1U);
6001         }
6002 
6003         BASIC_BLOCK(4U, 5U) {}
6004 
6005         BASIC_BLOCK(5U, 6U) {}
6006 
6007         BASIC_BLOCK(6U, -1L)
6008         {
6009             INST(8U, Opcode::Phi).b().Inputs(1U, 2U);
6010             INST(9U, Opcode::Return).b().Inputs(8U);
6011         }
6012     }
6013     ASSERT_FALSE(GetGraph()->RunPass<Peepholes>());
6014 }
6015 
6016 /* We can go to true branch, to block 5, to block 4, and to block 5 again
6017  * So we need to check that block 3 has one predecessor
6018  *    [entry]
6019  *       |
6020  *       v F
6021  *      [2]-->[3]<--\
6022  *     T |     |    |
6023  *       |     v    |
6024  *       \--->[4]---/
6025  *             |
6026  *             v
6027  *            [5]
6028  *             |
6029  *             v
6030  *           [exit]
6031  */
TEST_F(PeepholesTest,ConditionalAssignmentLoopTriangle)6032 TEST_F(PeepholesTest, ConditionalAssignmentLoopTriangle)
6033 {
6034     for (auto inverse : {true, false}) {
6035         auto graph = CreateEmptyGraph();
6036         GRAPH(graph)
6037         {
6038             PARAMETER(0U, 0U).u64();
6039             PARAMETER(1U, 1U).u64();
6040             CONSTANT(2U, 0U);
6041             CONSTANT(3U, 1U);
6042 
6043             BASIC_BLOCK(2U, 4U, 3U)
6044             {
6045                 INST(4U, Opcode::Compare).b().SrcType(DataType::UINT64).CC(CC_NE).Inputs(0U, 2U);
6046                 INST(5U, Opcode::IfImm)
6047                     .SrcType(compiler::DataType::BOOL)
6048                     .CC(inverse ? CC_EQ : CC_NE)
6049                     .Imm(0U)
6050                     .Inputs(4U);
6051             }
6052 
6053             BASIC_BLOCK(3U, 4U) {}
6054 
6055             BASIC_BLOCK(4U, 5U, 3U)
6056             {
6057                 INST(6U, Opcode::Phi).b().Inputs(2U, 3U);
6058                 INST(7U, Opcode::Compare).b().SrcType(DataType::UINT64).CC(CC_LT).Inputs(1U, 3U);
6059                 INST(8U, Opcode::IfImm).SrcType(compiler::DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(7U);
6060             }
6061 
6062             BASIC_BLOCK(5U, -1L)
6063             {
6064                 INST(9U, Opcode::Return).b().Inputs(6U);
6065             }
6066         }
6067         EXPECT_FALSE(graph->RunPass<Peepholes>());
6068     }
6069 }
6070 
6071 /* We can go to true branch, to block 5, to block 4, and to block 5 again
6072  * So we need to check that block 3 has one predecessor
6073  *
6074  *       [entry]
6075  *          |
6076  *          v F
6077  *         [2]-->[3]<--\
6078  *        T |     |    |
6079  *          v     v    |
6080  *         [4]-->[5]---/
6081  *                |
6082  *                v
6083  *               [6]
6084  *                |
6085  *                v
6086  *              [exit]
6087  */
TEST_F(PeepholesTest,ConditionalAssignmentLoopDiamond)6088 TEST_F(PeepholesTest, ConditionalAssignmentLoopDiamond)
6089 {
6090     for (auto inverse : {true, false}) {
6091         auto graph = CreateEmptyGraph();
6092         GRAPH(graph)
6093         {
6094             PARAMETER(0U, 0U).u64();
6095             PARAMETER(1U, 1U).u64();
6096             CONSTANT(2U, 0U);
6097             CONSTANT(3U, 1U);
6098 
6099             BASIC_BLOCK(2U, 4U, 3U)
6100             {
6101                 INST(4U, Opcode::Compare).b().SrcType(DataType::UINT64).CC(CC_NE).Inputs(0U, 2U);
6102                 INST(5U, Opcode::IfImm)
6103                     .SrcType(compiler::DataType::BOOL)
6104                     .CC(inverse ? CC_EQ : CC_NE)
6105                     .Imm(0U)
6106                     .Inputs(4U);
6107             }
6108 
6109             BASIC_BLOCK(3U, 5U) {}
6110 
6111             BASIC_BLOCK(4U, 5U)
6112             {
6113                 INST(6U, Opcode::SaveState).NoVregs();
6114                 INST(7U, Opcode::CallStatic).u64().InputsAutoType(0U, 6U);
6115             }
6116 
6117             BASIC_BLOCK(5U, 6U, 3U)
6118             {
6119                 INST(8U, Opcode::Phi).b().Inputs(2U, 3U);
6120                 INST(9U, Opcode::Compare).b().SrcType(DataType::UINT64).CC(CC_LT).Inputs(1U, 3U);
6121                 INST(10U, Opcode::IfImm).SrcType(compiler::DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(9U);
6122             }
6123 
6124             BASIC_BLOCK(6U, -1L)
6125             {
6126                 INST(11U, Opcode::Return).b().Inputs(8U);
6127             }
6128         }
6129         EXPECT_FALSE(graph->RunPass<Peepholes>());
6130     }
6131 }
6132 
6133 /*
6134  *    [entry]
6135  *       |
6136  *       v
6137  *      [2]------\
6138  *       |       |
6139  *       |       v
6140  *       |  /---[3]---\
6141  *       |  |         |
6142  *       |  v         v
6143  *       | [4]       [5]
6144  *       |  |         |
6145  *       |  \-->[6]<--/
6146  *       |       |
6147  *       v       |
6148  *      [7]<-----/
6149  *       |
6150  *       v
6151  *     [exit]
6152  */
TEST_F(PeepholesTest,ConditionalAssignmentNestedIfs)6153 TEST_F(PeepholesTest, ConditionalAssignmentNestedIfs)
6154 {
6155     GRAPH(GetGraph())
6156     {
6157         PARAMETER(0U, 0U).s64();
6158         CONSTANT(1U, 0U);
6159         CONSTANT(2U, 1U);
6160 
6161         BASIC_BLOCK(2U, 7U, 3U)
6162         {
6163             INST(3U, Opcode::Compare).b().SrcType(DataType::INT64).CC(CC_LT).Inputs(0U, 1U);
6164             INST(4U, Opcode::IfImm).SrcType(compiler::DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
6165         }
6166 
6167         BASIC_BLOCK(3U, 4U, 5U)
6168         {
6169             INST(5U, Opcode::Compare).b().SrcType(DataType::INT64).CC(CC_GT).Inputs(0U, 2U);
6170             INST(6U, Opcode::IfImm).SrcType(compiler::DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
6171         }
6172 
6173         BASIC_BLOCK(4U, 6U)
6174         {
6175             INST(7U, Opcode::Add).s64().Inputs(0U, 2U);
6176         }
6177         BASIC_BLOCK(5U, 6U)
6178         {
6179             INST(8U, Opcode::Sub).s64().Inputs(0U, 2U);
6180         }
6181 
6182         BASIC_BLOCK(6U, 7U)
6183         {
6184             INST(9U, Opcode::Phi).s64().Inputs(7U, 8U);
6185         }
6186 
6187         BASIC_BLOCK(7U, -1L)
6188         {
6189             INST(10U, Opcode::Phi).b().Inputs(2U, 1U);
6190             INST(11U, Opcode::Phi).s64().Inputs(0U, 9U);
6191             INST(12U, Opcode::SaveState).NoVregs();
6192             INST(13U, Opcode::CallStatic).u64().InputsAutoType(10U, 11U, 12U);
6193             INST(14U, Opcode::Return).u64().Inputs(13U);
6194         }
6195     }
6196 
6197     ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
6198 
6199     ASSERT_EQ(INS(13U).GetInput(0U).GetInst(), &INS(3U));
6200 }
6201 
TEST_F(PeepholesTest,OverflowChecksOptimize)6202 TEST_F(PeepholesTest, OverflowChecksOptimize)
6203 {
6204     GRAPH(GetGraph())
6205     {
6206         CONSTANT(0U, 0U);
6207         PARAMETER(1U, 0U).s32();
6208         BASIC_BLOCK(2U, -1L)
6209         {
6210             INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
6211             INST(3U, Opcode::AddOverflowCheck).s32().Inputs(1U, 0U, 2U);
6212             INST(4U, Opcode::AddOverflowCheck).s32().Inputs(0U, 1U, 2U);
6213             INST(5U, Opcode::SubOverflowCheck).s32().Inputs(1U, 0U, 2U);
6214             INST(6U, Opcode::SubOverflowCheck).s32().Inputs(0U, 1U, 2U);  // can't optimize (0 - x)
6215             INST(7U, Opcode::CallStatic).v0id().InputsAutoType(3U, 4U, 5U, 6U, 2U);
6216             INST(8U, Opcode::ReturnVoid).v0id();
6217         }
6218     }
6219     ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
6220     ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
6221     auto graph = CreateEmptyGraph();
6222     GRAPH(graph)
6223     {
6224         CONSTANT(0U, 0U);
6225         PARAMETER(1U, 0U).s32();
6226         BASIC_BLOCK(2U, -1L)
6227         {
6228             INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
6229             INST(6U, Opcode::SubOverflowCheck).s32().Inputs(0U, 1U, 2U);  // can't optimize (0 - x)
6230             INST(7U, Opcode::CallStatic).v0id().InputsAutoType(1U, 1U, 1U, 6U, 2U);
6231             INST(8U, Opcode::ReturnVoid).v0id();
6232         }
6233     }
6234     ASSERT_TRUE(GraphComparator().Compare(graph, GetGraph()));
6235 }
6236 
6237 /* We check, that in Peephole if new inputs (which is not Constant) and inst in different BB in OSR mode,
6238  *  optimization will not apply.
6239  *
6240  *  What check:
6241  *  0.u64  Param
6242  *  1.u64  Param
6243  *  14.u64 Param
6244  *  ...
6245  *  BB 2
6246  *  15.u64 Add v1, v0
6247  *  16.u64 Add v0, v14
6248  *  ...
6249  *  BB 3
6250  *  17.u64 Sub v15, v16   <<== Inputs will NOT change
6251  */
TEST_F(PeepholesTest,SubAddAddFromOtherBBInOsrMode)6252 TEST_F(PeepholesTest, SubAddAddFromOtherBBInOsrMode)
6253 {
6254     auto graphOsr = CreateEmptyGraph();
6255     graphOsr->SetMode(GraphMode::Osr());
6256 
6257     GRAPH(graphOsr)
6258     {
6259         PARAMETER(0U, 0U).u64();
6260         PARAMETER(1U, 1U).u64();
6261         PARAMETER(14U, 2U).u64();
6262         BASIC_BLOCK(2U, 3U, 4U)
6263         {
6264             INST(15U, Opcode::Add).u64().Inputs(1U, 0U);
6265             INST(16U, Opcode::Add).u64().Inputs(0U, 14U);
6266 
6267             INST(2U, Opcode::Add).u64().Inputs(0U, 1U);
6268             INST(3U, Opcode::Compare).b().Inputs(0U, 2U);
6269             INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
6270         }
6271         BASIC_BLOCK(3U, 3U, 4U)
6272         {
6273             INST(5U, Opcode::Phi).u64().Inputs({{2U, 0U}, {3U, 6U}});
6274             INST(13U, Opcode::SaveStateOsr).Inputs(0U, 1U, 5U, 15U, 16U).SrcVregs({0U, 1U, 2U, 3U, 4U});
6275             INST(6U, Opcode::Sub).u64().Inputs(5U, 1U);
6276             // This INST 17 will not change!
6277             INST(17U, Opcode::Sub).u64().Inputs(15U, 16U);
6278             INST(7U, Opcode::Compare).b().Inputs(6U, 1U);
6279             INST(8U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(7U);
6280         }
6281         BASIC_BLOCK(4U, -1L)
6282         {
6283             INST(9U, Opcode::Phi).u64().Inputs({{2U, 0U}, {3U, 6U}});
6284             INST(10U, Opcode::Add).u64().Inputs(0U, 1U);
6285             INST(11U, Opcode::Add).u64().Inputs(9U, 10U);
6286             INST(12U, Opcode::Return).u64().Inputs(11U);
6287         }
6288     }
6289 
6290     for (auto bb : graphOsr->GetBlocksRPO()) {
6291         if (bb->IsLoopHeader()) {
6292             bb->SetOsrEntry(true);
6293         }
6294     }
6295     auto cloneOsr = GraphCloner(graphOsr, graphOsr->GetAllocator(), graphOsr->GetLocalAllocator()).CloneGraph();
6296     cloneOsr->RunPass<Peepholes>();
6297     ASSERT_TRUE(GraphComparator().Compare(graphOsr, cloneOsr));
6298 }
6299 
6300 /* We check, that if in Peephole new inputs and inst in different BB in OSR mode for Constants,
6301  *  optimization will apply.
6302  *
6303  *  What check:
6304  *  14.    Const -> v15
6305  *  19.    Const -> v16
6306  *  ...
6307  *  BB 2
6308  *  15.u64 Add v14, v1 -> v17
6309  *  16.u64 Add v1, v19 -> v17
6310  *  ...
6311  *  BB 3
6312  *  17.u64 Sub v15, v16   <<== Inputs will change
6313  *  ============>
6314  *  14.    Const -> v15, v17
6315  *  19.    Const -> v16, v17
6316  *  ...
6317  *  BB 2
6318  *  15.u64 Add v14, v1
6319  *  16.u64 Add v1, v19
6320  *  ...
6321  *  BB 3
6322  *  17.u64 Sub v14, v19   <<== Inputs changed
6323  */
TEST_F(PeepholesTest,SubAddAddSameBBInOsrMode)6324 TEST_F(PeepholesTest, SubAddAddSameBBInOsrMode)
6325 {
6326     GetGraph()->SetMode(GraphMode::Osr());
6327     // (const0 + param) - (param + const1) = const0 - const1
6328     GRAPH(GetGraph())
6329     {
6330         PARAMETER(0U, 0U).u64();
6331         PARAMETER(1U, 1U).u64();
6332 
6333         CONSTANT(14U, 0U);
6334         CONSTANT(19U, 2U);
6335 
6336         BASIC_BLOCK(2U, 3U, 4U)
6337         {
6338             INST(2U, Opcode::Add).u64().Inputs(0U, 1U);
6339             INST(3U, Opcode::Compare).b().Inputs(0U, 2U);
6340             INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(3U);
6341         }
6342         BASIC_BLOCK(3U, 3U, 4U)
6343         {
6344             INST(5U, Opcode::Phi).u64().Inputs({{2U, 0U}, {3U, 6U}});
6345             INST(13U, Opcode::SaveStateOsr).Inputs(0U, 1U, 5U).SrcVregs({0U, 1U, 2U});
6346             INST(6U, Opcode::Sub).u64().Inputs(5U, 1U);
6347 
6348             INST(15U, Opcode::Add).u64().Inputs(14U, 1U);
6349             INST(16U, Opcode::Add).u64().Inputs(1U, 19U);
6350             // INST 17 will change
6351             INST(17U, Opcode::Sub).u64().Inputs(15U, 16U);
6352             INST(7U, Opcode::Compare).b().Inputs(6U, 1U);
6353             INST(8U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(7U);
6354         }
6355         BASIC_BLOCK(4U, -1L)
6356         {
6357             INST(9U, Opcode::Phi).u64().Inputs({{2U, 0U}, {3U, 6U}});
6358             INST(10U, Opcode::Add).u64().Inputs(0U, 1U);
6359             INST(11U, Opcode::Add).u64().Inputs(9U, 10U);
6360             INST(12U, Opcode::Return).u64().Inputs(11U);
6361         }
6362     }
6363 
6364     for (auto bb : GetGraph()->GetBlocksRPO()) {
6365         if (bb->IsLoopHeader()) {
6366             bb->SetOsrEntry(true);
6367         }
6368     }
6369     GetGraph()->RunPass<Peepholes>();
6370     GraphChecker(GetGraph()).Check();
6371     ASSERT_EQ(INS(17U).GetInput(0U).GetInst(), &INS(14U));
6372     ASSERT_EQ(INS(17U).GetInput(1U).GetInst(), &INS(19U));
6373 }
6374 
TEST_F(PeepholesTest,GetInstanceClassTest)6375 TEST_F(PeepholesTest, GetInstanceClassTest)
6376 {
6377     auto klass = reinterpret_cast<RuntimeInterface::ClassPtr>(2U);
6378     GRAPH(GetGraph())
6379     {
6380         BASIC_BLOCK(2U, -1L)
6381         {
6382             INST(0U, Opcode::SaveState).NoVregs();
6383             INST(1U, Opcode::LoadAndInitClass).ref().Inputs(0U).TypeId(1U).Class(klass);
6384             INST(2U, Opcode::NewObject).ref().Inputs(1U, 0U).TypeId(1U);
6385             INST(3U, Opcode::GetInstanceClass).ref().Inputs(2U);
6386             INST(4U, Opcode::Return).ref().Inputs(3U);
6387         }
6388     }
6389     GetGraph()->RunPass<ObjectTypePropagation>();  // set analysis valid
6390     INS(2U).SetObjectTypeInfo(ObjectTypeInfo(klass, true));
6391     ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
6392     ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
6393     auto graph = CreateEmptyGraph();
6394     GRAPH(graph)
6395     {
6396         BASIC_BLOCK(2U, -1L)
6397         {
6398             INST(0U, Opcode::SaveState).NoVregs();
6399             INST(1U, Opcode::LoadAndInitClass).ref().Inputs(0U).TypeId(1U).Class(klass);
6400             INST(2U, Opcode::NewObject).ref().Inputs(1U, 0U).TypeId(1U);
6401             INST(3U, Opcode::LoadImmediate).ref().Class(klass);
6402             INST(4U, Opcode::Return).ref().Inputs(3U);
6403         }
6404     }
6405     ASSERT_TRUE(GraphComparator().Compare(graph, GetGraph()));
6406 }
6407 
6408 // Replace by Neg
TEST_F(PeepholesTest,NegOverflowAndZeroCheckShl)6409 TEST_F(PeepholesTest, NegOverflowAndZeroCheckShl)
6410 {
6411     auto graph1 = CreateEmptyGraph();
6412     GRAPH(graph1)
6413     {
6414         PARAMETER(0U, 0U).s32();
6415         CONSTANT(1U, 1U);
6416         BASIC_BLOCK(2U, -1L)
6417         {
6418             INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
6419             INST(6U, Opcode::NegOverflowAndZeroCheck).s32().Inputs(0U, 5U);
6420             INST(7U, Opcode::Shl).s32().Inputs(6U, 1U);
6421             INST(8U, Opcode::Return).s32().Inputs(7U);
6422         }
6423     }
6424     ASSERT_TRUE(graph1->RunPass<Peepholes>());
6425     auto graph2 = CreateEmptyGraph();
6426     GRAPH(graph2)
6427     {
6428         PARAMETER(0U, 0U).s32();
6429         CONSTANT(1U, 1U);
6430         BASIC_BLOCK(2U, -1L)
6431         {
6432             INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
6433             INST(6U, Opcode::Neg).s32().Inputs(0U);
6434             INST(7U, Opcode::Shl).s32().Inputs(6U, 1U);
6435             INST(8U, Opcode::Return).s32().Inputs(7U);
6436         }
6437     }
6438     ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
6439 }
6440 
TEST_F(PeepholesTest,NegOverflowAndZeroCheckShr)6441 TEST_F(PeepholesTest, NegOverflowAndZeroCheckShr)
6442 {
6443     auto graph1 = CreateEmptyGraph();
6444     GRAPH(graph1)
6445     {
6446         PARAMETER(0U, 0U).s32();
6447         CONSTANT(1U, 1U);
6448         BASIC_BLOCK(2U, -1L)
6449         {
6450             INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
6451             INST(6U, Opcode::NegOverflowAndZeroCheck).s32().Inputs(0U, 5U);
6452             INST(7U, Opcode::Shr).s32().Inputs(6U, 1U);
6453             INST(8U, Opcode::Return).s32().Inputs(7U);
6454         }
6455     }
6456     ASSERT_TRUE(graph1->RunPass<Peepholes>());
6457     auto graph2 = CreateEmptyGraph();
6458     GRAPH(graph2)
6459     {
6460         PARAMETER(0U, 0U).s32();
6461         CONSTANT(1U, 1U);
6462         BASIC_BLOCK(2U, -1L)
6463         {
6464             INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
6465             INST(6U, Opcode::Neg).s32().Inputs(0U);
6466             INST(7U, Opcode::Shr).s32().Inputs(6U, 1U);
6467             INST(8U, Opcode::Return).s32().Inputs(7U);
6468         }
6469     }
6470     ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
6471 }
6472 
TEST_F(PeepholesTest,NegOverflowAndZeroCheckAShr)6473 TEST_F(PeepholesTest, NegOverflowAndZeroCheckAShr)
6474 {
6475     auto graph1 = CreateEmptyGraph();
6476     GRAPH(graph1)
6477     {
6478         PARAMETER(0U, 0U).s32();
6479         CONSTANT(1U, 1U);
6480         BASIC_BLOCK(2U, -1L)
6481         {
6482             INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
6483             INST(6U, Opcode::NegOverflowAndZeroCheck).s32().Inputs(0U, 5U);
6484             INST(7U, Opcode::AShr).s32().Inputs(6U, 1U);
6485             INST(8U, Opcode::Return).s32().Inputs(7U);
6486         }
6487     }
6488     ASSERT_TRUE(graph1->RunPass<Peepholes>());
6489     auto graph2 = CreateEmptyGraph();
6490     GRAPH(graph2)
6491     {
6492         PARAMETER(0U, 0U).s32();
6493         CONSTANT(1U, 1U);
6494         BASIC_BLOCK(2U, -1L)
6495         {
6496             INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
6497             INST(6U, Opcode::Neg).s32().Inputs(0U);
6498             INST(7U, Opcode::AShr).s32().Inputs(6U, 1U);
6499             INST(8U, Opcode::Return).s32().Inputs(7U);
6500         }
6501     }
6502     ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
6503 }
6504 
TEST_F(PeepholesTest,NegOverflowAndZeroCheckAnd)6505 TEST_F(PeepholesTest, NegOverflowAndZeroCheckAnd)
6506 {
6507     auto graph1 = CreateEmptyGraph();
6508     GRAPH(graph1)
6509     {
6510         PARAMETER(0U, 0U).s32();
6511         CONSTANT(1U, 1U);
6512         BASIC_BLOCK(2U, -1L)
6513         {
6514             INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
6515             INST(6U, Opcode::NegOverflowAndZeroCheck).s32().Inputs(0U, 5U);
6516             INST(7U, Opcode::And).u32().Inputs(6U, 1U);
6517             INST(8U, Opcode::Return).u32().Inputs(7U);
6518         }
6519     }
6520     ASSERT_TRUE(graph1->RunPass<Peepholes>());
6521     auto graph2 = CreateEmptyGraph();
6522     GRAPH(graph2)
6523     {
6524         PARAMETER(0U, 0U).s32();
6525         CONSTANT(1U, 1U);
6526         BASIC_BLOCK(2U, -1L)
6527         {
6528             INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
6529             INST(6U, Opcode::Neg).s32().Inputs(0U);
6530             INST(7U, Opcode::And).u32().Inputs(6U, 1U);
6531             INST(8U, Opcode::Return).u32().Inputs(7U);
6532         }
6533     }
6534     ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
6535 }
6536 
TEST_F(PeepholesTest,NegOverflowAndZeroCheckOr)6537 TEST_F(PeepholesTest, NegOverflowAndZeroCheckOr)
6538 {
6539     auto graph1 = CreateEmptyGraph();
6540     GRAPH(graph1)
6541     {
6542         PARAMETER(0U, 0U).s32();
6543         CONSTANT(1U, 1U);
6544         BASIC_BLOCK(2U, -1L)
6545         {
6546             INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
6547             INST(6U, Opcode::NegOverflowAndZeroCheck).s32().Inputs(0U, 5U);
6548             INST(7U, Opcode::Or).u32().Inputs(6U, 1U);
6549             INST(8U, Opcode::Return).u32().Inputs(7U);
6550         }
6551     }
6552     ASSERT_TRUE(graph1->RunPass<Peepholes>());
6553     auto graph2 = CreateEmptyGraph();
6554     GRAPH(graph2)
6555     {
6556         PARAMETER(0U, 0U).s32();
6557         CONSTANT(1U, 1U);
6558         BASIC_BLOCK(2U, -1L)
6559         {
6560             INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
6561             INST(6U, Opcode::Neg).s32().Inputs(0U);
6562             INST(7U, Opcode::Or).u32().Inputs(6U, 1U);
6563             INST(8U, Opcode::Return).u32().Inputs(7U);
6564         }
6565     }
6566     ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
6567 }
6568 
TEST_F(PeepholesTest,NegOverflowAndZeroCheckXor)6569 TEST_F(PeepholesTest, NegOverflowAndZeroCheckXor)
6570 {
6571     auto graph1 = CreateEmptyGraph();
6572     GRAPH(graph1)
6573     {
6574         PARAMETER(0U, 0U).s32();
6575         CONSTANT(1U, 1U);
6576         BASIC_BLOCK(2U, -1L)
6577         {
6578             INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
6579             INST(6U, Opcode::NegOverflowAndZeroCheck).s32().Inputs(0U, 5U);
6580             INST(7U, Opcode::Xor).u32().Inputs(6U, 1U);
6581             INST(8U, Opcode::Return).u32().Inputs(7U);
6582         }
6583     }
6584     ASSERT_TRUE(graph1->RunPass<Peepholes>());
6585     auto graph2 = CreateEmptyGraph();
6586     GRAPH(graph2)
6587     {
6588         PARAMETER(0U, 0U).s32();
6589         CONSTANT(1U, 1U);
6590         BASIC_BLOCK(2U, -1L)
6591         {
6592             INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
6593             INST(6U, Opcode::Neg).s32().Inputs(0U);
6594             INST(7U, Opcode::Xor).u32().Inputs(6U, 1U);
6595             INST(8U, Opcode::Return).u32().Inputs(7U);
6596         }
6597     }
6598     ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
6599 }
6600 
TEST_F(PeepholesTest,NegOverflowAndZeroCheckNotApplied)6601 TEST_F(PeepholesTest, NegOverflowAndZeroCheckNotApplied)
6602 {
6603     GRAPH(GetGraph())
6604     {
6605         PARAMETER(0U, 0U).s32();
6606         CONSTANT(1U, 1U);
6607         BASIC_BLOCK(2U, -1L)
6608         {
6609             INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
6610             INST(6U, Opcode::NegOverflowAndZeroCheck).s32().Inputs(0U, 5U);
6611             INST(7U, Opcode::Add).s32().Inputs(6U, 1U);
6612             INST(8U, Opcode::Return).s32().Inputs(7U);
6613         }
6614     }
6615     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
6616     ASSERT_FALSE(GetGraph()->RunPass<Peepholes>());
6617     GraphChecker(GetGraph()).Check();
6618     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
6619 }
6620 
SRC_GRAPH(OverflowCheckAsBitwiseInput,Graph * graph)6621 SRC_GRAPH(OverflowCheckAsBitwiseInput, Graph *graph)
6622 {
6623     GRAPH(graph)
6624     {
6625         PARAMETER(0U, 0U).s32();
6626         PARAMETER(1U, 1U).s32();
6627         PARAMETER(2U, 2U).s32();
6628         CONSTANT(3U, 0U);
6629         BASIC_BLOCK(2U, 4U, 3U)
6630         {
6631             INST(4U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
6632             INST(5U, Opcode::AddOverflowCheck).s32().Inputs(0U, 1U, 4U);
6633 
6634             INST(6U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U, 5U).SrcVregs({0U, 1U, 2U, 3U, 4U});
6635             INST(7U, Opcode::SubOverflowCheck).s32().Inputs(5U, 2U, 6U);
6636 
6637             INST(8U, Opcode::Compare).b().CC(CC_GE).SrcType(DataType::Type::INT32).Inputs(2U, 0U);
6638             INST(9U, Opcode::IfImm).SrcType(compiler::DataType::BOOL).CC(compiler::CC_NE).Imm(0U).Inputs(8U);
6639         }
6640 
6641         BASIC_BLOCK(4U, 3U)
6642         {
6643             INST(10U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U, 5U, 7U).SrcVregs({0U, 1U, 2U, 3U, 4U, 5U});
6644             INST(11U, Opcode::NegOverflowAndZeroCheck).s32().Inputs(2U, 10U);
6645         }
6646 
6647         BASIC_BLOCK(3U, -1L)
6648         {
6649             INST(12U, Opcode::Phi).s32().Inputs({{2U, 7U}, {4U, 11U}});
6650             INST(13U, Opcode::Or).s32().Inputs(12U, 3U);
6651             INST(14U, Opcode::Return).s32().Inputs(13U);
6652         }
6653     }
6654 }
6655 
OUT_GRAPH(OverflowCheckAsBitwiseInput,Graph * graph)6656 OUT_GRAPH(OverflowCheckAsBitwiseInput, Graph *graph)
6657 {
6658     GRAPH(graph)
6659     {
6660         PARAMETER(0U, 0U).s32();
6661         PARAMETER(1U, 1U).s32();
6662         PARAMETER(2U, 2U).s32();
6663         CONSTANT(3U, 0U);
6664         BASIC_BLOCK(2U, 4U, 3U)
6665         {
6666             INST(4U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
6667             INST(5U, Opcode::Add).s32().Inputs(0U, 1U);
6668 
6669             INST(6U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U, 5U).SrcVregs({0U, 1U, 2U, 3U, 4U});
6670             INST(7U, Opcode::Sub).s32().Inputs(5U, 2U);
6671 
6672             INST(8U, Opcode::Compare).b().CC(CC_GE).SrcType(DataType::Type::INT32).Inputs(2U, 0U);
6673             INST(9U, Opcode::IfImm).SrcType(compiler::DataType::BOOL).CC(compiler::CC_NE).Imm(0U).Inputs(8U);
6674         }
6675 
6676         BASIC_BLOCK(4U, 3U)
6677         {
6678             INST(10U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U, 5U, 7U).SrcVregs({0U, 1U, 2U, 3U, 4U, 5U});
6679             INST(11U, Opcode::Neg).s32().Inputs(2U);
6680         }
6681 
6682         BASIC_BLOCK(3U, -1L)
6683         {
6684             INST(12U, Opcode::Phi).s32().Inputs({{2U, 7U}, {4U, 11U}});
6685             INST(13U, Opcode::Or).s32().Inputs(12U, 3U);
6686             INST(14U, Opcode::Return).s32().Inputs(12U);
6687         }
6688     }
6689 }
6690 
TEST_F(PeepholesTest,OverflowCheckAsBitwiseInput)6691 TEST_F(PeepholesTest, OverflowCheckAsBitwiseInput)
6692 {
6693     src_graph::OverflowCheckAsBitwiseInput::CREATE(GetGraph());
6694     ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
6695     auto graph = CreateEmptyGraph();
6696     out_graph::OverflowCheckAsBitwiseInput::CREATE(graph);
6697     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
6698 }
6699 
TEST_F(PeepholesTest,OverflowCheckAsBitwiseAndSSInput)6700 TEST_F(PeepholesTest, OverflowCheckAsBitwiseAndSSInput)
6701 {
6702     GRAPH(GetGraph())
6703     {
6704         PARAMETER(0U, 0U).s32();
6705         CONSTANT(1U, 255U);
6706         BASIC_BLOCK(2U, -1L)
6707         {
6708             INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
6709             INST(3U, Opcode::AddOverflowCheck).s32().Inputs(0U, 1U, 2U);
6710 
6711             INST(6U, Opcode::And).s32().Inputs(3U, 1U);
6712             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 3U, 6U).SrcVregs({0U, 1U, 2U, 3U});
6713             INST(8U, Opcode::AddOverflowCheck).s32().Inputs(6U, 1U, 7U);
6714             INST(9U, Opcode::Return).s32().Inputs(8U);
6715         }
6716     }
6717     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
6718     ASSERT_FALSE(GetGraph()->RunPass<Peepholes>());
6719     GraphChecker(GetGraph()).Check();
6720     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
6721 }
6722 
TEST_F(PeepholesTest,ReplacingXorWithCompare)6723 TEST_F(PeepholesTest, ReplacingXorWithCompare)
6724 {
6725     GRAPH(GetGraph())
6726     {
6727         CONSTANT(0U, 1U);
6728         BASIC_BLOCK(2U, -1L)
6729         {
6730             INST(1U, Opcode::SaveState).NoVregs();
6731             INST(2U, Opcode::CallStatic).b().InputsAutoType(1U);
6732             INST(3U, Opcode::Xor).s32().Inputs(0U, 2U);
6733             INST(9U, Opcode::Return).s32().Inputs(3U);
6734         }
6735     }
6736 
6737     auto graph = CreateEmptyGraph();
6738     GRAPH(graph)
6739     {
6740         CONSTANT(10U, 0U);
6741         BASIC_BLOCK(2U, -1L)
6742         {
6743             INST(1U, Opcode::SaveState).NoVregs();
6744             INST(2U, Opcode::CallStatic).b().InputsAutoType(1U);
6745             INST(11U, Opcode::Compare).b().CC(ConditionCode::CC_EQ).Inputs(2U, 10U);
6746             INST(9U, Opcode::Return).s32().Inputs(11U);
6747         }
6748     }
6749     ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
6750     ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
6751 
6752     GraphChecker(GetGraph()).Check();
6753     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
6754 }
6755 
TEST_F(PeepholesTest,MultiArrayWithLenArrayFirstLayer)6756 TEST_F(PeepholesTest, MultiArrayWithLenArrayFirstLayer)
6757 {
6758     auto class1 = reinterpret_cast<RuntimeInterface::ClassPtr>(1U);
6759     GRAPH(GetGraph())
6760     {
6761         CONSTANT(0U, 0x3U);
6762         CONSTANT(1U, 0x2U);
6763         CONSTANT(7U, 0x1U);
6764 
6765         BASIC_BLOCK(2U, -1L)
6766         {
6767             INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
6768             INST(3U, Opcode::LoadImmediate).ref().Class(class1);
6769             INST(4U, Opcode::MultiArray)
6770                 .ref()
6771                 .InputsAutoType(3U, 0U, 1U, 2U);  // Will be create [ [ [][] ], [ [][] ], [ [][] ] ]
6772             INST(5U, Opcode::LenArray).Inputs(4U).s32();
6773             INST(10U, Opcode::Return).s32().Inputs(5U);
6774         }
6775     }
6776 
6777     auto graph = CreateEmptyGraph();
6778     GRAPH(graph)
6779     {
6780         CONSTANT(0U, 0x3U);
6781         CONSTANT(1U, 0x2U);
6782         CONSTANT(7U, 0x1U);
6783 
6784         BASIC_BLOCK(2U, -1L)
6785         {
6786             INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
6787             INST(3U, Opcode::LoadImmediate).ref().Class(class1);
6788             INST(4U, Opcode::MultiArray)
6789                 .ref()
6790                 .InputsAutoType(3U, 0U, 1U, 2U);  // Will be create [ [ [][] ], [ [][] ], [ [][] ] ]
6791             INST(5U, Opcode::LenArray).Inputs(4U).s32();
6792             INST(10U, Opcode::Return).s32().Inputs(0U);
6793         }
6794     }
6795     ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
6796     GraphChecker(GetGraph()).Check();
6797     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
6798 }
6799 
SRC_GRAPH(MultiArrayWithLenArraySecondLayer,Graph * graph)6800 SRC_GRAPH(MultiArrayWithLenArraySecondLayer, Graph *graph)
6801 {
6802     auto class1 = reinterpret_cast<RuntimeInterface::ClassPtr>(1U);
6803     GRAPH(graph)
6804     {
6805         PARAMETER(0U, 0x3U).s32();
6806         CONSTANT(1U, 0x2U);
6807         CONSTANT(7U, 0x1U);
6808 
6809         BASIC_BLOCK(2U, -1L)
6810         {
6811             INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
6812             INST(3U, Opcode::LoadImmediate).ref().Class(class1);
6813             INST(4U, Opcode::MultiArray)
6814                 .ref()
6815                 .InputsAutoType(3U, 0U, 1U, 2U);  // Will be create [ [ [][] ], [ [][] ], [ [][] ] ]
6816             INST(5U, Opcode::LenArray).Inputs(4U).s32();
6817             INST(11U, Opcode::LoadArray).ref().Inputs(4U, 7U);
6818             INST(12U, Opcode::NullCheck).ref().Inputs(11U, 2U);
6819             INST(13U, Opcode::LenArray).Inputs(12U).s32();
6820             INST(14U, Opcode::Add).Inputs(5U, 13U).s32();
6821             INST(10U, Opcode::Return).s32().Inputs(14U);
6822         }
6823     }
6824 }
6825 
OUT_GRAPH(MultiArrayWithLenArraySecondLayer,Graph * graph)6826 OUT_GRAPH(MultiArrayWithLenArraySecondLayer, Graph *graph)
6827 {
6828     auto class1 = reinterpret_cast<RuntimeInterface::ClassPtr>(1U);
6829     GRAPH(graph)
6830     {
6831         PARAMETER(0U, 0x3U).s32();
6832         CONSTANT(1U, 0x2U);
6833         CONSTANT(7U, 0x1U);
6834 
6835         BASIC_BLOCK(2U, -1L)
6836         {
6837             INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
6838             INST(3U, Opcode::LoadImmediate).ref().Class(class1);
6839             INST(4U, Opcode::MultiArray)
6840                 .ref()
6841                 .InputsAutoType(3U, 0U, 1U, 2U);  // Will be create [ [ [][] ], [ [][] ], [ [][] ] ]
6842             INST(5U, Opcode::LenArray).Inputs(4U).s32();
6843             INST(11U, Opcode::LoadArray).ref().Inputs(4U, 7U);
6844             INST(12U, Opcode::NullCheck).ref().Inputs(11U, 2U);
6845             INST(13U, Opcode::LenArray).Inputs(12U).s32();
6846             INST(14U, Opcode::Add).Inputs(0U, 1U).s32();
6847             INST(10U, Opcode::Return).s32().Inputs(14U);
6848         }
6849     }
6850 }
6851 
TEST_F(PeepholesTest,MultiArrayWithLenArraySecondLayer)6852 TEST_F(PeepholesTest, MultiArrayWithLenArraySecondLayer)
6853 {
6854     src_graph::MultiArrayWithLenArraySecondLayer::CREATE(GetGraph());
6855 
6856     auto graph = CreateEmptyGraph();
6857     out_graph::MultiArrayWithLenArraySecondLayer::CREATE(graph);
6858     ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
6859     GraphChecker(GetGraph()).Check();
6860     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
6861 }
6862 
SRC_GRAPH(MultiArrayWithLenArrayOfString,Graph * graph)6863 SRC_GRAPH(MultiArrayWithLenArrayOfString, Graph *graph)
6864 {
6865     auto class1 = reinterpret_cast<RuntimeInterface::ClassPtr>(1U);
6866     GRAPH(graph)
6867     {
6868         PARAMETER(0U, 0x1U).s32();
6869         CONSTANT(1U, 0x3U);
6870         PARAMETER(2U, 0x2U).s32();  // Will think, that value is 0x2
6871 
6872         BASIC_BLOCK(2U, -1L)
6873         {
6874             INST(3U, Opcode::SaveState);
6875             INST(4U, Opcode::LoadImmediate).ref().Class(class1);
6876             INST(5U, Opcode::MultiArray)
6877                 .ref()
6878                 .InputsAutoType(4U, 1U, 2U,
6879                                 3U);  // Will be create [ [ String, String ], [ String, String ], [ String, String ] ]
6880             INST(6U, Opcode::LenArray).Inputs(5U).s32();
6881 
6882             INST(7U, Opcode::LoadArray).ref().Inputs(5U, 0U);  // Loaded: [ String, String ]
6883             INST(8U, Opcode::NullCheck).ref().Inputs(7U, 3U);
6884             INST(9U, Opcode::LenArray).Inputs(8U).s32();
6885 
6886             INST(10U, Opcode::LoadArray).ref().Inputs(8U, 0U);  // Loaded: String
6887             INST(11U, Opcode::NullCheck).ref().Inputs(10U, 3U);
6888             INST(12U, Opcode::LenArray).Inputs(11U).s32();  // Length of String
6889 
6890             INST(13U, Opcode::Add).Inputs(9U, 6U).s32();
6891             INST(14U, Opcode::Add).Inputs(13U, 12U).s32();
6892             INST(15U, Opcode::Return).s32().Inputs(14U);
6893         }
6894     }
6895 }
6896 
OUT_GRAPH(MultiArrayWithLenArrayOfString,Graph * graph)6897 OUT_GRAPH(MultiArrayWithLenArrayOfString, Graph *graph)
6898 {
6899     auto class1 = reinterpret_cast<RuntimeInterface::ClassPtr>(1U);
6900     GRAPH(graph)
6901     {
6902         PARAMETER(0U, 0x1U).s32();
6903         CONSTANT(1U, 0x3U);
6904         PARAMETER(2U, 0x2U).s32();  // Will think, that value is 0x2
6905 
6906         BASIC_BLOCK(2U, -1L)
6907         {
6908             INST(3U, Opcode::SaveState);
6909             INST(4U, Opcode::LoadImmediate).ref().Class(class1);
6910             INST(5U, Opcode::MultiArray)
6911                 .ref()
6912                 .InputsAutoType(4U, 1U, 2U,
6913                                 3U);  // Will be create [ [ String, String ], [ String, String ], [ String, String ] ]
6914             INST(6U, Opcode::LenArray).Inputs(5U).s32();
6915 
6916             INST(7U, Opcode::LoadArray).ref().Inputs(5U, 0U);  // Loaded: [ String, String ]
6917             INST(8U, Opcode::NullCheck).ref().Inputs(7U, 3U);
6918             INST(9U, Opcode::LenArray).Inputs(8U).s32();
6919 
6920             INST(10U, Opcode::LoadArray).ref().Inputs(8U, 0U);  // Loaded: String
6921             INST(11U, Opcode::NullCheck).ref().Inputs(10U, 3U);
6922             INST(12U, Opcode::LenArray).Inputs(11U).s32();  // Length of String
6923 
6924             INST(13U, Opcode::Add).Inputs(2U, 1U).s32();
6925             INST(14U, Opcode::Add).Inputs(13U, 12U).s32();
6926             INST(15U, Opcode::Return).s32().Inputs(14U);
6927         }
6928     }
6929 }
6930 
TEST_F(PeepholesTest,MultiArrayWithLenArrayOfString)6931 TEST_F(PeepholesTest, MultiArrayWithLenArrayOfString)
6932 {
6933     src_graph::MultiArrayWithLenArrayOfString::CREATE(GetGraph());
6934 
6935     auto graph = CreateEmptyGraph();
6936     out_graph::MultiArrayWithLenArrayOfString::CREATE(graph);
6937 
6938     ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
6939     GraphChecker(GetGraph()).Check();
6940     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
6941 }
6942 
TEST_F(PeepholesTest,RemoveDoubleXor)6943 TEST_F(PeepholesTest, RemoveDoubleXor)
6944 {
6945     GRAPH(GetGraph())
6946     {
6947         PARAMETER(0U, 0U).i32();  // arg 0
6948         CONSTANT(1U, 1U).i64();   // Constant i64 0x1
6949         BASIC_BLOCK(2U, -1L)
6950         {
6951             INST(2U, Opcode::Xor).i32().Inputs(0U, 1U);
6952             INST(3U, Opcode::Xor).i32().Inputs(2U, 1U);
6953             INST(4U, Opcode::Return).b().Inputs(3U);
6954         }
6955     }
6956     ASSERT_TRUE(GetGraph()->RunPass<Peepholes>());
6957     GetGraph()->RunPass<Cleanup>();
6958     auto graph = CreateEmptyGraph();
6959     GRAPH(graph)
6960     {
6961         PARAMETER(0U, 0U).i32();  // arg 0
6962         BASIC_BLOCK(2U, -1L)
6963         {
6964             INST(4U, Opcode::Return).b().Inputs(0U);
6965         }
6966     }
6967     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
6968 }
6969 
TEST_F(PeepholesTest,RemoveDoubleXorNeg1)6970 TEST_F(PeepholesTest, RemoveDoubleXorNeg1)
6971 {
6972     GRAPH(GetGraph())
6973     {
6974         PARAMETER(0U, 0U).i32();  // arg 0
6975         PARAMETER(1U, 1U).i32();  // arg 1 (non-const input)
6976         BASIC_BLOCK(2U, -1L)
6977         {
6978             INST(2U, Opcode::Xor).i32().Inputs(0U, 1U);
6979             INST(3U, Opcode::Xor).i32().Inputs(2U, 1U);
6980             INST(4U, Opcode::Return).b().Inputs(3U);
6981         }
6982     }
6983     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
6984     ASSERT_FALSE(GetGraph()->RunPass<Peepholes>());
6985     GraphChecker(GetGraph()).Check();
6986     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
6987 }
6988 
TEST_F(PeepholesTest,RemoveDoubleXorNeg2)6989 TEST_F(PeepholesTest, RemoveDoubleXorNeg2)
6990 {
6991     GRAPH(GetGraph())
6992     {
6993         PARAMETER(0U, 0U).i32();  // arg 0
6994         CONSTANT(1U, 1U).i64();   // Constant i64 0x1
6995         BASIC_BLOCK(2U, -1L)
6996         {
6997             INST(2U, Opcode::Add).i32().Inputs(0U, 1U);  // Non-Xor input of the second Xor
6998             INST(3U, Opcode::Xor).i32().Inputs(2U, 1U);
6999             INST(4U, Opcode::Return).b().Inputs(3U);
7000         }
7001     }
7002     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
7003     ASSERT_FALSE(GetGraph()->RunPass<Peepholes>());
7004     GraphChecker(GetGraph()).Check();
7005     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
7006 }
7007 
TEST_F(PeepholesTest,RemoveDoubleXorNeg3)7008 TEST_F(PeepholesTest, RemoveDoubleXorNeg3)
7009 {
7010     GRAPH(GetGraph())
7011     {
7012         PARAMETER(0U, 0U).i32();  // arg 0
7013         CONSTANT(1U, 1U).i64();   // Constant i64 0x1
7014         BASIC_BLOCK(2U, -1L)
7015         {
7016             INST(2U, Opcode::Xor).i32().Inputs(0U, 1U);
7017             INST(3U, Opcode::Xor).i32().Inputs(2U, 1U);
7018             INST(4U, Opcode::Add).i32().Inputs(2U, 0U);  // Extra user of first Xor
7019             INST(5U, Opcode::Return).b().Inputs(3U);
7020         }
7021     }
7022     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
7023     ASSERT_FALSE(GetGraph()->RunPass<Peepholes>());
7024     GraphChecker(GetGraph()).Check();
7025     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
7026 }
7027 
TEST_F(PeepholesTest,RemoveDoubleXorNeg4)7028 TEST_F(PeepholesTest, RemoveDoubleXorNeg4)
7029 {
7030     GRAPH(GetGraph())
7031     {
7032         PARAMETER(0U, 0U).i32();  // arg 0
7033         CONSTANT(1U, 1U).i64();   // Constant i64 0x1
7034         CONSTANT(2U, 2U).i64();   // Another constant i64 0x2
7035         BASIC_BLOCK(2U, -1L)
7036         {
7037             INST(3U, Opcode::Xor).i32().Inputs(0U, 1U);
7038             INST(4U, Opcode::Xor).i32().Inputs(3U, 2U);
7039             INST(5U, Opcode::Return).b().Inputs(4U);
7040         }
7041     }
7042     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
7043     ASSERT_FALSE(GetGraph()->RunPass<Peepholes>());
7044     GraphChecker(GetGraph()).Check();
7045     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
7046 }
7047 
7048 // NOLINTEND(readability-magic-numbers)
7049 
7050 }  // namespace ark::compiler
7051