• 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 "unit_test.h"
17 #include "optimizer/optimizations/checks_elimination.h"
18 #include "optimizer/optimizations/cleanup.h"
19 #include "optimizer/ir/runtime_interface.h"
20 #include "optimizer/ir/graph_cloner.h"
21 
22 namespace ark::compiler {
23 class ChecksEliminationTest : public CommonTest {
24 public:
ChecksEliminationTest()25     ChecksEliminationTest() : graph_(CreateGraphStartEndBlocks()) {}
26 
GetGraph()27     Graph *GetGraph()
28     {
29         return graph_;
30     }
31 
32     struct RuntimeInterfaceNotStaticMethod : public compiler::RuntimeInterface {
IsMethodStaticark::compiler::ChecksEliminationTest::RuntimeInterfaceNotStaticMethod33         bool IsMethodStatic([[maybe_unused]] MethodPtr method) const override
34         {
35             return false;
36         }
37     };
38 
39     // NOLINTBEGIN(readability-magic-numbers)
40     template <bool IS_APPLIED>
SimpleTest(int32_t index,int32_t arrayLen)41     void SimpleTest(int32_t index, int32_t arrayLen)
42     {
43         auto graph1 = CreateEmptyGraph();
44         GRAPH(graph1)
45         {
46             CONSTANT(0U, arrayLen);
47             CONSTANT(1U, index);
48             BASIC_BLOCK(2U, 1U)
49             {
50                 INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
51                 INST(44U, Opcode::LoadAndInitClass).ref().Inputs(2U).TypeId(68U);
52                 INST(3U, Opcode::NewArray).ref().Inputs(44U, 0U, 2U);
53                 INST(4U, Opcode::BoundsCheck).s32().Inputs(0U, 1U, 2U);
54                 INST(5U, Opcode::LoadArray).s32().Inputs(3U, 4U);
55                 INST(6U, Opcode::Return).s32().Inputs(5U);
56             }
57         }
58         graph1->RunPass<ChecksElimination>();
59         auto graph2 = CreateEmptyGraph();
60         if constexpr (IS_APPLIED) {
61             GRAPH(graph2)
62             {
63                 CONSTANT(0U, arrayLen);
64                 CONSTANT(1U, index);
65                 BASIC_BLOCK(2U, 1U)
66                 {
67                     INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
68                     INST(44U, Opcode::LoadAndInitClass).ref().Inputs(2U).TypeId(68U);
69                     INST(3U, Opcode::NewArray).ref().Inputs(44U, 0U, 2U);
70                     INST(4U, Opcode::NOP);
71                     INST(5U, Opcode::LoadArray).s32().Inputs(3U, 1U);
72                     INST(6U, Opcode::Return).s32().Inputs(5U);
73                 }
74             }
75         } else {
76             GRAPH(graph2)
77             {
78                 CONSTANT(0U, arrayLen);
79                 CONSTANT(1U, index);
80                 BASIC_BLOCK(2U, 1U)
81                 {
82                     INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
83                     INST(44U, Opcode::LoadAndInitClass).ref().Inputs(2U).TypeId(68U);
84                     INST(3U, Opcode::NewArray).ref().Inputs(44U, 0U, 2U);
85                     INST(4U, Opcode::Deoptimize).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(2U);
86                 }
87             }
88         }
89         ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
90     }
91 
92     enum AppliedType { NOT_APPLIED, REMOVED, REPLACED };
93 
ArithmeticTestInput(int32_t index,int32_t arrayLen,Opcode opc,int32_t val)94     Graph *ArithmeticTestInput(int32_t index, int32_t arrayLen, Opcode opc, int32_t val)
95     {
96         auto graph = CreateEmptyGraph();
97         GRAPH(graph)
98         {
99             CONSTANT(0U, arrayLen);
100             CONSTANT(1U, index);
101             CONSTANT(2U, val);
102             BASIC_BLOCK(2U, 1U)
103             {
104                 INST(3U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
105                 INST(44U, Opcode::LoadAndInitClass).ref().Inputs(3U).TypeId(68U);
106                 INST(4U, Opcode::NewArray).ref().Inputs(44U, 0U, 3U);
107                 INST(5U, opc).s32().Inputs(1U, 2U);
108                 INST(6U, Opcode::BoundsCheck).s32().Inputs(0U, 5U, 3U);
109                 INST(7U, Opcode::LoadArray).s32().Inputs(4U, 6U);
110                 INST(8U, Opcode::Return).s32().Inputs(7U);
111             }
112         }
113         return graph;
114     }
115 
ArithmeticTestOutput1(int32_t index,int32_t arrayLen,Opcode opc,int32_t val)116     Graph *ArithmeticTestOutput1(int32_t index, int32_t arrayLen, Opcode opc, int32_t val)
117     {
118         auto graph = CreateEmptyGraph();
119 
120         GRAPH(graph)
121         {
122             CONSTANT(0U, arrayLen);
123             CONSTANT(1U, index);
124             CONSTANT(2U, val);
125             BASIC_BLOCK(2U, 1U)
126             {
127                 INST(3U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
128                 INST(44U, Opcode::LoadAndInitClass).ref().Inputs(3U).TypeId(68U);
129                 INST(4U, Opcode::NewArray).ref().Inputs(44U, 0U, 3U);
130                 INST(5U, opc).s32().Inputs(1U, 2U);
131                 INST(6U, Opcode::NOP);
132                 INST(7U, Opcode::LoadArray).s32().Inputs(4U, 5U);
133                 INST(8U, Opcode::Return).s32().Inputs(7U);
134             }
135         }
136 
137         return graph;
138     }
139 
ArithmeticTestOutput2(int32_t index,int32_t arrayLen,Opcode opc,int32_t val)140     Graph *ArithmeticTestOutput2(int32_t index, int32_t arrayLen, Opcode opc, int32_t val)
141     {
142         auto graph = CreateEmptyGraph();
143 
144         GRAPH(graph)
145         {
146             CONSTANT(0U, arrayLen);
147             CONSTANT(1U, index);
148             CONSTANT(2U, val);
149             BASIC_BLOCK(2U, 1U)
150             {
151                 INST(3U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
152                 INST(44U, Opcode::LoadAndInitClass).ref().Inputs(3U).TypeId(68U);
153                 INST(4U, Opcode::NewArray).ref().Inputs(44U, 0U, 3U);
154                 INST(5U, opc).s32().Inputs(1U, 2U);
155                 INST(6U, Opcode::Deoptimize).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(3U);
156             }
157         }
158         return graph;
159     }
160 
161     template <AppliedType APPLIED_TYPE>
ArithmeticTest(int32_t index,int32_t arrayLen,Opcode opc,int32_t val)162     void ArithmeticTest(int32_t index, int32_t arrayLen, Opcode opc, int32_t val)
163     {
164         auto graph1 = ArithmeticTestInput(index, arrayLen, opc, val);
165         auto clone = GraphCloner(graph1, graph1->GetAllocator(), graph1->GetLocalAllocator()).CloneGraph();
166         bool result = graph1->RunPass<ChecksElimination>();
167         Graph *graph2 = nullptr;
168         if constexpr (APPLIED_TYPE == AppliedType::REMOVED) {
169             graph2 = ArithmeticTestOutput1(index, arrayLen, opc, val);
170             ASSERT_TRUE(result);
171         } else if constexpr (APPLIED_TYPE == AppliedType::REPLACED) {
172             graph2 = ArithmeticTestOutput2(index, arrayLen, opc, val);
173             ASSERT_TRUE(result);
174         } else {
175             ASSERT_FALSE(result);
176         }
177         ASSERT_TRUE(GraphComparator().Compare(graph1, (APPLIED_TYPE == AppliedType::NOT_APPLIED) ? clone : graph2));
178     }
179 
ModTestInput(int32_t arrayLen,int32_t mod)180     Graph *ModTestInput(int32_t arrayLen, int32_t mod)
181     {
182         auto graph = CreateEmptyGraph();
183 
184         GRAPH(graph)
185         {
186             CONSTANT(0U, arrayLen);
187             CONSTANT(1U, mod);
188             CONSTANT(12U, 0U);
189             PARAMETER(2U, 0U).s32();
190             BASIC_BLOCK(2U, 3U, 4U)
191             {
192                 INST(10U, Opcode::Compare).b().CC(CC_GE).SrcType(DataType::Type::INT32).Inputs(2U, 12U);
193                 INST(11U, Opcode::IfImm).SrcType(compiler::DataType::BOOL).CC(compiler::CC_NE).Imm(0U).Inputs(10U);
194             }
195             BASIC_BLOCK(3U, 1U)
196             {
197                 INST(3U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
198                 INST(44U, Opcode::LoadAndInitClass).ref().Inputs(3U).TypeId(68U);
199                 INST(4U, Opcode::NewArray).ref().Inputs(44U, 0U, 3U);
200                 INST(5U, Opcode::Mod).s32().Inputs(2U, 1U);
201                 INST(6U, Opcode::BoundsCheck).s32().Inputs(0U, 5U, 3U);
202                 INST(7U, Opcode::LoadArray).s32().Inputs(4U, 6U);
203                 INST(8U, Opcode::Return).s32().Inputs(7U);
204             }
205             BASIC_BLOCK(4U, 1U)
206             {
207                 INST(9U, Opcode::Return).s32().Inputs(1U);
208             }
209         }
210 
211         return graph;
212     }
213 
ModTestOutput(int32_t arrayLen,int32_t mod)214     Graph *ModTestOutput(int32_t arrayLen, int32_t mod)
215     {
216         auto graph = CreateEmptyGraph();
217 
218         GRAPH(graph)
219         {
220             CONSTANT(0U, arrayLen);
221             CONSTANT(1U, mod);
222             CONSTANT(12U, 0U);
223             PARAMETER(2U, 0U).s32();
224             BASIC_BLOCK(2U, 3U, 4U)
225             {
226                 INST(10U, Opcode::Compare).b().CC(CC_GE).SrcType(DataType::Type::INT32).Inputs(2U, 12U);
227                 INST(11U, Opcode::IfImm).SrcType(compiler::DataType::BOOL).CC(compiler::CC_NE).Imm(0U).Inputs(10U);
228             }
229             BASIC_BLOCK(3U, 1U)
230             {
231                 INST(3U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
232                 INST(44U, Opcode::LoadAndInitClass).ref().Inputs(3U).TypeId(68U);
233                 INST(4U, Opcode::NewArray).ref().Inputs(44U, 0U, 3U);
234                 INST(5U, Opcode::Mod).s32().Inputs(2U, 1U);
235                 INST(6U, Opcode::NOP);
236                 INST(7U, Opcode::LoadArray).s32().Inputs(4U, 5U);
237                 INST(8U, Opcode::Return).s32().Inputs(7U);
238             }
239             BASIC_BLOCK(4U, 1U)
240             {
241                 INST(9U, Opcode::Return).s32().Inputs(1U);
242             }
243         }
244         return graph;
245     }
246 
247     template <bool IS_APPLIED>
ModTest(int32_t arrayLen,int32_t mod)248     void ModTest(int32_t arrayLen, int32_t mod)
249     {
250         auto graph1 = ModTestInput(arrayLen, mod);
251 
252         Graph *graph2 = nullptr;
253         if constexpr (IS_APPLIED) {
254             graph2 = ModTestOutput(arrayLen, mod);
255         } else {
256             graph2 = GraphCloner(graph1, graph1->GetAllocator(), graph1->GetLocalAllocator()).CloneGraph();
257         }
258         graph1->RunPass<ChecksElimination>();
259         ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
260     }
261 
PhiTestInput(int32_t index,int32_t lenArray,int32_t mod)262     Graph *PhiTestInput(int32_t index, int32_t lenArray, int32_t mod)
263     {
264         auto graph = CreateEmptyGraph();
265 
266         GRAPH(graph)
267         {
268             PARAMETER(0U, 0U).b();
269             PARAMETER(1U, 1U).s32();
270             CONSTANT(2U, lenArray);  // len array
271             CONSTANT(3U, index);     // index 2
272             CONSTANT(12U, mod);
273             CONSTANT(13U, 0U);
274             BASIC_BLOCK(11U, 2U, 5U)
275             {
276                 INST(41U, Opcode::Compare).b().CC(CC_GE).SrcType(DataType::Type::INT32).Inputs(1U, 13U);
277                 INST(42U, Opcode::IfImm).SrcType(compiler::DataType::BOOL).CC(compiler::CC_NE).Imm(0U).Inputs(41U);
278             }
279             BASIC_BLOCK(2U, 3U, 4U)
280             {
281                 INST(43U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
282                 INST(44U, Opcode::LoadAndInitClass).ref().Inputs().TypeId(68U);
283                 INST(4U, Opcode::NewArray).ref().Inputs(44U, 2U, 43U);
284                 INST(5U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(0U);
285             }
286             BASIC_BLOCK(3U, 4U)
287             {
288                 INST(6U, Opcode::Mod).s32().Inputs(1U, 12U);
289             }
290             BASIC_BLOCK(4U, -1)
291             {
292                 INST(7U, Opcode::Phi).s32().Inputs(3U, 6U);
293                 INST(8U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U, 4U).SrcVregs({0U, 1U, 2U, 3U, 4U});
294                 INST(9U, Opcode::BoundsCheck).s32().Inputs(2U, 7U, 8U);
295                 INST(10U, Opcode::LoadArray).s32().Inputs(4U, 9U);
296                 INST(11U, Opcode::Return).s32().Inputs(10U);
297             }
298             BASIC_BLOCK(5U, -1)
299             {
300                 INST(19U, Opcode::Return).s32().Inputs(1U);
301             }
302         }
303 
304         return graph;
305     }
PhiTestOutput1(int32_t index,int32_t lenArray,int32_t mod)306     Graph *PhiTestOutput1(int32_t index, int32_t lenArray, int32_t mod)
307     {
308         auto graph = CreateEmptyGraph();
309 
310         GRAPH(graph)
311         {
312             PARAMETER(0U, 0U).b();
313             PARAMETER(1U, 1U).s32();  // index 1
314             CONSTANT(2U, lenArray);   // len array
315             CONSTANT(3U, index);      // index 2
316             CONSTANT(12U, mod);
317             CONSTANT(13U, 0U);
318             BASIC_BLOCK(11U, 2U, 5U)
319             {
320                 INST(41U, Opcode::Compare).b().CC(CC_GE).SrcType(DataType::Type::INT32).Inputs(1U, 13U);
321                 INST(42U, Opcode::IfImm).SrcType(compiler::DataType::BOOL).CC(compiler::CC_NE).Imm(0U).Inputs(41U);
322             }
323             BASIC_BLOCK(2U, 3U, 4U)
324             {
325                 INST(43U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
326                 INST(44U, Opcode::LoadAndInitClass).ref().Inputs().TypeId(68U);
327                 INST(4U, Opcode::NewArray).ref().Inputs(44U, 2U, 43U);
328                 INST(5U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(0U);
329             }
330             BASIC_BLOCK(3U, 4U)
331             {
332                 INST(6U, Opcode::Mod).s32().Inputs(1U, 12U);
333             }
334             BASIC_BLOCK(4U, -1)
335             {
336                 INST(7U, Opcode::Phi).s32().Inputs(3U, 6U);
337                 INST(8U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U, 4U).SrcVregs({0U, 1U, 2U, 3U, 4U});
338                 INST(9U, Opcode::NOP);
339                 INST(10U, Opcode::LoadArray).s32().Inputs(4U, 7U);
340                 INST(11U, Opcode::Return).s32().Inputs(10U);
341             }
342             BASIC_BLOCK(5U, -1)
343             {
344                 INST(19U, Opcode::Return).s32().Inputs(1U);
345             }
346         }
347 
348         return graph;
349     }
350 
351     template <bool IS_APPLIED>
PhiTest(int32_t index,int32_t lenArray,int32_t mod)352     void PhiTest(int32_t index, int32_t lenArray, int32_t mod)
353     {
354         auto graph1 = PhiTestInput(index, lenArray, mod);
355         [[maybe_unused]] Graph *graph2 = nullptr;
356         if constexpr (IS_APPLIED) {
357             ASSERT_TRUE(graph1->RunPass<ChecksElimination>());
358             graph2 = PhiTestOutput1(index, lenArray, mod);
359         } else {
360             ASSERT_FALSE(graph1->RunPass<ChecksElimination>());
361             graph2 = PhiTestInput(index, lenArray, mod);
362         }
363         ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
364     }
365 
366     void BuildHoistRefTypeCheckGraph();
367     void BuildHoistCheckCastGraph();
368     Graph *BuildGraphLoopWithUnknowLowerUpperValueDown(ConditionCode cc);
369     void BuildGraphNullCheckTest3();
370     void BuildGraphNullCheckTest4();
371     void BuildGraphHoistNegativeCheckTest();
372     void BuildGraphHoistZeroCheckTest();
373     void BuildGraphIfTestTrueBlock();
374     void BuildGraphIfTestFalseBlock();
375     void BuildGraphIfTestTrueBlock1();
376     void BuildGraphIfTestTrueBlock2();
377     void BuildGraphIfTestTrueBlock3();
378     void BuildGraphIfTestFalseBlock1();
379     void BuildGraphIfTestFalseBlock2();
380     void BuildGraphIfTestFalseBlock3();
381     void BuildGraphSimpleLoopTestInc();
382     void BuildGraphSimpleLoopTestIncAfterPeeling();
383     void BuildGraphSimpleLoopTestIncAfterPeeling1();
384     void BuildGraphSimpleLoopTestDec();
385     void BuildGraphLoopWithUnknowLowerUpperValue();
386     void BuildGraphUpperOOB();
387     void BuildGraphUpperWithDec();
388     void BuildGraphUnknownUpperWithDec();
389     void BuildGraphLoopWithUnknowLowerValue();
390     void BuildGraphLoopWithUnknowUpperValueLE();
391     void BuildGraphLoopWithUnknowUpperValueLT();
392     void BuildGraphLoopSeveralBoundsChecks();
393     void BuildGraphLoopSeveralIndexesBoundsChecks();
394     void BuildGraphHeadExitLoop();
395     void BuildGraphLoopTest1();
396     void BuildGraphBatchLoopTest();
397     void BuildGraphGroupedBoundsCheck();
398     void BuildGraphGroupedBoundsCheckConstIndex();
399     void BuildGraphRefTypeCheck();
400     void BuildGraphRefTypeCheckFirstNullCheckEliminated();
401     void BuildGraphBugWithNullCheck();
402     void BuildGraphNullAndBoundsChecksNestedLoop();
403     void BuildGraphLoopWithTwoPhi();
404     void BuildGraphLoopWithBigStepGE();
405     void BuildGraphLoopWithBigStepLE();
406     void BuildGraphLoopWithBigStepLT();
407     void BuildGraphLoopWithBoundsCheckUnderIfGE();
408     void BuildGraphLoopWithBoundsCheckUnderIfLT();
409     void BuildGraphCheckCastAfterIsInstance();
410     void BuildGraphOverflowCheckOptimize();
411 
412 private:
413     Graph *graph_ {nullptr};
414 };
415 
TEST_F(ChecksEliminationTest,NullCheckTest)416 TEST_F(ChecksEliminationTest, NullCheckTest)
417 {
418     // Check Elimination for NullCheck is applied.
419     GRAPH(GetGraph())
420     {
421         PARAMETER(0U, 0U).ref();
422         CONSTANT(1U, 10U);
423         BASIC_BLOCK(2U, 1U)
424         {
425             INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
426             INST(3U, Opcode::NullCheck).ref().Inputs(0U, 2U);
427             INST(4U, Opcode::LoadArray).s32().Inputs(3U, 1U);
428             INST(5U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
429             INST(6U, Opcode::NullCheck).ref().Inputs(0U, 5U);
430             INST(7U, Opcode::StoreArray).s32().Inputs(6U, 1U, 4U);
431             INST(8U, Opcode::Return).s32().Inputs(4U);
432         }
433     }
434     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
435     auto graph = CreateEmptyGraph();
436     GRAPH(graph)
437     {
438         PARAMETER(0U, 0U).ref();
439         CONSTANT(1U, 10U);
440         BASIC_BLOCK(2U, 1U)
441         {
442             INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
443             INST(3U, Opcode::NullCheck).ref().Inputs(0U, 2U);
444             INST(4U, Opcode::LoadArray).s32().Inputs(3U, 1U);
445             INST(5U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
446             INST(6U, Opcode::NOP);
447             INST(7U, Opcode::StoreArray).s32().Inputs(3U, 1U, 4U);
448             INST(8U, Opcode::Return).s32().Inputs(4U);
449         }
450     }
451     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
452 }
453 
TEST_F(ChecksEliminationTest,NullCheckTest1)454 TEST_F(ChecksEliminationTest, NullCheckTest1)
455 {
456     // Check Elimination for NullCheck isn't applied. Different inputs in NullCheck insts.
457     GRAPH(GetGraph())
458     {
459         PARAMETER(0U, 0U).ref();
460         PARAMETER(1U, 1U).ref();
461         CONSTANT(2U, 10U);
462 
463         BASIC_BLOCK(2U, 1U)
464         {
465             INST(3U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
466             INST(4U, Opcode::NullCheck).ref().Inputs(0U, 3U);
467             INST(5U, Opcode::LoadArray).s32().Inputs(4U, 2U);
468             INST(6U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
469             INST(7U, Opcode::NullCheck).ref().Inputs(1U, 6U);
470             INST(8U, Opcode::StoreArray).s32().Inputs(7U, 2U, 5U);
471             INST(9U, Opcode::Return).s32().Inputs(5U);
472         }
473     }
474     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
475     ASSERT_FALSE(GetGraph()->RunPass<ChecksElimination>());
476     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
477 }
478 
TEST_F(ChecksEliminationTest,NullCheckTest2)479 TEST_F(ChecksEliminationTest, NullCheckTest2)
480 {
481     // Check Elimination for NullCheck isn't applied. NullCheck(5) isn't dominator of NullCheck(8).
482     GRAPH(GetGraph())
483     {
484         PARAMETER(0U, 0U).ref();
485         CONSTANT(1U, 10U);
486 
487         BASIC_BLOCK(2U, 3U, 4U)
488         {
489             INST(2U, Opcode::Compare).b().SrcType(DataType::Type::INT64).Inputs(1U, 1U);
490             INST(3U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(2U);
491         }
492 
493         BASIC_BLOCK(3U, 5U)
494         {
495             INST(4U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
496             INST(5U, Opcode::NullCheck).ref().Inputs(0U, 4U);
497             INST(6U, Opcode::LoadArray).s32().Inputs(5U, 1U);
498         }
499 
500         BASIC_BLOCK(4U, 5U)
501         {
502             INST(7U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
503             INST(8U, Opcode::NullCheck).ref().Inputs(0U, 7U);
504             INST(9U, Opcode::LoadArray).s32().Inputs(8U, 1U);
505         }
506 
507         BASIC_BLOCK(5U, 1U)
508         {
509             INST(10U, Opcode::Phi).s32().Inputs(6U, 9U);
510             INST(11U, Opcode::Return).s32().Inputs(10U);
511         }
512     }
513     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
514     ASSERT_FALSE(GetGraph()->RunPass<ChecksElimination>());
515     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
516 }
517 
BuildGraphNullCheckTest3()518 void ChecksEliminationTest::BuildGraphNullCheckTest3()
519 {
520     GRAPH(GetGraph())
521     {
522         CONSTANT(0U, 0U);  // initial
523         CONSTANT(1U, 1U);  // increment
524         CONSTANT(2U, 10U);
525         PARAMETER(3U, 0U).ref();
526         BASIC_BLOCK(2U, 3U, 5U)
527         {
528             INST(16U, Opcode::LenArray).s32().Inputs(3U);
529             INST(20U, Opcode::SaveStateDeoptimize).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
530             INST(5U, Opcode::Compare).SrcType(DataType::INT32).CC(CC_LT).b().Inputs(0U, 2U);  // 0 < 10
531             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
532         }
533         BASIC_BLOCK(3U, 3U, 5U)
534         {
535             INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);
536             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
537             INST(15U, Opcode::NullCheck).ref().Inputs(3U, 7U);
538             INST(8U, Opcode::BoundsCheck).s32().Inputs(16U, 4U, 7U);
539             INST(9U, Opcode::StoreArray).s32().Inputs(15U, 8U, 0U);    // a[i] = 0
540             INST(10U, Opcode::Add).s32().Inputs(4U, 1U);               // i++
541             INST(13U, Opcode::Compare).CC(CC_LT).b().Inputs(10U, 2U);  // i < 10
542             INST(14U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(13U);
543         }
544         BASIC_BLOCK(5U, 1U)
545         {
546             INST(12U, Opcode::Return).ref().Inputs(3U);
547         }
548     }
549 }
550 
TEST_F(ChecksEliminationTest,NullCheckTest3)551 TEST_F(ChecksEliminationTest, NullCheckTest3)
552 {
553     BuildGraphNullCheckTest3();
554     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
555     auto graph = CreateEmptyGraph();
556     GRAPH(graph)
557     {
558         CONSTANT(0U, 0U);  // initial
559         CONSTANT(1U, 1U);  // increment
560         CONSTANT(2U, 10U);
561         PARAMETER(3U, 0U).ref();
562         BASIC_BLOCK(2U, 3U, 5U)
563         {
564             INST(16U, Opcode::LenArray).s32().Inputs(3U);
565             INST(20U, Opcode::SaveStateDeoptimize).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
566             INST(19U, Opcode::NullCheck).ref().Inputs(3U, 20U).SetFlag(inst_flags::CAN_DEOPTIMIZE);
567             INST(23U, Opcode::Compare).SrcType(DataType::INT32).CC(CC_LT).b().Inputs(16U, 2U);  // len_array < 10
568             INST(24U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(23U, 20U);
569             INST(5U, Opcode::Compare).SrcType(DataType::INT32).CC(CC_LT).b().Inputs(0U, 2U);  // 0 < 10
570             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
571         }
572         BASIC_BLOCK(3U, 3U, 5U)
573         {
574             INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);
575             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
576             INST(8U, Opcode::NOP);
577             INST(9U, Opcode::StoreArray).s32().Inputs(19U, 4U, 0U);    // a[i] = 0
578             INST(10U, Opcode::Add).s32().Inputs(4U, 1U);               // i++
579             INST(13U, Opcode::Compare).CC(CC_LT).b().Inputs(10U, 2U);  // i < 10
580             INST(14U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(13U);
581         }
582         BASIC_BLOCK(5U, 1U)
583         {
584             INST(12U, Opcode::Return).ref().Inputs(3U);
585         }
586     }
587     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
588 }
589 
BuildGraphNullCheckTest4()590 void ChecksEliminationTest::BuildGraphNullCheckTest4()
591 {
592     GRAPH(GetGraph())
593     {
594         CONSTANT(0U, 0U);  // initial
595         CONSTANT(1U, 1U);  // increment
596         CONSTANT(2U, 10U);
597         CONSTANT(3U, nullptr);
598         BASIC_BLOCK(2U, 3U, 5U)
599         {
600             INST(20U, Opcode::SaveStateDeoptimize).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
601             INST(5U, Opcode::Compare).SrcType(DataType::INT32).CC(CC_LT).b().Inputs(0U, 2U);  // 0 < 10
602             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
603         }
604         BASIC_BLOCK(3U, 3U, 5U)
605         {
606             INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);
607             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
608             INST(15U, Opcode::NullCheck).ref().Inputs(3U, 7U);
609             INST(9U, Opcode::StoreArray).s32().Inputs(15U, 4U, 0U);    // a[i] = 0
610             INST(10U, Opcode::Add).s32().Inputs(4U, 1U);               // i++
611             INST(13U, Opcode::Compare).CC(CC_LT).b().Inputs(10U, 2U);  // i < 10
612             INST(14U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(13U);
613         }
614         BASIC_BLOCK(5U, 1U)
615         {
616             INST(12U, Opcode::Return).ref().Inputs(3U);
617         }
618     }
619 }
620 
TEST_F(ChecksEliminationTest,NullCheckTest4)621 TEST_F(ChecksEliminationTest, NullCheckTest4)
622 {
623     BuildGraphNullCheckTest4();
624     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
625     auto graph = CreateEmptyGraph();
626     GRAPH(graph)
627     {
628         CONSTANT(0U, 0U);  // initial
629         CONSTANT(1U, 1U);  // increment
630         CONSTANT(2U, 10U);
631         CONSTANT(3U, nullptr);
632         BASIC_BLOCK(2U, 3U, 5U)
633         {
634             INST(20U, Opcode::SaveStateDeoptimize).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
635             INST(5U, Opcode::Compare).SrcType(DataType::INT32).CC(CC_LT).b().Inputs(0U, 2U);  // 0 < 10
636             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
637         }
638         BASIC_BLOCK(3U, 1U)
639         {
640             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
641             INST(15U, Opcode::Deoptimize).DeoptimizeType(DeoptimizeType::NULL_CHECK).Inputs(7U);
642         }
643         BASIC_BLOCK(5U, 1U)
644         {
645             INST(12U, Opcode::Return).ref().Inputs(3U);
646         }
647     }
648     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
649 }
650 
TEST_F(ChecksEliminationTest,NegativeCheckTest)651 TEST_F(ChecksEliminationTest, NegativeCheckTest)
652 {
653     // Check Elimination for NegativeCheck is applied.
654     GRAPH(GetGraph())
655     {
656         CONSTANT(0U, 10U);
657         BASIC_BLOCK(2U, 1U)
658         {
659             INST(1U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
660             INST(2U, Opcode::NegativeCheck).s32().Inputs(0U, 1U);
661             INST(44U, Opcode::LoadAndInitClass).ref().Inputs(1U).TypeId(68U);
662             INST(3U, Opcode::NewArray).ref().Inputs(44U, 0U, 1U);
663             INST(4U, Opcode::Return).ref().Inputs(3U);
664         }
665     }
666     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
667     auto graph = CreateEmptyGraph();
668     GRAPH(graph)
669     {
670         CONSTANT(0U, 10U);
671         BASIC_BLOCK(2U, 1U)
672         {
673             INST(1U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
674             INST(2U, Opcode::NOP);
675             INST(44U, Opcode::LoadAndInitClass).ref().Inputs(1U).TypeId(68U);
676             INST(3U, Opcode::NewArray).ref().Inputs(44U, 0U, 1U);
677             INST(4U, Opcode::Return).ref().Inputs(3U);
678         }
679     }
680     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
681 }
682 
TEST_F(ChecksEliminationTest,NegativeCheckTestZero)683 TEST_F(ChecksEliminationTest, NegativeCheckTestZero)
684 {
685     // Check Elimination for NegativeCheck is applied.
686     GRAPH(GetGraph())
687     {
688         CONSTANT(0U, 0U);
689         BASIC_BLOCK(2U, 1U)
690         {
691             INST(1U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
692             INST(2U, Opcode::NegativeCheck).s32().Inputs(0U, 1U);
693             INST(44U, Opcode::LoadAndInitClass).ref().Inputs(1U).TypeId(68U);
694             INST(3U, Opcode::NewArray).ref().Inputs(44U, 2U, 1U);
695             INST(4U, Opcode::Return).ref().Inputs(3U);
696         }
697     }
698     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
699     auto graph = CreateEmptyGraph();
700     GRAPH(graph)
701     {
702         CONSTANT(0U, 0U);
703         BASIC_BLOCK(2U, 1U)
704         {
705             INST(1U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
706             INST(2U, Opcode::NOP);
707             INST(44U, Opcode::LoadAndInitClass).ref().Inputs(1U).TypeId(68U);
708             INST(3U, Opcode::NewArray).ref().Inputs(44U, 0U, 1U);
709             INST(4U, Opcode::Return).ref().Inputs(3U);
710         }
711     }
712     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
713 }
714 
TEST_F(ChecksEliminationTest,NegativeCheckTest1)715 TEST_F(ChecksEliminationTest, NegativeCheckTest1)
716 {
717     // Check Elimination for NegativeCheck is applied. Negative constant.
718     // Check replaced by deoptimize
719     GRAPH(GetGraph())
720     {
721         CONSTANT(0U, -5L);
722         BASIC_BLOCK(2U, 1U)
723         {
724             INST(1U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
725             INST(2U, Opcode::NegativeCheck).s32().Inputs(0U, 1U);
726             INST(44U, Opcode::LoadAndInitClass).ref().Inputs(1U).TypeId(68U);
727             INST(3U, Opcode::NewArray).ref().Inputs(44U, 2U, 1U);
728             INST(4U, Opcode::Return).ref().Inputs(3U);
729         }
730     }
731     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
732     auto graph = CreateEmptyGraph();
733     GRAPH(graph)
734     {
735         CONSTANT(0U, -5L);
736         BASIC_BLOCK(2U, 1U)
737         {
738             INST(1U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
739             INST(2U, Opcode::Deoptimize).DeoptimizeType(DeoptimizeType::NEGATIVE_CHECK).Inputs(1U);
740         }
741     }
742     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
743 }
744 
TEST_F(ChecksEliminationTest,NegativeCheckTest3)745 TEST_F(ChecksEliminationTest, NegativeCheckTest3)
746 {
747     // Check Elimination for NegativeCheck is applied. Positiv value.
748     GRAPH(GetGraph())
749     {
750         CONSTANT(0U, -5L);
751         BASIC_BLOCK(2U, 1U)
752         {
753             INST(5U, Opcode::Neg).s32().Inputs(0U);
754             INST(1U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
755             INST(2U, Opcode::NegativeCheck).s32().Inputs(5U, 1U);
756             INST(44U, Opcode::LoadAndInitClass).ref().Inputs(1U).TypeId(68U);
757             INST(3U, Opcode::NewArray).ref().Inputs(44U, 2U, 1U);
758             INST(4U, Opcode::Return).ref().Inputs(3U);
759         }
760     }
761     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
762     auto graph = CreateEmptyGraph();
763     GRAPH(graph)
764     {
765         CONSTANT(0U, -5L);
766         BASIC_BLOCK(2U, 1U)
767         {
768             INST(5U, Opcode::Neg).s32().Inputs(0U);
769             INST(1U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
770             INST(2U, Opcode::NOP);
771             INST(44U, Opcode::LoadAndInitClass).ref().Inputs(1U).TypeId(68U);
772             INST(3U, Opcode::NewArray).ref().Inputs(44U, 5U, 1U);
773             INST(4U, Opcode::Return).ref().Inputs(3U);
774         }
775     }
776     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
777 }
778 
TEST_F(ChecksEliminationTest,NegativeCheckTest4)779 TEST_F(ChecksEliminationTest, NegativeCheckTest4)
780 {
781     // Check Elimination for NegativeCheck is applied. Negative value.
782     // Check replaced by deoptimize
783     GRAPH(GetGraph())
784     {
785         CONSTANT(0U, 5U);
786         BASIC_BLOCK(2U, 1U)
787         {
788             INST(5U, Opcode::Neg).s32().Inputs(0U);
789             INST(1U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
790             INST(2U, Opcode::NegativeCheck).s32().Inputs(5U, 1U);
791             INST(44U, Opcode::LoadAndInitClass).ref().Inputs(1U).TypeId(68U);
792             INST(3U, Opcode::NewArray).ref().Inputs(44U, 2U, 1U);
793             INST(4U, Opcode::Return).ref().Inputs(3U);
794         }
795     }
796     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
797     auto graph = CreateEmptyGraph();
798     GRAPH(graph)
799     {
800         CONSTANT(0U, 5U);
801         BASIC_BLOCK(2U, 1U)
802         {
803             INST(5U, Opcode::Neg).s32().Inputs(0U);
804             INST(1U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
805             INST(2U, Opcode::Deoptimize).DeoptimizeType(DeoptimizeType::NEGATIVE_CHECK).Inputs(1U);
806         }
807     }
808     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
809 }
810 
BuildGraphHoistNegativeCheckTest()811 void ChecksEliminationTest::BuildGraphHoistNegativeCheckTest()
812 {
813     GRAPH(GetGraph())
814     {
815         CONSTANT(0U, 0U);  // initial
816         CONSTANT(1U, 1U);  // increment
817         CONSTANT(2U, 10U);
818         PARAMETER(3U, 0U).s32();
819         BASIC_BLOCK(2U, 3U, 5U)
820         {
821             INST(20U, Opcode::SaveStateDeoptimize).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
822             INST(5U, Opcode::Compare).SrcType(DataType::INT32).CC(CC_LT).b().Inputs(0U, 2U);  // 0 < 10
823             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
824         }
825         BASIC_BLOCK(3U, 3U, 5U)
826         {
827             INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);
828             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
829             INST(8U, Opcode::NegativeCheck).s32().Inputs(3U, 7U);
830             INST(9U, Opcode::LoadAndInitClass).ref().Inputs(7U).TypeId(68U);
831             INST(11U, Opcode::NewArray).ref().Inputs(9U, 8U, 7U);
832             INST(10U, Opcode::Add).s32().Inputs(4U, 1U);               // i++
833             INST(13U, Opcode::Compare).CC(CC_LT).b().Inputs(10U, 2U);  // i < 10
834             INST(14U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(13U);
835         }
836         BASIC_BLOCK(5U, 1U)
837         {
838             INST(12U, Opcode::ReturnVoid).v0id();
839         }
840     }
841 }
842 
TEST_F(ChecksEliminationTest,HoistNegativeCheckTest)843 TEST_F(ChecksEliminationTest, HoistNegativeCheckTest)
844 {
845     BuildGraphHoistNegativeCheckTest();
846     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
847     auto graph = CreateEmptyGraph();
848     GRAPH(graph)
849     {
850         CONSTANT(0U, 0U);  // initial
851         CONSTANT(1U, 1U);  // increment
852         CONSTANT(2U, 10U);
853         PARAMETER(3U, 0U).s32();
854         BASIC_BLOCK(2U, 3U, 5U)
855         {
856             INST(20U, Opcode::SaveStateDeoptimize).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
857             INST(22U, Opcode::NegativeCheck).s32().Inputs(3U, 20U).SetFlag(inst_flags::CAN_DEOPTIMIZE);
858             INST(5U, Opcode::Compare).SrcType(DataType::INT32).CC(CC_LT).b().Inputs(0U, 2U);  // 0 < 10
859             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
860         }
861         BASIC_BLOCK(3U, 3U, 5U)
862         {
863             INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);
864             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
865             INST(9U, Opcode::LoadAndInitClass).ref().Inputs(7U).TypeId(68U);
866             INST(11U, Opcode::NewArray).ref().Inputs(9U, 22U, 7U);
867             INST(10U, Opcode::Add).s32().Inputs(4U, 1U);               // i++
868             INST(13U, Opcode::Compare).CC(CC_LT).b().Inputs(10U, 2U);  // i < 10
869             INST(14U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(13U);
870         }
871         BASIC_BLOCK(5U, 1U)
872         {
873             INST(12U, Opcode::ReturnVoid).v0id();
874         }
875     }
876     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
877 }
878 
TEST_F(ChecksEliminationTest,ZeroCheckTest)879 TEST_F(ChecksEliminationTest, ZeroCheckTest)
880 {
881     // Check Elimination for ZeroCheck is applied.
882     GRAPH(GetGraph())
883     {
884         CONSTANT(0U, 10U);
885         CONSTANT(1U, 12U);
886         BASIC_BLOCK(2U, 1U)
887         {
888             INST(2U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
889             INST(3U, Opcode::ZeroCheck).s32().Inputs(1U, 2U);
890             INST(4U, Opcode::Div).s32().Inputs(0U, 3U);
891             INST(5U, Opcode::Return).s32().Inputs(4U);
892         }
893     }
894     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
895     auto graph = CreateEmptyGraph();
896     GRAPH(graph)
897     {
898         CONSTANT(0U, 10U);
899         CONSTANT(1U, 12U);
900         BASIC_BLOCK(2U, 1U)
901         {
902             INST(2U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
903             INST(3U, Opcode::NOP);
904             INST(4U, Opcode::Div).s32().Inputs(0U, 1U);
905             INST(5U, Opcode::Return).s32().Inputs(4U);
906         }
907     }
908     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
909 }
910 
TEST_F(ChecksEliminationTest,ZeroCheckTestBigConst)911 TEST_F(ChecksEliminationTest, ZeroCheckTestBigConst)
912 {
913     // Check Elimination for ZeroCheck is applied.
914     GRAPH(GetGraph())
915     {
916         CONSTANT(0U, 10U);
917         CONSTANT(1U, 0x8000000000000000U);
918         BASIC_BLOCK(2U, 1U)
919         {
920             INST(2U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
921             INST(3U, Opcode::ZeroCheck).s32().Inputs(1U, 2U);
922             INST(4U, Opcode::Div).s32().Inputs(0U, 3U);
923             INST(5U, Opcode::Return).s32().Inputs(4U);
924         }
925     }
926     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
927     auto graph = CreateEmptyGraph();
928     GRAPH(graph)
929     {
930         CONSTANT(0U, 10U);
931         CONSTANT(1U, 0x8000000000000000U);
932         BASIC_BLOCK(2U, 1U)
933         {
934             INST(2U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
935             INST(3U, Opcode::NOP);
936             INST(4U, Opcode::Div).s32().Inputs(0U, 1U);
937             INST(5U, Opcode::Return).s32().Inputs(4U);
938         }
939     }
940     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
941 }
942 
TEST_F(ChecksEliminationTest,ZeroCheckTest1)943 TEST_F(ChecksEliminationTest, ZeroCheckTest1)
944 {
945     // Check Elimination for ZeroCheck isn't applied. Zero constant.
946     GRAPH(GetGraph())
947     {
948         CONSTANT(0U, 10U);
949         CONSTANT(1U, 0U);
950         BASIC_BLOCK(2U, 1U)
951         {
952             INST(2U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
953             INST(3U, Opcode::ZeroCheck).s32().Inputs(1U, 2U);
954             INST(4U, Opcode::Div).s32().Inputs(0U, 3U);
955             INST(5U, Opcode::Return).s32().Inputs(4U);
956         }
957     }
958     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
959     auto graph = CreateEmptyGraph();
960     GRAPH(graph)
961     {
962         CONSTANT(0U, 10U);
963         CONSTANT(1U, 0U);
964         BASIC_BLOCK(2U, 1U)
965         {
966             INST(2U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
967             INST(3U, Opcode::Deoptimize).DeoptimizeType(DeoptimizeType::ZERO_CHECK).Inputs(2U);
968         }
969     }
970     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
971 }
972 
TEST_F(ChecksEliminationTest,ZeroCheckTest2)973 TEST_F(ChecksEliminationTest, ZeroCheckTest2)
974 {
975     // Check Elimination for ZeroCheck is applied. Positiv value.
976     GRAPH(GetGraph())
977     {
978         CONSTANT(0U, -5L);
979         BASIC_BLOCK(2U, 1U)
980         {
981             INST(5U, Opcode::Abs).s32().Inputs(0U);
982             INST(1U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
983             INST(2U, Opcode::NegativeCheck).s32().Inputs(5U, 1U);
984             INST(44U, Opcode::LoadAndInitClass).ref().Inputs(1U).TypeId(68U);
985             INST(3U, Opcode::NewArray).ref().Inputs(44U, 2U, 1U);
986             INST(4U, Opcode::Return).ref().Inputs(3U);
987         }
988     }
989     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
990     auto graph = CreateEmptyGraph();
991     GRAPH(graph)
992     {
993         CONSTANT(0U, -5L);
994         BASIC_BLOCK(2U, 1U)
995         {
996             INST(5U, Opcode::Abs).s32().Inputs(0U);
997             INST(1U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
998             INST(2U, Opcode::NOP);
999             INST(44U, Opcode::LoadAndInitClass).ref().Inputs(1U).TypeId(68U);
1000             INST(3U, Opcode::NewArray).ref().Inputs(44U, 5U, 1U);
1001             INST(4U, Opcode::Return).ref().Inputs(3U);
1002         }
1003     }
1004     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
1005 }
1006 
TEST_F(ChecksEliminationTest,NegativeZeroCheckTest)1007 TEST_F(ChecksEliminationTest, NegativeZeroCheckTest)
1008 {
1009     // Test with NegativeCheck and ZeroCheck.
1010     GRAPH(GetGraph())
1011     {
1012         CONSTANT(0U, 1U);
1013         CONSTANT(1U, 2U);
1014         BASIC_BLOCK(2U, 1U)
1015         {
1016             INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
1017             INST(3U, Opcode::NegativeCheck).s32().Inputs(0U, 2U);
1018             INST(44U, Opcode::LoadAndInitClass).ref().Inputs(2U).TypeId(68U);
1019             INST(4U, Opcode::NewArray).ref().Inputs(44U, 3U, 2U);
1020             INST(5U, Opcode::ZeroCheck).s32().Inputs(0U, 2U);
1021             INST(6U, Opcode::Div).s32().Inputs(1U, 5U);
1022             INST(7U, Opcode::StoreArray).s32().Inputs(4U, 0U, 6U);
1023             INST(8U, Opcode::Return).ref().Inputs(4U);
1024         }
1025     }
1026     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
1027     auto graph = CreateEmptyGraph();
1028     GRAPH(graph)
1029     {
1030         CONSTANT(0U, 1U);
1031         CONSTANT(1U, 2U);
1032         BASIC_BLOCK(2U, 1U)
1033         {
1034             INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
1035             INST(3U, Opcode::NOP);
1036             INST(44U, Opcode::LoadAndInitClass).ref().Inputs(2U).TypeId(68U);
1037             INST(4U, Opcode::NewArray).ref().Inputs(44U, 0U, 2U);
1038             INST(5U, Opcode::NOP);
1039             INST(6U, Opcode::Div).s32().Inputs(1U, 0U);
1040             INST(7U, Opcode::StoreArray).s32().Inputs(4U, 0U, 6U);
1041             INST(8U, Opcode::Return).ref().Inputs(4U);
1042         }
1043     }
1044     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
1045 }
1046 
BuildGraphHoistZeroCheckTest()1047 void ChecksEliminationTest::BuildGraphHoistZeroCheckTest()
1048 {
1049     {
1050         GRAPH(GetGraph())
1051         {
1052             CONSTANT(0U, 0U);  // initial
1053             CONSTANT(1U, 1U);  // increment
1054             CONSTANT(2U, 10U);
1055             PARAMETER(3U, 0U).s32();
1056             BASIC_BLOCK(2U, 3U, 5U)
1057             {
1058                 INST(20U, Opcode::SaveStateDeoptimize).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
1059                 INST(5U, Opcode::Compare).SrcType(DataType::INT32).CC(CC_LT).b().Inputs(0U, 2U);  // 0 < 10
1060                 INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
1061             }
1062             BASIC_BLOCK(3U, 3U, 5U)
1063             {
1064                 INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);   // i
1065                 INST(16U, Opcode::Phi).s32().Inputs(0U, 15U);  // s
1066                 INST(7U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
1067                 INST(8U, Opcode::ZeroCheck).s32().Inputs(3U, 7U);
1068                 INST(17U, Opcode::Div).s32().Inputs(4U, 8U);
1069                 INST(15U, Opcode::Add).s32().Inputs(16U, 17U);             // s += i / x
1070                 INST(10U, Opcode::Add).s32().Inputs(4U, 1U);               // i++
1071                 INST(13U, Opcode::Compare).CC(CC_LT).b().Inputs(10U, 2U);  // i < 10
1072                 INST(14U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(13U);
1073             }
1074             BASIC_BLOCK(5U, 1U)
1075             {
1076                 INST(18U, Opcode::Phi).s32().Inputs(0U, 16U);
1077                 INST(12U, Opcode::Return).s32().Inputs(18U);
1078             }
1079         }
1080     }
1081 }
TEST_F(ChecksEliminationTest,HoistZeroCheckTest)1082 TEST_F(ChecksEliminationTest, HoistZeroCheckTest)
1083 {
1084     BuildGraphHoistZeroCheckTest();
1085     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
1086     auto graph = CreateEmptyGraph();
1087     GRAPH(graph)
1088     {
1089         CONSTANT(0U, 0U);  // initial
1090         CONSTANT(1U, 1U);  // increment
1091         CONSTANT(2U, 10U);
1092         PARAMETER(3U, 0U).s32();
1093         BASIC_BLOCK(2U, 3U, 5U)
1094         {
1095             INST(20U, Opcode::SaveStateDeoptimize).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
1096             INST(22U, Opcode::ZeroCheck).s32().Inputs(3U, 20U).SetFlag(inst_flags::CAN_DEOPTIMIZE);
1097             INST(5U, Opcode::Compare).SrcType(DataType::INT32).CC(CC_LT).b().Inputs(0U, 2U);  // 0 < 10
1098             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
1099         }
1100         BASIC_BLOCK(3U, 3U, 5U)
1101         {
1102             INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);   // i
1103             INST(16U, Opcode::Phi).s32().Inputs(0U, 15U);  // s
1104             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
1105             INST(17U, Opcode::Div).s32().Inputs(4U, 22U);
1106             INST(15U, Opcode::Add).s32().Inputs(16U, 17U);             // s += i / x
1107             INST(10U, Opcode::Add).s32().Inputs(4U, 1U);               // i++
1108             INST(13U, Opcode::Compare).CC(CC_LT).b().Inputs(10U, 2U);  // i < 10
1109             INST(14U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(13U);
1110         }
1111         BASIC_BLOCK(5U, 1U)
1112         {
1113             INST(18U, Opcode::Phi).s32().Inputs(0U, 16U);
1114             INST(12U, Opcode::Return).s32().Inputs(18U);
1115         }
1116     }
1117     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
1118 }
1119 
TEST_F(ChecksEliminationTest,SimpleBoundsCheckTest)1120 TEST_F(ChecksEliminationTest, SimpleBoundsCheckTest)
1121 {
1122     SimpleTest<true>(2U, 10U);
1123     SimpleTest<true>(9U, 10U);
1124     SimpleTest<true>(0U, 10U);
1125     SimpleTest<false>(10U, 10U);
1126     SimpleTest<false>(12U, 10U);
1127     SimpleTest<false>(-1L, 10U);
1128 }
1129 
TEST_F(ChecksEliminationTest,SimpleBoundsCheckTest1)1130 TEST_F(ChecksEliminationTest, SimpleBoundsCheckTest1)
1131 {
1132     // not applied, we know nothing about len array
1133     GRAPH(GetGraph())
1134     {
1135         PARAMETER(0U, 0U).s32();  // len array
1136         CONSTANT(1U, 5U);
1137         BASIC_BLOCK(2U, 1U)
1138         {
1139             INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
1140             INST(44U, Opcode::LoadAndInitClass).ref().Inputs(2U).TypeId(68U);
1141             INST(3U, Opcode::NewArray).ref().Inputs(44U, 0U, 2U);
1142             INST(4U, Opcode::BoundsCheck).s32().Inputs(0U, 1U, 2U);
1143             INST(5U, Opcode::LoadArray).s32().Inputs(3U, 4U);
1144             INST(6U, Opcode::Return).s32().Inputs(5U);
1145         }
1146     }
1147     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
1148     ASSERT_FALSE(GetGraph()->RunPass<ChecksElimination>());
1149     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
1150 }
1151 
TEST_F(ChecksEliminationTest,SimpleBoundsCheckTest2)1152 TEST_F(ChecksEliminationTest, SimpleBoundsCheckTest2)
1153 {
1154     // not applied, we know nothing about index
1155     GRAPH(GetGraph())
1156     {
1157         CONSTANT(0U, 10U);
1158         PARAMETER(1U, 0U).s32();  // index
1159         BASIC_BLOCK(2U, 1U)
1160         {
1161             INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
1162             INST(44U, Opcode::LoadAndInitClass).ref().Inputs(2U).TypeId(68U);
1163             INST(3U, Opcode::NewArray).ref().Inputs(44U, 0U, 2U);
1164             INST(4U, Opcode::BoundsCheck).s32().Inputs(0U, 1U, 2U);
1165             INST(5U, Opcode::LoadArray).s32().Inputs(3U, 4U);
1166             INST(6U, Opcode::Return).s32().Inputs(5U);
1167         }
1168     }
1169     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
1170     ASSERT_FALSE(GetGraph()->RunPass<ChecksElimination>());
1171     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
1172 }
1173 
TEST_F(ChecksEliminationTest,ArithmeticTest)1174 TEST_F(ChecksEliminationTest, ArithmeticTest)
1175 {
1176     ArithmeticTest<AppliedType::REMOVED>(-1L, 20U, Opcode::Add, 1U);
1177     ArithmeticTest<AppliedType::REMOVED>(-1L, 20U, Opcode::Add, 5U);
1178     ArithmeticTest<AppliedType::REMOVED>(-1L, 20U, Opcode::Add, 20U);
1179     ArithmeticTest<AppliedType::REMOVED>(-100L, 20U, Opcode::Add, 115U);
1180     ArithmeticTest<AppliedType::REPLACED>(-1L, 20U, Opcode::Add, 0U);
1181     ArithmeticTest<AppliedType::REPLACED>(0U, 20U, Opcode::Add, 20U);
1182     ArithmeticTest<AppliedType::REPLACED>(-100L, 20U, Opcode::Add, 5U);
1183     ArithmeticTest<AppliedType::REPLACED>(-100L, 20U, Opcode::Add, 125U);
1184     // overflow
1185     ArithmeticTest<AppliedType::NOT_APPLIED>(INT32_MAX, INT32_MAX, Opcode::Add, 1U);
1186     ArithmeticTest<AppliedType::NOT_APPLIED>(INT32_MIN, INT32_MAX, Opcode::Add, -1L);
1187     ArithmeticTest<AppliedType::NOT_APPLIED>(1U, INT32_MAX, Opcode::Add, INT32_MAX);
1188     ArithmeticTest<AppliedType::NOT_APPLIED>(-1L, INT32_MAX, Opcode::Add, INT32_MIN);
1189 
1190     ArithmeticTest<AppliedType::REMOVED>(20U, 20U, Opcode::Sub, 1U);
1191     ArithmeticTest<AppliedType::REMOVED>(20U, 20U, Opcode::Sub, 5U);
1192     ArithmeticTest<AppliedType::REMOVED>(20U, 20U, Opcode::Sub, 19U);
1193     ArithmeticTest<AppliedType::REPLACED>(25U, 20U, Opcode::Sub, 3U);
1194     ArithmeticTest<AppliedType::REPLACED>(20U, 20U, Opcode::Sub, 60U);
1195     // overflow
1196     ArithmeticTest<AppliedType::NOT_APPLIED>(INT32_MIN, INT32_MAX, Opcode::Sub, 1U);
1197     ArithmeticTest<AppliedType::NOT_APPLIED>(INT32_MAX, INT32_MAX, Opcode::Sub, -1L);
1198     ArithmeticTest<AppliedType::NOT_APPLIED>(1U, INT32_MAX, Opcode::Sub, INT32_MIN);
1199     ArithmeticTest<AppliedType::REPLACED>(-1L, INT32_MAX, Opcode::Sub, INT32_MAX);
1200 
1201     ArithmeticTest<AppliedType::REMOVED>(1U, 20U, Opcode::Mod, 20U);
1202     ArithmeticTest<AppliedType::REMOVED>(101U, 20U, Opcode::Mod, 5U);
1203     ArithmeticTest<AppliedType::REMOVED>(205U, 20U, Opcode::Mod, 5U);
1204     ArithmeticTest<AppliedType::REMOVED>(16U, 5U, Opcode::Mod, 3U);
1205 }
1206 
TEST_F(ChecksEliminationTest,ArithmeticTestMul)1207 TEST_F(ChecksEliminationTest, ArithmeticTestMul)
1208 {
1209     ArithmeticTest<AppliedType::REMOVED>(5U, 20U, Opcode::Mul, 2U);
1210     ArithmeticTest<AppliedType::REMOVED>(-5L, 20U, Opcode::Mul, -2L);
1211     ArithmeticTest<AppliedType::REMOVED>(3U, 20U, Opcode::Mul, 5U);
1212     ArithmeticTest<AppliedType::REPLACED>(5U, 20U, Opcode::Mul, -2L);
1213     ArithmeticTest<AppliedType::REPLACED>(-2L, 20U, Opcode::Mul, 5U);
1214     // Zero
1215     ArithmeticTest<AppliedType::REMOVED>(INT32_MAX, 20U, Opcode::Mul, 0U);
1216     ArithmeticTest<AppliedType::REMOVED>(0U, 20U, Opcode::Mul, INT32_MAX);
1217     ArithmeticTest<AppliedType::REMOVED>(INT32_MIN, 20U, Opcode::Mul, 0U);
1218     ArithmeticTest<AppliedType::REMOVED>(0U, 20U, Opcode::Mul, INT32_MIN);
1219     // overflow
1220     ArithmeticTest<AppliedType::NOT_APPLIED>(INT32_MAX, 20U, Opcode::Mul, 2U);
1221     ArithmeticTest<AppliedType::NOT_APPLIED>(INT32_MIN, 20U, Opcode::Mul, -2L);
1222     ArithmeticTest<AppliedType::NOT_APPLIED>(-2L, 20U, Opcode::Mul, INT32_MIN);
1223     ArithmeticTest<AppliedType::NOT_APPLIED>(2U, 20U, Opcode::Mul, INT32_MAX);
1224     ArithmeticTest<AppliedType::NOT_APPLIED>(INT32_MAX, 20U, Opcode::Mul, -2L);
1225     ArithmeticTest<AppliedType::NOT_APPLIED>(INT32_MIN, 20U, Opcode::Mul, 2U);
1226     ArithmeticTest<AppliedType::NOT_APPLIED>(2U, 20U, Opcode::Mul, INT32_MIN);
1227     ArithmeticTest<AppliedType::NOT_APPLIED>(-2L, 20U, Opcode::Mul, INT32_MAX);
1228 }
1229 
TEST_F(ChecksEliminationTest,ModTest)1230 TEST_F(ChecksEliminationTest, ModTest)
1231 {
1232     ModTest<true>(10U, 10U);
1233     ModTest<true>(10U, 5U);
1234     ModTest<false>(10U, 11U);
1235     ModTest<false>(10U, 20U);
1236 }
1237 
BuildGraphIfTestTrueBlock()1238 void ChecksEliminationTest::BuildGraphIfTestTrueBlock()
1239 {
1240     // we can norrow bounds range for true block
1241     GRAPH(GetGraph())
1242     {
1243         PARAMETER(0U, 0U).s32();  // index
1244         PARAMETER(1U, 1U).ref();
1245         CONSTANT(2U, 10U);  // len array
1246         CONSTANT(3U, 0U);
1247         BASIC_BLOCK(2U, 3U, 5U)
1248         {
1249             INST(4U, Opcode::Compare).b().CC(CC_LT).Inputs(0U, 2U);
1250             INST(5U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(4U);
1251         }
1252         BASIC_BLOCK(3U, 4U, 5U)
1253         {
1254             INST(6U, Opcode::Compare).b().CC(CC_GE).Inputs(0U, 3U);
1255             INST(7U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(6U);
1256         }
1257         BASIC_BLOCK(4U, 1U)
1258         {
1259             INST(8U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
1260             INST(9U, Opcode::BoundsCheck).s32().Inputs(2U, 0U, 8U);
1261             INST(10U, Opcode::LoadArray).s32().Inputs(1U, 9U);
1262             INST(11U, Opcode::Return).s32().Inputs(10U);
1263         }
1264         BASIC_BLOCK(5U, 1U)
1265         {
1266             INST(12U, Opcode::Return).s32().Inputs(3U);
1267         }
1268     }
1269 }
1270 
TEST_F(ChecksEliminationTest,IfTestTrueBlock)1271 TEST_F(ChecksEliminationTest, IfTestTrueBlock)
1272 {
1273     BuildGraphIfTestTrueBlock();
1274     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
1275     auto graph = CreateEmptyGraph();
1276     GRAPH(graph)
1277     {
1278         PARAMETER(0U, 0U).s32();
1279         PARAMETER(1U, 1U).ref();
1280         CONSTANT(2U, 10U);
1281         CONSTANT(3U, 0U);
1282         BASIC_BLOCK(2U, 3U, 5U)
1283         {
1284             INST(4U, Opcode::Compare).b().CC(CC_LT).Inputs(0U, 2U);
1285             INST(5U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(4U);
1286         }
1287         BASIC_BLOCK(3U, 4U, 5U)
1288         {
1289             INST(6U, Opcode::Compare).b().CC(CC_GE).Inputs(0U, 3U);
1290             INST(7U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(6U);
1291         }
1292         BASIC_BLOCK(4U, 1U)
1293         {
1294             INST(8U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
1295             INST(9U, Opcode::NOP);
1296             INST(10U, Opcode::LoadArray).s32().Inputs(1U, 0U);
1297             INST(11U, Opcode::Return).s32().Inputs(10U);
1298         }
1299         BASIC_BLOCK(5U, 1U)
1300         {
1301             INST(12U, Opcode::Return).s32().Inputs(3U);
1302         }
1303     }
1304     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
1305 }
1306 
BuildGraphIfTestFalseBlock()1307 void ChecksEliminationTest::BuildGraphIfTestFalseBlock()
1308 {
1309     // we can norrow bounds range for false block
1310     GRAPH(GetGraph())
1311     {
1312         PARAMETER(0U, 0U).s32();  // index
1313         PARAMETER(1U, 1U).ref();
1314         CONSTANT(2U, 10U);  // len array
1315         CONSTANT(3U, 0U);
1316         BASIC_BLOCK(2U, 5U, 3U)
1317         {
1318             INST(4U, Opcode::Compare).b().CC(CC_GE).Inputs(0U, 2U);
1319             INST(5U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(4U);
1320         }
1321         BASIC_BLOCK(3U, 5U, 4U)
1322         {
1323             INST(6U, Opcode::Compare).b().CC(CC_LT).Inputs(0U, 3U);
1324             INST(7U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(6U);
1325         }
1326         BASIC_BLOCK(4U, 1U)
1327         {
1328             INST(8U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
1329             INST(9U, Opcode::BoundsCheck).s32().Inputs(2U, 0U, 8U);
1330             INST(10U, Opcode::LoadArray).s32().Inputs(1U, 9U);
1331             INST(11U, Opcode::Return).s32().Inputs(10U);
1332         }
1333         BASIC_BLOCK(5U, 1U)
1334         {
1335             INST(12U, Opcode::Return).s32().Inputs(3U);
1336         }
1337     }
1338 }
1339 
TEST_F(ChecksEliminationTest,IfTestFalseBlock)1340 TEST_F(ChecksEliminationTest, IfTestFalseBlock)
1341 {
1342     BuildGraphIfTestFalseBlock();
1343     GetGraph()->RunPass<ChecksElimination>();
1344     auto graph = CreateEmptyGraph();
1345     GRAPH(graph)
1346     {
1347         PARAMETER(0U, 0U).s32();
1348         PARAMETER(1U, 1U).ref();
1349         CONSTANT(2U, 10U);
1350         CONSTANT(3U, 0U);
1351         BASIC_BLOCK(2U, 5U, 3U)
1352         {
1353             INST(4U, Opcode::Compare).b().CC(CC_GE).Inputs(0U, 2U);  // index >= len array
1354             INST(5U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(4U);
1355         }
1356         BASIC_BLOCK(3U, 5U, 4U)
1357         {
1358             INST(6U, Opcode::Compare).b().CC(CC_LT).Inputs(0U, 3U);  // index < 0
1359             INST(7U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(6U);
1360         }
1361         BASIC_BLOCK(4U, 1U)
1362         {
1363             INST(8U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
1364             INST(9U, Opcode::NOP);
1365             INST(10U, Opcode::LoadArray).s32().Inputs(1U, 0U);
1366             INST(11U, Opcode::Return).s32().Inputs(10U);
1367         }
1368         BASIC_BLOCK(5U, 1U)
1369         {
1370             INST(12U, Opcode::Return).s32().Inputs(3U);
1371         }
1372     }
1373     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
1374 }
1375 
BuildGraphIfTestTrueBlock1()1376 void ChecksEliminationTest::BuildGraphIfTestTrueBlock1()
1377 {
1378     // we can norrow bounds range for true block
1379     GRAPH(GetGraph())
1380     {
1381         PARAMETER(0U, 0U).s32();  // index
1382         PARAMETER(1U, 1U).ref();
1383         CONSTANT(3U, 0U);
1384         BASIC_BLOCK(6U, 3U, 5U)
1385         {
1386             INST(14U, Opcode::LenArray).s32().Inputs(1U);
1387             INST(4U, Opcode::Compare).b().CC(CC_LT).Inputs(0U, 14U);
1388             INST(5U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(4U);
1389         }
1390         BASIC_BLOCK(3U, 4U, 5U)
1391         {
1392             INST(6U, Opcode::Compare).b().CC(CC_GE).Inputs(0U, 3U);
1393             INST(7U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(6U);
1394         }
1395         BASIC_BLOCK(4U, 1U)
1396         {
1397             INST(8U, Opcode::SaveState).Inputs(0U, 1U, 3U).SrcVregs({0U, 1U, 3U});
1398             INST(9U, Opcode::BoundsCheck).s32().Inputs(14U, 0U, 8U);
1399             INST(10U, Opcode::LoadArray).s32().Inputs(1U, 9U);
1400             INST(11U, Opcode::Return).s32().Inputs(10U);
1401         }
1402         BASIC_BLOCK(5U, 1U)
1403         {
1404             INST(12U, Opcode::Return).s32().Inputs(3U);
1405         }
1406     }
1407 }
1408 
TEST_F(ChecksEliminationTest,IfTestTrueBlock1)1409 TEST_F(ChecksEliminationTest, IfTestTrueBlock1)
1410 {
1411     BuildGraphIfTestTrueBlock1();
1412     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
1413     auto graph = CreateEmptyGraph();
1414     GRAPH(graph)
1415     {
1416         PARAMETER(0U, 0U).s32();  // index
1417         PARAMETER(1U, 1U).ref();
1418         CONSTANT(3U, 0U);
1419         BASIC_BLOCK(6U, 3U, 5U)
1420         {
1421             INST(14U, Opcode::LenArray).s32().Inputs(1U);
1422             INST(4U, Opcode::Compare).b().CC(CC_LT).Inputs(0U, 14U);
1423             INST(5U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(4U);
1424         }
1425         BASIC_BLOCK(3U, 4U, 5U)
1426         {
1427             INST(6U, Opcode::Compare).b().CC(CC_GE).Inputs(0U, 3U);
1428             INST(7U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(6U);
1429         }
1430         BASIC_BLOCK(4U, 1U)
1431         {
1432             INST(8U, Opcode::SaveState).Inputs(0U, 1U, 3U).SrcVregs({0U, 1U, 3U});
1433             INST(9U, Opcode::NOP);
1434             INST(10U, Opcode::LoadArray).s32().Inputs(1U, 0U);
1435             INST(11U, Opcode::Return).s32().Inputs(10U);
1436         }
1437         BASIC_BLOCK(5U, 1U)
1438         {
1439             INST(12U, Opcode::Return).s32().Inputs(3U);
1440         }
1441     }
1442     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
1443 }
1444 
BuildGraphIfTestTrueBlock2()1445 void ChecksEliminationTest::BuildGraphIfTestTrueBlock2()
1446 {
1447     // we can norrow bounds range for true block
1448     GRAPH(GetGraph())
1449     {
1450         PARAMETER(0U, 0U).s32();  // index
1451         PARAMETER(1U, 1U).ref();
1452         CONSTANT(3U, 0U);
1453         BASIC_BLOCK(2U, 3U, 5U)
1454         {
1455             INST(14U, Opcode::LenArray).s32().Inputs(1U);
1456             INST(4U, Opcode::Compare).b().CC(CC_GE).Inputs(0U, 3U);
1457             INST(5U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(4U);
1458         }
1459         BASIC_BLOCK(3U, 4U, 5U)
1460         {
1461             INST(6U, Opcode::Compare).b().CC(CC_LT).Inputs(0U, 14U);
1462             INST(7U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(6U);
1463         }
1464         BASIC_BLOCK(4U, 1U)
1465         {
1466             INST(8U, Opcode::SaveState).Inputs(0U, 1U, 3U).SrcVregs({0U, 1U, 3U});
1467             INST(9U, Opcode::BoundsCheck).s32().Inputs(14U, 0U, 8U);
1468             INST(10U, Opcode::LoadArray).s32().Inputs(1U, 9U);
1469             INST(11U, Opcode::Return).s32().Inputs(10U);
1470         }
1471         BASIC_BLOCK(5U, 1U)
1472         {
1473             INST(12U, Opcode::Return).s32().Inputs(3U);
1474         }
1475     }
1476 }
1477 
TEST_F(ChecksEliminationTest,IfTestTrueBlock2)1478 TEST_F(ChecksEliminationTest, IfTestTrueBlock2)
1479 {
1480     BuildGraphIfTestTrueBlock2();
1481     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
1482     auto graph = CreateEmptyGraph();
1483     GRAPH(graph)
1484     {
1485         PARAMETER(0U, 0U).s32();  // index
1486         PARAMETER(1U, 1U).ref();
1487         CONSTANT(3U, 0U);
1488         BASIC_BLOCK(6U, 3U, 5U)
1489         {
1490             INST(14U, Opcode::LenArray).s32().Inputs(1U);
1491             INST(4U, Opcode::Compare).b().CC(CC_GE).Inputs(0U, 3U);
1492             INST(5U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(4U);
1493         }
1494         BASIC_BLOCK(3U, 4U, 5U)
1495         {
1496             INST(6U, Opcode::Compare).b().CC(CC_LT).Inputs(0U, 14U);
1497             INST(7U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(6U);
1498         }
1499         BASIC_BLOCK(4U, 1U)
1500         {
1501             INST(8U, Opcode::SaveState).Inputs(0U, 1U, 3U).SrcVregs({0U, 1U, 3U});
1502             INST(9U, Opcode::NOP);
1503             INST(10U, Opcode::LoadArray).s32().Inputs(1U, 0U);
1504             INST(11U, Opcode::Return).s32().Inputs(10U);
1505         }
1506         BASIC_BLOCK(5U, 1U)
1507         {
1508             INST(12U, Opcode::Return).s32().Inputs(3U);
1509         }
1510     }
1511     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
1512 }
1513 
BuildGraphIfTestTrueBlock3()1514 void ChecksEliminationTest::BuildGraphIfTestTrueBlock3()
1515 {
1516     // we can norrow bounds range for true block
1517     GRAPH(GetGraph())
1518     {
1519         PARAMETER(0U, 0U).s32();  // index
1520         PARAMETER(1U, 1U).ref();
1521         CONSTANT(3U, 0U);
1522         BASIC_BLOCK(6U, 3U, 5U)
1523         {
1524             INST(14U, Opcode::LenArray).s32().Inputs(1U);
1525             INST(4U, Opcode::Compare).b().CC(CC_GT).Inputs(14U, 0U);
1526             INST(5U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(4U);
1527         }
1528         BASIC_BLOCK(3U, 4U, 5U)
1529         {
1530             INST(6U, Opcode::Compare).b().CC(CC_GE).Inputs(0U, 3U);
1531             INST(7U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(6U);
1532         }
1533         BASIC_BLOCK(4U, 1U)
1534         {
1535             INST(8U, Opcode::SaveState).Inputs(0U, 1U, 3U).SrcVregs({0U, 1U, 3U});
1536             INST(9U, Opcode::BoundsCheck).s32().Inputs(14U, 0U, 8U);
1537             INST(10U, Opcode::LoadArray).s32().Inputs(1U, 9U);
1538             INST(11U, Opcode::Return).s32().Inputs(10U);
1539         }
1540         BASIC_BLOCK(5U, 1U)
1541         {
1542             INST(12U, Opcode::Return).s32().Inputs(3U);
1543         }
1544     }
1545 }
1546 
TEST_F(ChecksEliminationTest,IfTestTrueBlock3)1547 TEST_F(ChecksEliminationTest, IfTestTrueBlock3)
1548 {
1549     BuildGraphIfTestTrueBlock3();
1550     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
1551     auto graph = CreateEmptyGraph();
1552     GRAPH(graph)
1553     {
1554         PARAMETER(0U, 0U).s32();  // index
1555         PARAMETER(1U, 1U).ref();
1556         CONSTANT(3U, 0U);
1557         BASIC_BLOCK(6U, 3U, 5U)
1558         {
1559             INST(14U, Opcode::LenArray).s32().Inputs(1U);
1560             INST(4U, Opcode::Compare).b().CC(CC_GT).Inputs(14U, 0U);
1561             INST(5U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(4U);
1562         }
1563         BASIC_BLOCK(3U, 4U, 5U)
1564         {
1565             INST(6U, Opcode::Compare).b().CC(CC_GE).Inputs(0U, 3U);
1566             INST(7U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(6U);
1567         }
1568         BASIC_BLOCK(4U, 1U)
1569         {
1570             INST(8U, Opcode::SaveState).Inputs(0U, 1U, 3U).SrcVregs({0U, 1U, 3U});
1571             INST(9U, Opcode::NOP);
1572             INST(10U, Opcode::LoadArray).s32().Inputs(1U, 0U);
1573             INST(11U, Opcode::Return).s32().Inputs(10U);
1574         }
1575         BASIC_BLOCK(5U, 1U)
1576         {
1577             INST(12U, Opcode::Return).s32().Inputs(3U);
1578         }
1579     }
1580     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
1581 }
1582 
BuildGraphIfTestFalseBlock1()1583 void ChecksEliminationTest::BuildGraphIfTestFalseBlock1()
1584 {
1585     // we can norrow bounds range for false block
1586     GRAPH(GetGraph())
1587     {
1588         PARAMETER(0U, 0U).s32();  // index
1589         PARAMETER(1U, 1U).ref();
1590         CONSTANT(3U, 0U);
1591         BASIC_BLOCK(2U, 5U, 3U)
1592         {
1593             INST(14U, Opcode::LenArray).s32().Inputs(1U);
1594             INST(4U, Opcode::Compare).b().CC(CC_GE).Inputs(0U, 14U);  // index >= len array
1595             INST(5U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(4U);
1596         }
1597         BASIC_BLOCK(3U, 5U, 4U)
1598         {
1599             INST(6U, Opcode::Compare).b().CC(CC_LT).Inputs(0U, 3U);  // index < 0
1600             INST(7U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(6U);
1601         }
1602         BASIC_BLOCK(4U, 1U)
1603         {
1604             INST(8U, Opcode::SaveState).Inputs(0U, 1U, 3U).SrcVregs({0U, 1U, 3U});
1605             INST(9U, Opcode::BoundsCheck).s32().Inputs(14U, 0U, 8U);
1606             INST(10U, Opcode::LoadArray).s32().Inputs(1U, 9U);
1607             INST(11U, Opcode::Return).s32().Inputs(10U);
1608         }
1609         BASIC_BLOCK(5U, 1U)
1610         {
1611             INST(12U, Opcode::Return).s32().Inputs(3U);
1612         }
1613     }
1614 }
1615 
TEST_F(ChecksEliminationTest,IfTestFalseBlock1)1616 TEST_F(ChecksEliminationTest, IfTestFalseBlock1)
1617 {
1618     BuildGraphIfTestFalseBlock1();
1619     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
1620     auto graph = CreateEmptyGraph();
1621     GRAPH(graph)
1622     {
1623         PARAMETER(0U, 0U).s32();
1624         PARAMETER(1U, 1U).ref();
1625         CONSTANT(3U, 0U);
1626         BASIC_BLOCK(2U, 5U, 3U)
1627         {
1628             INST(14U, Opcode::LenArray).s32().Inputs(1U);
1629             INST(4U, Opcode::Compare).b().CC(CC_GE).Inputs(0U, 14U);  // index >= len array
1630             INST(5U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(4U);
1631         }
1632         BASIC_BLOCK(3U, 5U, 4U)
1633         {
1634             INST(6U, Opcode::Compare).b().CC(CC_LT).Inputs(0U, 3U);  // index < 0
1635             INST(7U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(6U);
1636         }
1637         BASIC_BLOCK(4U, 1U)
1638         {
1639             INST(8U, Opcode::SaveState).Inputs(0U, 1U, 3U).SrcVregs({0U, 1U, 3U});
1640             INST(9U, Opcode::NOP);
1641             INST(10U, Opcode::LoadArray).s32().Inputs(1U, 0U);
1642             INST(11U, Opcode::Return).s32().Inputs(10U);
1643         }
1644         BASIC_BLOCK(5U, 1U)
1645         {
1646             INST(12U, Opcode::Return).s32().Inputs(3U);
1647         }
1648     }
1649     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
1650 }
1651 
BuildGraphIfTestFalseBlock2()1652 void ChecksEliminationTest::BuildGraphIfTestFalseBlock2()
1653 {
1654     // we can norrow bounds range for false block
1655     GRAPH(GetGraph())
1656     {
1657         PARAMETER(0U, 0U).s32();  // index
1658         PARAMETER(1U, 1U).ref();
1659         CONSTANT(3U, 0U);
1660         BASIC_BLOCK(2U, 5U, 3U)
1661         {
1662             INST(14U, Opcode::LenArray).s32().Inputs(1U);
1663             INST(4U, Opcode::Compare).b().CC(CC_LT).Inputs(0U, 3U);  // index < 0
1664             INST(5U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(4U);
1665         }
1666         BASIC_BLOCK(3U, 5U, 4U)
1667         {
1668             INST(6U, Opcode::Compare).b().CC(CC_GE).Inputs(0U, 14U);  // index >= len array
1669             INST(7U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(6U);
1670         }
1671         BASIC_BLOCK(4U, 1U)
1672         {
1673             INST(8U, Opcode::SaveState).Inputs(0U, 1U, 3U).SrcVregs({0U, 1U, 3U});
1674             INST(9U, Opcode::BoundsCheck).s32().Inputs(14U, 0U, 8U);
1675             INST(10U, Opcode::LoadArray).s32().Inputs(1U, 9U);
1676             INST(11U, Opcode::Return).s32().Inputs(10U);
1677         }
1678         BASIC_BLOCK(5U, 1U)
1679         {
1680             INST(12U, Opcode::Return).s32().Inputs(3U);
1681         }
1682     }
1683 }
1684 
TEST_F(ChecksEliminationTest,IfTestFalseBlock2)1685 TEST_F(ChecksEliminationTest, IfTestFalseBlock2)
1686 {
1687     BuildGraphIfTestFalseBlock2();
1688     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
1689     auto graph = CreateEmptyGraph();
1690     GRAPH(graph)
1691     {
1692         PARAMETER(0U, 0U).s32();
1693         PARAMETER(1U, 1U).ref();
1694         CONSTANT(3U, 0U);
1695         BASIC_BLOCK(2U, 5U, 3U)
1696         {
1697             INST(14U, Opcode::LenArray).s32().Inputs(1U);
1698             INST(4U, Opcode::Compare).b().CC(CC_LT).Inputs(0U, 3U);  // index < 0
1699             INST(5U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(4U);
1700         }
1701         BASIC_BLOCK(3U, 5U, 4U)
1702         {
1703             INST(6U, Opcode::Compare).b().CC(CC_GE).Inputs(0U, 14U);  // index >= len array
1704             INST(7U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(6U);
1705         }
1706         BASIC_BLOCK(4U, 1U)
1707         {
1708             INST(8U, Opcode::SaveState).Inputs(0U, 1U, 3U).SrcVregs({0U, 1U, 3U});
1709             INST(9U, Opcode::NOP);
1710             INST(10U, Opcode::LoadArray).s32().Inputs(1U, 0U);
1711             INST(11U, Opcode::Return).s32().Inputs(10U);
1712         }
1713         BASIC_BLOCK(5U, 1U)
1714         {
1715             INST(12U, Opcode::Return).s32().Inputs(3U);
1716         }
1717     }
1718     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
1719 }
1720 
BuildGraphIfTestFalseBlock3()1721 void ChecksEliminationTest::BuildGraphIfTestFalseBlock3()
1722 {
1723     // we can norrow bounds range for false block
1724     GRAPH(GetGraph())
1725     {
1726         PARAMETER(0U, 0U).s32();  // index
1727         PARAMETER(1U, 1U).ref();
1728         CONSTANT(3U, 0U);
1729         BASIC_BLOCK(2U, 5U, 3U)
1730         {
1731             INST(14U, Opcode::LenArray).s32().Inputs(1U);
1732             INST(4U, Opcode::Compare).b().CC(CC_LE).Inputs(14U, 0U);  // len array < index
1733             INST(5U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(4U);
1734         }
1735         BASIC_BLOCK(3U, 5U, 4U)
1736         {
1737             INST(6U, Opcode::Compare).b().CC(CC_LT).Inputs(0U, 3U);  // index < 0
1738             INST(7U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(6U);
1739         }
1740         BASIC_BLOCK(4U, 1U)
1741         {
1742             INST(8U, Opcode::SaveState).Inputs(0U, 1U, 3U).SrcVregs({0U, 1U, 3U});
1743             INST(9U, Opcode::BoundsCheck).s32().Inputs(14U, 0U, 8U);
1744             INST(10U, Opcode::LoadArray).s32().Inputs(1U, 9U);
1745             INST(11U, Opcode::Return).s32().Inputs(10U);
1746         }
1747         BASIC_BLOCK(5U, 1U)
1748         {
1749             INST(12U, Opcode::Return).s32().Inputs(3U);
1750         }
1751     }
1752 }
1753 
TEST_F(ChecksEliminationTest,IfTestFalseBlock3)1754 TEST_F(ChecksEliminationTest, IfTestFalseBlock3)
1755 {
1756     BuildGraphIfTestFalseBlock3();
1757     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
1758     auto graph = CreateEmptyGraph();
1759     GRAPH(graph)
1760     {
1761         PARAMETER(0U, 0U).s32();
1762         PARAMETER(1U, 1U).ref();
1763         CONSTANT(3U, 0U);
1764         BASIC_BLOCK(2U, 5U, 3U)
1765         {
1766             INST(14U, Opcode::LenArray).s32().Inputs(1U);
1767             INST(4U, Opcode::Compare).b().CC(CC_LE).Inputs(14U, 0U);  // len array < index
1768             INST(5U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(4U);
1769         }
1770         BASIC_BLOCK(3U, 5U, 4U)
1771         {
1772             INST(6U, Opcode::Compare).b().CC(CC_LT).Inputs(0U, 3U);  // index < 0
1773             INST(7U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(6U);
1774         }
1775         BASIC_BLOCK(4U, 1U)
1776         {
1777             INST(8U, Opcode::SaveState).Inputs(0U, 1U, 3U).SrcVregs({0U, 1U, 3U});
1778             INST(9U, Opcode::NOP);
1779             INST(10U, Opcode::LoadArray).s32().Inputs(1U, 0U);
1780             INST(11U, Opcode::Return).s32().Inputs(10U);
1781         }
1782         BASIC_BLOCK(5U, 1U)
1783         {
1784             INST(12U, Opcode::Return).s32().Inputs(3U);
1785         }
1786     }
1787     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
1788 }
1789 
TEST_F(ChecksEliminationTest,IfTest1)1790 TEST_F(ChecksEliminationTest, IfTest1)
1791 {
1792     // not applied if without compare
1793     GRAPH(GetGraph())
1794     {
1795         PARAMETER(0U, 0U).s32();  // index
1796         PARAMETER(1U, 1U).ref();
1797         PARAMETER(13U, 2U).b();
1798         CONSTANT(2U, 10U);  // len array
1799         CONSTANT(3U, 0U);
1800         BASIC_BLOCK(2U, 3U, 5U)
1801         {
1802             INST(5U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(13U);
1803         }
1804         BASIC_BLOCK(3U, 4U, 5U)
1805         {
1806             INST(7U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(13U);
1807         }
1808         BASIC_BLOCK(4U, 1U)
1809         {
1810             INST(8U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
1811             INST(9U, Opcode::BoundsCheck).s32().Inputs(2U, 0U, 8U);
1812             INST(10U, Opcode::LoadArray).s32().Inputs(1U, 9U);
1813             INST(11U, Opcode::Return).s32().Inputs(10U);
1814         }
1815         BASIC_BLOCK(5U, 1U)
1816         {
1817             INST(12U, Opcode::Return).s32().Inputs(3U);
1818         }
1819     }
1820     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
1821     ASSERT_FALSE(GetGraph()->RunPass<ChecksElimination>());
1822     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
1823 }
1824 
TEST_F(ChecksEliminationTest,IfTest2)1825 TEST_F(ChecksEliminationTest, IfTest2)
1826 {
1827     // not applied, compare intputs not int32
1828     GRAPH(GetGraph())
1829     {
1830         PARAMETER(0U, 0U).s32();  // index
1831         PARAMETER(1U, 1U).ref();
1832         PARAMETER(13U, 2U).s64();
1833         PARAMETER(14U, 3U).s64();
1834         CONSTANT(2U, 10U);  // len array
1835         CONSTANT(3U, 0U);
1836         BASIC_BLOCK(2U, 3U, 5U)
1837         {
1838             INST(15U, Opcode::Compare).b().CC(CC_GE).Inputs(13U, 14U);
1839             INST(5U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(15U);
1840         }
1841         BASIC_BLOCK(3U, 4U, 5U)
1842         {
1843             INST(16U, Opcode::Compare).b().CC(CC_GE).Inputs(13U, 14U);
1844             INST(7U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(16U);
1845         }
1846         BASIC_BLOCK(4U, 1U)
1847         {
1848             INST(8U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
1849             INST(9U, Opcode::BoundsCheck).s32().Inputs(2U, 0U, 8U);
1850             INST(10U, Opcode::LoadArray).s32().Inputs(1U, 9U);
1851             INST(11U, Opcode::Return).s32().Inputs(10U);
1852         }
1853         BASIC_BLOCK(5U, 1U)
1854         {
1855             INST(12U, Opcode::Return).s32().Inputs(3U);
1856         }
1857     }
1858     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
1859     ASSERT_FALSE(GetGraph()->RunPass<ChecksElimination>());
1860     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
1861 }
1862 
TEST_F(ChecksEliminationTest,PhiTest)1863 TEST_F(ChecksEliminationTest, PhiTest)
1864 {
1865     PhiTest<true>(5U, 10U, 10U);
1866     PhiTest<true>(9U, 10U, 5U);
1867     PhiTest<false>(10U, 10U, 10U);
1868     PhiTest<false>(-1L, 10U, 10U);
1869     PhiTest<false>(5U, 10U, 11U);
1870 }
1871 
BuildGraphSimpleLoopTestInc()1872 void ChecksEliminationTest::BuildGraphSimpleLoopTestInc()
1873 {
1874     // new_array(len_array)
1875     // For(int i = 0, i < len_array, i++) begin
1876     //  boundscheck(len_array, i) - can remove
1877     //  a[i] = 0
1878     // end
1879     // return new_array
1880     GRAPH(GetGraph())
1881     {
1882         CONSTANT(0U, 0U);   // initial
1883         CONSTANT(1U, 1U);   // increment
1884         CONSTANT(2U, 10U);  // len_array
1885         BASIC_BLOCK(2U, 3U)
1886         {
1887             INST(43U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
1888             INST(44U, Opcode::LoadAndInitClass).ref().Inputs().TypeId(68U);
1889             INST(3U, Opcode::NewArray).ref().Inputs(44U, 2U, 43U);
1890         }
1891         BASIC_BLOCK(3U, 4U, 5U)
1892         {
1893             INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);
1894             INST(5U, Opcode::Compare).CC(CC_LT).b().Inputs(4U, 2U);  // i < len_array
1895             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
1896         }
1897         BASIC_BLOCK(4U, 3U)
1898         {
1899             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
1900             INST(8U, Opcode::BoundsCheck).s32().Inputs(2U, 4U, 7U);
1901             INST(9U, Opcode::StoreArray).s32().Inputs(3U, 8U, 0U);  // a[i] = 0
1902             INST(10U, Opcode::Add).s32().Inputs(4U, 1U);            // i++
1903         }
1904         BASIC_BLOCK(5U, 1U)
1905         {
1906             INST(12U, Opcode::Return).ref().Inputs(3U);
1907         }
1908     }
1909 }
1910 
TEST_F(ChecksEliminationTest,SimpleLoopTestInc)1911 TEST_F(ChecksEliminationTest, SimpleLoopTestInc)
1912 {
1913     BuildGraphSimpleLoopTestInc();
1914     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
1915     auto graph = CreateEmptyGraph();
1916     GRAPH(graph)
1917     {
1918         CONSTANT(0U, 0U);   // initial
1919         CONSTANT(1U, 1U);   // increment
1920         CONSTANT(2U, 10U);  // len_array
1921         BASIC_BLOCK(2U, 3U)
1922         {
1923             INST(43U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
1924             INST(44U, Opcode::LoadAndInitClass).ref().Inputs().TypeId(68U);
1925             INST(3U, Opcode::NewArray).ref().Inputs(44U, 2U, 43U);
1926         }
1927         BASIC_BLOCK(3U, 4U, 5U)
1928         {
1929             INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);
1930             INST(5U, Opcode::Compare).CC(CC_LT).b().Inputs(4U, 2U);  // i < len_array
1931             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
1932         }
1933         BASIC_BLOCK(4U, 3U)
1934         {
1935             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
1936             INST(8U, Opcode::NOP);
1937             INST(9U, Opcode::StoreArray).s32().Inputs(3U, 4U, 0U);  // a[i] = 0
1938             INST(10U, Opcode::Add).s32().Inputs(4U, 1U);            // i++
1939         }
1940         BASIC_BLOCK(5U, 1U)
1941         {
1942             INST(12U, Opcode::Return).ref().Inputs(3U);
1943         }
1944     }
1945     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
1946 }
1947 
BuildGraphSimpleLoopTestIncAfterPeeling()1948 void ChecksEliminationTest::BuildGraphSimpleLoopTestIncAfterPeeling()
1949 {
1950     // new_array(len_array)
1951     // For(int i = 0, i < len_array, i++) begin
1952     //  boundscheck(len_array, i) - can remove
1953     //  a[i] = 0
1954     // end
1955     // return new_array
1956     GRAPH(GetGraph())
1957     {
1958         CONSTANT(0U, 0U);   // initial
1959         CONSTANT(1U, 1U);   // increment
1960         CONSTANT(2U, 10U);  // len_array
1961         BASIC_BLOCK(2U, 3U, 5U)
1962         {
1963             INST(43U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
1964             INST(44U, Opcode::LoadAndInitClass).ref().Inputs().TypeId(68U);
1965             INST(3U, Opcode::NewArray).ref().Inputs(44U, 2U, 43U);
1966             INST(5U, Opcode::Compare).SrcType(DataType::INT32).CC(CC_LT).b().Inputs(0U, 2U);  // 0 < len_array
1967             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
1968         }
1969         BASIC_BLOCK(3U, 3U, 5U)
1970         {
1971             INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);
1972             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
1973             INST(8U, Opcode::BoundsCheck).s32().Inputs(2U, 4U, 7U);
1974             INST(9U, Opcode::StoreArray).s32().Inputs(3U, 8U, 0U);     // a[i] = 0
1975             INST(10U, Opcode::Add).s32().Inputs(4U, 1U);               // i++
1976             INST(13U, Opcode::Compare).CC(CC_LT).b().Inputs(10U, 2U);  // i < len_array
1977             INST(14U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(13U);
1978         }
1979         BASIC_BLOCK(5U, 1U)
1980         {
1981             INST(12U, Opcode::Return).ref().Inputs(3U);
1982         }
1983     }
1984 }
1985 
TEST_F(ChecksEliminationTest,SimpleLoopTestIncAfterPeeling)1986 TEST_F(ChecksEliminationTest, SimpleLoopTestIncAfterPeeling)
1987 {
1988     BuildGraphSimpleLoopTestIncAfterPeeling();
1989     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
1990     auto graph = CreateEmptyGraph();
1991     GRAPH(graph)
1992     {
1993         CONSTANT(0U, 0U);   // initial
1994         CONSTANT(1U, 1U);   // increment
1995         CONSTANT(2U, 10U);  // len_array
1996         BASIC_BLOCK(2U, 3U, 5U)
1997         {
1998             INST(43U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
1999             INST(44U, Opcode::LoadAndInitClass).ref().Inputs().TypeId(68U);
2000             INST(3U, Opcode::NewArray).ref().Inputs(44U, 2U, 43U);
2001             INST(5U, Opcode::Compare).SrcType(DataType::INT32).CC(CC_LT).b().Inputs(0U, 2U);  // 0 < len_array
2002             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
2003         }
2004         BASIC_BLOCK(3U, 3U, 5U)
2005         {
2006             INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);
2007             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
2008             INST(8U, Opcode::NOP);
2009             INST(9U, Opcode::StoreArray).s32().Inputs(3U, 4U, 0U);     // a[i] = 0
2010             INST(10U, Opcode::Add).s32().Inputs(4U, 1U);               // i++
2011             INST(13U, Opcode::Compare).CC(CC_LT).b().Inputs(10U, 2U);  // i < len_array
2012             INST(14U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(13U);
2013         }
2014         BASIC_BLOCK(5U, 1U)
2015         {
2016             INST(12U, Opcode::Return).ref().Inputs(3U);
2017         }
2018     }
2019     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
2020 }
2021 
BuildGraphSimpleLoopTestIncAfterPeeling1()2022 void ChecksEliminationTest::BuildGraphSimpleLoopTestIncAfterPeeling1()
2023 {
2024     // new_array(len_array)
2025     // For(int i = 0, i < len_array, i++) begin
2026     //  boundscheck(len_array, i) - can remove
2027     //  a[i] = 0
2028     // end
2029     // return new_array
2030     GRAPH(GetGraph())
2031     {
2032         CONSTANT(0U, 0U);         // initial
2033         CONSTANT(1U, 1U);         // increment
2034         PARAMETER(3U, 0U).ref();  // array
2035         BASIC_BLOCK(2U, 3U, 5U)
2036         {
2037             INST(16U, Opcode::LenArray).s32().Inputs(3U);
2038             INST(5U, Opcode::Compare).SrcType(DataType::INT32).CC(CC_LT).b().Inputs(0U, 16U);  // 0 < len_array
2039             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
2040         }
2041         BASIC_BLOCK(3U, 3U, 5U)
2042         {
2043             INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);
2044             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 3U).SrcVregs({0U, 1U, 3U});
2045             INST(8U, Opcode::BoundsCheck).s32().Inputs(16U, 4U, 7U);
2046             INST(9U, Opcode::StoreArray).s32().Inputs(3U, 8U, 0U);      // a[i] = 0
2047             INST(10U, Opcode::Add).s32().Inputs(4U, 1U);                // i++
2048             INST(13U, Opcode::Compare).CC(CC_LT).b().Inputs(10U, 16U);  // i < len_array
2049             INST(14U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(13U);
2050         }
2051         BASIC_BLOCK(5U, 1U)
2052         {
2053             INST(12U, Opcode::Return).ref().Inputs(3U);
2054         }
2055     }
2056 }
2057 
TEST_F(ChecksEliminationTest,SimpleLoopTestIncAfterPeeling1)2058 TEST_F(ChecksEliminationTest, SimpleLoopTestIncAfterPeeling1)
2059 {
2060     BuildGraphSimpleLoopTestIncAfterPeeling1();
2061     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
2062     auto graph = CreateEmptyGraph();
2063     GRAPH(graph)
2064     {
2065         CONSTANT(0U, 0U);         // initial
2066         CONSTANT(1U, 1U);         // increment
2067         PARAMETER(3U, 0U).ref();  // array
2068         BASIC_BLOCK(2U, 3U, 5U)
2069         {
2070             INST(16U, Opcode::LenArray).s32().Inputs(3U);
2071             INST(5U, Opcode::Compare).SrcType(DataType::INT32).CC(CC_LT).b().Inputs(0U, 16U);  // 0 < len_array
2072             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
2073         }
2074         BASIC_BLOCK(3U, 3U, 5U)
2075         {
2076             INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);
2077             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 3U).SrcVregs({0U, 1U, 3U});
2078             INST(8U, Opcode::NOP);
2079             INST(9U, Opcode::StoreArray).s32().Inputs(3U, 4U, 0U);      // a[i] = 0
2080             INST(10U, Opcode::Add).s32().Inputs(4U, 1U);                // i++
2081             INST(13U, Opcode::Compare).CC(CC_LT).b().Inputs(10U, 16U);  // i < len_array
2082             INST(14U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(13U);
2083         }
2084         BASIC_BLOCK(5U, 1U)
2085         {
2086             INST(12U, Opcode::Return).ref().Inputs(3U);
2087         }
2088     }
2089     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
2090 }
2091 
BuildGraphSimpleLoopTestDec()2092 void ChecksEliminationTest::BuildGraphSimpleLoopTestDec()
2093 {
2094     // new_array(len_array)
2095     // For(int i = len_array-1, i >= 0, i--) begin
2096     //  boundscheck(len_array, i) - can remove
2097     //  a[i] = 0
2098     // end
2099     // return new_array
2100     GRAPH(GetGraph())
2101     {
2102         CONSTANT(0U, 0U);
2103         CONSTANT(1U, 1U);   // increment
2104         CONSTANT(2U, 10U);  // initial and len_array
2105         BASIC_BLOCK(2U, 3U)
2106         {
2107             INST(43U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
2108             INST(44U, Opcode::LoadAndInitClass).ref().Inputs().TypeId(68U);
2109             INST(3U, Opcode::NewArray).ref().Inputs(44U, 2U, 43U);
2110             INST(13U, Opcode::Sub).s32().Inputs(2U, 1U);  // len_array - 1
2111         }
2112         BASIC_BLOCK(3U, 4U, 5U)
2113         {
2114             INST(4U, Opcode::Phi).s32().Inputs(13U, 10U);
2115             INST(5U, Opcode::Compare).CC(CC_GE).b().Inputs(4U, 0U);  // i >= 0
2116             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
2117         }
2118         BASIC_BLOCK(4U, 3U)
2119         {
2120             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
2121             INST(8U, Opcode::BoundsCheck).s32().Inputs(2U, 4U, 7U);
2122             INST(9U, Opcode::StoreArray).s32().Inputs(3U, 8U, 0U);  // a[i] = 0
2123             INST(10U, Opcode::Sub).s32().Inputs(4U, 1U);            // i--
2124         }
2125         BASIC_BLOCK(5U, 1U)
2126         {
2127             INST(12U, Opcode::Return).ref().Inputs(3U);
2128         }
2129     }
2130 }
2131 
TEST_F(ChecksEliminationTest,SimpleLoopTestDec)2132 TEST_F(ChecksEliminationTest, SimpleLoopTestDec)
2133 {
2134     BuildGraphSimpleLoopTestDec();
2135     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
2136     auto graph = CreateEmptyGraph();
2137     GRAPH(graph)
2138     {
2139         CONSTANT(0U, 0U);
2140         CONSTANT(1U, 1U);   // increment
2141         CONSTANT(2U, 10U);  // initial and len_array
2142         BASIC_BLOCK(2U, 3U)
2143         {
2144             INST(43U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
2145             INST(44U, Opcode::LoadAndInitClass).ref().Inputs().TypeId(68U);
2146             INST(3U, Opcode::NewArray).ref().Inputs(44U, 2U, 43U);
2147             INST(13U, Opcode::Sub).s32().Inputs(2U, 1U);  // len_array - 1
2148         }
2149         BASIC_BLOCK(3U, 4U, 5U)
2150         {
2151             INST(4U, Opcode::Phi).s32().Inputs(13U, 10U);
2152             INST(5U, Opcode::Compare).CC(CC_GE).b().Inputs(4U, 0U);  // i >= 0
2153             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
2154         }
2155         BASIC_BLOCK(4U, 3U)
2156         {
2157             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
2158             INST(8U, Opcode::NOP);
2159             INST(9U, Opcode::StoreArray).s32().Inputs(3U, 4U, 0U);  // a[i] = 0
2160             INST(10U, Opcode::Sub).s32().Inputs(4U, 1U);            // i--
2161         }
2162         BASIC_BLOCK(5U, 1U)
2163         {
2164             INST(12U, Opcode::Return).ref().Inputs(3U);
2165         }
2166     }
2167     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
2168 }
2169 
BuildGraphLoopWithUnknowLowerUpperValue()2170 void ChecksEliminationTest::BuildGraphLoopWithUnknowLowerUpperValue()
2171 {
2172     // applied
2173     GRAPH(GetGraph())
2174     {
2175         CONSTANT(0U, 1U);         // increment
2176         PARAMETER(1U, 0U).s32();  // lower
2177         PARAMETER(2U, 1U).s32();  // upper
2178         PARAMETER(3U, 2U).ref();  // array
2179         BASIC_BLOCK(7U, 3U, 6U)
2180         {
2181             INST(4U, Opcode::SaveState).Inputs(0U, 3U).SrcVregs({0U, 1U});
2182             INST(5U, Opcode::NullCheck).ref().Inputs(3U, 4U);
2183             INST(6U, Opcode::LenArray).s32().Inputs(5U);
2184             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
2185             INST(7U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(1U, 2U);  // lower < upper
2186             INST(8U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(7U);
2187         }
2188         BASIC_BLOCK(3U, 3U, 6U)
2189         {
2190             INST(9U, Opcode::Phi).s32().Inputs(1U, 13U);
2191             INST(10U, Opcode::SaveState).Inputs(0U, 3U).SrcVregs({0U, 1U});
2192             INST(11U, Opcode::BoundsCheck).s32().Inputs(6U, 9U, 10U);
2193             INST(12U, Opcode::StoreArray).s32().Inputs(3U, 11U, 0U);                  // a[i] = 0
2194             INST(13U, Opcode::Add).s32().Inputs(9U, 0U);                              // i++
2195             INST(14U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(13U, 2U);  // i < upper
2196             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(14U);
2197         }
2198         BASIC_BLOCK(6U, 1U)
2199         {
2200             INST(16U, Opcode::Phi).s32().Inputs(0U, 13U);
2201             INST(17U, Opcode::Return).s32().Inputs(16U);
2202         }
2203     }
2204 }
2205 
TEST_F(ChecksEliminationTest,LoopWithUnknowLowerUpperValue)2206 TEST_F(ChecksEliminationTest, LoopWithUnknowLowerUpperValue)
2207 {
2208     BuildGraphLoopWithUnknowLowerUpperValue();
2209     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
2210     auto graph1 = CreateEmptyGraph();
2211     GRAPH(graph1)
2212     {
2213         CONSTANT(0U, 1U);         // increment
2214         PARAMETER(1U, 0U).s32();  // lower
2215         PARAMETER(2U, 1U).s32();  // upper
2216         PARAMETER(3U, 2U).ref();  // array
2217         CONSTANT(22U, 0U);
2218         BASIC_BLOCK(7U, 3U, 6U)
2219         {
2220             INST(4U, Opcode::SaveState).Inputs(0U, 3U).SrcVregs({0U, 1U});
2221             INST(5U, Opcode::NullCheck).ref().Inputs(3U, 4U);
2222             INST(6U, Opcode::LenArray).s32().Inputs(5U);
2223             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
2224             INST(20U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(1U, 22U);  // (lower) < 0
2225             INST(21U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(20U, 30U);
2226             INST(18U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(6U, 2U);  // len_array < (upper)
2227             INST(19U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(18U, 30U);
2228             INST(7U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(1U, 2U);  // lower < X
2229             INST(8U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(7U);
2230         }
2231         BASIC_BLOCK(3U, 3U, 6U)
2232         {
2233             INST(9U, Opcode::Phi).s32().Inputs(1U, 13U);
2234             INST(10U, Opcode::SaveState).Inputs(0U, 3U).SrcVregs({0U, 1U});
2235             INST(11U, Opcode::NOP);
2236             INST(12U, Opcode::StoreArray).s32().Inputs(3U, 9U, 0U);                   // a[i] = 0
2237             INST(13U, Opcode::Add).s32().Inputs(9U, 0U);                              // i++
2238             INST(14U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(13U, 2U);  // i < upper
2239             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(14U);
2240         }
2241         BASIC_BLOCK(6U, 1U)
2242         {
2243             INST(16U, Opcode::Phi).s32().Inputs(0U, 13U);
2244             INST(17U, Opcode::Return).s32().Inputs(16U);
2245         }
2246     }
2247     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
2248 }
2249 
BuildGraphLoopWithUnknowLowerUpperValueDown(ConditionCode cc)2250 Graph *ChecksEliminationTest::BuildGraphLoopWithUnknowLowerUpperValueDown(ConditionCode cc)
2251 {
2252     auto graph = CreateEmptyGraph();
2253     GRAPH(graph)
2254     {
2255         CONSTANT(0U, 1U);         // increment
2256         PARAMETER(1U, 0U).s32();  // lower
2257         PARAMETER(2U, 1U).s32();  // upper
2258         PARAMETER(3U, 2U).ref();  // array
2259         BASIC_BLOCK(7U, 3U, 6U)
2260         {
2261             INST(4U, Opcode::SaveState).Inputs(0U, 3U).SrcVregs({0U, 1U});
2262             INST(5U, Opcode::NullCheck).ref().Inputs(3U, 4U);
2263             INST(6U, Opcode::LenArray).s32().Inputs(5U);
2264             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
2265             INST(7U, Opcode::Compare).CC(cc).b().Inputs(2U, 1U);  // upper >(>=) lower
2266             INST(8U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(7U);
2267         }
2268         BASIC_BLOCK(3U, 3U, 6U)
2269         {
2270             INST(9U, Opcode::Phi).s32().Inputs(2U, 13U);
2271             INST(10U, Opcode::SaveState).Inputs(0U, 3U).SrcVregs({0U, 1U});
2272             INST(11U, Opcode::BoundsCheck).s32().Inputs(6U, 9U, 10U);
2273             INST(12U, Opcode::StoreArray).s32().Inputs(3U, 11U, 0U);  // a[i] = 0
2274             INST(13U, Opcode::Sub).s32().Inputs(9U, 0U);              // i--
2275             INST(14U, Opcode::Compare).CC(cc).b().Inputs(13U, 1U);    // i >(>=) lower
2276             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(14U);
2277         }
2278         BASIC_BLOCK(6U, 1U)
2279         {
2280             INST(16U, Opcode::Phi).s32().Inputs(0U, 13U);
2281             INST(17U, Opcode::Return).s32().Inputs(16U);
2282         }
2283     }
2284     return graph;
2285 }
2286 
TEST_F(ChecksEliminationTest,LoopWithUnknowLowerUpperValueDown)2287 TEST_F(ChecksEliminationTest, LoopWithUnknowLowerUpperValueDown)
2288 {
2289     for (auto cc : {CC_GT, CC_GE}) {
2290         // applied
2291         auto *graph = BuildGraphLoopWithUnknowLowerUpperValueDown(cc);
2292         EXPECT_TRUE(graph->RunPass<ChecksElimination>());
2293         auto graph1 = CreateEmptyGraph();
2294         GRAPH(graph1)
2295         {
2296             CONSTANT(0U, 1U);         // increment
2297             PARAMETER(1U, 0U).s32();  // lower
2298             PARAMETER(2U, 1U).s32();  // upper
2299             PARAMETER(3U, 2U).ref();  // array
2300             CONSTANT(22U, cc == CC_GT ? static_cast<uint64_t>(-1L) : 0U);
2301             BASIC_BLOCK(7U, 3U, 6U)
2302             {
2303                 INST(4U, Opcode::SaveState).Inputs(0U, 3U).SrcVregs({0U, 1U});
2304                 INST(5U, Opcode::NullCheck).ref().Inputs(3U, 4U);
2305                 INST(6U, Opcode::LenArray).s32().Inputs(5U);
2306                 INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
2307                 INST(20U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(1U, 22U);  // (lower) < -1 (0)
2308                 INST(21U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(20U, 30U);
2309                 INST(18U, Opcode::Compare).CC(ConditionCode::CC_LE).b().Inputs(6U, 2U);  // len_array <= (upper)
2310                 INST(19U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(18U, 30U);
2311                 INST(7U, Opcode::Compare).CC(cc).b().Inputs(2U, 1U);  // upper >(>=) lower
2312                 INST(8U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(7U);
2313             }
2314             BASIC_BLOCK(3U, 3U, 6U)
2315             {
2316                 INST(9U, Opcode::Phi).s32().Inputs(2U, 13U);
2317                 INST(10U, Opcode::SaveState).Inputs(0U, 3U).SrcVregs({0U, 1U});
2318                 INST(11U, Opcode::NOP);
2319                 INST(12U, Opcode::StoreArray).s32().Inputs(3U, 9U, 0U);  // a[i] = 0
2320                 INST(13U, Opcode::Sub).s32().Inputs(9U, 0U);             // i--
2321                 INST(14U, Opcode::Compare).CC(cc).b().Inputs(13U, 1U);   // i >(>=) lower
2322                 INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(14U);
2323             }
2324             BASIC_BLOCK(6U, 1U)
2325             {
2326                 INST(16U, Opcode::Phi).s32().Inputs(0U, 13U);
2327                 INST(17U, Opcode::Return).s32().Inputs(16U);
2328             }
2329         }
2330         EXPECT_TRUE(GraphComparator().Compare(graph, graph1));
2331     }
2332 }
2333 
BuildGraphUpperOOB()2334 void ChecksEliminationTest::BuildGraphUpperOOB()
2335 {
2336     GRAPH(GetGraph())
2337     {
2338         PARAMETER(0U, 0U).ref();  // array
2339         CONSTANT(3U, 0U);
2340         CONSTANT(25U, 1U);
2341         BASIC_BLOCK(4U, 3U, 2U)
2342         {
2343             INST(2U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
2344             INST(27U, Opcode::SaveState).Inputs(3U, 0U).SrcVregs({0U, 3U});
2345             INST(28U, Opcode::NullCheck).ref().Inputs(0U, 27U);
2346             INST(29U, Opcode::LenArray).s32().Inputs(28U);
2347             INST(30U, Opcode::Compare).Inputs(29U, 3U).CC(CC_LT).b();
2348             INST(31U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(30U);
2349         }
2350         BASIC_BLOCK(2U, 3U, 2U)
2351         {
2352             INST(4U, Opcode::Phi).s32().Inputs(3U, 24U);
2353             INST(15U, Opcode::SaveState).Inputs(4U, 0U, 4U).SrcVregs({0U, 3U, 4U});
2354             INST(16U, Opcode::NullCheck).ref().Inputs(0U, 15U);
2355             INST(18U, Opcode::BoundsCheck).s32().Inputs(29U, 4U, 15U);
2356             INST(19U, Opcode::StoreArray).s32().Inputs(16U, 18U, 3U);
2357             INST(24U, Opcode::Add).s32().Inputs(4U, 25U);
2358             INST(10U, Opcode::Compare).b().CC(CC_LT).Inputs(29U, 24U);
2359             INST(11U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(10U);
2360         }
2361         BASIC_BLOCK(3U, -1L)
2362         {
2363             INST(26U, Opcode::ReturnVoid).v0id();
2364         }
2365     }
2366 }
2367 
TEST_F(ChecksEliminationTest,UpperOOB)2368 TEST_F(ChecksEliminationTest, UpperOOB)
2369 {
2370     BuildGraphUpperOOB();
2371     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
2372     auto graph1 = CreateEmptyGraph();
2373     GRAPH(graph1)
2374     {
2375         PARAMETER(0U, 0U).ref();  // array
2376         CONSTANT(3U, 0U);
2377         CONSTANT(25U, 1U);
2378         CONSTANT(35U, 0x7ffffffeU);
2379         BASIC_BLOCK(4U, 3U, 2U)
2380         {
2381             INST(2U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
2382             INST(27U, Opcode::SaveState).Inputs(3U, 0U).SrcVregs({0U, 3U});
2383             INST(28U, Opcode::NullCheck).ref().Inputs(0U, 27U);
2384             INST(29U, Opcode::LenArray).s32().Inputs(28U);
2385             INST(33U, Opcode::Compare).Inputs(35U, 29U).CC(CC_LT).b();
2386             INST(34U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(33U, 27U);
2387             INST(36U, Opcode::Compare).Inputs(29U, 29U).CC(CC_LE).b();
2388             INST(37U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(36U, 27U);
2389             INST(30U, Opcode::Compare).Inputs(29U, 3U).CC(CC_LT).b();
2390             INST(31U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(30U);
2391         }
2392         BASIC_BLOCK(2U, 3U, 2U)
2393         {
2394             INST(4U, Opcode::Phi).s32().Inputs(3U, 24U);
2395             INST(15U, Opcode::SaveState).Inputs(4U, 0U, 4U).SrcVregs({0U, 3U, 4U});
2396             INST(16U, Opcode::NOP);
2397             INST(18U, Opcode::NOP);
2398             INST(19U, Opcode::StoreArray).s32().Inputs(28U, 4U, 3U);
2399             INST(24U, Opcode::Add).s32().Inputs(4U, 25U);
2400             INST(10U, Opcode::Compare).b().CC(CC_LT).Inputs(29U, 24U);
2401             INST(11U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(10U);
2402         }
2403         BASIC_BLOCK(3U, 1U)
2404         {
2405             INST(26U, Opcode::ReturnVoid).v0id();
2406         }
2407     }
2408     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
2409 }
2410 
BuildGraphUpperWithDec()2411 void ChecksEliminationTest::BuildGraphUpperWithDec()
2412 {
2413     GRAPH(GetGraph())
2414     {
2415         PARAMETER(0U, 0U).ref();  // array
2416         CONSTANT(3U, 0U);         // lower
2417         CONSTANT(25U, 1U);        // increment
2418         BASIC_BLOCK(4U, 3U, 2U)
2419         {
2420             INST(2U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
2421             INST(27U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
2422             INST(28U, Opcode::NullCheck).ref().Inputs(0U, 27U);
2423             INST(29U, Opcode::LenArray).s32().Inputs(28U);
2424             INST(30U, Opcode::Sub).s32().Inputs(29U, 25U);             // upper = len_array - 1
2425             INST(31U, Opcode::Compare).Inputs(30U, 3U).CC(CC_LE).b();  // lower < upper
2426             INST(32U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(31U);
2427         }
2428         BASIC_BLOCK(2U, 3U, 2U)
2429         {
2430             INST(4U, Opcode::Phi).s32().Inputs(3U, 5U);
2431             INST(5U, Opcode::Add).s32().Inputs(4U, 25U);
2432             INST(15U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
2433             INST(16U, Opcode::NullCheck).ref().Inputs(0U, 15U);
2434             INST(18U, Opcode::BoundsCheck).s32().Inputs(29U, 5U, 15U);
2435             INST(19U, Opcode::LoadArray).s32().Inputs(16U, 18U);
2436             INST(20U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
2437             INST(21U, Opcode::NullCheck).ref().Inputs(0U, 20U);
2438             INST(22U, Opcode::BoundsCheck).s32().Inputs(29U, 4U, 20U);
2439             INST(23U, Opcode::StoreArray).s32().Inputs(21U, 22U, 19U);  // a[i] = a[i + 1]
2440             INST(10U, Opcode::Compare).b().CC(CC_LE).Inputs(30U, 5U);
2441             INST(11U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(10U);
2442         }
2443         BASIC_BLOCK(3U, -1L)
2444         {
2445             INST(26U, Opcode::ReturnVoid).v0id();
2446         }
2447     }
2448 }
2449 
TEST_F(ChecksEliminationTest,UpperWithDec)2450 TEST_F(ChecksEliminationTest, UpperWithDec)
2451 {
2452     BuildGraphUpperWithDec();
2453     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
2454     auto graph1 = CreateEmptyGraph();
2455     GRAPH(graph1)
2456     {
2457         PARAMETER(0U, 0U).ref();  // array
2458         CONSTANT(3U, 0U);         // lower
2459         CONSTANT(25U, 1U);        // increment
2460         BASIC_BLOCK(4U, 3U, 2U)
2461         {
2462             INST(2U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
2463             INST(27U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
2464             INST(28U, Opcode::NullCheck).ref().Inputs(0U, 27U);
2465             INST(29U, Opcode::LenArray).s32().Inputs(28U);
2466             INST(30U, Opcode::Sub).s32().Inputs(29U, 25U);             // upper = len_array - 1
2467             INST(31U, Opcode::Compare).Inputs(30U, 3U).CC(CC_LE).b();  // lower < upper
2468             INST(32U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(31U);
2469         }
2470         BASIC_BLOCK(2U, 3U, 2U)
2471         {
2472             INST(4U, Opcode::Phi).s32().Inputs(3U, 5U);
2473             INST(5U, Opcode::Add).s32().Inputs(4U, 25U);
2474             INST(15U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
2475             INST(16U, Opcode::NOP);
2476             INST(18U, Opcode::NOP);
2477             INST(19U, Opcode::LoadArray).s32().Inputs(28U, 5U);
2478             INST(20U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
2479             INST(21U, Opcode::NOP);
2480             INST(22U, Opcode::NOP);
2481             INST(23U, Opcode::StoreArray).s32().Inputs(28U, 4U, 19U);  // a[i] = a[i + 1]
2482             INST(10U, Opcode::Compare).b().CC(CC_LE).Inputs(30U, 5U);  // i < upper
2483             INST(11U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(10U);
2484         }
2485         BASIC_BLOCK(3U, -1L)
2486         {
2487             INST(26U, Opcode::ReturnVoid).v0id();
2488         }
2489     }
2490     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
2491 }
2492 
BuildGraphUnknownUpperWithDec()2493 void ChecksEliminationTest::BuildGraphUnknownUpperWithDec()
2494 {
2495     GRAPH(GetGraph())
2496     {
2497         PARAMETER(0U, 0U).ref();  // array
2498         PARAMETER(1U, 1U).s32();  // X
2499         CONSTANT(3U, 0U);         // lower
2500         CONSTANT(6U, 3U);
2501         CONSTANT(25U, 1U);  // increment
2502         BASIC_BLOCK(4U, 3U, 2U)
2503         {
2504             INST(2U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
2505             INST(27U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
2506             INST(28U, Opcode::NullCheck).ref().Inputs(0U, 27U);
2507             INST(29U, Opcode::LenArray).s32().Inputs(28U);
2508             INST(30U, Opcode::Sub).s32().Inputs(1U, 6U);               // upper = X - 3
2509             INST(31U, Opcode::Compare).Inputs(30U, 3U).CC(CC_LE).b();  // lower < upper
2510             INST(32U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(31U);
2511         }
2512         BASIC_BLOCK(2U, 3U, 2U)
2513         {
2514             INST(4U, Opcode::Phi).s32().Inputs(3U, 5U);
2515             INST(5U, Opcode::Add).s32().Inputs(4U, 25U);
2516             INST(15U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
2517             INST(16U, Opcode::NullCheck).ref().Inputs(0U, 15U);
2518             INST(18U, Opcode::BoundsCheck).s32().Inputs(29U, 5U, 15U);
2519             INST(19U, Opcode::LoadArray).s32().Inputs(16U, 18U);
2520             INST(20U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
2521             INST(21U, Opcode::NullCheck).ref().Inputs(0U, 20U);
2522             INST(22U, Opcode::BoundsCheck).s32().Inputs(29U, 4U, 20U);
2523             INST(23U, Opcode::StoreArray).s32().Inputs(21U, 22U, 19U);  // a[i] = a[i + 1]
2524             INST(10U, Opcode::Compare).b().CC(CC_LE).Inputs(30U, 5U);   // i + 1 < upper
2525             INST(11U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(10U);
2526         }
2527         BASIC_BLOCK(3U, -1L)
2528         {
2529             INST(26U, Opcode::ReturnVoid).v0id();
2530         }
2531     }
2532 }
2533 
TEST_F(ChecksEliminationTest,UnknownUpperWithDec)2534 TEST_F(ChecksEliminationTest, UnknownUpperWithDec)
2535 {
2536     BuildGraphUnknownUpperWithDec();
2537     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
2538     auto graph1 = CreateEmptyGraph();
2539     GRAPH(graph1)
2540     {
2541         PARAMETER(0U, 0U).ref();  // array
2542         PARAMETER(1U, 1U).s32();  // X
2543         CONSTANT(3U, 0U);         // lower
2544         CONSTANT(6U, 3U);
2545         CONSTANT(25U, 1U);  // increment
2546         BASIC_BLOCK(4U, 3U, 2U)
2547         {
2548             INST(2U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
2549             INST(27U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
2550             INST(37U, Opcode::NullCheck).ref().Inputs(0U, 27U).SetFlag(inst_flags::CAN_DEOPTIMIZE);
2551             INST(35U, Opcode::LenArray).s32().Inputs(37U);
2552             INST(39U, Opcode::NOP);
2553             INST(29U, Opcode::LenArray).s32().Inputs(37U);
2554             INST(30U, Opcode::Sub).s32().Inputs(1U, 6U);  // upper = X - 3
2555             INST(41U, Opcode::Sub).s32().Inputs(35U, 25U);
2556             // Deoptimize if len_array - 1 < X - 3
2557             INST(42U, Opcode::Compare).SrcType(DataType::INT32).CC(CC_LT).b().Inputs(41U, 30U);
2558             INST(43U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(42U, 27U);
2559             INST(31U, Opcode::Compare).Inputs(30U, 3U).CC(CC_LE).b();  // lower < upper
2560             INST(32U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(31U);
2561         }
2562         BASIC_BLOCK(2U, 3U, 2U)
2563         {
2564             INST(4U, Opcode::Phi).s32().Inputs(3U, 5U);
2565             INST(5U, Opcode::Add).s32().Inputs(4U, 25U);
2566             INST(15U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
2567             INST(16U, Opcode::NOP);
2568             INST(18U, Opcode::NOP);
2569             INST(19U, Opcode::LoadArray).s32().Inputs(37U, 5U);
2570             INST(20U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
2571             INST(21U, Opcode::NOP);
2572             INST(22U, Opcode::NOP);
2573             INST(23U, Opcode::StoreArray).s32().Inputs(37U, 4U, 19U);  // a[i] = a[i + 1]
2574             INST(10U, Opcode::Compare).b().CC(CC_LE).Inputs(30U, 5U);  // i + 1 < upper
2575             INST(11U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(10U);
2576         }
2577         BASIC_BLOCK(3U, -1L)
2578         {
2579             INST(26U, Opcode::ReturnVoid).v0id();
2580         }
2581     }
2582     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
2583 }
2584 
TEST_F(ChecksEliminationTest,LoopWithoutPreHeaderCompare)2585 TEST_F(ChecksEliminationTest, LoopWithoutPreHeaderCompare)
2586 {
2587     // not applied
2588     GRAPH(GetGraph())
2589     {
2590         CONSTANT(0U, 1U);         // increment
2591         PARAMETER(1U, 0U).s32();  // lower
2592         PARAMETER(2U, 1U).s32();  // upper
2593         PARAMETER(3U, 2U).ref();  // array
2594         BASIC_BLOCK(7U, 3U)
2595         {
2596             INST(4U, Opcode::SaveState).Inputs(0U, 3U).SrcVregs({0U, 1U});
2597             INST(5U, Opcode::NullCheck).ref().Inputs(3U, 4U);
2598             INST(6U, Opcode::LenArray).s32().Inputs(5U);
2599             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
2600         }
2601         BASIC_BLOCK(3U, 4U)
2602         {
2603             INST(9U, Opcode::Phi).s32().Inputs(1U, 13U);
2604             INST(10U, Opcode::SaveState).Inputs(0U, 3U).SrcVregs({0U, 1U});
2605             INST(11U, Opcode::BoundsCheck).s32().Inputs(6U, 9U, 10U);
2606             INST(12U, Opcode::StoreArray).s32().Inputs(3U, 11U, 0U);  // a[i] = 0
2607         }
2608         BASIC_BLOCK(4U, 3U, 6U)
2609         {
2610             INST(13U, Opcode::Add).s32().Inputs(9U, 0U);                              // i++
2611             INST(14U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(13U, 2U);  // i < upper
2612             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(14U);
2613         }
2614         BASIC_BLOCK(6U, 1U)
2615         {
2616             INST(17U, Opcode::Return).s32().Inputs(13U);
2617         }
2618     }
2619     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
2620     ASSERT_FALSE(GetGraph()->RunPass<ChecksElimination>());
2621     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
2622 }
2623 
BuildGraphLoopWithUnknowLowerValue()2624 void ChecksEliminationTest::BuildGraphLoopWithUnknowLowerValue()
2625 {
2626     // applied
2627     GRAPH(GetGraph())
2628     {
2629         CONSTANT(0U, 1U);         // increment
2630         PARAMETER(1U, 0U).s32();  // lower
2631         PARAMETER(3U, 2U).ref();  // array
2632         BASIC_BLOCK(7U, 3U, 6U)
2633         {
2634             INST(4U, Opcode::SaveState).Inputs(0U, 3U).SrcVregs({0U, 1U});
2635             INST(5U, Opcode::NullCheck).ref().Inputs(3U, 4U);
2636             INST(6U, Opcode::LenArray).s32().Inputs(5U);
2637             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
2638             INST(7U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(1U, 6U);  // lower < len_array
2639             INST(8U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(7U);
2640         }
2641         BASIC_BLOCK(3U, 3U, 6U)
2642         {
2643             INST(9U, Opcode::Phi).s32().Inputs(1U, 13U);
2644             INST(10U, Opcode::SaveState).Inputs(0U, 3U).SrcVregs({0U, 1U});
2645             INST(11U, Opcode::BoundsCheck).s32().Inputs(6U, 9U, 10U);
2646             INST(12U, Opcode::StoreArray).s32().Inputs(3U, 11U, 0U);                  // a[i] = 0
2647             INST(13U, Opcode::Add).s32().Inputs(9U, 0U);                              // i++
2648             INST(14U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(13U, 6U);  // i < len_array
2649             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(14U);
2650         }
2651         BASIC_BLOCK(6U, 1U)
2652         {
2653             INST(16U, Opcode::Phi).s32().Inputs(0U, 13U);
2654             INST(17U, Opcode::Return).s32().Inputs(16U);
2655         }
2656     }
2657 }
2658 
TEST_F(ChecksEliminationTest,LoopWithUnknowLowerValue)2659 TEST_F(ChecksEliminationTest, LoopWithUnknowLowerValue)
2660 {
2661     BuildGraphLoopWithUnknowLowerValue();
2662     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
2663     auto graph1 = CreateEmptyGraph();
2664     GRAPH(graph1)
2665     {
2666         CONSTANT(0U, 1U);         // increment
2667         PARAMETER(1U, 0U).s32();  // lower
2668         PARAMETER(3U, 2U).ref();  // array
2669         CONSTANT(22U, 0U);
2670         BASIC_BLOCK(7U, 3U, 6U)
2671         {
2672             INST(4U, Opcode::SaveState).Inputs(0U, 3U).SrcVregs({0U, 1U});
2673             INST(5U, Opcode::NullCheck).ref().Inputs(3U, 4U);
2674             INST(6U, Opcode::LenArray).s32().Inputs(5U);
2675             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
2676             INST(20U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(1U, 22U);  // lower < 0
2677             INST(21U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(20U, 30U);
2678             INST(7U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(1U, 6U);  // lower < len_aray
2679             INST(8U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(7U);
2680         }
2681         BASIC_BLOCK(3U, 3U, 6U)
2682         {
2683             INST(9U, Opcode::Phi).s32().Inputs(1U, 13U);
2684             INST(10U, Opcode::SaveState).Inputs(0U, 3U).SrcVregs({0U, 1U});
2685             INST(11U, Opcode::NOP);
2686             INST(12U, Opcode::StoreArray).s32().Inputs(3U, 9U, 0U);                   // a[i] = 0
2687             INST(13U, Opcode::Add).s32().Inputs(9U, 0U);                              // i++
2688             INST(14U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(13U, 6U);  // i < upper
2689             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(14U);
2690         }
2691         BASIC_BLOCK(6U, 1U)
2692         {
2693             INST(16U, Opcode::Phi).s32().Inputs(0U, 13U);
2694             INST(17U, Opcode::Return).s32().Inputs(16U);
2695         }
2696     }
2697     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
2698 }
2699 
BuildGraphLoopWithUnknowUpperValueLE()2700 void ChecksEliminationTest::BuildGraphLoopWithUnknowUpperValueLE()
2701 {
2702     // applied
2703     GRAPH(GetGraph())
2704     {
2705         CONSTANT(0U, 0U);         // initial
2706         CONSTANT(1U, 1U);         // increment
2707         PARAMETER(2U, 0U).s32();  // X
2708         PARAMETER(3U, 1U).ref();  // array
2709         BASIC_BLOCK(7U, 3U, 6U)
2710         {
2711             INST(4U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
2712             INST(5U, Opcode::NullCheck).ref().Inputs(3U, 4U);
2713             INST(6U, Opcode::LenArray).s32().Inputs(5U);
2714             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
2715             INST(7U, Opcode::Compare).CC(ConditionCode::CC_LE).b().Inputs(0U, 2U);  // i <= X
2716             INST(8U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(7U);
2717         }
2718         BASIC_BLOCK(3U, 3U, 6U)
2719         {
2720             INST(9U, Opcode::Phi).s32().Inputs(0U, 13U);
2721             INST(10U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
2722             INST(11U, Opcode::BoundsCheck).s32().Inputs(6U, 9U, 10U);
2723             INST(12U, Opcode::StoreArray).s32().Inputs(3U, 11U, 0U);                  // a[i] = 0
2724             INST(13U, Opcode::Add).s32().Inputs(9U, 1U);                              // i++
2725             INST(14U, Opcode::Compare).CC(ConditionCode::CC_LE).b().Inputs(13U, 2U);  // i <= X
2726             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(14U);
2727         }
2728         BASIC_BLOCK(6U, 1U)
2729         {
2730             INST(16U, Opcode::Phi).s32().Inputs(0U, 13U);
2731             INST(17U, Opcode::Return).s32().Inputs(16U);
2732         }
2733     }
2734     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
2735 }
2736 
TEST_F(ChecksEliminationTest,LoopWithUnknowUpperValueLE)2737 TEST_F(ChecksEliminationTest, LoopWithUnknowUpperValueLE)
2738 {
2739     BuildGraphLoopWithUnknowUpperValueLE();
2740     auto graph1 = CreateEmptyGraph();
2741     GRAPH(graph1)
2742     {
2743         CONSTANT(0U, 0U);            // initial
2744         CONSTANT(1U, 1U);            // increment
2745         PARAMETER(2U, 0U).s32();     // X
2746         PARAMETER(3U, 1U).ref();     // array
2747         CONSTANT(31U, 0x7ffffffeU);  // max
2748         BASIC_BLOCK(7U, 3U, 6U)
2749         {
2750             INST(4U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
2751             INST(5U, Opcode::NullCheck).ref().Inputs(3U, 4U);
2752             INST(6U, Opcode::LenArray).s32().Inputs(5U);
2753             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
2754             INST(18U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(31U, 2U);  // INT_MAX - 1 < X - infinite loop
2755             INST(19U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(18U, 30U);
2756             INST(32U, Opcode::Compare).CC(ConditionCode::CC_LE).b().Inputs(6U, 2U);  // len_array < X
2757             INST(33U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(32U, 30U);
2758             INST(7U, Opcode::Compare).CC(ConditionCode::CC_LE).b().Inputs(0U, 2U);  // i <= X
2759             INST(8U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(7U);
2760         }
2761         BASIC_BLOCK(3U, 3U, 6U)
2762         {
2763             INST(9U, Opcode::Phi).s32().Inputs(0U, 13U);
2764             INST(10U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
2765             INST(11U, Opcode::NOP);
2766             INST(12U, Opcode::StoreArray).s32().Inputs(3U, 9U, 0U);                   // a[i] = 0
2767             INST(13U, Opcode::Add).s32().Inputs(9U, 1U);                              // i++
2768             INST(14U, Opcode::Compare).CC(ConditionCode::CC_LE).b().Inputs(13U, 2U);  // i <= X
2769             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(14U);
2770         }
2771         BASIC_BLOCK(6U, 1U)
2772         {
2773             INST(16U, Opcode::Phi).s32().Inputs(0U, 13U);
2774             INST(17U, Opcode::Return).s32().Inputs(16U);
2775         }
2776     }
2777     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
2778 }
2779 
BuildGraphLoopWithUnknowUpperValueLT()2780 void ChecksEliminationTest::BuildGraphLoopWithUnknowUpperValueLT()
2781 {
2782     // applied
2783     GRAPH(GetGraph())
2784     {
2785         CONSTANT(0U, 0U);         // initial
2786         CONSTANT(1U, 1U);         // increment
2787         PARAMETER(2U, 0U).s32();  // X
2788         PARAMETER(3U, 1U).ref();  // array
2789         BASIC_BLOCK(7U, 3U, 6U)
2790         {
2791             INST(4U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
2792             INST(5U, Opcode::NullCheck).ref().Inputs(3U, 4U);
2793             INST(6U, Opcode::LenArray).s32().Inputs(5U);
2794             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
2795             INST(7U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(0U, 2U);  // i < X
2796             INST(8U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(7U);
2797         }
2798         BASIC_BLOCK(3U, 3U, 6U)
2799         {
2800             INST(9U, Opcode::Phi).s32().Inputs(0U, 13U);
2801             INST(10U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
2802             INST(11U, Opcode::BoundsCheck).s32().Inputs(6U, 9U, 10U);
2803             INST(12U, Opcode::StoreArray).s32().Inputs(3U, 11U, 0U);                  // a[i] = 0
2804             INST(13U, Opcode::Add).s32().Inputs(9U, 1U);                              // i++
2805             INST(14U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(13U, 2U);  // i < X
2806             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(14U);
2807         }
2808         BASIC_BLOCK(6U, 1U)
2809         {
2810             INST(16U, Opcode::Phi).s32().Inputs(0U, 13U);
2811             INST(17U, Opcode::Return).s32().Inputs(16U);
2812         }
2813     }
2814 }
2815 
TEST_F(ChecksEliminationTest,LoopWithUnknowUpperValueLT)2816 TEST_F(ChecksEliminationTest, LoopWithUnknowUpperValueLT)
2817 {
2818     BuildGraphLoopWithUnknowUpperValueLT();
2819     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
2820 
2821     auto graph1 = CreateEmptyGraph();
2822     GRAPH(graph1)
2823     {
2824         CONSTANT(0U, 0U);         // initial
2825         CONSTANT(1U, 1U);         // increment
2826         PARAMETER(2U, 0U).s32();  // X
2827         PARAMETER(3U, 1U).ref();  // array
2828         BASIC_BLOCK(7U, 3U, 6U)
2829         {
2830             INST(4U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
2831             INST(5U, Opcode::NullCheck).ref().Inputs(3U, 4U);
2832             INST(6U, Opcode::LenArray).s32().Inputs(5U);
2833             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
2834             INST(18U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(6U, 2U);
2835             INST(19U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(18U, 30U);
2836             INST(7U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(0U, 2U);  // i < X
2837             INST(8U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(7U);
2838         }
2839         BASIC_BLOCK(3U, 3U, 6U)
2840         {
2841             INST(9U, Opcode::Phi).s32().Inputs(0U, 13U);
2842             INST(10U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
2843             INST(11U, Opcode::NOP);
2844             INST(12U, Opcode::StoreArray).s32().Inputs(3U, 9U, 0U);                   // a[i] = 0
2845             INST(13U, Opcode::Add).s32().Inputs(9U, 1U);                              // i++
2846             INST(14U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(13U, 2U);  // i < X
2847             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(14U);
2848         }
2849         BASIC_BLOCK(6U, 1U)
2850         {
2851             INST(16U, Opcode::Phi).s32().Inputs(0U, 13U);
2852             INST(17U, Opcode::Return).s32().Inputs(16U);
2853         }
2854     }
2855     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
2856 }
2857 
BuildGraphLoopSeveralBoundsChecks()2858 void ChecksEliminationTest::BuildGraphLoopSeveralBoundsChecks()
2859 {
2860     // applied
2861     // array coping
2862     GRAPH(GetGraph())
2863     {
2864         CONSTANT(0U, 0U);         // initial
2865         CONSTANT(1U, 1U);         // increment
2866         PARAMETER(2U, 0U).ref();  // array1
2867         PARAMETER(3U, 1U).ref();  // array2
2868         PARAMETER(4U, 2U).s32();  // X
2869 
2870         BASIC_BLOCK(7U, 3U, 6U)
2871         {
2872             // check array 1
2873             INST(5U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
2874             INST(6U, Opcode::NullCheck).ref().Inputs(2U, 5U);
2875             INST(7U, Opcode::LenArray).s32().Inputs(6U);
2876             // check array 2
2877             INST(8U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
2878             INST(9U, Opcode::NullCheck).ref().Inputs(3U, 8U);
2879             INST(10U, Opcode::LenArray).s32().Inputs(9U);
2880 
2881             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
2882 
2883             INST(11U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(0U, 4U);  // 0 < X
2884             INST(12U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(11U);
2885         }
2886         BASIC_BLOCK(3U, 3U, 6U)
2887         {
2888             INST(13U, Opcode::Phi).s32().Inputs(0U, 20U);  // i
2889             INST(14U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
2890             INST(15U, Opcode::BoundsCheck).s32().Inputs(7U, 13U, 14U);
2891             INST(16U, Opcode::LoadArray).s32().Inputs(2U, 15U);
2892             INST(17U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
2893             INST(18U, Opcode::BoundsCheck).s32().Inputs(10U, 13U, 17U);
2894             INST(19U, Opcode::StoreArray).s32().Inputs(3U, 18U, 16U);                 // array2[i] = array1[i]
2895             INST(20U, Opcode::Add).s32().Inputs(13U, 1U);                             // i++
2896             INST(21U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(20U, 4U);  // i < X
2897             INST(22U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(21U);
2898         }
2899         BASIC_BLOCK(6U, 1U)
2900         {
2901             INST(23U, Opcode::Phi).s32().Inputs(0U, 20U);
2902             INST(24U, Opcode::Return).s32().Inputs(23U);
2903         }
2904     }
2905 }
2906 
TEST_F(ChecksEliminationTest,LoopSeveralBoundsChecks)2907 TEST_F(ChecksEliminationTest, LoopSeveralBoundsChecks)
2908 {
2909     BuildGraphLoopSeveralBoundsChecks();
2910     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
2911     auto graph1 = CreateEmptyGraph();
2912     GRAPH(graph1)
2913     {
2914         CONSTANT(0U, 0U);         // initial
2915         CONSTANT(1U, 1U);         // increment
2916         PARAMETER(2U, 0U).ref();  // array1
2917         PARAMETER(3U, 1U).ref();  // array2
2918         PARAMETER(4U, 2U).s32();  // X
2919 
2920         BASIC_BLOCK(7U, 3U, 6U)
2921         {
2922             // check array 1
2923             INST(5U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
2924             INST(6U, Opcode::NullCheck).ref().Inputs(2U, 5U);
2925             INST(7U, Opcode::LenArray).s32().Inputs(6U);
2926             // check array 2
2927             INST(8U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
2928             INST(9U, Opcode::NullCheck).ref().Inputs(3U, 8U);
2929             INST(10U, Opcode::LenArray).s32().Inputs(9U);
2930 
2931             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
2932             INST(27U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(7U, 4U);  // len_array1 < X
2933             INST(28U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(27U, 30U);
2934             INST(25U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(10U, 4U);  // len_array2 < X
2935             INST(26U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(25U, 30U);
2936 
2937             INST(11U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(0U, 4U);  // 0 < X
2938             INST(12U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(11U);
2939         }
2940         BASIC_BLOCK(3U, 3U, 6U)
2941         {
2942             INST(13U, Opcode::Phi).s32().Inputs(0U, 20U);  // i
2943             INST(14U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
2944             INST(15U, Opcode::NOP);
2945             INST(16U, Opcode::LoadArray).s32().Inputs(2U, 13U);
2946             INST(17U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
2947             INST(18U, Opcode::NOP);
2948             INST(19U, Opcode::StoreArray).s32().Inputs(3U, 13U, 16U);                 // array2[i] = array1[i]
2949             INST(20U, Opcode::Add).s32().Inputs(13U, 1U);                             // i++
2950             INST(21U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(20U, 4U);  // i < X
2951             INST(22U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(21U);
2952         }
2953         BASIC_BLOCK(6U, 1U)
2954         {
2955             INST(23U, Opcode::Phi).s32().Inputs(0U, 20U);
2956             INST(24U, Opcode::Return).s32().Inputs(23U);
2957         }
2958     }
2959     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
2960 }
2961 
BuildGraphLoopSeveralIndexesBoundsChecks()2962 void ChecksEliminationTest::BuildGraphLoopSeveralIndexesBoundsChecks()
2963 {
2964     // applied
2965     // array coping
2966     GRAPH(GetGraph())
2967     {
2968         CONSTANT(0U, 0U);         // initial
2969         CONSTANT(1U, 1U);         // increment
2970         PARAMETER(2U, 0U).ref();  // array
2971         PARAMETER(3U, 1U).s32();  // Y
2972         PARAMETER(4U, 2U).s32();  // X
2973 
2974         BASIC_BLOCK(7U, 3U, 6U)
2975         {
2976             // check array
2977             INST(5U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
2978             INST(6U, Opcode::NullCheck).ref().Inputs(2U, 5U);
2979             INST(7U, Opcode::LenArray).s32().Inputs(6U);
2980 
2981             INST(36U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
2982 
2983             INST(11U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(3U, 4U);  // Y < X
2984             INST(12U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(11U);
2985         }
2986         BASIC_BLOCK(3U, 3U, 6U)
2987         {
2988             INST(13U, Opcode::Phi).s32().Inputs(3U, 20U);  // i
2989 
2990             INST(14U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
2991             INST(15U, Opcode::BoundsCheck).s32().Inputs(7U, 13U, 14U);
2992             INST(16U, Opcode::LoadArray).s32().Inputs(2U, 15U);  // array[i]
2993 
2994             INST(26U, Opcode::Sub).s32().Inputs(13U, 1U);  // i - 1
2995             INST(27U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
2996             INST(28U, Opcode::BoundsCheck).s32().Inputs(7U, 26U, 27U);
2997             INST(29U, Opcode::LoadArray).s32().Inputs(2U, 28U);  // array[i-1]
2998 
2999             INST(30U, Opcode::Add).s32().Inputs(13U, 1U);  // i + 1
3000             INST(31U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
3001             INST(32U, Opcode::BoundsCheck).s32().Inputs(7U, 30U, 31U);
3002             INST(33U, Opcode::LoadArray).s32().Inputs(2U, 32U);  // array[i+1]
3003 
3004             INST(34U, Opcode::Add).s32().Inputs(16U, 29U);  // array[i-1] + array[i]
3005             INST(35U, Opcode::Add).s32().Inputs(34U, 33U);  // array[i-1] + array[i] + array[i+1]
3006 
3007             INST(17U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
3008             INST(18U, Opcode::BoundsCheck).s32().Inputs(7U, 13U, 17U);
3009             INST(19U, Opcode::StoreArray).s32().Inputs(2U, 18U, 35U);  // array[i] = array[i-1] + array[i] + array[i+1]
3010 
3011             INST(20U, Opcode::Add).s32().Inputs(13U, 1U);                             // i++
3012             INST(21U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(20U, 4U);  // i < X
3013             INST(22U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(21U);
3014         }
3015         BASIC_BLOCK(6U, 1U)
3016         {
3017             INST(23U, Opcode::Phi).s32().Inputs(0U, 20U);
3018             INST(24U, Opcode::Return).s32().Inputs(23U);
3019         }
3020     }
3021 }
3022 
3023 // CC-OFFNXT(huge_method, G.FUN.01) graph creation
TEST_F(ChecksEliminationTest,LoopSeveralIndexesBoundsChecks)3024 TEST_F(ChecksEliminationTest, LoopSeveralIndexesBoundsChecks)
3025 {
3026     BuildGraphLoopSeveralIndexesBoundsChecks();
3027     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
3028     auto graph1 = CreateEmptyGraph();
3029     GRAPH(graph1)
3030     {
3031         CONSTANT(0U, 0U);         // initial
3032         CONSTANT(1U, 1U);         // increment
3033         PARAMETER(2U, 0U).ref();  // array
3034         PARAMETER(3U, 1U).s32();  // Y
3035         PARAMETER(4U, 2U).s32();  // X
3036         CONSTANT(43U, -1L);
3037         BASIC_BLOCK(7U, 3U, 6U)
3038         {
3039             // check array
3040             INST(5U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
3041             INST(6U, Opcode::NullCheck).ref().Inputs(2U, 5U);
3042             INST(7U, Opcode::LenArray).s32().Inputs(6U);
3043 
3044             INST(36U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
3045             INST(37U, Opcode::Add).s32().Inputs(3U, 43U);
3046             INST(38U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(37U, 0U);  // Y-1 < 0
3047             INST(39U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(38U, 36U);
3048 
3049             INST(40U, Opcode::Sub).s32().Inputs(7U, 1U);
3050             INST(41U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(40U, 4U);  // len_array - 1 < X
3051             INST(42U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(41U, 36U);
3052 
3053             INST(11U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(3U, 4U);  // Y < X
3054             INST(12U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(11U);
3055         }
3056         BASIC_BLOCK(3U, 3U, 6U)
3057         {
3058             INST(13U, Opcode::Phi).s32().Inputs(3U, 20U);  // i
3059 
3060             INST(14U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
3061             INST(15U, Opcode::NOP);
3062             INST(16U, Opcode::LoadArray).s32().Inputs(2U, 13U);  // array[i]
3063 
3064             INST(26U, Opcode::Sub).s32().Inputs(13U, 1U);  // i - 1
3065             INST(27U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
3066             INST(28U, Opcode::NOP);
3067             INST(29U, Opcode::LoadArray).s32().Inputs(2U, 26U);  // array[i-1]
3068 
3069             INST(30U, Opcode::Add).s32().Inputs(13U, 1U);  // i + 1
3070             INST(31U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
3071             INST(32U, Opcode::NOP);
3072             INST(33U, Opcode::LoadArray).s32().Inputs(2U, 30U);  // array[i+1]
3073 
3074             INST(34U, Opcode::Add).s32().Inputs(16U, 29U);  // array[i-1] + array[i]
3075             INST(35U, Opcode::Add).s32().Inputs(34U, 33U);  // array[i-1] + array[i] + array[i+1]
3076 
3077             INST(17U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
3078             INST(18U, Opcode::NOP);
3079             INST(19U, Opcode::StoreArray).s32().Inputs(2U, 13U, 35U);  // array[i] = array[i-1] + array[i] + array[i+1]
3080 
3081             INST(20U, Opcode::Add).s32().Inputs(13U, 1U);                             // i++
3082             INST(21U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(20U, 4U);  // i < X
3083             INST(22U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(21U);
3084         }
3085         BASIC_BLOCK(6U, 1U)
3086         {
3087             INST(23U, Opcode::Phi).s32().Inputs(0U, 20U);
3088             INST(24U, Opcode::Return).s32().Inputs(23U);
3089         }
3090     }
3091     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
3092 }
3093 
BuildGraphHeadExitLoop()3094 void ChecksEliminationTest::BuildGraphHeadExitLoop()
3095 {
3096     GRAPH(GetGraph())
3097     {
3098         CONSTANT(0U, 0U);  // initial
3099         CONSTANT(1U, 1U);  // increment
3100         PARAMETER(2U, 0U).ref();
3101         PARAMETER(3U, 1U).s32();  // X
3102         BASIC_BLOCK(2U, 3U)
3103         {
3104             INST(4U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
3105             INST(5U, Opcode::NullCheck).ref().Inputs(2U, 4U);
3106             INST(6U, Opcode::LenArray).s32().Inputs(5U);
3107             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
3108         }
3109         BASIC_BLOCK(3U, 4U, 5U)
3110         {
3111             INST(7U, Opcode::Phi).s32().Inputs(0U, 13U);
3112             INST(8U, Opcode::Compare).CC(CC_LT).b().Inputs(7U, 3U);  // i < X
3113             INST(9U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(8U);
3114         }
3115         BASIC_BLOCK(4U, 3U)
3116         {
3117             INST(10U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
3118             INST(11U, Opcode::BoundsCheck).s32().Inputs(6U, 7U, 10U);
3119             INST(12U, Opcode::StoreArray).s32().Inputs(5U, 11U, 0U);  // a[i] = 0
3120             INST(13U, Opcode::Add).s32().Inputs(7U, 1U);              // i++
3121         }
3122         BASIC_BLOCK(5U, 1U)
3123         {
3124             INST(14U, Opcode::Return).ref().Inputs(5U);
3125         }
3126     }
3127 }
3128 
TEST_F(ChecksEliminationTest,HeadExitLoop)3129 TEST_F(ChecksEliminationTest, HeadExitLoop)
3130 {
3131     BuildGraphHeadExitLoop();
3132     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
3133     auto graph = CreateEmptyGraph();
3134     GRAPH(graph)
3135     {
3136         CONSTANT(0U, 0U);  // initial
3137         CONSTANT(1U, 1U);  // increment
3138         PARAMETER(2U, 0U).ref();
3139         PARAMETER(3U, 1U).s32();
3140         BASIC_BLOCK(2U, 3U)
3141         {
3142             INST(4U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
3143             INST(5U, Opcode::NullCheck).ref().Inputs(2U, 4U);
3144             INST(6U, Opcode::LenArray).s32().Inputs(5U);
3145             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
3146             INST(15U, Opcode::Compare).b().CC(ConditionCode::CC_LT).Inputs(6U, 3U);  // len_array < X
3147             INST(16U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(15U, 30U);
3148         }
3149         BASIC_BLOCK(3U, 4U, 5U)
3150         {
3151             INST(7U, Opcode::Phi).s32().Inputs(0U, 13U);
3152             INST(8U, Opcode::Compare).CC(CC_LT).b().Inputs(7U, 3U);  // i < X
3153             INST(9U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(8U);
3154         }
3155         BASIC_BLOCK(4U, 3U)
3156         {
3157             INST(10U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
3158             INST(11U, Opcode::NOP);
3159             INST(12U, Opcode::StoreArray).s32().Inputs(5U, 7U, 0U);  // a[i] = 0
3160             INST(13U, Opcode::Add).s32().Inputs(7U, 1U);             // i++
3161         }
3162         BASIC_BLOCK(5U, 1U)
3163         {
3164             INST(14U, Opcode::Return).ref().Inputs(5U);
3165         }
3166     }
3167     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3168 }
3169 
TEST_F(ChecksEliminationTest,BoundsCheckInHeader)3170 TEST_F(ChecksEliminationTest, BoundsCheckInHeader)
3171 {
3172     GRAPH(GetGraph())
3173     {
3174         CONSTANT(0U, 0U);  // initial
3175         CONSTANT(1U, 1U);  // increment
3176         PARAMETER(2U, 0U).ref();
3177         PARAMETER(3U, 1U).s32();
3178         BASIC_BLOCK(2U, 3U)
3179         {
3180             INST(4U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
3181             INST(5U, Opcode::NullCheck).ref().Inputs(2U, 4U);
3182             INST(6U, Opcode::LenArray).s32().Inputs(5U);
3183             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
3184         }
3185         BASIC_BLOCK(3U, 4U, 5U)
3186         {
3187             INST(7U, Opcode::Phi).s32().Inputs(0U, 13U);
3188             INST(10U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
3189             INST(11U, Opcode::BoundsCheck).s32().Inputs(6U, 7U, 10U);
3190             INST(12U, Opcode::StoreArray).s32().Inputs(5U, 11U, 0U);  // a[i] = 0
3191             INST(8U, Opcode::Compare).CC(CC_LT).b().Inputs(7U, 3U);   // i < X
3192             INST(9U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(8U);
3193         }
3194         BASIC_BLOCK(4U, 3U)
3195         {
3196             INST(13U, Opcode::Add).s32().Inputs(7U, 1U);  // i++
3197         }
3198         BASIC_BLOCK(5U, 1U)
3199         {
3200             INST(14U, Opcode::Return).ref().Inputs(5U);
3201         }
3202     }
3203     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
3204     ASSERT_FALSE(GetGraph()->RunPass<ChecksElimination>());
3205     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
3206 }
3207 
BuildGraphLoopTest1()3208 void ChecksEliminationTest::BuildGraphLoopTest1()
3209 {
3210     GRAPH(GetGraph())
3211     {
3212         CONSTANT(0U, 0U);          // initial
3213         CONSTANT(1U, 1U);          // increment
3214         PARAMETER(13U, 0U).ref();  // Array
3215         PARAMETER(27U, 1U).s32();  // X
3216         BASIC_BLOCK(2U, 6U, 3U)
3217         {
3218             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
3219             INST(14U, Opcode::Compare).CC(ConditionCode::CC_GE).b().Inputs(0U, 27U);  // i < X
3220             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(14U);
3221         }
3222         BASIC_BLOCK(3U, 6U, 3U)
3223         {
3224             INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);
3225             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 13U, 27U).SrcVregs({0U, 1U, 2U, 3U});
3226             INST(16U, Opcode::NullCheck).ref().Inputs(13U, 7U);
3227             INST(17U, Opcode::LenArray).s32().Inputs(16U);
3228             INST(8U, Opcode::BoundsCheck).s32().Inputs(17U, 4U, 7U);
3229             INST(9U, Opcode::StoreArray).s32().Inputs(16U, 8U, 0U);                   // a[i] = 0
3230             INST(10U, Opcode::Add).s32().Inputs(4U, 1U);                              // i++
3231             INST(5U, Opcode::Compare).CC(ConditionCode::CC_GE).b().Inputs(10U, 27U);  // i < X
3232             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
3233         }
3234         BASIC_BLOCK(6U, 1U)
3235         {
3236             INST(26U, Opcode::Phi).s32().Inputs(0U, 10U);
3237             INST(12U, Opcode::Return).s32().Inputs(26U);
3238         }
3239     }
3240 }
3241 
TEST_F(ChecksEliminationTest,LoopTest1)3242 TEST_F(ChecksEliminationTest, LoopTest1)
3243 {
3244     BuildGraphLoopTest1();
3245     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
3246     auto graph1 = CreateEmptyGraph();
3247     GRAPH(graph1)
3248     {
3249         CONSTANT(0U, 0U);  // initial
3250         CONSTANT(1U, 1U);  // increment
3251         PARAMETER(3U, 0U).ref();
3252         PARAMETER(2U, 1U).s32();
3253         BASIC_BLOCK(2U, 5U, 3U)
3254         {
3255             INST(20U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
3256             INST(33U, Opcode::NullCheck).ref().Inputs(3U, 20U).SetFlag(inst_flags::CAN_DEOPTIMIZE);  // array != nullptr
3257             INST(22U, Opcode::LenArray).s32().Inputs(33U);
3258             INST(23U, Opcode::Compare).SrcType(DataType::INT32).CC(CC_LT).b().Inputs(22U, 2U);  // len_array < X
3259             INST(24U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(23U, 20U);
3260             INST(5U, Opcode::Compare).SrcType(DataType::INT32).CC(CC_GE).b().Inputs(0U, 2U);  // 0 < X
3261             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
3262         }
3263         BASIC_BLOCK(3U, 5U, 3U)
3264         {
3265             INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);
3266             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 3U, 2U).SrcVregs({0U, 1U, 2U, 3U});
3267             INST(15U, Opcode::NOP);
3268             INST(16U, Opcode::LenArray).s32().Inputs(33U);
3269             INST(8U, Opcode::NOP);
3270             INST(9U, Opcode::StoreArray).s32().Inputs(33U, 4U, 0U);    // a[i] = 0
3271             INST(10U, Opcode::Add).s32().Inputs(4U, 1U);               // i++
3272             INST(13U, Opcode::Compare).CC(CC_GE).b().Inputs(10U, 2U);  // i < X
3273             INST(14U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(13U);
3274         }
3275         BASIC_BLOCK(5U, 1U)
3276         {
3277             INST(26U, Opcode::Phi).s32().Inputs(0U, 10U);
3278             INST(12U, Opcode::Return).s32().Inputs(26U);
3279         }
3280     }
3281     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
3282 }
3283 
BuildGraphBatchLoopTest()3284 void ChecksEliminationTest::BuildGraphBatchLoopTest()
3285 {
3286     GRAPH(GetGraph())
3287     {
3288         CONSTANT(0U, 0U);  // initial
3289         CONSTANT(1U, 1U);
3290         CONSTANT(2U, 2U);
3291         CONSTANT(3U, 3U);         // increment
3292         PARAMETER(4U, 0U).ref();  // Array
3293         BASIC_BLOCK(2U, 4U, 3U)
3294         {
3295             INST(5U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U, 4U).SrcVregs({0U, 1U, 2U, 3U, 4U});
3296             INST(6U, Opcode::NullCheck).ref().Inputs(4U, 5U);
3297             INST(7U, Opcode::LenArray).s32().Inputs(6U);
3298             INST(30U, Opcode::SaveStateDeoptimize).Inputs(4U).SrcVregs({0U});
3299             INST(25U, Opcode::Compare).CC(CC_GE).b().Inputs(0U, 7U);
3300             INST(26U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(25U);
3301         }
3302         BASIC_BLOCK(3U, 4U, 3U)
3303         {
3304             INST(8U, Opcode::Phi).s32().Inputs(0U, 20U);
3305             INST(9U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U, 4U, 7U).SrcVregs({0U, 1U, 2U, 3U, 4U, 7U});
3306             INST(10U, Opcode::NullCheck).ref().Inputs(4U, 9U);
3307 
3308             INST(12U, Opcode::Add).s32().Inputs(8U, 1U);
3309             INST(13U, Opcode::BoundsCheck).s32().Inputs(7U, 12U, 9U);
3310             INST(14U, Opcode::LoadArray).s32().Inputs(10U, 13U);
3311 
3312             INST(15U, Opcode::BoundsCheck).s32().Inputs(7U, 8U, 9U);
3313             INST(16U, Opcode::StoreArray).s32().Inputs(10U, 15U, 14U);  // a[i] = a[i + 1]
3314 
3315             INST(17U, Opcode::Add).s32().Inputs(8U, 2U);
3316             INST(18U, Opcode::BoundsCheck).s32().Inputs(7U, 17U, 9U);
3317             INST(19U, Opcode::StoreArray).s32().Inputs(10U, 18U, 14U);  // a[i + 2] = a[i + 1]
3318 
3319             INST(20U, Opcode::Add).s32().Inputs(8U, 3U);               // i += 3
3320             INST(21U, Opcode::Compare).CC(CC_GE).b().Inputs(20U, 7U);  // i < X
3321             INST(22U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(21U);
3322         }
3323         BASIC_BLOCK(4U, 1U)
3324         {
3325             INST(23U, Opcode::ReturnVoid).v0id();
3326         }
3327     }
3328 }
3329 
TEST_F(ChecksEliminationTest,BatchLoopTest)3330 TEST_F(ChecksEliminationTest, BatchLoopTest)
3331 {
3332     BuildGraphBatchLoopTest();
3333     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
3334     auto graph1 = CreateEmptyGraph();
3335     GRAPH(graph1)
3336     {
3337         CONSTANT(0U, 0U);  // initial
3338         CONSTANT(1U, 1U);
3339         CONSTANT(2U, 2U);
3340         CONSTANT(3U, 3U);         // increment
3341         PARAMETER(4U, 0U).ref();  // Array
3342         CONSTANT(36U, 0x7ffffffdU);
3343         BASIC_BLOCK(2U, 4U, 3U)
3344         {
3345             INST(5U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U, 4U).SrcVregs({0U, 1U, 2U, 3U, 4U});
3346             INST(6U, Opcode::NullCheck).ref().Inputs(4U, 5U);
3347             INST(7U, Opcode::LenArray).s32().Inputs(6U);
3348             INST(30U, Opcode::SaveStateDeoptimize).Inputs(4U).SrcVregs({0U});
3349             INST(31U, Opcode::Compare).CC(CC_LT).b().Inputs(36U, 7U);
3350             INST(32U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(31U, 30U);
3351             INST(33U, Opcode::Mod).s32().Inputs(7U, 3U);
3352             INST(34U, Opcode::Compare).CC(CC_NE).b().Inputs(33U, 0U);
3353             INST(35U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(34U, 30U);
3354             INST(25U, Opcode::Compare).CC(CC_GE).b().Inputs(0U, 7U);
3355             INST(26U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(25U);
3356         }
3357         BASIC_BLOCK(3U, 4U, 3U)
3358         {
3359             INST(8U, Opcode::Phi).s32().Inputs(0U, 20U);
3360             INST(9U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U, 4U, 7U).SrcVregs({0U, 1U, 2U, 3U, 4U, 7U});
3361             INST(10U, Opcode::NOP);
3362 
3363             INST(12U, Opcode::Add).s32().Inputs(8U, 1U);
3364             INST(13U, Opcode::NOP);
3365             INST(14U, Opcode::LoadArray).s32().Inputs(6U, 12U);
3366 
3367             INST(15U, Opcode::NOP);
3368             INST(16U, Opcode::StoreArray).s32().Inputs(6U, 8U, 14U);  // a[i] = a[i + 1]
3369 
3370             INST(17U, Opcode::Add).s32().Inputs(8U, 2U);
3371             INST(18U, Opcode::NOP);
3372             INST(19U, Opcode::StoreArray).s32().Inputs(6U, 17U, 14U);  // a[i + 2] = a[i + 1]
3373 
3374             INST(20U, Opcode::Add).s32().Inputs(8U, 3U);               // i += 3
3375             INST(21U, Opcode::Compare).CC(CC_GE).b().Inputs(20U, 7U);  // i < X
3376             INST(22U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(21U);
3377         }
3378         BASIC_BLOCK(4U, 1U)
3379         {
3380             INST(23U, Opcode::ReturnVoid).v0id();
3381         }
3382     }
3383     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
3384 }
3385 
TEST_F(ChecksEliminationTest,NewlyAlllocatedCheck)3386 TEST_F(ChecksEliminationTest, NewlyAlllocatedCheck)
3387 {
3388     GRAPH(GetGraph())
3389     {
3390         CONSTANT(0U, 0x1U).s64();
3391         CONSTANT(1U, 0x0U).s64();
3392         CONSTANT(5U, 0x2aU).s64();
3393         BASIC_BLOCK(2U, -1L)
3394         {
3395             INST(43U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
3396             INST(44U, Opcode::LoadAndInitClass).ref().Inputs().TypeId(68U);
3397             INST(4U, Opcode::NewArray).ref().Inputs(44U, 0U, 43U).TypeId(79U);
3398             INST(6U, Opcode::SaveState).Inputs(5U, 1U, 4U).SrcVregs({2U, 1U, 0U});
3399             INST(7U, Opcode::NullCheck).ref().Inputs(4U, 6U);
3400             INST(10U, Opcode::StoreArray).s32().Inputs(7U, 1U, 5U);
3401             INST(11U, Opcode::Return).ref().Inputs(4U);
3402         }
3403     }
3404     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
3405     auto graph1 = CreateEmptyGraph();
3406     GRAPH(graph1)
3407     {
3408         CONSTANT(0U, 0x1U).s64();
3409         CONSTANT(1U, 0x0U).s64();
3410         CONSTANT(5U, 0x2aU).s64();
3411         BASIC_BLOCK(2U, -1L)
3412         {
3413             INST(43U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
3414             INST(44U, Opcode::LoadAndInitClass).ref().Inputs().TypeId(68U);
3415             INST(4U, Opcode::NewArray).ref().Inputs(44U, 0U, 43U).TypeId(79U);
3416             INST(6U, Opcode::SaveState).Inputs(5U, 1U, 4U).SrcVregs({2U, 1U, 0U});
3417             INST(7U, Opcode::NOP);
3418             INST(10U, Opcode::StoreArray).s32().Inputs(4U, 1U, 5U);
3419             INST(11U, Opcode::Return).ref().Inputs(4U);
3420         }
3421     }
3422     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
3423 }
3424 
TEST_F(ChecksEliminationTest,DominatedBoundsCheck)3425 TEST_F(ChecksEliminationTest, DominatedBoundsCheck)
3426 {
3427     GRAPH(GetGraph())
3428     {
3429         PARAMETER(0U, 0U).ref();
3430         PARAMETER(1U, 1U).s64();
3431         BASIC_BLOCK(2U, -1L)
3432         {
3433             INST(2U, Opcode::SaveState).Inputs(1U, 1U, 0U).SrcVregs({2U, 1U, 0U});
3434             INST(4U, Opcode::LenArray).s32().Inputs(0U);
3435             INST(5U, Opcode::BoundsCheck).s32().Inputs(4U, 1U, 2U);
3436             INST(6U, Opcode::LoadArray).s64().Inputs(0U, 5U);
3437             INST(7U, Opcode::SaveState).Inputs(6U, 1U, 0U).SrcVregs({2U, 1U, 0U});
3438             INST(10U, Opcode::BoundsCheck).s32().Inputs(4U, 1U, 7U);
3439             INST(11U, Opcode::StoreArray).s64().Inputs(0U, 10U, 6U);
3440             INST(12U, Opcode::ReturnVoid).v0id();
3441         }
3442     }
3443     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
3444     auto graph1 = CreateEmptyGraph();
3445     GRAPH(graph1)
3446     {
3447         PARAMETER(0U, 0U).ref();
3448         PARAMETER(1U, 1U).s64();
3449         BASIC_BLOCK(2U, -1L)
3450         {
3451             INST(2U, Opcode::SaveState).Inputs(1U, 1U, 0U).SrcVregs({2U, 1U, 0U});
3452             INST(4U, Opcode::LenArray).s32().Inputs(0U);
3453             INST(5U, Opcode::BoundsCheck).s32().Inputs(4U, 1U, 2U);
3454             INST(6U, Opcode::LoadArray).s64().Inputs(0U, 5U);
3455             INST(7U, Opcode::SaveState).Inputs(6U, 1U, 0U).SrcVregs({2U, 1U, 0U});
3456             INST(10U, Opcode::NOP);
3457             INST(11U, Opcode::StoreArray).s64().Inputs(0U, 5U, 6U);
3458             INST(12U, Opcode::ReturnVoid).v0id();
3459         }
3460     }
3461     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
3462 }
3463 
BuildGraphGroupedBoundsCheck()3464 void ChecksEliminationTest::BuildGraphGroupedBoundsCheck()
3465 {
3466     GRAPH(GetGraph())
3467     {
3468         PARAMETER(0U, 0U).ref();  // a
3469         PARAMETER(1U, 1U).s32();  // x
3470         CONSTANT(2U, 1U);
3471         CONSTANT(5U, -2L);
3472         BASIC_BLOCK(2U, -1L)
3473         {
3474             INST(6U, Opcode::LenArray).s32().Inputs(0U);
3475             // a[x] = 1
3476             INST(7U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
3477             INST(8U, Opcode::BoundsCheck).s32().Inputs(6U, 1U, 7U);
3478             INST(9U, Opcode::StoreArray).s64().Inputs(0U, 8U, 2U);
3479             // a[x-1] = 1
3480             INST(10U, Opcode::Sub).s32().Inputs(1U, 2U);
3481             INST(11U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
3482             INST(12U, Opcode::BoundsCheck).s32().Inputs(6U, 10U, 11U);
3483             INST(13U, Opcode::StoreArray).s64().Inputs(0U, 12U, 2U);
3484             // a[x+1] = 1
3485             INST(14U, Opcode::Add).s32().Inputs(1U, 2U);
3486             INST(15U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
3487             INST(16U, Opcode::BoundsCheck).s32().Inputs(6U, 14U, 15U);
3488             INST(17U, Opcode::StoreArray).s64().Inputs(0U, 16U, 2U);
3489             // a[x+(-2)] = 1
3490             INST(18U, Opcode::Add).s32().Inputs(1U, 5U);
3491             INST(19U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
3492             INST(20U, Opcode::BoundsCheck).s32().Inputs(6U, 18U, 19U);
3493             INST(21U, Opcode::StoreArray).s64().Inputs(0U, 20U, 2U);
3494             // a[x-(-2)] = 1
3495             INST(22U, Opcode::Sub).s32().Inputs(1U, 5U);
3496             INST(23U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
3497             INST(24U, Opcode::BoundsCheck).s32().Inputs(6U, 22U, 23U);
3498             INST(25U, Opcode::StoreArray).s64().Inputs(0U, 24U, 2U);
3499             INST(26U, Opcode::ReturnVoid).v0id();
3500         }
3501     }
3502 }
3503 
TEST_F(ChecksEliminationTest,GroupedBoundsCheck)3504 TEST_F(ChecksEliminationTest, GroupedBoundsCheck)
3505 {
3506     BuildGraphGroupedBoundsCheck();
3507     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
3508     auto graph1 = CreateEmptyGraph();
3509     GRAPH(graph1)
3510     {
3511         PARAMETER(0U, 0U).ref();  // a
3512         PARAMETER(1U, 1U).s32();  // x
3513         CONSTANT(2U, 1U);
3514         CONSTANT(5U, -2L);
3515         CONSTANT(3U, 2U);
3516         CONSTANT(4U, 0U);
3517         BASIC_BLOCK(2U, -1L)
3518         {
3519             INST(6U, Opcode::LenArray).s32().Inputs(0U);
3520             INST(7U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
3521 
3522             INST(30U, Opcode::Add).s32().Inputs(1U, 5U);
3523             INST(31U, Opcode::Compare).b().CC(CC_LT).SrcType(DataType::INT32).Inputs(30U, 4U);
3524             INST(32U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(31U, 7U);
3525             INST(27U, Opcode::Add).s32().Inputs(1U, 3U);
3526             INST(28U, Opcode::Compare).b().CC(CC_GE).SrcType(DataType::INT32).Inputs(27U, 6U);
3527             INST(29U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(28U, 7U);
3528 
3529             // a[x] = 1
3530             INST(8U, Opcode::NOP);
3531             INST(9U, Opcode::StoreArray).s64().Inputs(0U, 1U, 2U);
3532             // a[x-1] = 1
3533             INST(10U, Opcode::Sub).s32().Inputs(1U, 2U);
3534             INST(11U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
3535             INST(12U, Opcode::NOP);
3536             INST(13U, Opcode::StoreArray).s64().Inputs(0U, 10U, 2U);
3537             // a[x+1] = 1
3538             INST(14U, Opcode::Add).s32().Inputs(1U, 2U);
3539             INST(15U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
3540             INST(16U, Opcode::NOP);
3541             INST(17U, Opcode::StoreArray).s64().Inputs(0U, 14U, 2U);
3542             // a[x+(-2)] = 1
3543             INST(18U, Opcode::Add).s32().Inputs(1U, 5U);
3544             INST(19U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
3545             INST(20U, Opcode::NOP);
3546             INST(21U, Opcode::StoreArray).s64().Inputs(0U, 18U, 2U);
3547             // a[x-(-2)] = 1
3548             INST(22U, Opcode::Sub).s32().Inputs(1U, 5U);
3549             INST(23U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
3550             INST(24U, Opcode::NOP);
3551             INST(25U, Opcode::StoreArray).s64().Inputs(0U, 22U, 2U);
3552             INST(26U, Opcode::ReturnVoid).v0id();
3553         }
3554     }
3555     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
3556 }
3557 
BuildGraphGroupedBoundsCheckConstIndex()3558 void ChecksEliminationTest::BuildGraphGroupedBoundsCheckConstIndex()
3559 {
3560     GRAPH(GetGraph())
3561     {
3562         PARAMETER(0U, 0U).ref();  // a
3563         CONSTANT(2U, 0U);
3564         CONSTANT(3U, 1U);
3565         CONSTANT(4U, 2U);
3566         CONSTANT(5U, 3U);
3567         BASIC_BLOCK(2U, -1L)
3568         {
3569             INST(6U, Opcode::LenArray).s32().Inputs(0U);
3570             INST(7U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
3571 
3572             // a[0] = 1
3573             INST(8U, Opcode::BoundsCheck).s32().Inputs(6U, 2U, 7U);
3574             INST(9U, Opcode::StoreArray).s64().Inputs(0U, 8U, 2U);
3575             // a[1] = 1
3576             INST(11U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
3577             INST(12U, Opcode::BoundsCheck).s32().Inputs(6U, 3U, 11U);
3578             INST(13U, Opcode::StoreArray).s64().Inputs(0U, 12U, 2U);
3579             // a[2] = 1
3580             INST(15U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
3581             INST(16U, Opcode::BoundsCheck).s32().Inputs(6U, 4U, 15U);
3582             INST(17U, Opcode::StoreArray).s64().Inputs(0U, 16U, 2U);
3583             // a[3] = 1
3584             INST(19U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
3585             INST(20U, Opcode::BoundsCheck).s32().Inputs(6U, 5U, 19U);
3586             INST(21U, Opcode::StoreArray).s64().Inputs(0U, 20U, 2U);
3587             INST(26U, Opcode::ReturnVoid).v0id();
3588         }
3589     }
3590 }
3591 
TEST_F(ChecksEliminationTest,GroupedBoundsCheckConstIndex)3592 TEST_F(ChecksEliminationTest, GroupedBoundsCheckConstIndex)
3593 {
3594     BuildGraphGroupedBoundsCheckConstIndex();
3595     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
3596     auto graph1 = CreateEmptyGraph();
3597     GRAPH(graph1)
3598     {
3599         PARAMETER(0U, 0U).ref();  // a
3600         CONSTANT(2U, 0U);
3601         CONSTANT(3U, 1U);
3602         CONSTANT(4U, 2U);
3603         CONSTANT(5U, 3U);
3604         BASIC_BLOCK(2U, -1L)
3605         {
3606             INST(6U, Opcode::LenArray).s32().Inputs(0U);
3607             INST(7U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
3608 
3609             INST(28U, Opcode::Compare).b().CC(CC_GE).SrcType(DataType::INT32).Inputs(5U, 6U);
3610             INST(29U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(28U, 7U);
3611 
3612             // a[0] = 1
3613             INST(8U, Opcode::NOP);
3614             INST(9U, Opcode::StoreArray).s64().Inputs(0U, 2U, 2U);
3615             // a[1] = 1
3616             INST(11U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
3617             INST(12U, Opcode::NOP);
3618             INST(13U, Opcode::StoreArray).s64().Inputs(0U, 3U, 2U);
3619             // a[2] = 1
3620             INST(15U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
3621             INST(16U, Opcode::NOP);
3622             INST(17U, Opcode::StoreArray).s64().Inputs(0U, 4U, 2U);
3623             // a[3] = 1
3624             INST(19U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
3625             INST(20U, Opcode::NOP);
3626             INST(21U, Opcode::StoreArray).s64().Inputs(0U, 5U, 2U);
3627             INST(26U, Opcode::ReturnVoid).v0id();
3628         }
3629     }
3630     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
3631 }
3632 
TEST_F(ChecksEliminationTest,ConsecutiveNullChecks)3633 TEST_F(ChecksEliminationTest, ConsecutiveNullChecks)
3634 {
3635     builder_->EnableGraphChecker(false);
3636     GRAPH(GetGraph())
3637     {
3638         PARAMETER(0U, 0U).ref();
3639         BASIC_BLOCK(2U, 1U)
3640         {
3641             INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
3642             INST(1U, Opcode::NullCheck).ref().Inputs(0U, 5U);
3643             INST(2U, Opcode::NullCheck).ref().Inputs(1U, 5U);
3644             INST(3U, Opcode::NullCheck).ref().Inputs(2U, 5U);
3645             INST(6U, Opcode::StoreObject).ref().Inputs(3U, 0U).TypeId(1U);
3646             INST(4U, Opcode::Return).ref().Inputs(3U);
3647         }
3648     }
3649     builder_->EnableGraphChecker(true);
3650     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
3651     auto graph = CreateEmptyGraph();
3652     GRAPH(graph)
3653     {
3654         PARAMETER(0U, 0U).ref();
3655         BASIC_BLOCK(2U, 1U)
3656         {
3657             INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
3658             INST(1U, Opcode::NullCheck).ref().Inputs(0U, 5U);
3659             INST(2U, Opcode::NOP);
3660             INST(3U, Opcode::NOP);
3661             INST(6U, Opcode::StoreObject).ref().Inputs(1U, 0U).TypeId(1U);
3662             INST(4U, Opcode::Return).ref().Inputs(1U);
3663         }
3664     }
3665     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3666 }
3667 
TEST_F(ChecksEliminationTest,NullCheckInCallVirt)3668 TEST_F(ChecksEliminationTest, NullCheckInCallVirt)
3669 {
3670     GRAPH(GetGraph())
3671     {
3672         PARAMETER(0U, 0U).ref();
3673         PARAMETER(1U, 1U).ref();
3674         BASIC_BLOCK(2U, 1U)
3675         {
3676             INST(5U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
3677             INST(2U, Opcode::NullCheck).ref().Inputs(0U, 5U);
3678             INST(3U, Opcode::NullCheck).ref().Inputs(1U, 5U);
3679             INST(4U, Opcode::CallVirtual)
3680                 .s32()
3681                 .Inputs({{DataType::REFERENCE, 2U}, {DataType::REFERENCE, 3U}, {DataType::NO_TYPE, 5U}});
3682             INST(6U, Opcode::Return).s32().Inputs(4U);
3683         }
3684     }
3685     // Doesn't remove nullchecks if the method static
3686     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
3687     ASSERT_FALSE(GetGraph()->RunPass<ChecksElimination>());
3688     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
3689 
3690     // Removes nullcheck from first parameter for not static method
3691     RuntimeInterfaceNotStaticMethod runtime;
3692     GetGraph()->SetRuntime(&runtime);
3693     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
3694     auto graph1 = CreateEmptyGraph();
3695     GRAPH(graph1)
3696     {
3697         PARAMETER(0U, 0U).ref();
3698         PARAMETER(1U, 1U).ref();
3699         BASIC_BLOCK(2U, 1U)
3700         {
3701             INST(5U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
3702             INST(2U, Opcode::NOP);
3703             INST(3U, Opcode::NullCheck).ref().Inputs(1U, 5U);
3704             INST(4U, Opcode::CallVirtual)
3705                 .s32()
3706                 .Inputs({{DataType::REFERENCE, 0U}, {DataType::REFERENCE, 3U}, {DataType::NO_TYPE, 5U}});
3707             INST(6U, Opcode::Return).s32().Inputs(4U);
3708         }
3709     }
3710     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
3711 }
3712 
TEST_F(ChecksEliminationTest,DominatedChecksWithDifferentTypes)3713 TEST_F(ChecksEliminationTest, DominatedChecksWithDifferentTypes)
3714 {
3715     GRAPH(GetGraph())
3716     {
3717         PARAMETER(0U, 0U).s64();
3718         PARAMETER(1U, 1U).s64();
3719         BASIC_BLOCK(2U, 1U)
3720         {
3721             INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
3722             INST(3U, Opcode::ZeroCheck).s32().Inputs(0U, 2U);
3723             INST(4U, Opcode::Div).s32().Inputs(1U, 3U);
3724             INST(5U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
3725             INST(6U, Opcode::ZeroCheck).s64().Inputs(0U, 5U);
3726             INST(7U, Opcode::Mod).s64().Inputs(1U, 6U);
3727             INST(20U, Opcode::SaveState).NoVregs();
3728             INST(8U, Opcode::CallStatic).s32().InputsAutoType(4U, 7U, 20U);
3729             INST(9U, Opcode::Return).s32().Inputs(8U);
3730         }
3731     }
3732     auto initial = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
3733     ASSERT_FALSE(GetGraph()->RunPass<ChecksElimination>());
3734     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), initial));
3735 }
3736 
BuildGraphRefTypeCheck()3737 void ChecksEliminationTest::BuildGraphRefTypeCheck()
3738 {
3739     GRAPH(GetGraph())
3740     {
3741         PARAMETER(0U, 0U).ref();
3742         PARAMETER(1U, 1U).ref();
3743         PARAMETER(2U, 2U).s32();
3744         PARAMETER(3U, 3U).s32();
3745         PARAMETER(4U, 4U).s32();
3746         CONSTANT(5U, nullptr);
3747         BASIC_BLOCK(2U, 1U)
3748         {
3749             INST(10U, Opcode::SaveState).Inputs(0U, 1U, 2U, 2U, 5U).SrcVregs({0U, 1U, 2U, 3U, 4U});
3750             INST(11U, Opcode::NullCheck).ref().Inputs(1U, 10U);
3751             INST(12U, Opcode::LenArray).s32().Inputs(11U);
3752             INST(13U, Opcode::BoundsCheck).s32().Inputs(12U, 2U, 10U);
3753             INST(14U, Opcode::RefTypeCheck).ref().Inputs(11U, 0U, 10U);
3754             INST(15U, Opcode::StoreArray).ref().Inputs(11U, 13U, 14U);
3755 
3756             INST(20U, Opcode::SaveState).Inputs(0U, 1U, 2U, 2U, 5U).SrcVregs({0U, 1U, 2U, 3U, 4U});
3757             INST(21U, Opcode::NullCheck).ref().Inputs(1U, 20U);
3758             INST(22U, Opcode::LenArray).s32().Inputs(21U);
3759             INST(23U, Opcode::BoundsCheck).s32().Inputs(22U, 3U, 20U);
3760             INST(24U, Opcode::RefTypeCheck).ref().Inputs(21U, 0U, 20U);
3761             INST(25U, Opcode::StoreArray).ref().Inputs(21U, 23U, 24U);
3762 
3763             INST(30U, Opcode::SaveState).Inputs(0U, 1U, 2U, 2U, 5U).SrcVregs({0U, 1U, 2U, 3U, 4U});
3764             INST(31U, Opcode::NullCheck).ref().Inputs(1U, 30U);
3765             INST(32U, Opcode::LenArray).s32().Inputs(31U);
3766             INST(33U, Opcode::BoundsCheck).s32().Inputs(32U, 4U, 30U);
3767             INST(34U, Opcode::RefTypeCheck).ref().Inputs(31U, 5U, 30U);
3768             INST(35U, Opcode::StoreArray).ref().Inputs(31U, 33U, 34U);
3769 
3770             INST(6U, Opcode::ReturnVoid).v0id();
3771         }
3772     }
3773 }
3774 
TEST_F(ChecksEliminationTest,RefTypeCheck)3775 TEST_F(ChecksEliminationTest, RefTypeCheck)
3776 {
3777     BuildGraphRefTypeCheck();
3778     // `24, Opcode::RefTypeCheck` is removed because `14, Opcode::RefTypeCheck` checks equal array and eqaul
3779     // Reference `34, Opcode::RefTypeCheck` is removed because store value id NullPtr
3780     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
3781     auto graph = CreateEmptyGraph();
3782     GRAPH(graph)
3783     {
3784         PARAMETER(0U, 0U).ref();
3785         PARAMETER(1U, 1U).ref();
3786         PARAMETER(2U, 2U).s32();
3787         PARAMETER(3U, 3U).s32();
3788         PARAMETER(4U, 4U).s32();
3789         CONSTANT(5U, nullptr);
3790         BASIC_BLOCK(2U, 1U)
3791         {
3792             INST(10U, Opcode::SaveState).Inputs(0U, 1U, 2U, 2U, 5U).SrcVregs({0U, 1U, 2U, 3U, 4U});
3793             INST(11U, Opcode::NullCheck).ref().Inputs(1U, 10U);
3794             INST(12U, Opcode::LenArray).s32().Inputs(11U);
3795             INST(13U, Opcode::BoundsCheck).s32().Inputs(12U, 2U, 10U);
3796             INST(14U, Opcode::RefTypeCheck).ref().Inputs(11U, 0U, 10U);
3797             INST(15U, Opcode::StoreArray).ref().Inputs(11U, 13U, 14U);
3798 
3799             INST(20U, Opcode::SaveState).Inputs(0U, 1U, 2U, 2U, 5U).SrcVregs({0U, 1U, 2U, 3U, 4U});
3800             INST(21U, Opcode::NOP);
3801             INST(22U, Opcode::LenArray).s32().Inputs(11U);
3802             INST(23U, Opcode::BoundsCheck).s32().Inputs(22U, 3U, 20U);
3803             INST(24U, Opcode::NOP);
3804             INST(25U, Opcode::StoreArray).ref().Inputs(11U, 23U, 14U);
3805 
3806             INST(30U, Opcode::SaveState).Inputs(0U, 1U, 2U, 2U, 5U).SrcVregs({0U, 1U, 2U, 3U, 4U});
3807             INST(31U, Opcode::NOP);
3808             INST(32U, Opcode::LenArray).s32().Inputs(11U);
3809             INST(33U, Opcode::BoundsCheck).s32().Inputs(32U, 4U, 30U);
3810             INST(34U, Opcode::NOP);
3811             INST(35U, Opcode::StoreArray).ref().Inputs(11U, 33U, 5U);
3812 
3813             INST(6U, Opcode::ReturnVoid).v0id();
3814         }
3815     }
3816     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3817 }
3818 
BuildGraphRefTypeCheckFirstNullCheckEliminated()3819 void ChecksEliminationTest::BuildGraphRefTypeCheckFirstNullCheckEliminated()
3820 {
3821     GRAPH(GetGraph())
3822     {
3823         PARAMETER(0U, 0U).ref();
3824         PARAMETER(1U, 2U).s32();
3825         PARAMETER(2U, 3U).s32();
3826         CONSTANT(3U, 10U);
3827         BASIC_BLOCK(2U, 1U)
3828         {
3829             INST(4U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
3830             INST(5U, Opcode::NewArray).ref().Inputs(0U, 3U, 4U);
3831             INST(6U, Opcode::RefTypeCheck).ref().Inputs(5U, 0U, 4U);
3832             INST(7U, Opcode::StoreArray).ref().Inputs(5U, 1U, 6U);
3833 
3834             INST(14U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
3835             INST(15U, Opcode::NullCheck).ref().Inputs(5U, 14U);
3836             INST(16U, Opcode::RefTypeCheck).ref().Inputs(15U, 0U, 14U);
3837             INST(17U, Opcode::StoreArray).ref().Inputs(5U, 2U, 16U);
3838 
3839             INST(18U, Opcode::ReturnVoid).v0id();
3840         }
3841     }
3842 }
3843 
TEST_F(ChecksEliminationTest,RefTypeCheckFirstNullCheckEliminated)3844 TEST_F(ChecksEliminationTest, RefTypeCheckFirstNullCheckEliminated)
3845 {
3846     BuildGraphRefTypeCheckFirstNullCheckEliminated();
3847     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
3848     auto graph = CreateEmptyGraph();
3849     GRAPH(graph)
3850     {
3851         PARAMETER(0U, 0U).ref();
3852         PARAMETER(1U, 2U).s32();
3853         PARAMETER(2U, 3U).s32();
3854         CONSTANT(3U, 10U);
3855         BASIC_BLOCK(2U, 1U)
3856         {
3857             INST(4U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
3858             INST(5U, Opcode::NewArray).ref().Inputs(0U, 3U, 4U);
3859             INST(6U, Opcode::RefTypeCheck).ref().Inputs(5U, 0U, 4U);
3860             INST(7U, Opcode::StoreArray).ref().Inputs(5U, 1U, 6U);
3861 
3862             INST(14U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
3863             INST(15U, Opcode::NOP);
3864             INST(16U, Opcode::NOP);
3865             INST(17U, Opcode::StoreArray).ref().Inputs(5U, 2U, 6U);
3866 
3867             INST(18U, Opcode::ReturnVoid).v0id();
3868         }
3869     }
3870     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3871 }
3872 
TEST_F(ChecksEliminationTest,RefTypeCheckEqualInputs)3873 TEST_F(ChecksEliminationTest, RefTypeCheckEqualInputs)
3874 {
3875     GRAPH(GetGraph())
3876     {
3877         PARAMETER(0U, 0U).ref();
3878         PARAMETER(1U, 2U).s32();
3879         PARAMETER(2U, 3U).s32();
3880         CONSTANT(3U, 10U);
3881         BASIC_BLOCK(2U, 1U)
3882         {
3883             INST(4U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
3884             INST(5U, Opcode::NewArray).ref().Inputs(0U, 3U, 4U);
3885             INST(6U, Opcode::RefTypeCheck).ref().Inputs(5U, 0U, 4U);
3886             INST(7U, Opcode::StoreArray).ref().Inputs(5U, 1U, 6U);
3887 
3888             INST(14U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
3889             INST(16U, Opcode::RefTypeCheck).ref().Inputs(5U, 5U, 14U);
3890             INST(17U, Opcode::StoreArray).ref().Inputs(5U, 2U, 16U);
3891 
3892             INST(18U, Opcode::ReturnVoid).v0id();
3893         }
3894     }
3895     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
3896     ASSERT_FALSE(GetGraph()->RunPass<ChecksElimination>());
3897     ASSERT_TRUE(GraphComparator().Compare(clone, GetGraph()));
3898 }
3899 
BuildHoistRefTypeCheckGraph()3900 void ChecksEliminationTest::BuildHoistRefTypeCheckGraph()
3901 {
3902     GRAPH(GetGraph())
3903     {
3904         CONSTANT(0U, 0U);  // initial
3905         CONSTANT(1U, 1U);  // increment
3906         CONSTANT(2U, 10U);
3907         PARAMETER(28U, 0U).ref();
3908         PARAMETER(29U, 1U).ref();
3909         BASIC_BLOCK(2U, 3U, 5U)
3910         {
3911             INST(20U, Opcode::SaveStateDeoptimize).Inputs(0U, 1U, 2U, 28U, 29U).SrcVregs({0U, 1U, 2U, 3U, 4U});
3912             INST(5U, Opcode::Compare).SrcType(DataType::INT32).CC(CC_LT).b().Inputs(0U, 2U);  // 0 < 10
3913             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
3914         }
3915         BASIC_BLOCK(3U, 3U, 5U)
3916         {
3917             INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);  // i
3918 
3919             INST(30U, Opcode::SaveState).Inputs(28U, 29U).SrcVregs({0U, 1U});
3920             INST(31U, Opcode::NullCheck).ref().Inputs(29U, 30U);
3921             INST(32U, Opcode::LenArray).s32().Inputs(31U);
3922             INST(34U, Opcode::RefTypeCheck).ref().Inputs(31U, 28U, 30U);
3923             INST(35U, Opcode::StoreArray).ref().Inputs(31U, 4U, 34U);
3924 
3925             INST(10U, Opcode::Add).s32().Inputs(4U, 1U);               // i++
3926             INST(13U, Opcode::Compare).CC(CC_LT).b().Inputs(10U, 2U);  // i < 10
3927             INST(14U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(13U);
3928         }
3929         BASIC_BLOCK(5U, 1U)
3930         {
3931             INST(12U, Opcode::ReturnVoid).v0id();
3932         }
3933     }
3934 }
3935 
TEST_F(ChecksEliminationTest,HoistRefTypeCheckTest)3936 TEST_F(ChecksEliminationTest, HoistRefTypeCheckTest)
3937 {
3938     BuildHoistRefTypeCheckGraph();
3939     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
3940 
3941     auto graph = CreateEmptyGraph();
3942     GRAPH(graph)
3943     {
3944         CONSTANT(0U, 0U);  // initial
3945         CONSTANT(1U, 1U);  // increment
3946         CONSTANT(2U, 10U);
3947         PARAMETER(28U, 0U).ref();
3948         PARAMETER(29U, 1U).ref();
3949         BASIC_BLOCK(2U, 3U, 5U)
3950         {
3951             INST(20U, Opcode::SaveStateDeoptimize).Inputs(0U, 1U, 2U, 28U, 29U).SrcVregs({0U, 1U, 2U, 3U, 4U});
3952             INST(31U, Opcode::NullCheck).ref().Inputs(29U, 20U).SetFlag(inst_flags::CAN_DEOPTIMIZE);
3953             INST(34U, Opcode::RefTypeCheck).ref().Inputs(31U, 28U, 20U).SetFlag(inst_flags::CAN_DEOPTIMIZE);
3954             INST(5U, Opcode::Compare).SrcType(DataType::INT32).CC(CC_LT).b().Inputs(0U, 2U);  // 0 < 10
3955             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
3956         }
3957         BASIC_BLOCK(3U, 3U, 5U)
3958         {
3959             INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);  // i
3960 
3961             INST(30U, Opcode::SaveState).Inputs(28U, 29U).SrcVregs({0U, 1U});
3962             INST(32U, Opcode::LenArray).s32().Inputs(31U);
3963             INST(35U, Opcode::StoreArray).ref().Inputs(31U, 4U, 34U);
3964 
3965             INST(10U, Opcode::Add).s32().Inputs(4U, 1U);               // i++
3966             INST(13U, Opcode::Compare).CC(CC_LT).b().Inputs(10U, 2U);  // i < 10
3967             INST(14U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(13U);
3968         }
3969         BASIC_BLOCK(5U, 1U)
3970         {
3971             INST(12U, Opcode::ReturnVoid).v0id();
3972         }
3973     }
3974     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3975 }
3976 
TEST_F(ChecksEliminationTest,NotLenArrayInput)3977 TEST_F(ChecksEliminationTest, NotLenArrayInput)
3978 {
3979     GRAPH(GetGraph())
3980     {
3981         PARAMETER(0U, 0U).s32();
3982         CONSTANT(4U, 1U);
3983         CONSTANT(7U, 10U);
3984         BASIC_BLOCK(2U, 3U)
3985         {
3986             INST(1U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
3987         }
3988         BASIC_BLOCK(3U, 4U, 5U)
3989         {
3990             INST(3U, Opcode::Phi).s32().Inputs(0U, 5U);
3991             INST(6U, Opcode::Compare).b().CC(CC_GE).Inputs(3U, 7U);
3992             INST(8U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(6U);
3993         }
3994         BASIC_BLOCK(5U, 3U)
3995         {
3996             INST(9U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
3997             INST(10U, Opcode::NegativeCheck).s32().Inputs(3U, 9U);
3998             INST(44U, Opcode::LoadAndInitClass).ref().Inputs(9U).TypeId(68U);
3999             INST(11U, Opcode::NewArray).ref().Inputs(44U, 10U, 9U);
4000             INST(12U, Opcode::BoundsCheck).s32().Inputs(3U, 0U, 9U);
4001             INST(13U, Opcode::StoreArray).s32().Inputs(11U, 12U, 0U);
4002             INST(5U, Opcode::Add).s32().Inputs(3U, 4U);
4003         }
4004         BASIC_BLOCK(4U, -1L)
4005         {
4006             INST(2U, Opcode::ReturnVoid).v0id();
4007         }
4008     }
4009     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
4010     ASSERT_FALSE(GetGraph()->RunPass<ChecksElimination>());
4011     ASSERT_TRUE(GraphComparator().Compare(clone, GetGraph()));
4012 }
4013 
BuildGraphBugWithNullCheck()4014 void ChecksEliminationTest::BuildGraphBugWithNullCheck()
4015 {
4016     GRAPH(GetGraph())
4017     {
4018         CONSTANT(0U, 0U);          // initial
4019         CONSTANT(1U, 1U);          // increment
4020         PARAMETER(27U, 1U).s32();  // X
4021         BASIC_BLOCK(2U, 6U, 3U)
4022         {
4023             INST(43U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
4024             INST(44U, Opcode::LoadAndInitClass).ref().Inputs().TypeId(68U);
4025             INST(13U, Opcode::NewArray).ref().Inputs(44U, 27U, 43U);
4026             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
4027             INST(14U, Opcode::Compare).CC(ConditionCode::CC_GE).b().Inputs(0U, 27U);  // i < X
4028             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(14U);
4029         }
4030         BASIC_BLOCK(3U, 6U, 3U)
4031         {
4032             INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);
4033             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 13U, 27U).SrcVregs({0U, 1U, 2U, 3U});
4034             INST(16U, Opcode::NullCheck).ref().Inputs(13U, 7U);
4035             INST(17U, Opcode::LenArray).s32().Inputs(16U);
4036             INST(8U, Opcode::BoundsCheck).s32().Inputs(17U, 4U, 7U);
4037             INST(9U, Opcode::StoreArray).s32().Inputs(16U, 8U, 0U);                   // a[i] = 0
4038             INST(10U, Opcode::Add).s32().Inputs(4U, 1U);                              // i++
4039             INST(5U, Opcode::Compare).CC(ConditionCode::CC_GE).b().Inputs(10U, 27U);  // i < X
4040             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
4041         }
4042         BASIC_BLOCK(6U, 1U)
4043         {
4044             INST(26U, Opcode::Phi).s32().Inputs(0U, 10U);
4045             INST(12U, Opcode::Return).s32().Inputs(26U);
4046         }
4047     }
4048 }
4049 
TEST_F(ChecksEliminationTest,BugWithNullCheck)4050 TEST_F(ChecksEliminationTest, BugWithNullCheck)
4051 {
4052     BuildGraphBugWithNullCheck();
4053     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
4054     auto graph1 = CreateEmptyGraph();
4055     GRAPH(graph1)
4056     {
4057         CONSTANT(0U, 0U);  // initial
4058         CONSTANT(1U, 1U);  // increment
4059         PARAMETER(2U, 1U).s32();
4060         BASIC_BLOCK(2U, 5U, 3U)
4061         {
4062             INST(43U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
4063             INST(44U, Opcode::LoadAndInitClass).ref().Inputs().TypeId(68U);
4064             INST(3U, Opcode::NewArray).ref().Inputs(44U, 2U, 43U);
4065             INST(20U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
4066             INST(34U, Opcode::NOP);
4067             INST(22U, Opcode::LenArray).s32().Inputs(3U);
4068             INST(23U, Opcode::Compare).SrcType(DataType::INT32).CC(CC_LT).b().Inputs(22U, 2U);  // len_array < X
4069             INST(24U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(23U, 20U);
4070             INST(5U, Opcode::Compare).SrcType(DataType::INT32).CC(CC_GE).b().Inputs(0U, 2U);  // 0 < X
4071             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
4072         }
4073         BASIC_BLOCK(3U, 5U, 3U)
4074         {
4075             INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);
4076             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 3U, 2U).SrcVregs({0U, 1U, 2U, 3U});
4077             INST(15U, Opcode::NOP);
4078             INST(16U, Opcode::LenArray).s32().Inputs(3U);
4079             INST(8U, Opcode::NOP);
4080             INST(9U, Opcode::StoreArray).s32().Inputs(3U, 4U, 0U);     // a[i] = 0
4081             INST(10U, Opcode::Add).s32().Inputs(4U, 1U);               // i++
4082             INST(13U, Opcode::Compare).CC(CC_GE).b().Inputs(10U, 2U);  // i < X
4083             INST(14U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(13U);
4084         }
4085         BASIC_BLOCK(5U, 1U)
4086         {
4087             INST(26U, Opcode::Phi).s32().Inputs(0U, 10U);
4088             INST(12U, Opcode::Return).s32().Inputs(26U);
4089         }
4090     }
4091     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
4092 }
4093 
4094 // CC-OFFNXT(huge_method, G.FUN.01) graph creation
BuildGraphNullAndBoundsChecksNestedLoop()4095 void ChecksEliminationTest::BuildGraphNullAndBoundsChecksNestedLoop()
4096 {
4097     GRAPH(GetGraph())
4098     {
4099         PARAMETER(0U, 0U).ref();
4100         CONSTANT(3U, 0U);
4101         CONSTANT(9U, 4U);
4102         CONSTANT(32U, 1U);
4103 
4104         // fill 2D array
4105         BASIC_BLOCK(2U, 3U)
4106         {
4107             INST(2U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
4108         }
4109         BASIC_BLOCK(3U, 7U, 8U)
4110         {
4111             INST(5U, Opcode::Phi).s32().Inputs(3U, 33U);
4112             INST(4U, Opcode::Compare).CC(CC_LE).b().Inputs(9U, 5U);
4113             INST(11U, Opcode::IfImm).CC(CC_NE).Imm(0U).Inputs(4U);
4114         }
4115         BASIC_BLOCK(8U, 4U)
4116         {
4117             INST(38U, Opcode::SaveStateDeoptimize).Inputs(0U, 3U, 5U).SrcVregs({0U, 1U, 2U});
4118         }
4119         BASIC_BLOCK(4U, 6U, 5U)
4120         {
4121             INST(15U, Opcode::Phi).s32().Inputs(3U, 31U);
4122             INST(19U, Opcode::Compare).CC(CC_LE).b().Inputs(9U, 15U);
4123             INST(20U, Opcode::IfImm).CC(CC_NE).Imm(0U).Inputs(19U);
4124         }
4125         BASIC_BLOCK(5U, 4U)
4126         {
4127             INST(21U, Opcode::SaveState).Inputs(0U, 3U, 5U, 15U).SrcVregs({0U, 1U, 2U, 3U});
4128             INST(22U, Opcode::NullCheck).ref().Inputs(0U, 21U);
4129             INST(23U, Opcode::LenArray).s32().Inputs(22U);
4130             INST(24U, Opcode::BoundsCheck).s32().Inputs(23U, 5U, 21U);
4131             INST(25U, Opcode::LoadArray).ref().Inputs(22U, 24U);
4132 
4133             INST(26U, Opcode::SaveState).Inputs(0U, 3U, 5U, 15U, 25U).SrcVregs({0U, 1U, 2U, 3U, 4U});
4134             INST(27U, Opcode::NullCheck).ref().Inputs(25U, 26U);
4135             INST(28U, Opcode::LenArray).s32().Inputs(27U);
4136             INST(29U, Opcode::BoundsCheck).s32().Inputs(28U, 15U, 26U);
4137             INST(30U, Opcode::StoreArray).s32().Inputs(27U, 29U, 5U);  // a[i][j] = i
4138             INST(31U, Opcode::Add).s32().Inputs(15U, 32U);
4139         }
4140         BASIC_BLOCK(6U, 3U)
4141         {
4142             INST(33U, Opcode::Add).s32().Inputs(5U, 32U);
4143         }
4144         BASIC_BLOCK(7U, -1L)
4145         {
4146             INST(34U, Opcode::ReturnVoid).v0id();
4147         }
4148     }
4149 }
4150 
4151 // CC-OFFNXT(huge_method, G.FUN.01) graph creation
TEST_F(ChecksEliminationTest,NullAndBoundsChecksNestedLoop)4152 TEST_F(ChecksEliminationTest, NullAndBoundsChecksNestedLoop)
4153 {
4154     BuildGraphNullAndBoundsChecksNestedLoop();
4155     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
4156 
4157     auto graph = CreateEmptyGraph();
4158     GRAPH(graph)
4159     {
4160         PARAMETER(0U, 0U).ref();
4161         CONSTANT(3U, 0U);
4162         CONSTANT(9U, 4U);
4163         CONSTANT(32U, 1U);
4164 
4165         BASIC_BLOCK(2U, 3U)
4166         {
4167             INST(2U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
4168             INST(35U, Opcode::NullCheck).ref().Inputs(0U, 2U).SetFlag(inst_flags::CAN_DEOPTIMIZE);
4169             INST(39U, Opcode::LenArray).s32().Inputs(35U);
4170             INST(44U, Opcode::Compare).b().SrcType(DataType::INT32).CC(CC_LT).Inputs(39U, 9U);
4171             INST(45U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(44U, 2U);
4172         }
4173         BASIC_BLOCK(3U, 7U, 8U)
4174         {
4175             INST(5U, Opcode::Phi).s32().Inputs(3U, 33U);
4176             INST(4U, Opcode::Compare).CC(CC_LE).b().Inputs(9U, 5U);
4177             INST(11U, Opcode::IfImm).CC(CC_NE).Imm(0U).Inputs(4U);
4178         }
4179         BASIC_BLOCK(8U, 4U)
4180         {
4181             INST(38U, Opcode::SaveStateDeoptimize).Inputs(0U, 3U, 5U).SrcVregs({0U, 1U, 2U});
4182             // we could put DeoptimizeIf NULL_CHECK here, but this is suboptimal
4183         }
4184         BASIC_BLOCK(4U, 6U, 5U)
4185         {
4186             INST(15U, Opcode::Phi).s32().Inputs(3U, 31U);
4187             INST(19U, Opcode::Compare).CC(CC_LE).b().Inputs(9U, 15U);
4188             INST(20U, Opcode::IfImm).CC(CC_NE).Imm(0U).Inputs(19U);
4189         }
4190         BASIC_BLOCK(5U, 4U)
4191         {
4192             INST(21U, Opcode::SaveState).Inputs(0U, 3U, 5U, 15U).SrcVregs({0U, 1U, 2U, 3U});
4193             INST(22U, Opcode::NOP);
4194             INST(23U, Opcode::LenArray).s32().Inputs(35U);
4195             INST(24U, Opcode::NOP);
4196             INST(25U, Opcode::LoadArray).ref().Inputs(35U, 5U);
4197             INST(26U, Opcode::SaveState).Inputs(0U, 3U, 5U, 15U, 25U).SrcVregs({0U, 1U, 2U, 3U, 4U});
4198             INST(27U, Opcode::NullCheck).ref().Inputs(25U, 26U);
4199             INST(28U, Opcode::LenArray).s32().Inputs(27U);
4200             INST(29U, Opcode::BoundsCheck).s32().Inputs(28U, 15U, 26U);
4201             INST(30U, Opcode::StoreArray).s32().Inputs(27U, 29U, 5U);  // a[i][j] = i
4202             INST(31U, Opcode::Add).s32().Inputs(15U, 32U);
4203         }
4204         BASIC_BLOCK(6U, 3U)
4205         {
4206             INST(33U, Opcode::Add).s32().Inputs(5U, 32U);
4207         }
4208         BASIC_BLOCK(7U, -1L)
4209         {
4210             INST(34U, Opcode::ReturnVoid).v0id();
4211         }
4212     }
4213     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
4214 }
4215 
BuildGraphLoopWithTwoPhi()4216 void ChecksEliminationTest::BuildGraphLoopWithTwoPhi()
4217 {
4218     GRAPH(GetGraph())
4219     {
4220         PARAMETER(0U, 0U).ref();
4221         PARAMETER(1U, 1U).s32();
4222         PARAMETER(2U, 2U).s32();
4223         CONSTANT(3U, 0U);
4224         CONSTANT(4U, 1U);
4225         BASIC_BLOCK(2U, 3U)
4226         {
4227             INST(5U, Opcode::SaveStateDeoptimize).Inputs(0U, 1U, 2U, 3U, 4U).SrcVregs({0U, 1U, 2U, 3U, 4U});
4228             INST(6U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U, 4U).SrcVregs({0U, 1U, 2U, 3U, 4U});
4229             INST(7U, Opcode::NullCheck).ref().Inputs(0U, 6U);
4230             INST(8U, Opcode::LoadObject).ref().Inputs(7U);
4231         }
4232         BASIC_BLOCK(3U, 4U, 5U)
4233         {
4234             INST(9U, Opcode::Phi).s32().Inputs(1U, 17U);
4235             INST(18U, Opcode::Phi).s32().Inputs(3U, 19U);
4236             INST(10U, Opcode::Compare).b().CC(CC_GE).Inputs(9U, 2U);
4237             INST(11U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(10U);
4238         }
4239         BASIC_BLOCK(5U, 3U)
4240         {
4241             INST(12U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U, 4U, 8U).SrcVregs({0U, 1U, 2U, 3U, 4U, 5U});
4242             INST(13U, Opcode::NullCheck).ref().Inputs(8U, 12U);
4243             INST(14U, Opcode::LenArray).s32().Inputs(13U);
4244             INST(15U, Opcode::BoundsCheck).s32().Inputs(14U, 9U, 12U);
4245             INST(16U, Opcode::LoadArray).s32().Inputs(13U, 15U);
4246             INST(17U, Opcode::Add).s32().Inputs(9U, 4U);
4247             INST(19U, Opcode::Add).s32().Inputs(18U, 16U);
4248         }
4249         BASIC_BLOCK(4U, -1L)
4250         {
4251             INST(20U, Opcode::Return).s32().Inputs(18U);
4252         }
4253     }
4254 }
4255 
TEST_F(ChecksEliminationTest,LoopWithTwoPhi)4256 TEST_F(ChecksEliminationTest, LoopWithTwoPhi)
4257 {
4258     BuildGraphLoopWithTwoPhi();
4259     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
4260     auto graph1 = CreateEmptyGraph();
4261     GRAPH(graph1)
4262     {
4263         PARAMETER(0U, 0U).ref();
4264         PARAMETER(1U, 1U).s32();
4265         PARAMETER(2U, 2U).s32();
4266         CONSTANT(3U, 0U);
4267         CONSTANT(4U, 1U);
4268         BASIC_BLOCK(2U, 3U)
4269         {
4270             INST(5U, Opcode::SaveStateDeoptimize).Inputs(0U, 1U, 2U, 3U, 4U).SrcVregs({0U, 1U, 2U, 3U, 4U});
4271             INST(6U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U, 4U).SrcVregs({0U, 1U, 2U, 3U, 4U});
4272             INST(7U, Opcode::NullCheck).ref().Inputs(0U, 6U);
4273             INST(8U, Opcode::LoadObject).ref().Inputs(7U);
4274             INST(22U, Opcode::NullCheck).ref().Inputs(8U, 6U).SetFlag(inst_flags::CAN_DEOPTIMIZE);
4275         }
4276         BASIC_BLOCK(3U, 4U, 5U)
4277         {
4278             INST(9U, Opcode::Phi).s32().Inputs(1U, 17U);
4279             INST(18U, Opcode::Phi).s32().Inputs(3U, 19U);
4280             INST(10U, Opcode::Compare).b().CC(CC_GE).Inputs(9U, 2U);
4281             INST(11U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(10U);
4282         }
4283         BASIC_BLOCK(5U, 3U)
4284         {
4285             INST(12U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U, 4U, 8U).SrcVregs({0U, 1U, 2U, 3U, 4U, 5U});
4286             INST(14U, Opcode::LenArray).s32().Inputs(22U);
4287             INST(15U, Opcode::BoundsCheck).s32().Inputs(14U, 9U, 12U);
4288             INST(16U, Opcode::LoadArray).s32().Inputs(22U, 15U);
4289             INST(17U, Opcode::Add).s32().Inputs(9U, 4U);
4290             INST(19U, Opcode::Add).s32().Inputs(18U, 16U);
4291         }
4292         BASIC_BLOCK(4U, -1L)
4293         {
4294             INST(20U, Opcode::Return).s32().Inputs(18U);
4295         }
4296     }
4297     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
4298 }
4299 
BuildGraphLoopWithBigStepGE()4300 void ChecksEliminationTest::BuildGraphLoopWithBigStepGE()
4301 {
4302     GRAPH(GetGraph())
4303     {
4304         CONSTANT(0U, 0U);
4305         CONSTANT(1U, 4U);  // increment
4306         CONSTANT(2U, 3U);
4307         PARAMETER(13U, 0U).ref();  // Array
4308         PARAMETER(27U, 1U).s32();  // X
4309         BASIC_BLOCK(2U, 3U)
4310         {
4311             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
4312         }
4313         BASIC_BLOCK(3U, 5U, 4U)
4314         {
4315             INST(4U, Opcode::Phi).s32().Inputs(27U, 10U);
4316             INST(14U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(4U, 0U);  // i >= 0
4317             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(14U);
4318         }
4319         BASIC_BLOCK(4U, 3U)
4320         {
4321             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 13U, 27U).SrcVregs({0U, 1U, 2U, 3U});
4322             INST(16U, Opcode::NullCheck).ref().Inputs(13U, 7U);
4323             INST(17U, Opcode::LenArray).s32().Inputs(16U);
4324             INST(8U, Opcode::BoundsCheck).s32().Inputs(17U, 4U, 7U);
4325             INST(9U, Opcode::StoreArray).s32().Inputs(16U, 8U, 4U);  // a[i] = i
4326             INST(10U, Opcode::Sub).s32().Inputs(4U, 1U);             // i -= 4
4327         }
4328         BASIC_BLOCK(5U, 1U)
4329         {
4330             INST(12U, Opcode::ReturnVoid).v0id();
4331         }
4332     }
4333 }
4334 
TEST_F(ChecksEliminationTest,LoopWithBigStepGE)4335 TEST_F(ChecksEliminationTest, LoopWithBigStepGE)
4336 {
4337     BuildGraphLoopWithBigStepGE();
4338     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
4339     auto graph1 = CreateEmptyGraph();
4340     GRAPH(graph1)
4341     {
4342         CONSTANT(0U, 0U);
4343         CONSTANT(1U, 4U);  // increment
4344         CONSTANT(2U, 3U);
4345         PARAMETER(13U, 0U).ref();  // Array
4346         PARAMETER(27U, 1U).s32();  // X
4347         BASIC_BLOCK(2U, 3U)
4348         {
4349             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
4350             INST(33U, Opcode::NullCheck).ref().Inputs(13U, 30U).SetFlag(inst_flags::CAN_DEOPTIMIZE);
4351             INST(31U, Opcode::LenArray).s32().Inputs(33U);
4352             INST(36U, Opcode::Compare).SrcType(DataType::INT32).CC(CC_LE).b().Inputs(31U, 27U);
4353             // DeoptimizeIf len_array <= X
4354             INST(37U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(36U, 30U);
4355         }
4356         BASIC_BLOCK(3U, 5U, 4U)
4357         {
4358             INST(4U, Opcode::Phi).s32().Inputs(27U, 10U);
4359             INST(14U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(4U, 0U);  // i >= 0
4360             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(14U);
4361         }
4362         BASIC_BLOCK(4U, 3U)
4363         {
4364             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 13U, 27U).SrcVregs({0U, 1U, 2U, 3U});
4365             INST(16U, Opcode::NOP);
4366             INST(17U, Opcode::LenArray).s32().Inputs(33U);
4367             INST(8U, Opcode::NOP);
4368             INST(9U, Opcode::StoreArray).s32().Inputs(33U, 4U, 4U);  // a[i] = i
4369             INST(10U, Opcode::Sub).s32().Inputs(4U, 1U);             // i -= 4
4370         }
4371         BASIC_BLOCK(5U, 1U)
4372         {
4373             INST(12U, Opcode::ReturnVoid).v0id();
4374         }
4375     }
4376     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
4377 }
4378 
BuildGraphLoopWithBigStepLE()4379 void ChecksEliminationTest::BuildGraphLoopWithBigStepLE()
4380 {
4381     GRAPH(GetGraph())
4382     {
4383         CONSTANT(0U, 2U);  // initial
4384         CONSTANT(1U, 8U);  // increment
4385         CONSTANT(2U, 3U);
4386         PARAMETER(13U, 0U).ref();  // Array
4387         PARAMETER(27U, 1U).s32();  // X
4388         BASIC_BLOCK(2U, 6U, 3U)
4389         {
4390             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
4391             INST(14U, Opcode::Compare).CC(ConditionCode::CC_GT).b().Inputs(0U, 27U);  // i <= X
4392             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(14U);
4393         }
4394         BASIC_BLOCK(3U, 6U, 3U)
4395         {
4396             INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);
4397             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 13U, 27U).SrcVregs({0U, 1U, 2U, 3U});
4398             INST(16U, Opcode::NullCheck).ref().Inputs(13U, 7U);
4399             INST(17U, Opcode::LenArray).s32().Inputs(16U);
4400             INST(8U, Opcode::BoundsCheck).s32().Inputs(17U, 4U, 7U);
4401             INST(9U, Opcode::LoadArray).s32().Inputs(16U, 8U);  // load a[i]
4402             INST(18U, Opcode::Add).s32().Inputs(4U, 2U);
4403             INST(19U, Opcode::BoundsCheck).s32().Inputs(17U, 18U, 7U);
4404             INST(20U, Opcode::StoreArray).s32().Inputs(16U, 19U, 9U);                 // a[i + 3] = a[i]
4405             INST(10U, Opcode::Add).s32().Inputs(4U, 1U);                              // i += 8
4406             INST(5U, Opcode::Compare).CC(ConditionCode::CC_GT).b().Inputs(10U, 27U);  // i <= X
4407             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
4408         }
4409         BASIC_BLOCK(6U, 1U)
4410         {
4411             INST(26U, Opcode::Phi).s32().Inputs(0U, 10U);
4412             INST(12U, Opcode::Return).s32().Inputs(26U);
4413         }
4414     }
4415 }
4416 
4417 // CC-OFFNXT(huge_method, G.FUN.01) graph creation
TEST_F(ChecksEliminationTest,LoopWithBigStepLE)4418 TEST_F(ChecksEliminationTest, LoopWithBigStepLE)
4419 {
4420     BuildGraphLoopWithBigStepLE();
4421     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
4422     auto graph1 = CreateEmptyGraph();
4423     GRAPH(graph1)
4424     {
4425         CONSTANT(0U, 2U);  // initial
4426         CONSTANT(1U, 8U);  // increment
4427         CONSTANT(2U, 3U);
4428         PARAMETER(13U, 0U).ref();  // Array
4429         PARAMETER(27U, 1U).s32();  // X
4430         CONSTANT(42U, 0x7ffffff7U);
4431 
4432         BASIC_BLOCK(2U, 6U, 3U)
4433         {
4434             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
4435             INST(44U, Opcode::Compare).Inputs(42U, 27U).CC(CC_LT).b();
4436             INST(45U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(44U, 30U);
4437             INST(33U, Opcode::NullCheck).ref().Inputs(13U, 30U).SetFlag(inst_flags::CAN_DEOPTIMIZE);
4438             INST(31U, Opcode::LenArray).s32().Inputs(33U);
4439             INST(36U, Opcode::Sub).s32().Inputs(27U, 0U);
4440             INST(37U, Opcode::Mod).s32().Inputs(36U, 1U);
4441             INST(38U, Opcode::Sub).s32().Inputs(27U, 37U);
4442             INST(39U, Opcode::Sub).s32().Inputs(31U, 2U);
4443             INST(40U, Opcode::Compare).b().CC(CC_LE).Inputs(39U, 38U);
4444             // DeoptimizeIf len - 3 <= X - (X - 2) % 8
4445             INST(41U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(40U, 30U);
4446             INST(14U, Opcode::Compare).CC(ConditionCode::CC_GT).b().Inputs(0U, 27U);  // i <= X
4447             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(14U);
4448         }
4449         BASIC_BLOCK(3U, 6U, 3U)
4450         {
4451             INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);
4452             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 13U, 27U).SrcVregs({0U, 1U, 2U, 3U});
4453             INST(16U, Opcode::NOP);
4454             INST(17U, Opcode::LenArray).s32().Inputs(33U);
4455             INST(8U, Opcode::NOP);
4456             INST(9U, Opcode::LoadArray).s32().Inputs(33U, 4U);  // load a[i]
4457             INST(18U, Opcode::Add).s32().Inputs(4U, 2U);
4458             INST(19U, Opcode::NOP);
4459             INST(20U, Opcode::StoreArray).s32().Inputs(33U, 18U, 9U);                 // a[i + 3] = a[i]
4460             INST(10U, Opcode::Add).s32().Inputs(4U, 1U);                              // i += 8
4461             INST(5U, Opcode::Compare).CC(ConditionCode::CC_GT).b().Inputs(10U, 27U);  // i <= X
4462             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
4463         }
4464         BASIC_BLOCK(6U, 1U)
4465         {
4466             INST(26U, Opcode::Phi).s32().Inputs(0U, 10U);
4467             INST(12U, Opcode::Return).s32().Inputs(26U);
4468         }
4469     }
4470     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
4471 }
4472 
BuildGraphLoopWithBigStepLT()4473 void ChecksEliminationTest::BuildGraphLoopWithBigStepLT()
4474 {
4475     GRAPH(GetGraph())
4476     {
4477         CONSTANT(0U, 2U);  // initial
4478         CONSTANT(1U, 8U);  // increment
4479         CONSTANT(2U, 3U);
4480         PARAMETER(13U, 0U).ref();  // Array
4481         PARAMETER(27U, 1U).s32();  // X
4482         BASIC_BLOCK(2U, 6U, 3U)
4483         {
4484             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
4485             INST(14U, Opcode::Compare).CC(ConditionCode::CC_GE).b().Inputs(0U, 27U);  // i < X
4486             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(14U);
4487         }
4488         BASIC_BLOCK(3U, 6U, 3U)
4489         {
4490             INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);
4491             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 13U, 27U).SrcVregs({0U, 1U, 2U, 3U});
4492             INST(16U, Opcode::NullCheck).ref().Inputs(13U, 7U);
4493             INST(17U, Opcode::LenArray).s32().Inputs(16U);
4494             INST(8U, Opcode::BoundsCheck).s32().Inputs(17U, 4U, 7U);
4495             INST(9U, Opcode::LoadArray).s32().Inputs(16U, 8U);  // load a[i]
4496             INST(18U, Opcode::Add).s32().Inputs(4U, 2U);
4497             INST(19U, Opcode::BoundsCheck).s32().Inputs(17U, 18U, 7U);
4498             INST(20U, Opcode::StoreArray).s32().Inputs(16U, 19U, 9U);                 // a[i + 3] = a[i]
4499             INST(10U, Opcode::Add).s32().Inputs(4U, 1U);                              // i += 8
4500             INST(5U, Opcode::Compare).CC(ConditionCode::CC_GE).b().Inputs(10U, 27U);  // i < X
4501             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
4502         }
4503         BASIC_BLOCK(6U, 1U)
4504         {
4505             INST(26U, Opcode::Phi).s32().Inputs(0U, 10U);
4506             INST(12U, Opcode::Return).s32().Inputs(26U);
4507         }
4508     }
4509 }
4510 
4511 // CC-OFFNXT(huge_method, G.FUN.01) graph creation
TEST_F(ChecksEliminationTest,LoopWithBigStepLT)4512 TEST_F(ChecksEliminationTest, LoopWithBigStepLT)
4513 {
4514     BuildGraphLoopWithBigStepLT();
4515     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
4516     auto graph1 = CreateEmptyGraph();
4517     GRAPH(graph1)
4518     {
4519         CONSTANT(0U, 2U);  // initial
4520         CONSTANT(1U, 8U);  // increment
4521         CONSTANT(2U, 3U);
4522         PARAMETER(13U, 0U).ref();  // Array
4523         PARAMETER(27U, 1U).s32();  // X
4524         CONSTANT(43U, 1U);
4525         CONSTANT(42U, 0x7ffffff8U);
4526 
4527         BASIC_BLOCK(2U, 6U, 3U)
4528         {
4529             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
4530             INST(44U, Opcode::Compare).Inputs(42U, 27U).CC(CC_LT).b();
4531             INST(45U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(44U, 30U);
4532             INST(33U, Opcode::NullCheck).ref().Inputs(13U, 30U).SetFlag(inst_flags::CAN_DEOPTIMIZE);
4533             INST(31U, Opcode::LenArray).s32().Inputs(33U);
4534             INST(35U, Opcode::Add).s32().Inputs(0U, 43U);
4535             INST(36U, Opcode::Sub).s32().Inputs(27U, 35U);
4536             INST(37U, Opcode::Mod).s32().Inputs(36U, 1U);
4537             INST(38U, Opcode::Sub).s32().Inputs(27U, 37U);
4538             INST(39U, Opcode::Sub).s32().Inputs(31U, 2U);
4539             INST(40U, Opcode::Compare).b().CC(CC_LT).Inputs(39U, 38U);
4540             // DeoptimizeIf len - 3 < X - (X - (2 + 1)) % 8
4541             INST(41U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(40U, 30U);
4542             INST(14U, Opcode::Compare).CC(ConditionCode::CC_GE).b().Inputs(0U, 27U);  // i < X
4543             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(14U);
4544         }
4545         BASIC_BLOCK(3U, 6U, 3U)
4546         {
4547             INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);
4548             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 13U, 27U).SrcVregs({0U, 1U, 2U, 3U});
4549             INST(16U, Opcode::NOP);
4550             INST(17U, Opcode::LenArray).s32().Inputs(33U);
4551             INST(8U, Opcode::NOP);
4552             INST(9U, Opcode::LoadArray).s32().Inputs(33U, 4U);  // load a[i]
4553             INST(18U, Opcode::Add).s32().Inputs(4U, 2U);
4554             INST(19U, Opcode::NOP);
4555             INST(20U, Opcode::StoreArray).s32().Inputs(33U, 18U, 9U);                 // a[i + 3] = a[i]
4556             INST(10U, Opcode::Add).s32().Inputs(4U, 1U);                              // i += 8
4557             INST(5U, Opcode::Compare).CC(ConditionCode::CC_GE).b().Inputs(10U, 27U);  // i < X
4558             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
4559         }
4560         BASIC_BLOCK(6U, 1U)
4561         {
4562             INST(26U, Opcode::Phi).s32().Inputs(0U, 10U);
4563             INST(12U, Opcode::Return).s32().Inputs(26U);
4564         }
4565     }
4566     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
4567 }
4568 
4569 // CC-OFFNXT(huge_method, G.FUN.01) graph creation
BuildGraphLoopWithBoundsCheckUnderIfGE()4570 void ChecksEliminationTest::BuildGraphLoopWithBoundsCheckUnderIfGE()
4571 {
4572     GRAPH(GetGraph())
4573     {
4574         CONSTANT(0U, 0U);  // initial
4575         CONSTANT(1U, 1U);  // increment
4576         CONSTANT(3U, 3U);
4577         PARAMETER(2U, 0U).ref();  // array
4578         PARAMETER(4U, 1U).s32();  // X
4579 
4580         BASIC_BLOCK(2U, 3U)
4581         {
4582             INST(5U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
4583             INST(6U, Opcode::NullCheck).ref().Inputs(2U, 5U);
4584             INST(7U, Opcode::LenArray).s32().Inputs(6U);
4585 
4586             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
4587         }
4588 
4589         BASIC_BLOCK(3U, 4U, 8U)
4590         {
4591             INST(8U, Opcode::Phi).s32().Inputs(0U, 24U);             // i
4592             INST(25U, Opcode::Phi).s32().Inputs(0U, 23U);            // sum
4593             INST(9U, Opcode::Compare).CC(CC_LT).b().Inputs(8U, 4U);  // i < X
4594             INST(10U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(9U);
4595         }
4596         BASIC_BLOCK(4U, 5U, 6U)
4597         {
4598             INST(14U, Opcode::Compare).CC(CC_LE).b().Inputs(3U, 8U);  // 3 <= i
4599             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(14U);
4600         }
4601         BASIC_BLOCK(5U, 7U)
4602         {
4603             INST(16U, Opcode::Sub).s32().Inputs(8U, 3U);
4604             INST(27U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
4605             INST(17U, Opcode::BoundsCheck).s32().Inputs(7U, 16U, 27U);
4606             INST(18U, Opcode::LoadArray).s32().Inputs(6U, 17U);  // a[i - 3]
4607         }
4608         BASIC_BLOCK(6U, 7U)
4609         {
4610             INST(19U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
4611             INST(20U, Opcode::BoundsCheck).s32().Inputs(7U, 8U, 19U);
4612             INST(21U, Opcode::LoadArray).s32().Inputs(6U, 20U);  // a[i]
4613         }
4614         BASIC_BLOCK(7U, 3U)
4615         {
4616             INST(22U, Opcode::Phi).s32().Inputs(18U, 21U);
4617             INST(23U, Opcode::Add).s32().Inputs(25U, 22U);
4618             INST(24U, Opcode::Add).s32().Inputs(8U, 1U);
4619         }
4620         BASIC_BLOCK(8U, 1U)
4621         {
4622             INST(26U, Opcode::Return).s32().Inputs(25U);
4623         }
4624     }
4625 }
4626 
4627 // Lower bound is correct in each branch based on BoundsAnalysis, build deoptimize only for upper bound
4628 // CC-OFFNXT(huge_method, G.FUN.01) graph creation
TEST_F(ChecksEliminationTest,LoopWithBoundsCheckUnderIfGE)4629 TEST_F(ChecksEliminationTest, LoopWithBoundsCheckUnderIfGE)
4630 {
4631     BuildGraphLoopWithBoundsCheckUnderIfGE();
4632     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
4633     auto graph1 = CreateEmptyGraph();
4634     GRAPH(graph1)
4635     {
4636         CONSTANT(0U, 0U);  // initial
4637         CONSTANT(1U, 1U);  // increment
4638         CONSTANT(3U, 3U);
4639         PARAMETER(2U, 0U).ref();  // array
4640         PARAMETER(4U, 1U).s32();  // X
4641 
4642         BASIC_BLOCK(2U, 3U)
4643         {
4644             INST(5U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
4645             INST(6U, Opcode::NullCheck).ref().Inputs(2U, 5U);
4646             INST(7U, Opcode::LenArray).s32().Inputs(6U);
4647 
4648             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
4649             INST(31U, Opcode::Compare).b().CC(CC_LT).Inputs(7U, 4U);
4650             INST(32U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(31U, 30U);
4651         }
4652 
4653         BASIC_BLOCK(3U, 4U, 8U)
4654         {
4655             INST(8U, Opcode::Phi).s32().Inputs(0U, 24U);             // i
4656             INST(25U, Opcode::Phi).s32().Inputs(0U, 23U);            // sum
4657             INST(9U, Opcode::Compare).CC(CC_LT).b().Inputs(8U, 4U);  // i < X
4658             INST(10U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(9U);
4659         }
4660         BASIC_BLOCK(4U, 5U, 6U)
4661         {
4662             INST(14U, Opcode::Compare).CC(CC_LE).b().Inputs(3U, 8U);  // 3 <= i
4663             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(14U);
4664         }
4665         BASIC_BLOCK(5U, 7U)
4666         {
4667             INST(16U, Opcode::Sub).s32().Inputs(8U, 3U);
4668             INST(27U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
4669             INST(17U, Opcode::NOP);
4670             INST(18U, Opcode::LoadArray).s32().Inputs(6U, 16U);  // a[i - 3]
4671         }
4672         BASIC_BLOCK(6U, 7U)
4673         {
4674             INST(19U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
4675             INST(20U, Opcode::NOP);
4676             INST(21U, Opcode::LoadArray).s32().Inputs(6U, 8U);  // a[i]
4677         }
4678         BASIC_BLOCK(7U, 3U)
4679         {
4680             INST(22U, Opcode::Phi).s32().Inputs(18U, 21U);
4681             INST(23U, Opcode::Add).s32().Inputs(25U, 22U);
4682             INST(24U, Opcode::Add).s32().Inputs(8U, 1U);
4683         }
4684         BASIC_BLOCK(8U, 1U)
4685         {
4686             INST(26U, Opcode::Return).s32().Inputs(25U);
4687         }
4688     }
4689     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
4690 }
4691 
BuildGraphLoopWithBoundsCheckUnderIfLT()4692 void ChecksEliminationTest::BuildGraphLoopWithBoundsCheckUnderIfLT()
4693 {
4694     GRAPH(GetGraph())
4695     {
4696         CONSTANT(0U, 0U);  // initial
4697         CONSTANT(1U, 1U);  // increment
4698         CONSTANT(3U, 3U);
4699         PARAMETER(2U, 0U).ref();  // array
4700         PARAMETER(4U, 1U).s32();  // X
4701 
4702         BASIC_BLOCK(2U, 3U, 8U)
4703         {
4704             INST(5U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
4705             INST(6U, Opcode::NullCheck).ref().Inputs(2U, 5U);
4706             INST(7U, Opcode::LenArray).s32().Inputs(6U);
4707 
4708             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
4709             INST(31U, Opcode::Compare).CC(CC_LT).b().Inputs(4U, 7U);  // X < len_array
4710             INST(32U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(31U);
4711         }
4712 
4713         BASIC_BLOCK(3U, 4U, 8U)
4714         {
4715             INST(8U, Opcode::Phi).s32().Inputs(4U, 24U);             // i = X
4716             INST(25U, Opcode::Phi).s32().Inputs(0U, 23U);            // sum
4717             INST(9U, Opcode::Compare).CC(CC_LT).b().Inputs(8U, 7U);  // i < len_array
4718             INST(10U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(9U);
4719         }
4720         BASIC_BLOCK(4U, 5U, 6U)
4721         {
4722             INST(13U, Opcode::Add).s32().Inputs(8U, 3U);
4723             INST(14U, Opcode::Compare).CC(CC_LT).b().Inputs(13U, 7U);  // i + 3 < len_array
4724             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(14U);
4725         }
4726         BASIC_BLOCK(5U, 6U)
4727         {
4728             INST(20U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
4729             INST(17U, Opcode::BoundsCheck).s32().Inputs(7U, 13U, 20U);
4730             INST(18U, Opcode::LoadArray).s32().Inputs(6U, 17U);
4731             INST(19U, Opcode::Mul).s32().Inputs(8U, 18U);  // i * a[i + 3]
4732         }
4733         BASIC_BLOCK(6U, 3U)
4734         {
4735             INST(22U, Opcode::Phi).s32().Inputs(8U, 19U);
4736             INST(23U, Opcode::Add).s32().Inputs(25U, 22U);
4737             INST(24U, Opcode::Add).s32().Inputs(8U, 1U);
4738         }
4739         BASIC_BLOCK(8U, 1U)
4740         {
4741             INST(26U, Opcode::Phi).s32().Inputs(0U, 25U);
4742             INST(27U, Opcode::Return).s32().Inputs(26U);
4743         }
4744     }
4745 }
4746 
4747 // Upper bound is correct in each branch based on BoundsAnalysis, build deoptimize only for lower bound
4748 // CC-OFFNXT(huge_method, G.FUN.01) graph creation
TEST_F(ChecksEliminationTest,LoopWithBoundsCheckUnderIfLT)4749 TEST_F(ChecksEliminationTest, LoopWithBoundsCheckUnderIfLT)
4750 {
4751     BuildGraphLoopWithBoundsCheckUnderIfLT();
4752     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
4753     auto graph1 = CreateEmptyGraph();
4754     GRAPH(graph1)
4755     {
4756         CONSTANT(0U, 0U);  // initial
4757         CONSTANT(1U, 1U);  // increment
4758         CONSTANT(3U, 3U);
4759         PARAMETER(2U, 0U).ref();  // array
4760         PARAMETER(4U, 1U).s32();  // X
4761 
4762         BASIC_BLOCK(2U, 3U, 8U)
4763         {
4764             INST(5U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
4765             INST(6U, Opcode::NullCheck).ref().Inputs(2U, 5U);
4766             INST(7U, Opcode::LenArray).s32().Inputs(6U);
4767 
4768             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
4769             INST(33U, Opcode::Add).s32().Inputs(4U, 3U);
4770             INST(34U, Opcode::Compare).b().CC(CC_LT).Inputs(33U, 0U);  // X + 3 < 0
4771             INST(35U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(34U, 30U);
4772             INST(31U, Opcode::Compare).CC(CC_LT).b().Inputs(4U, 7U);  // X < len_array
4773             INST(32U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(31U);
4774         }
4775         BASIC_BLOCK(3U, 4U, 8U)
4776         {
4777             INST(8U, Opcode::Phi).s32().Inputs(4U, 24U);             // i = X
4778             INST(25U, Opcode::Phi).s32().Inputs(0U, 23U);            // sum
4779             INST(9U, Opcode::Compare).CC(CC_LT).b().Inputs(8U, 7U);  // i < len_array
4780             INST(10U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(9U);
4781         }
4782         BASIC_BLOCK(4U, 5U, 6U)
4783         {
4784             INST(13U, Opcode::Add).s32().Inputs(8U, 3U);
4785             INST(14U, Opcode::Compare).CC(CC_LT).b().Inputs(13U, 7U);  // i + 3 < len_array
4786             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(14U);
4787         }
4788         BASIC_BLOCK(5U, 6U)
4789         {
4790             INST(20U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
4791             INST(17U, Opcode::NOP);
4792             INST(18U, Opcode::LoadArray).s32().Inputs(6U, 13U);
4793             INST(19U, Opcode::Mul).s32().Inputs(8U, 18U);  // i * a[i + 3]
4794         }
4795         BASIC_BLOCK(6U, 3U)
4796         {
4797             INST(22U, Opcode::Phi).s32().Inputs(8U, 19U);
4798             INST(23U, Opcode::Add).s32().Inputs(25U, 22U);
4799             INST(24U, Opcode::Add).s32().Inputs(8U, 1U);
4800         }
4801         BASIC_BLOCK(8U, 1U)
4802         {
4803             INST(26U, Opcode::Phi).s32().Inputs(0U, 25U);
4804             INST(27U, Opcode::Return).s32().Inputs(26U);
4805         }
4806     }
4807     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
4808 }
4809 
TEST_F(ChecksEliminationTest,DeoptTest)4810 TEST_F(ChecksEliminationTest, DeoptTest)
4811 {
4812     GRAPH(GetGraph())
4813     {
4814         CONSTANT(0U, 0U);
4815         CONSTANT(1U, nullptr);
4816         BASIC_BLOCK(2U, 1U)
4817         {
4818             INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
4819             INST(3U, Opcode::NullCheck).ref().Inputs(1U, 2U);
4820             INST(4U, Opcode::ZeroCheck).s32().Inputs(0U, 2U);
4821             INST(5U, Opcode::ReturnVoid).v0id();
4822         }
4823     }
4824     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
4825     auto graph = CreateEmptyGraph();
4826     GRAPH(graph)
4827     {
4828         CONSTANT(0U, 0U);
4829         CONSTANT(1U, nullptr);
4830         BASIC_BLOCK(2U, 1U)
4831         {
4832             INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
4833             INST(3U, Opcode::Deoptimize).DeoptimizeType(DeoptimizeType::NULL_CHECK).Inputs(2U);
4834         }
4835     }
4836 }
4837 
TEST_F(ChecksEliminationTest,CheckCastEqualInputs)4838 TEST_F(ChecksEliminationTest, CheckCastEqualInputs)
4839 {
4840     // Check Elimination for CheckCast is applied.
4841     GRAPH(GetGraph())
4842     {
4843         PARAMETER(0U, 0U).ref();
4844         BASIC_BLOCK(2U, 1U)
4845         {
4846             INST(1U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
4847             INST(2U, Opcode::LoadClass).ref().Inputs(1U).TypeId(1U);
4848             INST(3U, Opcode::CheckCast).TypeId(1U).Inputs(0U, 2U, 1U);
4849             INST(4U, Opcode::CheckCast).TypeId(1U).Inputs(0U, 2U, 1U);
4850             INST(5U, Opcode::Return).ref().Inputs(0U);
4851         }
4852     }
4853     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
4854     auto graph = CreateEmptyGraph();
4855     GRAPH(graph)
4856     {
4857         PARAMETER(0U, 0U).ref();
4858         BASIC_BLOCK(2U, 1U)
4859         {
4860             INST(1U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
4861             INST(2U, Opcode::LoadClass).ref().Inputs(1U).TypeId(1U);
4862             INST(3U, Opcode::CheckCast).TypeId(1U).Inputs(0U, 2U, 1U);
4863             INST(4U, Opcode::NOP);
4864             INST(5U, Opcode::Return).ref().Inputs(0U);
4865         }
4866     }
4867     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
4868 }
4869 
TEST_F(ChecksEliminationTest,CheckCastDifferentInputs)4870 TEST_F(ChecksEliminationTest, CheckCastDifferentInputs)
4871 {
4872     // Check Elimination for CheckCast is not applied.
4873     GRAPH(GetGraph())
4874     {
4875         PARAMETER(0U, 0U).ref();
4876         PARAMETER(1U, 1U).ref();
4877         BASIC_BLOCK(2U, 1U)
4878         {
4879             INST(8U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
4880             INST(2U, Opcode::LoadClass).ref().Inputs(8U).TypeId(1U);
4881             INST(3U, Opcode::LoadClass).ref().Inputs(8U).TypeId(2U);
4882             INST(4U, Opcode::CheckCast).TypeId(1U).Inputs(0U, 2U, 8U);
4883             INST(5U, Opcode::CheckCast).TypeId(2U).Inputs(0U, 3U, 8U);
4884             INST(6U, Opcode::CheckCast).TypeId(2U).Inputs(1U, 3U, 8U);
4885             INST(7U, Opcode::Return).ref().Inputs(0U);
4886         }
4887     }
4888     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
4889     ASSERT_FALSE(GetGraph()->RunPass<ChecksElimination>());
4890     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
4891 }
4892 
BuildGraphCheckCastAfterIsInstance()4893 void ChecksEliminationTest::BuildGraphCheckCastAfterIsInstance()
4894 {
4895     GRAPH(GetGraph())
4896     {
4897         PARAMETER(0U, 0U).ref();
4898         CONSTANT(9U, nullptr);
4899         BASIC_BLOCK(2U, 3U, 4U)
4900         {
4901             INST(1U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
4902             INST(2U, Opcode::LoadClass).ref().Inputs(1U).TypeId(1U);
4903             INST(3U, Opcode::IsInstance).b().Inputs(0U, 2U).TypeId(1U);
4904             INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_EQ).Imm(0U).Inputs(3U);
4905         }
4906 
4907         BASIC_BLOCK(4U, 1U)
4908         {
4909             INST(5U, Opcode::CheckCast).TypeId(1U).Inputs(0U, 2U, 1U);
4910             INST(6U, Opcode::LoadClass).ref().Inputs(1U).TypeId(2U);
4911             INST(7U, Opcode::CheckCast).TypeId(2U).Inputs(0U, 2U, 1U);
4912             INST(8U, Opcode::Return).ref().Inputs(0U);
4913         }
4914 
4915         BASIC_BLOCK(3U, 1U)
4916         {
4917             INST(10U, Opcode::Return).ref().Inputs(9U);
4918         }
4919     }
4920 }
4921 
TEST_F(ChecksEliminationTest,CheckCastAfterIsInstance)4922 TEST_F(ChecksEliminationTest, CheckCastAfterIsInstance)
4923 {
4924     // CheckCast after successful IsInstance can be removed.
4925     BuildGraphCheckCastAfterIsInstance();
4926 
4927     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
4928     ASSERT_TRUE(INS(7U).CastToCheckCast()->GetOmitNullCheck());
4929 
4930     auto graph = CreateEmptyGraph();
4931     GRAPH(graph)
4932     {
4933         PARAMETER(0U, 0U).ref();
4934         CONSTANT(9U, nullptr);
4935         BASIC_BLOCK(2U, 3U, 4U)
4936         {
4937             INST(1U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
4938             INST(2U, Opcode::LoadClass).ref().Inputs(1U).TypeId(1U);
4939             INST(3U, Opcode::IsInstance).b().Inputs(0U, 2U).TypeId(1U);
4940             INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_EQ).Imm(0U).Inputs(3U);
4941         }
4942 
4943         BASIC_BLOCK(4U, 1U)
4944         {
4945             INST(5U, Opcode::NOP);
4946             INST(6U, Opcode::LoadClass).ref().Inputs(1U).TypeId(2U);
4947             INST(7U, Opcode::CheckCast).TypeId(2U).Inputs(0U, 2U, 1U);
4948             INST(8U, Opcode::Return).ref().Inputs(0U);
4949         }
4950 
4951         BASIC_BLOCK(3U, 1U)
4952         {
4953             INST(10U, Opcode::Return).ref().Inputs(9U);
4954         }
4955     }
4956     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
4957 }
4958 
TEST_F(ChecksEliminationTest,CheckCastAfterIsInstanceTriangleCase)4959 TEST_F(ChecksEliminationTest, CheckCastAfterIsInstanceTriangleCase)
4960 {
4961     // CheckCast cannot be removed because dominating IsInstance can be false.
4962     GRAPH(GetGraph())
4963     {
4964         PARAMETER(0U, 0U).ref();
4965         CONSTANT(9U, nullptr);
4966         BASIC_BLOCK(2U, 3U, 4U)
4967         {
4968             INST(1U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
4969             INST(2U, Opcode::LoadClass).ref().Inputs(1U).TypeId(1U);
4970             INST(3U, Opcode::IsInstance).b().Inputs(0U, 2U).TypeId(1U);
4971             INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_EQ).Imm(0U).Inputs(3U);
4972         }
4973 
4974         BASIC_BLOCK(3U, 4U) {}
4975 
4976         BASIC_BLOCK(4U, 1U)
4977         {
4978             INST(5U, Opcode::Phi).ref().Inputs({{2U, 9U}, {3U, 0U}});
4979             INST(6U, Opcode::CheckCast).TypeId(1U).Inputs(0U, 2U, 1U);
4980             INST(7U, Opcode::Return).ref().Inputs(5U);
4981         }
4982     }
4983     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
4984     ASSERT_FALSE(GetGraph()->RunPass<ChecksElimination>());
4985     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
4986 }
4987 
TEST_F(ChecksEliminationTest,CheckCastAfterIsInstanceDiamondCase)4988 TEST_F(ChecksEliminationTest, CheckCastAfterIsInstanceDiamondCase)
4989 {
4990     // CheckCast cannot be removed because dominating IsInstance can be false.
4991     GRAPH(GetGraph())
4992     {
4993         PARAMETER(0U, 0U).ref();
4994         CONSTANT(9U, nullptr);
4995         BASIC_BLOCK(2U, 3U, 4U)
4996         {
4997             INST(1U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
4998             INST(2U, Opcode::LoadClass).ref().Inputs(1U).TypeId(1U);
4999             INST(3U, Opcode::IsInstance).b().Inputs(0U, 2U).TypeId(1U);
5000             INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_EQ).Imm(0U).Inputs(3U);
5001         }
5002 
5003         BASIC_BLOCK(3U, 5U) {}
5004 
5005         BASIC_BLOCK(4U, 5U) {}
5006 
5007         BASIC_BLOCK(5U, 1U)
5008         {
5009             INST(5U, Opcode::Phi).ref().Inputs({{3U, 9U}, {4U, 0U}});
5010             INST(6U, Opcode::CheckCast).TypeId(1U).Inputs(0U, 2U, 1U);
5011             INST(7U, Opcode::Return).ref().Inputs(5U);
5012         }
5013     }
5014     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
5015     ASSERT_FALSE(GetGraph()->RunPass<ChecksElimination>());
5016     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
5017 }
5018 
BuildHoistCheckCastGraph()5019 void ChecksEliminationTest::BuildHoistCheckCastGraph()
5020 {
5021     GRAPH(GetGraph())
5022     {
5023         CONSTANT(0U, 0U);  // initial
5024         CONSTANT(1U, 1U);  // increment
5025         CONSTANT(2U, 10U);
5026         PARAMETER(3U, 0U).ref();
5027         BASIC_BLOCK(2U, 3U, 5U)
5028         {
5029             INST(21U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
5030             INST(22U, Opcode::LoadClass).ref().Inputs(21U).TypeId(1U);
5031             INST(20U, Opcode::SaveStateDeoptimize).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
5032             INST(5U, Opcode::Compare).SrcType(DataType::INT32).CC(CC_LT).b().Inputs(0U, 2U);  // 0 < 10
5033             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
5034         }
5035         BASIC_BLOCK(3U, 3U, 5U)
5036         {
5037             INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);  // i
5038             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
5039             INST(8U, Opcode::CheckCast).Inputs(3U, 22U, 7U).TypeId(1U);
5040             INST(9U, Opcode::LoadObject).ref().Inputs(3U);
5041             INST(23U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U, 9U).SrcVregs({0U, 1U, 2U, 3U, 4U});
5042             INST(11U, Opcode::CheckCast).Inputs(9U, 22U, 23U).TypeId(1U);
5043 
5044             INST(10U, Opcode::Add).s32().Inputs(4U, 1U);               // i++
5045             INST(13U, Opcode::Compare).CC(CC_LT).b().Inputs(10U, 2U);  // i < 10
5046             INST(14U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(13U);
5047         }
5048         BASIC_BLOCK(5U, 1U)
5049         {
5050             INST(12U, Opcode::ReturnVoid).v0id();
5051         }
5052     }
5053 }
5054 
TEST_F(ChecksEliminationTest,HoistCheckCastTest)5055 TEST_F(ChecksEliminationTest, HoistCheckCastTest)
5056 {
5057     BuildHoistCheckCastGraph();
5058     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
5059     auto graph = CreateEmptyGraph();
5060     GRAPH(graph)
5061     {
5062         CONSTANT(0U, 0U);  // initial
5063         CONSTANT(1U, 1U);  // increment
5064         CONSTANT(2U, 10U);
5065         PARAMETER(3U, 0U).ref();
5066         BASIC_BLOCK(2U, 3U, 5U)
5067         {
5068             INST(21U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
5069             INST(22U, Opcode::LoadClass).ref().Inputs(21U).TypeId(1U);
5070             INST(20U, Opcode::SaveStateDeoptimize).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
5071             INST(8U, Opcode::CheckCast).Inputs(3U, 22U, 20U).TypeId(1U).SetFlag(inst_flags::CAN_DEOPTIMIZE);
5072             INST(5U, Opcode::Compare).SrcType(DataType::INT32).CC(CC_LT).b().Inputs(0U, 2U);  // 0 < 10
5073             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
5074         }
5075         BASIC_BLOCK(3U, 3U, 5U)
5076         {
5077             INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);  // i
5078             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
5079             INST(9U, Opcode::LoadObject).ref().Inputs(3U);
5080             INST(23U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U, 9U).SrcVregs({0U, 1U, 2U, 3U, 4U});
5081             INST(11U, Opcode::CheckCast).Inputs(9U, 22U, 23U).TypeId(1U);
5082 
5083             INST(10U, Opcode::Add).s32().Inputs(4U, 1U);               // i++
5084             INST(13U, Opcode::Compare).CC(CC_LT).b().Inputs(10U, 2U);  // i < 10
5085             INST(14U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(13U);
5086         }
5087         BASIC_BLOCK(5U, 1U)
5088         {
5089             INST(12U, Opcode::ReturnVoid).v0id();
5090         }
5091     }
5092     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
5093 }
5094 
TEST_F(ChecksEliminationTest,NullCheckAfterIsInstance)5095 TEST_F(ChecksEliminationTest, NullCheckAfterIsInstance)
5096 {
5097     // NullCheck after successful IsInstance can be removed.
5098     GRAPH(GetGraph())
5099     {
5100         PARAMETER(0U, 0U).ref();
5101         CONSTANT(9U, nullptr);
5102         BASIC_BLOCK(2U, 3U, 4U)
5103         {
5104             INST(1U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
5105             INST(2U, Opcode::LoadClass).ref().Inputs(1U).TypeId(1U);
5106             INST(3U, Opcode::IsInstance).b().Inputs(0U, 2U).TypeId(1U);
5107             INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_EQ).Imm(0U).Inputs(3U);
5108         }
5109 
5110         BASIC_BLOCK(4U, 1U)
5111         {
5112             INST(5U, Opcode::NullCheck).ref().Inputs(0U, 1U);
5113             INST(6U, Opcode::Return).ref().Inputs(5U);
5114         }
5115 
5116         BASIC_BLOCK(3U, 1U)
5117         {
5118             INST(10U, Opcode::Return).ref().Inputs(9U);
5119         }
5120     }
5121     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
5122 
5123     auto graph = CreateEmptyGraph();
5124     GRAPH(graph)
5125     {
5126         PARAMETER(0U, 0U).ref();
5127         CONSTANT(9U, nullptr);
5128         BASIC_BLOCK(2U, 3U, 4U)
5129         {
5130             INST(1U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
5131             INST(2U, Opcode::LoadClass).ref().Inputs(1U).TypeId(1U);
5132             INST(3U, Opcode::IsInstance).b().Inputs(0U, 2U).TypeId(1U);
5133             INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_EQ).Imm(0U).Inputs(3U);
5134         }
5135 
5136         BASIC_BLOCK(4U, 1U)
5137         {
5138             INST(5U, Opcode::NOP);
5139             INST(6U, Opcode::Return).ref().Inputs(0U);
5140         }
5141 
5142         BASIC_BLOCK(3U, 1U)
5143         {
5144             INST(10U, Opcode::Return).ref().Inputs(9U);
5145         }
5146     }
5147     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
5148 }
5149 
TEST_F(ChecksEliminationTest,OmitNullCheck)5150 TEST_F(ChecksEliminationTest, OmitNullCheck)
5151 {
5152     // Check Elimination for NullCheck is applied.
5153     GRAPH(GetGraph())
5154     {
5155         PARAMETER(0U, 0U).ref();
5156         CONSTANT(1U, 10U);
5157         BASIC_BLOCK(2U, 1U)
5158         {
5159             INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
5160             INST(3U, Opcode::NullCheck).ref().Inputs(0U, 2U);
5161             INST(4U, Opcode::LoadArray).s32().Inputs(3U, 1U);
5162             INST(5U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
5163             INST(6U, Opcode::LoadClass).ref().Inputs(5U);
5164             INST(7U, Opcode::CheckCast).TypeId(1U).Inputs(0U, 6U, 5U);
5165             INST(8U, Opcode::LoadClass).ref().Inputs(5U);
5166             INST(9U, Opcode::IsInstance).TypeId(2U).b().Inputs(0U, 8U, 5U);
5167             INST(10U, Opcode::Return).b().Inputs(9U);
5168         }
5169     }
5170     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
5171     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
5172     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
5173     ASSERT_TRUE(INS(7U).CastToCheckCast()->GetOmitNullCheck());
5174     ASSERT_TRUE(INS(9U).CastToIsInstance()->GetOmitNullCheck());
5175 }
5176 
TEST_F(ChecksEliminationTest,DoNotOmitNullCheck)5177 TEST_F(ChecksEliminationTest, DoNotOmitNullCheck)
5178 {
5179     // NullCheck inside CheckCast and IsInstance cannot be omitted. NullCheck doesn't dominate them.
5180     GRAPH(GetGraph())
5181     {
5182         PARAMETER(0U, 0U).ref();
5183         CONSTANT(1U, 10U);
5184 
5185         BASIC_BLOCK(2U, 3U, 4U)
5186         {
5187             INST(2U, Opcode::Compare).b().SrcType(DataType::Type::INT64).Inputs(1U, 1U);
5188             INST(3U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(2U);
5189         }
5190 
5191         BASIC_BLOCK(3U, 5U)
5192         {
5193             INST(4U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
5194             INST(5U, Opcode::NullCheck).ref().Inputs(0U, 4U);
5195             INST(6U, Opcode::LoadArray).s32().Inputs(5U, 1U);
5196         }
5197 
5198         BASIC_BLOCK(4U, 5U)
5199         {
5200             INST(7U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
5201             INST(8U, Opcode::LoadClass).TypeId(1U).ref().Inputs(7U);
5202             INST(9U, Opcode::CheckCast).TypeId(1U).Inputs(0U, 8U, 7U);
5203             INST(10U, Opcode::LoadClass).TypeId(2U).ref().Inputs(7U);
5204             INST(11U, Opcode::IsInstance).TypeId(2U).b().Inputs(0U, 10U, 7U);
5205         }
5206 
5207         BASIC_BLOCK(5U, 1U)
5208         {
5209             INST(12U, Opcode::Phi).s32().Inputs(6U, 1U);
5210             INST(13U, Opcode::Return).s32().Inputs(12U);
5211         }
5212     }
5213     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
5214     ASSERT_FALSE(GetGraph()->RunPass<ChecksElimination>());
5215     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
5216     ASSERT_FALSE(INS(9U).CastToCheckCast()->GetOmitNullCheck());
5217     ASSERT_FALSE(INS(11U).CastToIsInstance()->GetOmitNullCheck());
5218 }
5219 
5220 // NOTE(schernykh): It's possible to remove boundschecks from this test, but BoundsAnalysis must be upgrade for
5221 // it.
TEST_F(ChecksEliminationTest,OptimizeBoundsCheckElimination)5222 TEST_F(ChecksEliminationTest, OptimizeBoundsCheckElimination)
5223 {
5224     GRAPH(GetGraph())
5225     {
5226         CONSTANT(0U, 0U);
5227         CONSTANT(14U, 1U);
5228         PARAMETER(1U, 0U).s32();
5229         PARAMETER(2U, 1U).s32();
5230         BASIC_BLOCK(2U, 6U, 3U)
5231         {
5232             INST(43U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
5233             INST(44U, Opcode::LoadAndInitClass).ref().Inputs().TypeId(68U);
5234             INST(3U, Opcode::NewArray).ref().Inputs(44U, 1U, 43U);
5235             INST(4U, Opcode::Compare).b().SrcType(DataType::Type::INT32).CC(CC_LT).Inputs(2U, 0U);
5236             INST(5U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(4U);
5237         }
5238         BASIC_BLOCK(3U, 6U, 4U)
5239         {
5240             INST(6U, Opcode::Compare).b().SrcType(DataType::Type::INT32).CC(CC_GE).Inputs(2U, 1U);
5241             INST(7U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(6U);
5242         }
5243         BASIC_BLOCK(4U, 6U, 5U)
5244         {
5245             INST(8U, Opcode::Add).s32().Inputs(2U, 14U);
5246             INST(9U, Opcode::Compare).b().SrcType(DataType::Type::INT32).CC(CC_GE).Inputs(8U, 1U);
5247             INST(10U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(9U);
5248         }
5249         BASIC_BLOCK(5U, 6U)
5250         {
5251             INST(11U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
5252             INST(12U, Opcode::BoundsCheck).s32().Inputs(1U, 8U, 11U);
5253             INST(13U, Opcode::StoreArray).s32().Inputs(3U, 8U, 0U);
5254         }
5255         BASIC_BLOCK(6U, 1U)
5256         {
5257             INST(15U, Opcode::ReturnVoid).v0id();
5258         }
5259     }
5260     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
5261     ASSERT_FALSE(GetGraph()->RunPass<ChecksElimination>());
5262     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
5263 }
5264 
TEST_F(ChecksEliminationTest,BoundsCheckEqualInputs)5265 TEST_F(ChecksEliminationTest, BoundsCheckEqualInputs)
5266 {
5267     GRAPH(GetGraph())
5268     {
5269         PARAMETER(1U, 2U).s32();
5270         PARAMETER(2U, 3U).s32();
5271         CONSTANT(3U, 10U);
5272         BASIC_BLOCK(2U, 1U)
5273         {
5274             INST(4U, Opcode::SaveState).Inputs(1U, 2U).SrcVregs({1U, 2U});
5275             INST(44U, Opcode::LoadAndInitClass).ref().Inputs().TypeId(68U);
5276             INST(5U, Opcode::NewArray).ref().Inputs(44U, 3U, 4U);
5277             INST(6U, Opcode::BoundsCheck).s32().Inputs(3U, 1U, 4U);
5278             INST(7U, Opcode::StoreArray).s32().Inputs(5U, 6U, 3U);
5279 
5280             INST(14U, Opcode::SaveState).Inputs(1U, 2U).SrcVregs({1U, 2U});
5281             INST(15U, Opcode::NewArray).ref().Inputs(44U, 2U, 14U);
5282             INST(16U, Opcode::BoundsCheck).s32().Inputs(2U, 3U, 14U);
5283             INST(17U, Opcode::StoreArray).s32().Inputs(15U, 16U, 3U);
5284 
5285             INST(18U, Opcode::ReturnVoid).v0id();
5286         }
5287     }
5288     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
5289     ASSERT_FALSE(GetGraph()->RunPass<ChecksElimination>());
5290     ASSERT_TRUE(GraphComparator().Compare(clone, GetGraph()));
5291 }
5292 
5293 // dominated checks
TEST_F(ChecksEliminationTest,AddSubOverflowCheckDom)5294 TEST_F(ChecksEliminationTest, AddSubOverflowCheckDom)
5295 {
5296     GRAPH(GetGraph())
5297     {
5298         PARAMETER(0U, 0U).s32();
5299         PARAMETER(1U, 1U).s32();
5300         BASIC_BLOCK(2U, -1L)
5301         {
5302             INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5303             INST(3U, Opcode::AddOverflowCheck).s32().Inputs(0U, 1U, 2U);  // main
5304 
5305             INST(4U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5306             INST(5U, Opcode::AddOverflowCheck).s32().Inputs(0U, 1U, 4U);  // redundant
5307 
5308             INST(6U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5309             INST(7U, Opcode::AddOverflowCheck).s32().Inputs(1U, 0U, 6U);  // redundant, swapped inputs
5310 
5311             INST(8U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5312             INST(9U, Opcode::SubOverflowCheck).s32().Inputs(0U, 1U, 8U);  // main
5313 
5314             INST(10U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5315             INST(11U, Opcode::SubOverflowCheck).s32().Inputs(0U, 1U, 10U);  // redundant
5316 
5317             INST(12U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5318             INST(13U, Opcode::SubOverflowCheck).s32().Inputs(1U, 0U, 12U);  // not redundant, swapped inputs
5319 
5320             INST(14U, Opcode::ReturnVoid).v0id();
5321         }
5322     }
5323     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
5324     ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
5325     auto graph = CreateEmptyGraph();
5326     GRAPH(graph)
5327     {
5328         PARAMETER(0U, 0U).s32();
5329         PARAMETER(1U, 1U).s32();
5330         BASIC_BLOCK(2U, -1L)
5331         {
5332             INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5333             INST(3U, Opcode::AddOverflowCheck).s32().Inputs(0U, 1U, 2U);  // main
5334 
5335             INST(8U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5336             INST(9U, Opcode::SubOverflowCheck).s32().Inputs(0U, 1U, 8U);  // main
5337 
5338             INST(12U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5339             INST(13U, Opcode::SubOverflowCheck).s32().Inputs(1U, 0U, 12U);  // not redundant, swapped inputs
5340 
5341             INST(14U, Opcode::ReturnVoid).v0id();
5342         }
5343     }
5344     ASSERT_TRUE(GraphComparator().Compare(graph, GetGraph()));
5345 }
5346 
BuildGraphOverflowCheckOptimize()5347 void ChecksEliminationTest::BuildGraphOverflowCheckOptimize()
5348 {
5349     GRAPH(GetGraph())
5350     {
5351         PARAMETER(0U, 0U).s32();
5352         PARAMETER(1U, 1U).s32();
5353         CONSTANT(6U, 6U);
5354         CONSTANT(1000U, 0U);
5355         CONSTANT(13U, INT32_MAX);
5356         CONSTANT(14U, INT32_MIN);
5357         BASIC_BLOCK(2U, 3U, 4U)
5358         {
5359             INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5360             INST(3U, Opcode::AddOverflowCheck).s32().Inputs(0U, 1U, 2U);  // maybe overflow
5361 
5362             INST(4U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5363             INST(5U, Opcode::SubOverflowCheck).s32().Inputs(0U, 1U, 4U);  // maybe overflow
5364 
5365             INST(20U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5366             INST(30U, Opcode::AddOverflowCheck).s32().Inputs(0U, 6U, 20U);  // maybe overflow
5367 
5368             INST(40U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5369             INST(50U, Opcode::SubOverflowCheck).s32().Inputs(0U, 6U, 40U);  // maybe overflow
5370 
5371             INST(7U, Opcode::Div).s32().Inputs(0U, 6U);
5372             INST(8U, Opcode::Div).s32().Inputs(1U, 6U);
5373 
5374             INST(9U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5375             INST(10U, Opcode::AddOverflowCheck).s32().Inputs(7U, 8U, 9U);  // can't overflow
5376 
5377             INST(11U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5378             INST(12U, Opcode::SubOverflowCheck).s32().Inputs(7U, 8U, 11U);  // can't overflow
5379 
5380             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(1000U);
5381         }
5382         BASIC_BLOCK(3U, 5U)
5383         {
5384             INST(16U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5385             INST(17U, Opcode::AddOverflowCheck).s32().Inputs(13U, 6U, 16U);  // must overflow
5386         }
5387         BASIC_BLOCK(4U, 5U)
5388         {
5389             INST(18U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5390             INST(19U, Opcode::SubOverflowCheck).s32().Inputs(14U, 6U, 18U);  // must overflow
5391         }
5392         BASIC_BLOCK(5U, -1L)
5393         {
5394             INST(100U, Opcode::ReturnVoid).v0id();
5395         }
5396     }
5397 }
5398 
TEST_F(ChecksEliminationTest,OverflowCheckOptimize)5399 TEST_F(ChecksEliminationTest, OverflowCheckOptimize)
5400 {
5401     BuildGraphOverflowCheckOptimize();
5402     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
5403     auto graph = CreateEmptyGraph();
5404     GRAPH(graph)
5405     {
5406         PARAMETER(0U, 0U).s32();
5407         PARAMETER(1U, 1U).s32();
5408         CONSTANT(6U, 6U);
5409         CONSTANT(1000U, 0U);
5410         CONSTANT(13U, INT32_MAX);
5411         CONSTANT(14U, INT32_MIN);
5412         BASIC_BLOCK(2U, 3U, 4U)
5413         {
5414             INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5415             INST(3U, Opcode::AddOverflowCheck).s32().Inputs(0U, 1U, 2U);  // maybe overflow
5416 
5417             INST(4U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5418             INST(5U, Opcode::SubOverflowCheck).s32().Inputs(0U, 1U, 4U);  // maybe overflow
5419 
5420             INST(20U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5421             INST(30U, Opcode::AddOverflowCheck).s32().Inputs(0U, 6U, 20U);  // maybe overflow
5422 
5423             INST(40U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5424             INST(50U, Opcode::SubOverflowCheck).s32().Inputs(0U, 6U, 40U);  // maybe overflow
5425 
5426             INST(7U, Opcode::Div).s32().Inputs(0U, 6U);
5427             INST(8U, Opcode::Div).s32().Inputs(1U, 6U);
5428 
5429             INST(9U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5430             INST(10U, Opcode::Add).s32().Inputs(7U, 8U);
5431 
5432             INST(11U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5433             INST(12U, Opcode::Sub).s32().Inputs(7U, 8U);
5434 
5435             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(1000U);
5436         }
5437         BASIC_BLOCK(3U, -1L)
5438         {
5439             INST(16U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5440             INST(17U, Opcode::Deoptimize).DeoptimizeType(DeoptimizeType::OVERFLOW_TYPE).Inputs(16U);  // must overflow
5441         }
5442         BASIC_BLOCK(4U, -1L)
5443         {
5444             INST(18U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5445             INST(19U, Opcode::Deoptimize).DeoptimizeType(DeoptimizeType::OVERFLOW_TYPE).Inputs(18U);  // must overflow
5446         }
5447     }
5448     ASSERT_TRUE(GraphComparator().Compare(graph, GetGraph()));
5449 }
5450 
TEST_F(ChecksEliminationTest,LoopWithOverflowCheck)5451 TEST_F(ChecksEliminationTest, LoopWithOverflowCheck)
5452 {
5453     GRAPH(GetGraph())
5454     {
5455         PARAMETER(0U, 0U).s32();
5456         PARAMETER(1U, 1U).s32();
5457         CONSTANT(2U, 0U);
5458         BASIC_BLOCK(2U, 3U)
5459         {
5460             INST(3U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
5461         }
5462         BASIC_BLOCK(3U, 3U, 4U)
5463         {
5464             INST(4U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
5465             INST(5U, Opcode::AddOverflowCheck).s32().Inputs(0U, 1U, 4U);
5466             INST(6U, Opcode::SubOverflowCheck).s32().Inputs(0U, 1U, 4U);
5467             INST(7U, Opcode::IfImm).SrcType(DataType::BOOL).Inputs(2U).Imm(0U);
5468         }
5469         BASIC_BLOCK(4U, 1U)
5470         {
5471             INST(8U, Opcode::ReturnVoid).v0id();
5472         }
5473     }
5474     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
5475     auto graph = CreateEmptyGraph();
5476     GRAPH(graph)
5477     {
5478         PARAMETER(0U, 0U).s32();
5479         PARAMETER(1U, 1U).s32();
5480         CONSTANT(2U, 0U);
5481         BASIC_BLOCK(2U, 3U)
5482         {
5483             INST(3U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
5484             INST(5U, Opcode::SubOverflowCheck).s32().Inputs(0U, 1U, 3U);
5485             INST(6U, Opcode::AddOverflowCheck).s32().Inputs(0U, 1U, 3U);
5486         }
5487         BASIC_BLOCK(3U, 3U, 4U)
5488         {
5489             INST(4U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
5490             INST(7U, Opcode::IfImm).SrcType(DataType::BOOL).Inputs(2U).Imm(0U);
5491         }
5492         BASIC_BLOCK(4U, 1U)
5493         {
5494             INST(8U, Opcode::ReturnVoid).v0id();
5495         }
5496     }
5497     ASSERT_TRUE(GraphComparator().Compare(graph, GetGraph()));
5498 }
5499 
TEST_F(ChecksEliminationTest,LoopWithAddOverflowCheck)5500 TEST_F(ChecksEliminationTest, LoopWithAddOverflowCheck)
5501 {
5502     GRAPH(GetGraph())
5503     {
5504         PARAMETER(0U, 0U).s32();
5505         CONSTANT(1U, 1U);
5506         CONSTANT(10U, 10U);
5507 
5508         BASIC_BLOCK(2U, 3U, 4U)
5509         {
5510             INST(2U, Opcode::Phi).s32().Inputs(1U, 4U);
5511             INST(6U, Opcode::Compare).b().Inputs(2U, 10U).CC(CC_LT);
5512             INST(5U, Opcode::IfImm).SrcType(DataType::BOOL).Inputs(6U).Imm(0U).CC(CC_NE);
5513         }
5514         BASIC_BLOCK(3U, 2U)
5515         {
5516             INST(3U, Opcode::SaveState).Inputs(0U, 1U, 10U).SrcVregs({0U, 1U, 10U});
5517             INST(4U, Opcode::AddOverflowCheck).s32().Inputs(2U, 1U, 3U);  // can't be overflow
5518         }
5519         BASIC_BLOCK(4U, 1U)
5520         {
5521             INST(7U, Opcode::Return).s32().Inputs(2U);
5522         }
5523     }
5524     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
5525     auto graph = CreateEmptyGraph();
5526     GRAPH(graph)
5527     {
5528         PARAMETER(0U, 0U).s32();
5529         CONSTANT(1U, 1U);
5530         CONSTANT(10U, 10U);
5531 
5532         BASIC_BLOCK(2U, 3U, 4U)
5533         {
5534             INST(2U, Opcode::Phi).s32().Inputs(1U, 4U);
5535             INST(6U, Opcode::Compare).b().Inputs(2U, 10U).CC(CC_LT);
5536             INST(5U, Opcode::IfImm).SrcType(DataType::BOOL).Inputs(6U).Imm(0U).CC(CC_NE);
5537         }
5538         BASIC_BLOCK(3U, 2U)
5539         {
5540             INST(3U, Opcode::SaveState).Inputs(0U, 1U, 10U).SrcVregs({0U, 1U, 10U});
5541             INST(4U, Opcode::Add).s32().Inputs(2U, 1U);
5542         }
5543         BASIC_BLOCK(4U, 1U)
5544         {
5545             INST(7U, Opcode::Return).s32().Inputs(2U);
5546         }
5547     }
5548     ASSERT_TRUE(GraphComparator().Compare(graph, GetGraph()));
5549 }
5550 
TEST_F(ChecksEliminationTest,LoopWithSubOverflowCheck)5551 TEST_F(ChecksEliminationTest, LoopWithSubOverflowCheck)
5552 {
5553     GRAPH(GetGraph())
5554     {
5555         PARAMETER(0U, 0U).s32();
5556         CONSTANT(1U, 1U);
5557         CONSTANT(10U, 10U);
5558 
5559         BASIC_BLOCK(2U, 3U, 4U)
5560         {
5561             INST(2U, Opcode::Phi).s32().Inputs(10U, 4U);
5562             INST(6U, Opcode::Compare).b().Inputs(2U, 1U).CC(CC_GT);
5563             INST(5U, Opcode::IfImm).SrcType(DataType::BOOL).Inputs(6U).Imm(0U).CC(CC_NE);
5564         }
5565         BASIC_BLOCK(3U, 2U)
5566         {
5567             INST(3U, Opcode::SaveState).Inputs(0U, 1U, 10U).SrcVregs({0U, 1U, 10U});
5568             INST(4U, Opcode::SubOverflowCheck).s32().Inputs(2U, 1U, 3U);  // can't be overflow
5569         }
5570         BASIC_BLOCK(4U, 1U)
5571         {
5572             INST(7U, Opcode::Return).s32().Inputs(2U);
5573         }
5574     }
5575     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
5576     auto graph = CreateEmptyGraph();
5577     GRAPH(graph)
5578     {
5579         PARAMETER(0U, 0U).s32();
5580         CONSTANT(1U, 1U);
5581         CONSTANT(10U, 10U);
5582 
5583         BASIC_BLOCK(2U, 3U, 4U)
5584         {
5585             INST(2U, Opcode::Phi).s32().Inputs(10U, 4U);
5586             INST(6U, Opcode::Compare).b().Inputs(2U, 1U).CC(CC_GT);
5587             INST(5U, Opcode::IfImm).SrcType(DataType::BOOL).Inputs(6U).Imm(0U).CC(CC_NE);
5588         }
5589         BASIC_BLOCK(3U, 2U)
5590         {
5591             INST(3U, Opcode::SaveState).Inputs(0U, 1U, 10U).SrcVregs({0U, 1U, 10U});
5592             INST(4U, Opcode::Sub).s32().Inputs(2U, 1U);
5593         }
5594         BASIC_BLOCK(4U, 1U)
5595         {
5596             INST(7U, Opcode::Return).s32().Inputs(2U);
5597         }
5598     }
5599     ASSERT_TRUE(GraphComparator().Compare(graph, GetGraph()));
5600 }
5601 
TEST_F(ChecksEliminationTest,AndWithAddOverFlowCheck)5602 TEST_F(ChecksEliminationTest, AndWithAddOverFlowCheck)
5603 {
5604     GRAPH(GetGraph())
5605     {
5606         PARAMETER(0U, 0U).s64();
5607         PARAMETER(1U, 1U).s64();
5608         CONSTANT(2U, 0x3U);
5609         BASIC_BLOCK(2U, -1L)
5610         {
5611             INST(3U, Opcode::And).s32().Inputs(0U, 2U);
5612             INST(4U, Opcode::And).s32().Inputs(1U, 2U);
5613             INST(5U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
5614             INST(6U, Opcode::AddOverflowCheck).s32().Inputs(3U, 4U, 5U);
5615             INST(7U, Opcode::Return).s32().Inputs(6U);
5616         }
5617     }
5618     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
5619     auto graph = CreateEmptyGraph();
5620     GRAPH(graph)
5621     {
5622         PARAMETER(0U, 0U).s64();
5623         PARAMETER(1U, 1U).s64();
5624         CONSTANT(2U, 0x3U);
5625         BASIC_BLOCK(2U, -1L)
5626         {
5627             INST(3U, Opcode::And).s32().Inputs(0U, 2U);
5628             INST(4U, Opcode::And).s32().Inputs(1U, 2U);
5629             INST(5U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
5630             INST(6U, Opcode::Add).s32().Inputs(3U, 4U);
5631             INST(7U, Opcode::Return).s32().Inputs(6U);
5632         }
5633     }
5634     ASSERT_TRUE(GraphComparator().Compare(graph, GetGraph()));
5635 }
5636 
5637 // Must Deoptimize
TEST_F(ChecksEliminationTest,NegOverflowAndZeroCheck1)5638 TEST_F(ChecksEliminationTest, NegOverflowAndZeroCheck1)
5639 {
5640     for (auto cnst : {0, INT32_MIN}) {
5641         auto graph1 = CreateEmptyGraph();
5642         GRAPH(graph1)
5643         {
5644             CONSTANT(0U, cnst);
5645             BASIC_BLOCK(2U, -1L)
5646             {
5647                 INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
5648                 INST(6U, Opcode::NegOverflowAndZeroCheck).s32().Inputs(0U, 5U);
5649                 INST(7U, Opcode::Return).s32().Inputs(6U);
5650             }
5651         }
5652         ASSERT_TRUE(graph1->RunPass<ChecksElimination>());
5653         auto graph2 = CreateEmptyGraph();
5654         GRAPH(graph2)
5655         {
5656             CONSTANT(0U, cnst);
5657             BASIC_BLOCK(2U, -1L)
5658             {
5659                 INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
5660                 INST(6U, Opcode::Deoptimize).DeoptimizeType(DeoptimizeType::OVERFLOW_TYPE).Inputs(5U);
5661             }
5662         }
5663         ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
5664     }
5665 }
5666 
5667 // Remove dominated check
TEST_F(ChecksEliminationTest,NegOverflowAndZeroCheck2)5668 TEST_F(ChecksEliminationTest, NegOverflowAndZeroCheck2)
5669 {
5670     auto graph1 = CreateEmptyGraph();
5671     GRAPH(graph1)
5672     {
5673         PARAMETER(0U, 0U).u32();
5674         BASIC_BLOCK(2U, -1L)
5675         {
5676             INST(3U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
5677             INST(4U, Opcode::NegOverflowAndZeroCheck).s32().Inputs(0U, 3U);
5678             INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
5679             INST(6U, Opcode::NegOverflowAndZeroCheck).s32().Inputs(0U, 5U);
5680             INST(7U, Opcode::CallStatic).s32().InputsAutoType(4U, 6U, 3U);
5681             INST(8U, Opcode::Return).s32().Inputs(7U);
5682         }
5683     }
5684     ASSERT_TRUE(graph1->RunPass<ChecksElimination>());
5685     ASSERT_TRUE(graph1->RunPass<Cleanup>());
5686     auto graph2 = CreateEmptyGraph();
5687     GRAPH(graph2)
5688     {
5689         PARAMETER(0U, 0U).u32();
5690         BASIC_BLOCK(2U, -1L)
5691         {
5692             INST(3U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
5693             INST(4U, Opcode::NegOverflowAndZeroCheck).s32().Inputs(0U, 3U);
5694             INST(7U, Opcode::CallStatic).s32().InputsAutoType(4U, 4U, 3U);
5695             INST(8U, Opcode::Return).s32().Inputs(7U);
5696         }
5697     }
5698     ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
5699 }
5700 
5701 // Replace by Neg
TEST_F(ChecksEliminationTest,NegOverflowAndZeroCheck3)5702 TEST_F(ChecksEliminationTest, NegOverflowAndZeroCheck3)
5703 {
5704     auto graph1 = CreateEmptyGraph();
5705     GRAPH(graph1)
5706     {
5707         CONSTANT(0U, 1U);
5708         BASIC_BLOCK(2U, -1L)
5709         {
5710             INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
5711             INST(6U, Opcode::NegOverflowAndZeroCheck).s32().Inputs(0U, 5U);
5712             INST(7U, Opcode::Return).s32().Inputs(6U);
5713         }
5714     }
5715     ASSERT_TRUE(graph1->RunPass<ChecksElimination>());
5716     auto graph2 = CreateEmptyGraph();
5717     GRAPH(graph2)
5718     {
5719         CONSTANT(0U, 1U);
5720         BASIC_BLOCK(2U, -1L)
5721         {
5722             INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
5723             INST(6U, Opcode::Neg).s32().Inputs(0U);
5724             INST(7U, Opcode::Return).s32().Inputs(6U);
5725         }
5726     }
5727     ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
5728 }
5729 
TEST_F(ChecksEliminationTest,OsrMode)5730 TEST_F(ChecksEliminationTest, OsrMode)
5731 {
5732     auto osrGraph = CreateOsrGraph();
5733     GRAPH(osrGraph)
5734     {
5735         PARAMETER(0U, 0U).u32();
5736         PARAMETER(42U, 1U).ref();
5737         CONSTANT(1U, 0U);
5738         CONSTANT(2U, 1U);
5739 
5740         BASIC_BLOCK(2U, 3U)
5741         {
5742             INST(15U, Opcode::SaveState).Inputs(42U).SrcVregs({42U});
5743             INST(16U, Opcode::NullCheck).ref().Inputs(42U, 15U);
5744             INST(17U, Opcode::LenArray).s32().Inputs(16U);
5745         }
5746         BASIC_BLOCK(3U, 5U, 4U)
5747         {
5748             INST(3U, Opcode::Phi).s32().Inputs(0U, 7U);
5749             INST(4U, Opcode::SaveStateOsr).Inputs(3U, 42U).SrcVregs({1U, 42U});
5750             INST(5U, Opcode::Compare).b().SrcType(DataType::Type::INT32).CC(CC_LE).Inputs(3U, 1U);
5751             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
5752         }
5753         BASIC_BLOCK(4U, 3U)
5754         {
5755             INST(7U, Opcode::Sub).s32().Inputs(3U, 2U);
5756             INST(8U, Opcode::SaveState).Inputs(42U).SrcVregs({42U});
5757             INST(9U, Opcode::NullCheck).ref().Inputs(42U, 8U);
5758             INST(10U, Opcode::LenArray).s32().Inputs(9U);
5759         }
5760         BASIC_BLOCK(5U, 6U)
5761         {
5762             INST(11U, Opcode::SaveState).Inputs(42U).SrcVregs({42U});
5763             INST(12U, Opcode::NullCheck).ref().Inputs(42U, 11U);
5764             INST(13U, Opcode::LenArray).s32().Inputs(12U);
5765         }
5766         BASIC_BLOCK(6U, -1L)
5767         {
5768             INST(14U, Opcode::Return).u32().Inputs(3U);
5769         }
5770     }
5771     ASSERT_FALSE(osrGraph->RunPass<ChecksElimination>());
5772 }
5773 
5774 // NOLINTEND(readability-magic-numbers)
5775 
5776 }  // namespace ark::compiler
5777