• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 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 
TEST_F(ChecksEliminationTest,LoopSeveralIndexesBoundsChecks)3023 TEST_F(ChecksEliminationTest, LoopSeveralIndexesBoundsChecks)
3024 {
3025     BuildGraphLoopSeveralIndexesBoundsChecks();
3026     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
3027     auto graph1 = CreateEmptyGraph();
3028     GRAPH(graph1)
3029     {
3030         CONSTANT(0U, 0U);         // initial
3031         CONSTANT(1U, 1U);         // increment
3032         PARAMETER(2U, 0U).ref();  // array
3033         PARAMETER(3U, 1U).s32();  // Y
3034         PARAMETER(4U, 2U).s32();  // X
3035         CONSTANT(43U, -1L);
3036         BASIC_BLOCK(7U, 3U, 6U)
3037         {
3038             // check array
3039             INST(5U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
3040             INST(6U, Opcode::NullCheck).ref().Inputs(2U, 5U);
3041             INST(7U, Opcode::LenArray).s32().Inputs(6U);
3042 
3043             INST(36U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
3044             INST(37U, Opcode::Add).s32().Inputs(3U, 43U);
3045             INST(38U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(37U, 0U);  // Y-1 < 0
3046             INST(39U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(38U, 36U);
3047 
3048             INST(40U, Opcode::Sub).s32().Inputs(7U, 1U);
3049             INST(41U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(40U, 4U);  // len_array - 1 < X
3050             INST(42U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(41U, 36U);
3051 
3052             INST(11U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(3U, 4U);  // Y < X
3053             INST(12U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(11U);
3054         }
3055         BASIC_BLOCK(3U, 3U, 6U)
3056         {
3057             INST(13U, Opcode::Phi).s32().Inputs(3U, 20U);  // i
3058 
3059             INST(14U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
3060             INST(15U, Opcode::NOP);
3061             INST(16U, Opcode::LoadArray).s32().Inputs(2U, 13U);  // array[i]
3062 
3063             INST(26U, Opcode::Sub).s32().Inputs(13U, 1U);  // i - 1
3064             INST(27U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
3065             INST(28U, Opcode::NOP);
3066             INST(29U, Opcode::LoadArray).s32().Inputs(2U, 26U);  // array[i-1]
3067 
3068             INST(30U, Opcode::Add).s32().Inputs(13U, 1U);  // i + 1
3069             INST(31U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
3070             INST(32U, Opcode::NOP);
3071             INST(33U, Opcode::LoadArray).s32().Inputs(2U, 30U);  // array[i+1]
3072 
3073             INST(34U, Opcode::Add).s32().Inputs(16U, 29U);  // array[i-1] + array[i]
3074             INST(35U, Opcode::Add).s32().Inputs(34U, 33U);  // array[i-1] + array[i] + array[i+1]
3075 
3076             INST(17U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
3077             INST(18U, Opcode::NOP);
3078             INST(19U, Opcode::StoreArray).s32().Inputs(2U, 13U, 35U);  // array[i] = array[i-1] + array[i] + array[i+1]
3079 
3080             INST(20U, Opcode::Add).s32().Inputs(13U, 1U);                             // i++
3081             INST(21U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(20U, 4U);  // i < X
3082             INST(22U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(21U);
3083         }
3084         BASIC_BLOCK(6U, 1U)
3085         {
3086             INST(23U, Opcode::Phi).s32().Inputs(0U, 20U);
3087             INST(24U, Opcode::Return).s32().Inputs(23U);
3088         }
3089     }
3090     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
3091 }
3092 
BuildGraphHeadExitLoop()3093 void ChecksEliminationTest::BuildGraphHeadExitLoop()
3094 {
3095     GRAPH(GetGraph())
3096     {
3097         CONSTANT(0U, 0U);  // initial
3098         CONSTANT(1U, 1U);  // increment
3099         PARAMETER(2U, 0U).ref();
3100         PARAMETER(3U, 1U).s32();  // X
3101         BASIC_BLOCK(2U, 3U)
3102         {
3103             INST(4U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
3104             INST(5U, Opcode::NullCheck).ref().Inputs(2U, 4U);
3105             INST(6U, Opcode::LenArray).s32().Inputs(5U);
3106             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
3107         }
3108         BASIC_BLOCK(3U, 4U, 5U)
3109         {
3110             INST(7U, Opcode::Phi).s32().Inputs(0U, 13U);
3111             INST(8U, Opcode::Compare).CC(CC_LT).b().Inputs(7U, 3U);  // i < X
3112             INST(9U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(8U);
3113         }
3114         BASIC_BLOCK(4U, 3U)
3115         {
3116             INST(10U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
3117             INST(11U, Opcode::BoundsCheck).s32().Inputs(6U, 7U, 10U);
3118             INST(12U, Opcode::StoreArray).s32().Inputs(5U, 11U, 0U);  // a[i] = 0
3119             INST(13U, Opcode::Add).s32().Inputs(7U, 1U);              // i++
3120         }
3121         BASIC_BLOCK(5U, 1U)
3122         {
3123             INST(14U, Opcode::Return).ref().Inputs(5U);
3124         }
3125     }
3126 }
3127 
TEST_F(ChecksEliminationTest,HeadExitLoop)3128 TEST_F(ChecksEliminationTest, HeadExitLoop)
3129 {
3130     BuildGraphHeadExitLoop();
3131     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
3132     auto graph = CreateEmptyGraph();
3133     GRAPH(graph)
3134     {
3135         CONSTANT(0U, 0U);  // initial
3136         CONSTANT(1U, 1U);  // increment
3137         PARAMETER(2U, 0U).ref();
3138         PARAMETER(3U, 1U).s32();
3139         BASIC_BLOCK(2U, 3U)
3140         {
3141             INST(4U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
3142             INST(5U, Opcode::NullCheck).ref().Inputs(2U, 4U);
3143             INST(6U, Opcode::LenArray).s32().Inputs(5U);
3144             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
3145             INST(15U, Opcode::Compare).b().CC(ConditionCode::CC_LT).Inputs(6U, 3U);  // len_array < X
3146             INST(16U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(15U, 30U);
3147         }
3148         BASIC_BLOCK(3U, 4U, 5U)
3149         {
3150             INST(7U, Opcode::Phi).s32().Inputs(0U, 13U);
3151             INST(8U, Opcode::Compare).CC(CC_LT).b().Inputs(7U, 3U);  // i < X
3152             INST(9U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(8U);
3153         }
3154         BASIC_BLOCK(4U, 3U)
3155         {
3156             INST(10U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
3157             INST(11U, Opcode::NOP);
3158             INST(12U, Opcode::StoreArray).s32().Inputs(5U, 7U, 0U);  // a[i] = 0
3159             INST(13U, Opcode::Add).s32().Inputs(7U, 1U);             // i++
3160         }
3161         BASIC_BLOCK(5U, 1U)
3162         {
3163             INST(14U, Opcode::Return).ref().Inputs(5U);
3164         }
3165     }
3166     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3167 }
3168 
TEST_F(ChecksEliminationTest,BoundsCheckInHeader)3169 TEST_F(ChecksEliminationTest, BoundsCheckInHeader)
3170 {
3171     GRAPH(GetGraph())
3172     {
3173         CONSTANT(0U, 0U);  // initial
3174         CONSTANT(1U, 1U);  // increment
3175         PARAMETER(2U, 0U).ref();
3176         PARAMETER(3U, 1U).s32();
3177         BASIC_BLOCK(2U, 3U)
3178         {
3179             INST(4U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
3180             INST(5U, Opcode::NullCheck).ref().Inputs(2U, 4U);
3181             INST(6U, Opcode::LenArray).s32().Inputs(5U);
3182             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
3183         }
3184         BASIC_BLOCK(3U, 4U, 5U)
3185         {
3186             INST(7U, Opcode::Phi).s32().Inputs(0U, 13U);
3187             INST(10U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
3188             INST(11U, Opcode::BoundsCheck).s32().Inputs(6U, 7U, 10U);
3189             INST(12U, Opcode::StoreArray).s32().Inputs(5U, 11U, 0U);  // a[i] = 0
3190             INST(8U, Opcode::Compare).CC(CC_LT).b().Inputs(7U, 3U);   // i < X
3191             INST(9U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(8U);
3192         }
3193         BASIC_BLOCK(4U, 3U)
3194         {
3195             INST(13U, Opcode::Add).s32().Inputs(7U, 1U);  // i++
3196         }
3197         BASIC_BLOCK(5U, 1U)
3198         {
3199             INST(14U, Opcode::Return).ref().Inputs(5U);
3200         }
3201     }
3202     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
3203     ASSERT_FALSE(GetGraph()->RunPass<ChecksElimination>());
3204     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
3205 }
3206 
BuildGraphLoopTest1()3207 void ChecksEliminationTest::BuildGraphLoopTest1()
3208 {
3209     GRAPH(GetGraph())
3210     {
3211         CONSTANT(0U, 0U);          // initial
3212         CONSTANT(1U, 1U);          // increment
3213         PARAMETER(13U, 0U).ref();  // Array
3214         PARAMETER(27U, 1U).s32();  // X
3215         BASIC_BLOCK(2U, 6U, 3U)
3216         {
3217             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
3218             INST(14U, Opcode::Compare).CC(ConditionCode::CC_GE).b().Inputs(0U, 27U);  // i < X
3219             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(14U);
3220         }
3221         BASIC_BLOCK(3U, 6U, 3U)
3222         {
3223             INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);
3224             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 13U, 27U).SrcVregs({0U, 1U, 2U, 3U});
3225             INST(16U, Opcode::NullCheck).ref().Inputs(13U, 7U);
3226             INST(17U, Opcode::LenArray).s32().Inputs(16U);
3227             INST(8U, Opcode::BoundsCheck).s32().Inputs(17U, 4U, 7U);
3228             INST(9U, Opcode::StoreArray).s32().Inputs(16U, 8U, 0U);                   // a[i] = 0
3229             INST(10U, Opcode::Add).s32().Inputs(4U, 1U);                              // i++
3230             INST(5U, Opcode::Compare).CC(ConditionCode::CC_GE).b().Inputs(10U, 27U);  // i < X
3231             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
3232         }
3233         BASIC_BLOCK(6U, 1U)
3234         {
3235             INST(26U, Opcode::Phi).s32().Inputs(0U, 10U);
3236             INST(12U, Opcode::Return).s32().Inputs(26U);
3237         }
3238     }
3239 }
3240 
TEST_F(ChecksEliminationTest,LoopTest1)3241 TEST_F(ChecksEliminationTest, LoopTest1)
3242 {
3243     BuildGraphLoopTest1();
3244     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
3245     auto graph1 = CreateEmptyGraph();
3246     GRAPH(graph1)
3247     {
3248         CONSTANT(0U, 0U);  // initial
3249         CONSTANT(1U, 1U);  // increment
3250         PARAMETER(3U, 0U).ref();
3251         PARAMETER(2U, 1U).s32();
3252         BASIC_BLOCK(2U, 5U, 3U)
3253         {
3254             INST(20U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
3255             INST(33U, Opcode::NullCheck).ref().Inputs(3U, 20U).SetFlag(inst_flags::CAN_DEOPTIMIZE);  // array != nullptr
3256             INST(22U, Opcode::LenArray).s32().Inputs(33U);
3257             INST(23U, Opcode::Compare).SrcType(DataType::INT32).CC(CC_LT).b().Inputs(22U, 2U);  // len_array < X
3258             INST(24U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(23U, 20U);
3259             INST(5U, Opcode::Compare).SrcType(DataType::INT32).CC(CC_GE).b().Inputs(0U, 2U);  // 0 < X
3260             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
3261         }
3262         BASIC_BLOCK(3U, 5U, 3U)
3263         {
3264             INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);
3265             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 3U, 2U).SrcVregs({0U, 1U, 2U, 3U});
3266             INST(15U, Opcode::NOP);
3267             INST(16U, Opcode::LenArray).s32().Inputs(33U);
3268             INST(8U, Opcode::NOP);
3269             INST(9U, Opcode::StoreArray).s32().Inputs(33U, 4U, 0U);    // a[i] = 0
3270             INST(10U, Opcode::Add).s32().Inputs(4U, 1U);               // i++
3271             INST(13U, Opcode::Compare).CC(CC_GE).b().Inputs(10U, 2U);  // i < X
3272             INST(14U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(13U);
3273         }
3274         BASIC_BLOCK(5U, 1U)
3275         {
3276             INST(26U, Opcode::Phi).s32().Inputs(0U, 10U);
3277             INST(12U, Opcode::Return).s32().Inputs(26U);
3278         }
3279     }
3280     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
3281 }
3282 
BuildGraphBatchLoopTest()3283 void ChecksEliminationTest::BuildGraphBatchLoopTest()
3284 {
3285     GRAPH(GetGraph())
3286     {
3287         CONSTANT(0U, 0U);  // initial
3288         CONSTANT(1U, 1U);
3289         CONSTANT(2U, 2U);
3290         CONSTANT(3U, 3U);         // increment
3291         PARAMETER(4U, 0U).ref();  // Array
3292         BASIC_BLOCK(2U, 4U, 3U)
3293         {
3294             INST(5U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U, 4U).SrcVregs({0U, 1U, 2U, 3U, 4U});
3295             INST(6U, Opcode::NullCheck).ref().Inputs(4U, 5U);
3296             INST(7U, Opcode::LenArray).s32().Inputs(6U);
3297             INST(30U, Opcode::SaveStateDeoptimize).Inputs(4U).SrcVregs({0U});
3298             INST(25U, Opcode::Compare).CC(CC_GE).b().Inputs(0U, 7U);
3299             INST(26U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(25U);
3300         }
3301         BASIC_BLOCK(3U, 4U, 3U)
3302         {
3303             INST(8U, Opcode::Phi).s32().Inputs(0U, 20U);
3304             INST(9U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U, 4U, 7U).SrcVregs({0U, 1U, 2U, 3U, 4U, 7U});
3305             INST(10U, Opcode::NullCheck).ref().Inputs(4U, 9U);
3306 
3307             INST(12U, Opcode::Add).s32().Inputs(8U, 1U);
3308             INST(13U, Opcode::BoundsCheck).s32().Inputs(7U, 12U, 9U);
3309             INST(14U, Opcode::LoadArray).s32().Inputs(10U, 13U);
3310 
3311             INST(15U, Opcode::BoundsCheck).s32().Inputs(7U, 8U, 9U);
3312             INST(16U, Opcode::StoreArray).s32().Inputs(10U, 15U, 14U);  // a[i] = a[i + 1]
3313 
3314             INST(17U, Opcode::Add).s32().Inputs(8U, 2U);
3315             INST(18U, Opcode::BoundsCheck).s32().Inputs(7U, 17U, 9U);
3316             INST(19U, Opcode::StoreArray).s32().Inputs(10U, 18U, 14U);  // a[i + 2] = a[i + 1]
3317 
3318             INST(20U, Opcode::Add).s32().Inputs(8U, 3U);               // i += 3
3319             INST(21U, Opcode::Compare).CC(CC_GE).b().Inputs(20U, 7U);  // i < X
3320             INST(22U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(21U);
3321         }
3322         BASIC_BLOCK(4U, 1U)
3323         {
3324             INST(23U, Opcode::ReturnVoid).v0id();
3325         }
3326     }
3327 }
3328 
TEST_F(ChecksEliminationTest,BatchLoopTest)3329 TEST_F(ChecksEliminationTest, BatchLoopTest)
3330 {
3331     BuildGraphBatchLoopTest();
3332     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
3333     auto graph1 = CreateEmptyGraph();
3334     GRAPH(graph1)
3335     {
3336         CONSTANT(0U, 0U);  // initial
3337         CONSTANT(1U, 1U);
3338         CONSTANT(2U, 2U);
3339         CONSTANT(3U, 3U);         // increment
3340         PARAMETER(4U, 0U).ref();  // Array
3341         CONSTANT(36U, 0x7ffffffdU);
3342         BASIC_BLOCK(2U, 4U, 3U)
3343         {
3344             INST(5U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U, 4U).SrcVregs({0U, 1U, 2U, 3U, 4U});
3345             INST(6U, Opcode::NullCheck).ref().Inputs(4U, 5U);
3346             INST(7U, Opcode::LenArray).s32().Inputs(6U);
3347             INST(30U, Opcode::SaveStateDeoptimize).Inputs(4U).SrcVregs({0U});
3348             INST(31U, Opcode::Compare).CC(CC_LT).b().Inputs(36U, 7U);
3349             INST(32U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(31U, 30U);
3350             INST(33U, Opcode::Mod).s32().Inputs(7U, 3U);
3351             INST(34U, Opcode::Compare).CC(CC_NE).b().Inputs(33U, 0U);
3352             INST(35U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(34U, 30U);
3353             INST(25U, Opcode::Compare).CC(CC_GE).b().Inputs(0U, 7U);
3354             INST(26U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(25U);
3355         }
3356         BASIC_BLOCK(3U, 4U, 3U)
3357         {
3358             INST(8U, Opcode::Phi).s32().Inputs(0U, 20U);
3359             INST(9U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U, 4U, 7U).SrcVregs({0U, 1U, 2U, 3U, 4U, 7U});
3360             INST(10U, Opcode::NOP);
3361 
3362             INST(12U, Opcode::Add).s32().Inputs(8U, 1U);
3363             INST(13U, Opcode::NOP);
3364             INST(14U, Opcode::LoadArray).s32().Inputs(6U, 12U);
3365 
3366             INST(15U, Opcode::NOP);
3367             INST(16U, Opcode::StoreArray).s32().Inputs(6U, 8U, 14U);  // a[i] = a[i + 1]
3368 
3369             INST(17U, Opcode::Add).s32().Inputs(8U, 2U);
3370             INST(18U, Opcode::NOP);
3371             INST(19U, Opcode::StoreArray).s32().Inputs(6U, 17U, 14U);  // a[i + 2] = a[i + 1]
3372 
3373             INST(20U, Opcode::Add).s32().Inputs(8U, 3U);               // i += 3
3374             INST(21U, Opcode::Compare).CC(CC_GE).b().Inputs(20U, 7U);  // i < X
3375             INST(22U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(21U);
3376         }
3377         BASIC_BLOCK(4U, 1U)
3378         {
3379             INST(23U, Opcode::ReturnVoid).v0id();
3380         }
3381     }
3382     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
3383 }
3384 
TEST_F(ChecksEliminationTest,NewlyAlllocatedCheck)3385 TEST_F(ChecksEliminationTest, NewlyAlllocatedCheck)
3386 {
3387     GRAPH(GetGraph())
3388     {
3389         CONSTANT(0U, 0x1U).s64();
3390         CONSTANT(1U, 0x0U).s64();
3391         CONSTANT(5U, 0x2aU).s64();
3392         BASIC_BLOCK(2U, -1L)
3393         {
3394             INST(43U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
3395             INST(44U, Opcode::LoadAndInitClass).ref().Inputs().TypeId(68U);
3396             INST(4U, Opcode::NewArray).ref().Inputs(44U, 0U, 43U).TypeId(79U);
3397             INST(6U, Opcode::SaveState).Inputs(5U, 1U, 4U).SrcVregs({2U, 1U, 0U});
3398             INST(7U, Opcode::NullCheck).ref().Inputs(4U, 6U);
3399             INST(10U, Opcode::StoreArray).s32().Inputs(7U, 1U, 5U);
3400             INST(11U, Opcode::Return).ref().Inputs(4U);
3401         }
3402     }
3403     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
3404     auto graph1 = CreateEmptyGraph();
3405     GRAPH(graph1)
3406     {
3407         CONSTANT(0U, 0x1U).s64();
3408         CONSTANT(1U, 0x0U).s64();
3409         CONSTANT(5U, 0x2aU).s64();
3410         BASIC_BLOCK(2U, -1L)
3411         {
3412             INST(43U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
3413             INST(44U, Opcode::LoadAndInitClass).ref().Inputs().TypeId(68U);
3414             INST(4U, Opcode::NewArray).ref().Inputs(44U, 0U, 43U).TypeId(79U);
3415             INST(6U, Opcode::SaveState).Inputs(5U, 1U, 4U).SrcVregs({2U, 1U, 0U});
3416             INST(7U, Opcode::NOP);
3417             INST(10U, Opcode::StoreArray).s32().Inputs(4U, 1U, 5U);
3418             INST(11U, Opcode::Return).ref().Inputs(4U);
3419         }
3420     }
3421     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
3422 }
3423 
TEST_F(ChecksEliminationTest,DominatedBoundsCheck)3424 TEST_F(ChecksEliminationTest, DominatedBoundsCheck)
3425 {
3426     GRAPH(GetGraph())
3427     {
3428         PARAMETER(0U, 0U).ref();
3429         PARAMETER(1U, 1U).s64();
3430         BASIC_BLOCK(2U, -1L)
3431         {
3432             INST(2U, Opcode::SaveState).Inputs(1U, 1U, 0U).SrcVregs({2U, 1U, 0U});
3433             INST(4U, Opcode::LenArray).s32().Inputs(0U);
3434             INST(5U, Opcode::BoundsCheck).s32().Inputs(4U, 1U, 2U);
3435             INST(6U, Opcode::LoadArray).s64().Inputs(0U, 5U);
3436             INST(7U, Opcode::SaveState).Inputs(6U, 1U, 0U).SrcVregs({2U, 1U, 0U});
3437             INST(10U, Opcode::BoundsCheck).s32().Inputs(4U, 1U, 7U);
3438             INST(11U, Opcode::StoreArray).s64().Inputs(0U, 10U, 6U);
3439             INST(12U, Opcode::ReturnVoid).v0id();
3440         }
3441     }
3442     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
3443     auto graph1 = CreateEmptyGraph();
3444     GRAPH(graph1)
3445     {
3446         PARAMETER(0U, 0U).ref();
3447         PARAMETER(1U, 1U).s64();
3448         BASIC_BLOCK(2U, -1L)
3449         {
3450             INST(2U, Opcode::SaveState).Inputs(1U, 1U, 0U).SrcVregs({2U, 1U, 0U});
3451             INST(4U, Opcode::LenArray).s32().Inputs(0U);
3452             INST(5U, Opcode::BoundsCheck).s32().Inputs(4U, 1U, 2U);
3453             INST(6U, Opcode::LoadArray).s64().Inputs(0U, 5U);
3454             INST(7U, Opcode::SaveState).Inputs(6U, 1U, 0U).SrcVregs({2U, 1U, 0U});
3455             INST(10U, Opcode::NOP);
3456             INST(11U, Opcode::StoreArray).s64().Inputs(0U, 5U, 6U);
3457             INST(12U, Opcode::ReturnVoid).v0id();
3458         }
3459     }
3460     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
3461 }
3462 
BuildGraphGroupedBoundsCheck()3463 void ChecksEliminationTest::BuildGraphGroupedBoundsCheck()
3464 {
3465     GRAPH(GetGraph())
3466     {
3467         PARAMETER(0U, 0U).ref();  // a
3468         PARAMETER(1U, 1U).s32();  // x
3469         CONSTANT(2U, 1U);
3470         CONSTANT(5U, -2L);
3471         BASIC_BLOCK(2U, -1L)
3472         {
3473             INST(6U, Opcode::LenArray).s32().Inputs(0U);
3474             // a[x] = 1
3475             INST(7U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
3476             INST(8U, Opcode::BoundsCheck).s32().Inputs(6U, 1U, 7U);
3477             INST(9U, Opcode::StoreArray).s64().Inputs(0U, 8U, 2U);
3478             // a[x-1] = 1
3479             INST(10U, Opcode::Sub).s32().Inputs(1U, 2U);
3480             INST(11U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
3481             INST(12U, Opcode::BoundsCheck).s32().Inputs(6U, 10U, 11U);
3482             INST(13U, Opcode::StoreArray).s64().Inputs(0U, 12U, 2U);
3483             // a[x+1] = 1
3484             INST(14U, Opcode::Add).s32().Inputs(1U, 2U);
3485             INST(15U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
3486             INST(16U, Opcode::BoundsCheck).s32().Inputs(6U, 14U, 15U);
3487             INST(17U, Opcode::StoreArray).s64().Inputs(0U, 16U, 2U);
3488             // a[x+(-2)] = 1
3489             INST(18U, Opcode::Add).s32().Inputs(1U, 5U);
3490             INST(19U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
3491             INST(20U, Opcode::BoundsCheck).s32().Inputs(6U, 18U, 19U);
3492             INST(21U, Opcode::StoreArray).s64().Inputs(0U, 20U, 2U);
3493             // a[x-(-2)] = 1
3494             INST(22U, Opcode::Sub).s32().Inputs(1U, 5U);
3495             INST(23U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
3496             INST(24U, Opcode::BoundsCheck).s32().Inputs(6U, 22U, 23U);
3497             INST(25U, Opcode::StoreArray).s64().Inputs(0U, 24U, 2U);
3498             INST(26U, Opcode::ReturnVoid).v0id();
3499         }
3500     }
3501 }
3502 
TEST_F(ChecksEliminationTest,GroupedBoundsCheck)3503 TEST_F(ChecksEliminationTest, GroupedBoundsCheck)
3504 {
3505     BuildGraphGroupedBoundsCheck();
3506     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
3507     auto graph1 = CreateEmptyGraph();
3508     GRAPH(graph1)
3509     {
3510         PARAMETER(0U, 0U).ref();  // a
3511         PARAMETER(1U, 1U).s32();  // x
3512         CONSTANT(2U, 1U);
3513         CONSTANT(5U, -2L);
3514         CONSTANT(3U, 2U);
3515         CONSTANT(4U, 0U);
3516         BASIC_BLOCK(2U, -1L)
3517         {
3518             INST(6U, Opcode::LenArray).s32().Inputs(0U);
3519             INST(7U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
3520 
3521             INST(30U, Opcode::Add).s32().Inputs(1U, 5U);
3522             INST(31U, Opcode::Compare).b().CC(CC_LT).SrcType(DataType::INT32).Inputs(30U, 4U);
3523             INST(32U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(31U, 7U);
3524             INST(27U, Opcode::Add).s32().Inputs(1U, 3U);
3525             INST(28U, Opcode::Compare).b().CC(CC_GE).SrcType(DataType::INT32).Inputs(27U, 6U);
3526             INST(29U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(28U, 7U);
3527 
3528             // a[x] = 1
3529             INST(8U, Opcode::NOP);
3530             INST(9U, Opcode::StoreArray).s64().Inputs(0U, 1U, 2U);
3531             // a[x-1] = 1
3532             INST(10U, Opcode::Sub).s32().Inputs(1U, 2U);
3533             INST(11U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
3534             INST(12U, Opcode::NOP);
3535             INST(13U, Opcode::StoreArray).s64().Inputs(0U, 10U, 2U);
3536             // a[x+1] = 1
3537             INST(14U, Opcode::Add).s32().Inputs(1U, 2U);
3538             INST(15U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
3539             INST(16U, Opcode::NOP);
3540             INST(17U, Opcode::StoreArray).s64().Inputs(0U, 14U, 2U);
3541             // a[x+(-2)] = 1
3542             INST(18U, Opcode::Add).s32().Inputs(1U, 5U);
3543             INST(19U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
3544             INST(20U, Opcode::NOP);
3545             INST(21U, Opcode::StoreArray).s64().Inputs(0U, 18U, 2U);
3546             // a[x-(-2)] = 1
3547             INST(22U, Opcode::Sub).s32().Inputs(1U, 5U);
3548             INST(23U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
3549             INST(24U, Opcode::NOP);
3550             INST(25U, Opcode::StoreArray).s64().Inputs(0U, 22U, 2U);
3551             INST(26U, Opcode::ReturnVoid).v0id();
3552         }
3553     }
3554     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
3555 }
3556 
BuildGraphGroupedBoundsCheckConstIndex()3557 void ChecksEliminationTest::BuildGraphGroupedBoundsCheckConstIndex()
3558 {
3559     GRAPH(GetGraph())
3560     {
3561         PARAMETER(0U, 0U).ref();  // a
3562         CONSTANT(2U, 0U);
3563         CONSTANT(3U, 1U);
3564         CONSTANT(4U, 2U);
3565         CONSTANT(5U, 3U);
3566         BASIC_BLOCK(2U, -1L)
3567         {
3568             INST(6U, Opcode::LenArray).s32().Inputs(0U);
3569             INST(7U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
3570 
3571             // a[0] = 1
3572             INST(8U, Opcode::BoundsCheck).s32().Inputs(6U, 2U, 7U);
3573             INST(9U, Opcode::StoreArray).s64().Inputs(0U, 8U, 2U);
3574             // a[1] = 1
3575             INST(11U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
3576             INST(12U, Opcode::BoundsCheck).s32().Inputs(6U, 3U, 11U);
3577             INST(13U, Opcode::StoreArray).s64().Inputs(0U, 12U, 2U);
3578             // a[2] = 1
3579             INST(15U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
3580             INST(16U, Opcode::BoundsCheck).s32().Inputs(6U, 4U, 15U);
3581             INST(17U, Opcode::StoreArray).s64().Inputs(0U, 16U, 2U);
3582             // a[3] = 1
3583             INST(19U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
3584             INST(20U, Opcode::BoundsCheck).s32().Inputs(6U, 5U, 19U);
3585             INST(21U, Opcode::StoreArray).s64().Inputs(0U, 20U, 2U);
3586             INST(26U, Opcode::ReturnVoid).v0id();
3587         }
3588     }
3589 }
3590 
TEST_F(ChecksEliminationTest,GroupedBoundsCheckConstIndex)3591 TEST_F(ChecksEliminationTest, GroupedBoundsCheckConstIndex)
3592 {
3593     BuildGraphGroupedBoundsCheckConstIndex();
3594     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
3595     auto graph1 = CreateEmptyGraph();
3596     GRAPH(graph1)
3597     {
3598         PARAMETER(0U, 0U).ref();  // a
3599         CONSTANT(2U, 0U);
3600         CONSTANT(3U, 1U);
3601         CONSTANT(4U, 2U);
3602         CONSTANT(5U, 3U);
3603         BASIC_BLOCK(2U, -1L)
3604         {
3605             INST(6U, Opcode::LenArray).s32().Inputs(0U);
3606             INST(7U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
3607 
3608             INST(28U, Opcode::Compare).b().CC(CC_GE).SrcType(DataType::INT32).Inputs(5U, 6U);
3609             INST(29U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(28U, 7U);
3610 
3611             // a[0] = 1
3612             INST(8U, Opcode::NOP);
3613             INST(9U, Opcode::StoreArray).s64().Inputs(0U, 2U, 2U);
3614             // a[1] = 1
3615             INST(11U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
3616             INST(12U, Opcode::NOP);
3617             INST(13U, Opcode::StoreArray).s64().Inputs(0U, 3U, 2U);
3618             // a[2] = 1
3619             INST(15U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
3620             INST(16U, Opcode::NOP);
3621             INST(17U, Opcode::StoreArray).s64().Inputs(0U, 4U, 2U);
3622             // a[3] = 1
3623             INST(19U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
3624             INST(20U, Opcode::NOP);
3625             INST(21U, Opcode::StoreArray).s64().Inputs(0U, 5U, 2U);
3626             INST(26U, Opcode::ReturnVoid).v0id();
3627         }
3628     }
3629     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
3630 }
3631 
TEST_F(ChecksEliminationTest,ConsecutiveNullChecks)3632 TEST_F(ChecksEliminationTest, ConsecutiveNullChecks)
3633 {
3634     builder_->EnableGraphChecker(false);
3635     GRAPH(GetGraph())
3636     {
3637         PARAMETER(0U, 0U).ref();
3638         BASIC_BLOCK(2U, 1U)
3639         {
3640             INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
3641             INST(1U, Opcode::NullCheck).ref().Inputs(0U, 5U);
3642             INST(2U, Opcode::NullCheck).ref().Inputs(1U, 5U);
3643             INST(3U, Opcode::NullCheck).ref().Inputs(2U, 5U);
3644             INST(6U, Opcode::StoreObject).ref().Inputs(3U, 0U).TypeId(1U);
3645             INST(4U, Opcode::Return).ref().Inputs(3U);
3646         }
3647     }
3648     builder_->EnableGraphChecker(true);
3649     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
3650     auto graph = CreateEmptyGraph();
3651     GRAPH(graph)
3652     {
3653         PARAMETER(0U, 0U).ref();
3654         BASIC_BLOCK(2U, 1U)
3655         {
3656             INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
3657             INST(1U, Opcode::NullCheck).ref().Inputs(0U, 5U);
3658             INST(2U, Opcode::NOP);
3659             INST(3U, Opcode::NOP);
3660             INST(6U, Opcode::StoreObject).ref().Inputs(1U, 0U).TypeId(1U);
3661             INST(4U, Opcode::Return).ref().Inputs(1U);
3662         }
3663     }
3664     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3665 }
3666 
TEST_F(ChecksEliminationTest,NullCheckInCallVirt)3667 TEST_F(ChecksEliminationTest, NullCheckInCallVirt)
3668 {
3669     GRAPH(GetGraph())
3670     {
3671         PARAMETER(0U, 0U).ref();
3672         PARAMETER(1U, 1U).ref();
3673         BASIC_BLOCK(2U, 1U)
3674         {
3675             INST(5U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
3676             INST(2U, Opcode::NullCheck).ref().Inputs(0U, 5U);
3677             INST(3U, Opcode::NullCheck).ref().Inputs(1U, 5U);
3678             INST(4U, Opcode::CallVirtual)
3679                 .s32()
3680                 .Inputs({{DataType::REFERENCE, 2U}, {DataType::REFERENCE, 3U}, {DataType::NO_TYPE, 5U}});
3681             INST(6U, Opcode::Return).s32().Inputs(4U);
3682         }
3683     }
3684     // Doesn't remove nullchecks if the method static
3685     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
3686     ASSERT_FALSE(GetGraph()->RunPass<ChecksElimination>());
3687     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
3688 
3689     // Removes nullcheck from first parameter for not static method
3690     RuntimeInterfaceNotStaticMethod runtime;
3691     GetGraph()->SetRuntime(&runtime);
3692     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
3693     auto graph1 = CreateEmptyGraph();
3694     GRAPH(graph1)
3695     {
3696         PARAMETER(0U, 0U).ref();
3697         PARAMETER(1U, 1U).ref();
3698         BASIC_BLOCK(2U, 1U)
3699         {
3700             INST(5U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
3701             INST(2U, Opcode::NOP);
3702             INST(3U, Opcode::NullCheck).ref().Inputs(1U, 5U);
3703             INST(4U, Opcode::CallVirtual)
3704                 .s32()
3705                 .Inputs({{DataType::REFERENCE, 0U}, {DataType::REFERENCE, 3U}, {DataType::NO_TYPE, 5U}});
3706             INST(6U, Opcode::Return).s32().Inputs(4U);
3707         }
3708     }
3709     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
3710 }
3711 
TEST_F(ChecksEliminationTest,DominatedChecksWithDifferentTypes)3712 TEST_F(ChecksEliminationTest, DominatedChecksWithDifferentTypes)
3713 {
3714     GRAPH(GetGraph())
3715     {
3716         PARAMETER(0U, 0U).s64();
3717         PARAMETER(1U, 1U).s64();
3718         BASIC_BLOCK(2U, 1U)
3719         {
3720             INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
3721             INST(3U, Opcode::ZeroCheck).s32().Inputs(0U, 2U);
3722             INST(4U, Opcode::Div).s32().Inputs(1U, 3U);
3723             INST(5U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
3724             INST(6U, Opcode::ZeroCheck).s64().Inputs(0U, 5U);
3725             INST(7U, Opcode::Mod).s64().Inputs(1U, 6U);
3726             INST(20U, Opcode::SaveState).NoVregs();
3727             INST(8U, Opcode::CallStatic).s32().InputsAutoType(4U, 7U, 20U);
3728             INST(9U, Opcode::Return).s32().Inputs(8U);
3729         }
3730     }
3731     auto initial = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
3732     ASSERT_FALSE(GetGraph()->RunPass<ChecksElimination>());
3733     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), initial));
3734 }
3735 
BuildGraphRefTypeCheck()3736 void ChecksEliminationTest::BuildGraphRefTypeCheck()
3737 {
3738     GRAPH(GetGraph())
3739     {
3740         PARAMETER(0U, 0U).ref();
3741         PARAMETER(1U, 1U).ref();
3742         PARAMETER(2U, 2U).s32();
3743         PARAMETER(3U, 3U).s32();
3744         PARAMETER(4U, 4U).s32();
3745         CONSTANT(5U, nullptr);
3746         BASIC_BLOCK(2U, 1U)
3747         {
3748             INST(10U, Opcode::SaveState).Inputs(0U, 1U, 2U, 2U, 5U).SrcVregs({0U, 1U, 2U, 3U, 4U});
3749             INST(11U, Opcode::NullCheck).ref().Inputs(1U, 10U);
3750             INST(12U, Opcode::LenArray).s32().Inputs(11U);
3751             INST(13U, Opcode::BoundsCheck).s32().Inputs(12U, 2U, 10U);
3752             INST(14U, Opcode::RefTypeCheck).ref().Inputs(11U, 0U, 10U);
3753             INST(15U, Opcode::StoreArray).ref().Inputs(11U, 13U, 14U);
3754 
3755             INST(20U, Opcode::SaveState).Inputs(0U, 1U, 2U, 2U, 5U).SrcVregs({0U, 1U, 2U, 3U, 4U});
3756             INST(21U, Opcode::NullCheck).ref().Inputs(1U, 20U);
3757             INST(22U, Opcode::LenArray).s32().Inputs(21U);
3758             INST(23U, Opcode::BoundsCheck).s32().Inputs(22U, 3U, 20U);
3759             INST(24U, Opcode::RefTypeCheck).ref().Inputs(21U, 0U, 20U);
3760             INST(25U, Opcode::StoreArray).ref().Inputs(21U, 23U, 24U);
3761 
3762             INST(30U, Opcode::SaveState).Inputs(0U, 1U, 2U, 2U, 5U).SrcVregs({0U, 1U, 2U, 3U, 4U});
3763             INST(31U, Opcode::NullCheck).ref().Inputs(1U, 30U);
3764             INST(32U, Opcode::LenArray).s32().Inputs(31U);
3765             INST(33U, Opcode::BoundsCheck).s32().Inputs(32U, 4U, 30U);
3766             INST(34U, Opcode::RefTypeCheck).ref().Inputs(31U, 5U, 30U);
3767             INST(35U, Opcode::StoreArray).ref().Inputs(31U, 33U, 34U);
3768 
3769             INST(6U, Opcode::ReturnVoid).v0id();
3770         }
3771     }
3772 }
3773 
TEST_F(ChecksEliminationTest,RefTypeCheck)3774 TEST_F(ChecksEliminationTest, RefTypeCheck)
3775 {
3776     BuildGraphRefTypeCheck();
3777     // `24, Opcode::RefTypeCheck` is removed because `14, Opcode::RefTypeCheck` checks equal array and eqaul
3778     // Reference `34, Opcode::RefTypeCheck` is removed because store value id NullPtr
3779     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
3780     auto graph = CreateEmptyGraph();
3781     GRAPH(graph)
3782     {
3783         PARAMETER(0U, 0U).ref();
3784         PARAMETER(1U, 1U).ref();
3785         PARAMETER(2U, 2U).s32();
3786         PARAMETER(3U, 3U).s32();
3787         PARAMETER(4U, 4U).s32();
3788         CONSTANT(5U, nullptr);
3789         BASIC_BLOCK(2U, 1U)
3790         {
3791             INST(10U, Opcode::SaveState).Inputs(0U, 1U, 2U, 2U, 5U).SrcVregs({0U, 1U, 2U, 3U, 4U});
3792             INST(11U, Opcode::NullCheck).ref().Inputs(1U, 10U);
3793             INST(12U, Opcode::LenArray).s32().Inputs(11U);
3794             INST(13U, Opcode::BoundsCheck).s32().Inputs(12U, 2U, 10U);
3795             INST(14U, Opcode::RefTypeCheck).ref().Inputs(11U, 0U, 10U);
3796             INST(15U, Opcode::StoreArray).ref().Inputs(11U, 13U, 14U);
3797 
3798             INST(20U, Opcode::SaveState).Inputs(0U, 1U, 2U, 2U, 5U).SrcVregs({0U, 1U, 2U, 3U, 4U});
3799             INST(21U, Opcode::NOP);
3800             INST(22U, Opcode::LenArray).s32().Inputs(11U);
3801             INST(23U, Opcode::BoundsCheck).s32().Inputs(22U, 3U, 20U);
3802             INST(24U, Opcode::NOP);
3803             INST(25U, Opcode::StoreArray).ref().Inputs(11U, 23U, 14U);
3804 
3805             INST(30U, Opcode::SaveState).Inputs(0U, 1U, 2U, 2U, 5U).SrcVregs({0U, 1U, 2U, 3U, 4U});
3806             INST(31U, Opcode::NOP);
3807             INST(32U, Opcode::LenArray).s32().Inputs(11U);
3808             INST(33U, Opcode::BoundsCheck).s32().Inputs(32U, 4U, 30U);
3809             INST(34U, Opcode::NOP);
3810             INST(35U, Opcode::StoreArray).ref().Inputs(11U, 33U, 5U);
3811 
3812             INST(6U, Opcode::ReturnVoid).v0id();
3813         }
3814     }
3815     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3816 }
3817 
BuildGraphRefTypeCheckFirstNullCheckEliminated()3818 void ChecksEliminationTest::BuildGraphRefTypeCheckFirstNullCheckEliminated()
3819 {
3820     GRAPH(GetGraph())
3821     {
3822         PARAMETER(0U, 0U).ref();
3823         PARAMETER(1U, 2U).s32();
3824         PARAMETER(2U, 3U).s32();
3825         CONSTANT(3U, 10U);
3826         BASIC_BLOCK(2U, 1U)
3827         {
3828             INST(4U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
3829             INST(5U, Opcode::NewArray).ref().Inputs(0U, 3U, 4U);
3830             INST(6U, Opcode::RefTypeCheck).ref().Inputs(5U, 0U, 4U);
3831             INST(7U, Opcode::StoreArray).ref().Inputs(5U, 1U, 6U);
3832 
3833             INST(14U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
3834             INST(15U, Opcode::NullCheck).ref().Inputs(5U, 14U);
3835             INST(16U, Opcode::RefTypeCheck).ref().Inputs(15U, 0U, 14U);
3836             INST(17U, Opcode::StoreArray).ref().Inputs(5U, 2U, 16U);
3837 
3838             INST(18U, Opcode::ReturnVoid).v0id();
3839         }
3840     }
3841 }
3842 
TEST_F(ChecksEliminationTest,RefTypeCheckFirstNullCheckEliminated)3843 TEST_F(ChecksEliminationTest, RefTypeCheckFirstNullCheckEliminated)
3844 {
3845     BuildGraphRefTypeCheckFirstNullCheckEliminated();
3846     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
3847     auto graph = CreateEmptyGraph();
3848     GRAPH(graph)
3849     {
3850         PARAMETER(0U, 0U).ref();
3851         PARAMETER(1U, 2U).s32();
3852         PARAMETER(2U, 3U).s32();
3853         CONSTANT(3U, 10U);
3854         BASIC_BLOCK(2U, 1U)
3855         {
3856             INST(4U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
3857             INST(5U, Opcode::NewArray).ref().Inputs(0U, 3U, 4U);
3858             INST(6U, Opcode::RefTypeCheck).ref().Inputs(5U, 0U, 4U);
3859             INST(7U, Opcode::StoreArray).ref().Inputs(5U, 1U, 6U);
3860 
3861             INST(14U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
3862             INST(15U, Opcode::NOP);
3863             INST(16U, Opcode::NOP);
3864             INST(17U, Opcode::StoreArray).ref().Inputs(5U, 2U, 6U);
3865 
3866             INST(18U, Opcode::ReturnVoid).v0id();
3867         }
3868     }
3869     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3870 }
3871 
TEST_F(ChecksEliminationTest,RefTypeCheckEqualInputs)3872 TEST_F(ChecksEliminationTest, RefTypeCheckEqualInputs)
3873 {
3874     GRAPH(GetGraph())
3875     {
3876         PARAMETER(0U, 0U).ref();
3877         PARAMETER(1U, 2U).s32();
3878         PARAMETER(2U, 3U).s32();
3879         CONSTANT(3U, 10U);
3880         BASIC_BLOCK(2U, 1U)
3881         {
3882             INST(4U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
3883             INST(5U, Opcode::NewArray).ref().Inputs(0U, 3U, 4U);
3884             INST(6U, Opcode::RefTypeCheck).ref().Inputs(5U, 0U, 4U);
3885             INST(7U, Opcode::StoreArray).ref().Inputs(5U, 1U, 6U);
3886 
3887             INST(14U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
3888             INST(16U, Opcode::RefTypeCheck).ref().Inputs(5U, 5U, 14U);
3889             INST(17U, Opcode::StoreArray).ref().Inputs(5U, 2U, 16U);
3890 
3891             INST(18U, Opcode::ReturnVoid).v0id();
3892         }
3893     }
3894     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
3895     ASSERT_FALSE(GetGraph()->RunPass<ChecksElimination>());
3896     ASSERT_TRUE(GraphComparator().Compare(clone, GetGraph()));
3897 }
3898 
BuildHoistRefTypeCheckGraph()3899 void ChecksEliminationTest::BuildHoistRefTypeCheckGraph()
3900 {
3901     GRAPH(GetGraph())
3902     {
3903         CONSTANT(0U, 0U);  // initial
3904         CONSTANT(1U, 1U);  // increment
3905         CONSTANT(2U, 10U);
3906         PARAMETER(28U, 0U).ref();
3907         PARAMETER(29U, 1U).ref();
3908         BASIC_BLOCK(2U, 3U, 5U)
3909         {
3910             INST(20U, Opcode::SaveStateDeoptimize).Inputs(0U, 1U, 2U, 28U, 29U).SrcVregs({0U, 1U, 2U, 3U, 4U});
3911             INST(5U, Opcode::Compare).SrcType(DataType::INT32).CC(CC_LT).b().Inputs(0U, 2U);  // 0 < 10
3912             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
3913         }
3914         BASIC_BLOCK(3U, 3U, 5U)
3915         {
3916             INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);  // i
3917 
3918             INST(30U, Opcode::SaveState).Inputs(28U, 29U).SrcVregs({0U, 1U});
3919             INST(31U, Opcode::NullCheck).ref().Inputs(29U, 30U);
3920             INST(32U, Opcode::LenArray).s32().Inputs(31U);
3921             INST(34U, Opcode::RefTypeCheck).ref().Inputs(31U, 28U, 30U);
3922             INST(35U, Opcode::StoreArray).ref().Inputs(31U, 4U, 34U);
3923 
3924             INST(10U, Opcode::Add).s32().Inputs(4U, 1U);               // i++
3925             INST(13U, Opcode::Compare).CC(CC_LT).b().Inputs(10U, 2U);  // i < 10
3926             INST(14U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(13U);
3927         }
3928         BASIC_BLOCK(5U, 1U)
3929         {
3930             INST(12U, Opcode::ReturnVoid).v0id();
3931         }
3932     }
3933 }
3934 
TEST_F(ChecksEliminationTest,HoistRefTypeCheckTest)3935 TEST_F(ChecksEliminationTest, HoistRefTypeCheckTest)
3936 {
3937     BuildHoistRefTypeCheckGraph();
3938     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
3939 
3940     auto graph = CreateEmptyGraph();
3941     GRAPH(graph)
3942     {
3943         CONSTANT(0U, 0U);  // initial
3944         CONSTANT(1U, 1U);  // increment
3945         CONSTANT(2U, 10U);
3946         PARAMETER(28U, 0U).ref();
3947         PARAMETER(29U, 1U).ref();
3948         BASIC_BLOCK(2U, 3U, 5U)
3949         {
3950             INST(20U, Opcode::SaveStateDeoptimize).Inputs(0U, 1U, 2U, 28U, 29U).SrcVregs({0U, 1U, 2U, 3U, 4U});
3951             INST(31U, Opcode::NullCheck).ref().Inputs(29U, 20U).SetFlag(inst_flags::CAN_DEOPTIMIZE);
3952             INST(34U, Opcode::RefTypeCheck).ref().Inputs(31U, 28U, 20U).SetFlag(inst_flags::CAN_DEOPTIMIZE);
3953             INST(5U, Opcode::Compare).SrcType(DataType::INT32).CC(CC_LT).b().Inputs(0U, 2U);  // 0 < 10
3954             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
3955         }
3956         BASIC_BLOCK(3U, 3U, 5U)
3957         {
3958             INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);  // i
3959 
3960             INST(30U, Opcode::SaveState).Inputs(28U, 29U).SrcVregs({0U, 1U});
3961             INST(32U, Opcode::LenArray).s32().Inputs(31U);
3962             INST(35U, Opcode::StoreArray).ref().Inputs(31U, 4U, 34U);
3963 
3964             INST(10U, Opcode::Add).s32().Inputs(4U, 1U);               // i++
3965             INST(13U, Opcode::Compare).CC(CC_LT).b().Inputs(10U, 2U);  // i < 10
3966             INST(14U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(13U);
3967         }
3968         BASIC_BLOCK(5U, 1U)
3969         {
3970             INST(12U, Opcode::ReturnVoid).v0id();
3971         }
3972     }
3973     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
3974 }
3975 
TEST_F(ChecksEliminationTest,NotLenArrayInput)3976 TEST_F(ChecksEliminationTest, NotLenArrayInput)
3977 {
3978     GRAPH(GetGraph())
3979     {
3980         PARAMETER(0U, 0U).s32();
3981         CONSTANT(4U, 1U);
3982         CONSTANT(7U, 10U);
3983         BASIC_BLOCK(2U, 3U)
3984         {
3985             INST(1U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
3986         }
3987         BASIC_BLOCK(3U, 4U, 5U)
3988         {
3989             INST(3U, Opcode::Phi).s32().Inputs(0U, 5U);
3990             INST(6U, Opcode::Compare).b().CC(CC_GE).Inputs(3U, 7U);
3991             INST(8U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(6U);
3992         }
3993         BASIC_BLOCK(5U, 3U)
3994         {
3995             INST(9U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
3996             INST(10U, Opcode::NegativeCheck).s32().Inputs(3U, 9U);
3997             INST(44U, Opcode::LoadAndInitClass).ref().Inputs(9U).TypeId(68U);
3998             INST(11U, Opcode::NewArray).ref().Inputs(44U, 10U, 9U);
3999             INST(12U, Opcode::BoundsCheck).s32().Inputs(3U, 0U, 9U);
4000             INST(13U, Opcode::StoreArray).s32().Inputs(11U, 12U, 0U);
4001             INST(5U, Opcode::Add).s32().Inputs(3U, 4U);
4002         }
4003         BASIC_BLOCK(4U, -1L)
4004         {
4005             INST(2U, Opcode::ReturnVoid).v0id();
4006         }
4007     }
4008     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
4009     ASSERT_FALSE(GetGraph()->RunPass<ChecksElimination>());
4010     ASSERT_TRUE(GraphComparator().Compare(clone, GetGraph()));
4011 }
4012 
BuildGraphBugWithNullCheck()4013 void ChecksEliminationTest::BuildGraphBugWithNullCheck()
4014 {
4015     GRAPH(GetGraph())
4016     {
4017         CONSTANT(0U, 0U);          // initial
4018         CONSTANT(1U, 1U);          // increment
4019         PARAMETER(27U, 1U).s32();  // X
4020         BASIC_BLOCK(2U, 6U, 3U)
4021         {
4022             INST(43U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
4023             INST(44U, Opcode::LoadAndInitClass).ref().Inputs().TypeId(68U);
4024             INST(13U, Opcode::NewArray).ref().Inputs(44U, 27U, 43U);
4025             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
4026             INST(14U, Opcode::Compare).CC(ConditionCode::CC_GE).b().Inputs(0U, 27U);  // i < X
4027             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(14U);
4028         }
4029         BASIC_BLOCK(3U, 6U, 3U)
4030         {
4031             INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);
4032             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 13U, 27U).SrcVregs({0U, 1U, 2U, 3U});
4033             INST(16U, Opcode::NullCheck).ref().Inputs(13U, 7U);
4034             INST(17U, Opcode::LenArray).s32().Inputs(16U);
4035             INST(8U, Opcode::BoundsCheck).s32().Inputs(17U, 4U, 7U);
4036             INST(9U, Opcode::StoreArray).s32().Inputs(16U, 8U, 0U);                   // a[i] = 0
4037             INST(10U, Opcode::Add).s32().Inputs(4U, 1U);                              // i++
4038             INST(5U, Opcode::Compare).CC(ConditionCode::CC_GE).b().Inputs(10U, 27U);  // i < X
4039             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
4040         }
4041         BASIC_BLOCK(6U, 1U)
4042         {
4043             INST(26U, Opcode::Phi).s32().Inputs(0U, 10U);
4044             INST(12U, Opcode::Return).s32().Inputs(26U);
4045         }
4046     }
4047 }
4048 
TEST_F(ChecksEliminationTest,BugWithNullCheck)4049 TEST_F(ChecksEliminationTest, BugWithNullCheck)
4050 {
4051     BuildGraphBugWithNullCheck();
4052     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
4053     auto graph1 = CreateEmptyGraph();
4054     GRAPH(graph1)
4055     {
4056         CONSTANT(0U, 0U);  // initial
4057         CONSTANT(1U, 1U);  // increment
4058         PARAMETER(2U, 1U).s32();
4059         BASIC_BLOCK(2U, 5U, 3U)
4060         {
4061             INST(43U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
4062             INST(44U, Opcode::LoadAndInitClass).ref().Inputs().TypeId(68U);
4063             INST(3U, Opcode::NewArray).ref().Inputs(44U, 2U, 43U);
4064             INST(20U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
4065             INST(34U, Opcode::NOP);
4066             INST(22U, Opcode::LenArray).s32().Inputs(3U);
4067             INST(23U, Opcode::Compare).SrcType(DataType::INT32).CC(CC_LT).b().Inputs(22U, 2U);  // len_array < X
4068             INST(24U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(23U, 20U);
4069             INST(5U, Opcode::Compare).SrcType(DataType::INT32).CC(CC_GE).b().Inputs(0U, 2U);  // 0 < X
4070             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
4071         }
4072         BASIC_BLOCK(3U, 5U, 3U)
4073         {
4074             INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);
4075             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 3U, 2U).SrcVregs({0U, 1U, 2U, 3U});
4076             INST(15U, Opcode::NOP);
4077             INST(16U, Opcode::LenArray).s32().Inputs(3U);
4078             INST(8U, Opcode::NOP);
4079             INST(9U, Opcode::StoreArray).s32().Inputs(3U, 4U, 0U);     // a[i] = 0
4080             INST(10U, Opcode::Add).s32().Inputs(4U, 1U);               // i++
4081             INST(13U, Opcode::Compare).CC(CC_GE).b().Inputs(10U, 2U);  // i < X
4082             INST(14U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(13U);
4083         }
4084         BASIC_BLOCK(5U, 1U)
4085         {
4086             INST(26U, Opcode::Phi).s32().Inputs(0U, 10U);
4087             INST(12U, Opcode::Return).s32().Inputs(26U);
4088         }
4089     }
4090     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
4091 }
4092 
BuildGraphNullAndBoundsChecksNestedLoop()4093 void ChecksEliminationTest::BuildGraphNullAndBoundsChecksNestedLoop()
4094 {
4095     GRAPH(GetGraph())
4096     {
4097         PARAMETER(0U, 0U).ref();
4098         CONSTANT(3U, 0U);
4099         CONSTANT(9U, 4U);
4100         CONSTANT(32U, 1U);
4101 
4102         // fill 2D array
4103         BASIC_BLOCK(2U, 3U)
4104         {
4105             INST(2U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
4106         }
4107         BASIC_BLOCK(3U, 7U, 8U)
4108         {
4109             INST(5U, Opcode::Phi).s32().Inputs(3U, 33U);
4110             INST(4U, Opcode::Compare).CC(CC_LE).b().Inputs(9U, 5U);
4111             INST(11U, Opcode::IfImm).CC(CC_NE).Imm(0U).Inputs(4U);
4112         }
4113         BASIC_BLOCK(8U, 4U)
4114         {
4115             INST(38U, Opcode::SaveStateDeoptimize).Inputs(0U, 3U, 5U).SrcVregs({0U, 1U, 2U});
4116         }
4117         BASIC_BLOCK(4U, 6U, 5U)
4118         {
4119             INST(15U, Opcode::Phi).s32().Inputs(3U, 31U);
4120             INST(19U, Opcode::Compare).CC(CC_LE).b().Inputs(9U, 15U);
4121             INST(20U, Opcode::IfImm).CC(CC_NE).Imm(0U).Inputs(19U);
4122         }
4123         BASIC_BLOCK(5U, 4U)
4124         {
4125             INST(21U, Opcode::SaveState).Inputs(0U, 3U, 5U, 15U).SrcVregs({0U, 1U, 2U, 3U});
4126             INST(22U, Opcode::NullCheck).ref().Inputs(0U, 21U);
4127             INST(23U, Opcode::LenArray).s32().Inputs(22U);
4128             INST(24U, Opcode::BoundsCheck).s32().Inputs(23U, 5U, 21U);
4129             INST(25U, Opcode::LoadArray).ref().Inputs(22U, 24U);
4130 
4131             INST(26U, Opcode::SaveState).Inputs(0U, 3U, 5U, 15U, 25U).SrcVregs({0U, 1U, 2U, 3U, 4U});
4132             INST(27U, Opcode::NullCheck).ref().Inputs(25U, 26U);
4133             INST(28U, Opcode::LenArray).s32().Inputs(27U);
4134             INST(29U, Opcode::BoundsCheck).s32().Inputs(28U, 15U, 26U);
4135             INST(30U, Opcode::StoreArray).s32().Inputs(27U, 29U, 5U);  // a[i][j] = i
4136             INST(31U, Opcode::Add).s32().Inputs(15U, 32U);
4137         }
4138         BASIC_BLOCK(6U, 3U)
4139         {
4140             INST(33U, Opcode::Add).s32().Inputs(5U, 32U);
4141         }
4142         BASIC_BLOCK(7U, -1L)
4143         {
4144             INST(34U, Opcode::ReturnVoid).v0id();
4145         }
4146     }
4147 }
4148 
TEST_F(ChecksEliminationTest,NullAndBoundsChecksNestedLoop)4149 TEST_F(ChecksEliminationTest, NullAndBoundsChecksNestedLoop)
4150 {
4151     BuildGraphNullAndBoundsChecksNestedLoop();
4152     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
4153 
4154     auto graph = CreateEmptyGraph();
4155     GRAPH(graph)
4156     {
4157         PARAMETER(0U, 0U).ref();
4158         CONSTANT(3U, 0U);
4159         CONSTANT(9U, 4U);
4160         CONSTANT(32U, 1U);
4161 
4162         BASIC_BLOCK(2U, 3U)
4163         {
4164             INST(2U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
4165             INST(35U, Opcode::NullCheck).ref().Inputs(0U, 2U).SetFlag(inst_flags::CAN_DEOPTIMIZE);
4166             INST(39U, Opcode::LenArray).s32().Inputs(35U);
4167             INST(44U, Opcode::Compare).b().SrcType(DataType::INT32).CC(CC_LT).Inputs(39U, 9U);
4168             INST(45U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(44U, 2U);
4169         }
4170         BASIC_BLOCK(3U, 7U, 8U)
4171         {
4172             INST(5U, Opcode::Phi).s32().Inputs(3U, 33U);
4173             INST(4U, Opcode::Compare).CC(CC_LE).b().Inputs(9U, 5U);
4174             INST(11U, Opcode::IfImm).CC(CC_NE).Imm(0U).Inputs(4U);
4175         }
4176         BASIC_BLOCK(8U, 4U)
4177         {
4178             INST(38U, Opcode::SaveStateDeoptimize).Inputs(0U, 3U, 5U).SrcVregs({0U, 1U, 2U});
4179             // we could put DeoptimizeIf NULL_CHECK here, but this is suboptimal
4180         }
4181         BASIC_BLOCK(4U, 6U, 5U)
4182         {
4183             INST(15U, Opcode::Phi).s32().Inputs(3U, 31U);
4184             INST(19U, Opcode::Compare).CC(CC_LE).b().Inputs(9U, 15U);
4185             INST(20U, Opcode::IfImm).CC(CC_NE).Imm(0U).Inputs(19U);
4186         }
4187         BASIC_BLOCK(5U, 4U)
4188         {
4189             INST(21U, Opcode::SaveState).Inputs(0U, 3U, 5U, 15U).SrcVregs({0U, 1U, 2U, 3U});
4190             INST(22U, Opcode::NOP);
4191             INST(23U, Opcode::LenArray).s32().Inputs(35U);
4192             INST(24U, Opcode::NOP);
4193             INST(25U, Opcode::LoadArray).ref().Inputs(35U, 5U);
4194             INST(26U, Opcode::SaveState).Inputs(0U, 3U, 5U, 15U, 25U).SrcVregs({0U, 1U, 2U, 3U, 4U});
4195             INST(27U, Opcode::NullCheck).ref().Inputs(25U, 26U);
4196             INST(28U, Opcode::LenArray).s32().Inputs(27U);
4197             INST(29U, Opcode::BoundsCheck).s32().Inputs(28U, 15U, 26U);
4198             INST(30U, Opcode::StoreArray).s32().Inputs(27U, 29U, 5U);  // a[i][j] = i
4199             INST(31U, Opcode::Add).s32().Inputs(15U, 32U);
4200         }
4201         BASIC_BLOCK(6U, 3U)
4202         {
4203             INST(33U, Opcode::Add).s32().Inputs(5U, 32U);
4204         }
4205         BASIC_BLOCK(7U, -1L)
4206         {
4207             INST(34U, Opcode::ReturnVoid).v0id();
4208         }
4209     }
4210     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
4211 }
4212 
BuildGraphLoopWithTwoPhi()4213 void ChecksEliminationTest::BuildGraphLoopWithTwoPhi()
4214 {
4215     GRAPH(GetGraph())
4216     {
4217         PARAMETER(0U, 0U).ref();
4218         PARAMETER(1U, 1U).s32();
4219         PARAMETER(2U, 2U).s32();
4220         CONSTANT(3U, 0U);
4221         CONSTANT(4U, 1U);
4222         BASIC_BLOCK(2U, 3U)
4223         {
4224             INST(5U, Opcode::SaveStateDeoptimize).Inputs(0U, 1U, 2U, 3U, 4U).SrcVregs({0U, 1U, 2U, 3U, 4U});
4225             INST(6U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U, 4U).SrcVregs({0U, 1U, 2U, 3U, 4U});
4226             INST(7U, Opcode::NullCheck).ref().Inputs(0U, 6U);
4227             INST(8U, Opcode::LoadObject).ref().Inputs(7U);
4228         }
4229         BASIC_BLOCK(3U, 4U, 5U)
4230         {
4231             INST(9U, Opcode::Phi).s32().Inputs(1U, 17U);
4232             INST(18U, Opcode::Phi).s32().Inputs(3U, 19U);
4233             INST(10U, Opcode::Compare).b().CC(CC_GE).Inputs(9U, 2U);
4234             INST(11U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(10U);
4235         }
4236         BASIC_BLOCK(5U, 3U)
4237         {
4238             INST(12U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U, 4U, 8U).SrcVregs({0U, 1U, 2U, 3U, 4U, 5U});
4239             INST(13U, Opcode::NullCheck).ref().Inputs(8U, 12U);
4240             INST(14U, Opcode::LenArray).s32().Inputs(13U);
4241             INST(15U, Opcode::BoundsCheck).s32().Inputs(14U, 9U, 12U);
4242             INST(16U, Opcode::LoadArray).s32().Inputs(13U, 15U);
4243             INST(17U, Opcode::Add).s32().Inputs(9U, 4U);
4244             INST(19U, Opcode::Add).s32().Inputs(18U, 16U);
4245         }
4246         BASIC_BLOCK(4U, -1L)
4247         {
4248             INST(20U, Opcode::Return).s32().Inputs(18U);
4249         }
4250     }
4251 }
4252 
TEST_F(ChecksEliminationTest,LoopWithTwoPhi)4253 TEST_F(ChecksEliminationTest, LoopWithTwoPhi)
4254 {
4255     BuildGraphLoopWithTwoPhi();
4256     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
4257     auto graph1 = CreateEmptyGraph();
4258     GRAPH(graph1)
4259     {
4260         PARAMETER(0U, 0U).ref();
4261         PARAMETER(1U, 1U).s32();
4262         PARAMETER(2U, 2U).s32();
4263         CONSTANT(3U, 0U);
4264         CONSTANT(4U, 1U);
4265         BASIC_BLOCK(2U, 3U)
4266         {
4267             INST(5U, Opcode::SaveStateDeoptimize).Inputs(0U, 1U, 2U, 3U, 4U).SrcVregs({0U, 1U, 2U, 3U, 4U});
4268             INST(6U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U, 4U).SrcVregs({0U, 1U, 2U, 3U, 4U});
4269             INST(7U, Opcode::NullCheck).ref().Inputs(0U, 6U);
4270             INST(8U, Opcode::LoadObject).ref().Inputs(7U);
4271             INST(22U, Opcode::NullCheck).ref().Inputs(8U, 6U).SetFlag(inst_flags::CAN_DEOPTIMIZE);
4272         }
4273         BASIC_BLOCK(3U, 4U, 5U)
4274         {
4275             INST(9U, Opcode::Phi).s32().Inputs(1U, 17U);
4276             INST(18U, Opcode::Phi).s32().Inputs(3U, 19U);
4277             INST(10U, Opcode::Compare).b().CC(CC_GE).Inputs(9U, 2U);
4278             INST(11U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(10U);
4279         }
4280         BASIC_BLOCK(5U, 3U)
4281         {
4282             INST(12U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U, 4U, 8U).SrcVregs({0U, 1U, 2U, 3U, 4U, 5U});
4283             INST(14U, Opcode::LenArray).s32().Inputs(22U);
4284             INST(15U, Opcode::BoundsCheck).s32().Inputs(14U, 9U, 12U);
4285             INST(16U, Opcode::LoadArray).s32().Inputs(22U, 15U);
4286             INST(17U, Opcode::Add).s32().Inputs(9U, 4U);
4287             INST(19U, Opcode::Add).s32().Inputs(18U, 16U);
4288         }
4289         BASIC_BLOCK(4U, -1L)
4290         {
4291             INST(20U, Opcode::Return).s32().Inputs(18U);
4292         }
4293     }
4294     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
4295 }
4296 
BuildGraphLoopWithBigStepGE()4297 void ChecksEliminationTest::BuildGraphLoopWithBigStepGE()
4298 {
4299     GRAPH(GetGraph())
4300     {
4301         CONSTANT(0U, 0U);
4302         CONSTANT(1U, 4U);  // increment
4303         CONSTANT(2U, 3U);
4304         PARAMETER(13U, 0U).ref();  // Array
4305         PARAMETER(27U, 1U).s32();  // X
4306         BASIC_BLOCK(2U, 3U)
4307         {
4308             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
4309         }
4310         BASIC_BLOCK(3U, 5U, 4U)
4311         {
4312             INST(4U, Opcode::Phi).s32().Inputs(27U, 10U);
4313             INST(14U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(4U, 0U);  // i >= 0
4314             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(14U);
4315         }
4316         BASIC_BLOCK(4U, 3U)
4317         {
4318             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 13U, 27U).SrcVregs({0U, 1U, 2U, 3U});
4319             INST(16U, Opcode::NullCheck).ref().Inputs(13U, 7U);
4320             INST(17U, Opcode::LenArray).s32().Inputs(16U);
4321             INST(8U, Opcode::BoundsCheck).s32().Inputs(17U, 4U, 7U);
4322             INST(9U, Opcode::StoreArray).s32().Inputs(16U, 8U, 4U);  // a[i] = i
4323             INST(10U, Opcode::Sub).s32().Inputs(4U, 1U);             // i -= 4
4324         }
4325         BASIC_BLOCK(5U, 1U)
4326         {
4327             INST(12U, Opcode::ReturnVoid).v0id();
4328         }
4329     }
4330 }
4331 
TEST_F(ChecksEliminationTest,LoopWithBigStepGE)4332 TEST_F(ChecksEliminationTest, LoopWithBigStepGE)
4333 {
4334     BuildGraphLoopWithBigStepGE();
4335     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
4336     auto graph1 = CreateEmptyGraph();
4337     GRAPH(graph1)
4338     {
4339         CONSTANT(0U, 0U);
4340         CONSTANT(1U, 4U);  // increment
4341         CONSTANT(2U, 3U);
4342         PARAMETER(13U, 0U).ref();  // Array
4343         PARAMETER(27U, 1U).s32();  // X
4344         BASIC_BLOCK(2U, 3U)
4345         {
4346             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
4347             INST(33U, Opcode::NullCheck).ref().Inputs(13U, 30U).SetFlag(inst_flags::CAN_DEOPTIMIZE);
4348             INST(31U, Opcode::LenArray).s32().Inputs(33U);
4349             INST(36U, Opcode::Compare).SrcType(DataType::INT32).CC(CC_LE).b().Inputs(31U, 27U);
4350             // DeoptimizeIf len_array <= X
4351             INST(37U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(36U, 30U);
4352         }
4353         BASIC_BLOCK(3U, 5U, 4U)
4354         {
4355             INST(4U, Opcode::Phi).s32().Inputs(27U, 10U);
4356             INST(14U, Opcode::Compare).CC(ConditionCode::CC_LT).b().Inputs(4U, 0U);  // i >= 0
4357             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(14U);
4358         }
4359         BASIC_BLOCK(4U, 3U)
4360         {
4361             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 13U, 27U).SrcVregs({0U, 1U, 2U, 3U});
4362             INST(16U, Opcode::NOP);
4363             INST(17U, Opcode::LenArray).s32().Inputs(33U);
4364             INST(8U, Opcode::NOP);
4365             INST(9U, Opcode::StoreArray).s32().Inputs(33U, 4U, 4U);  // a[i] = i
4366             INST(10U, Opcode::Sub).s32().Inputs(4U, 1U);             // i -= 4
4367         }
4368         BASIC_BLOCK(5U, 1U)
4369         {
4370             INST(12U, Opcode::ReturnVoid).v0id();
4371         }
4372     }
4373     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
4374 }
4375 
BuildGraphLoopWithBigStepLE()4376 void ChecksEliminationTest::BuildGraphLoopWithBigStepLE()
4377 {
4378     GRAPH(GetGraph())
4379     {
4380         CONSTANT(0U, 2U);  // initial
4381         CONSTANT(1U, 8U);  // increment
4382         CONSTANT(2U, 3U);
4383         PARAMETER(13U, 0U).ref();  // Array
4384         PARAMETER(27U, 1U).s32();  // X
4385         BASIC_BLOCK(2U, 6U, 3U)
4386         {
4387             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
4388             INST(14U, Opcode::Compare).CC(ConditionCode::CC_GT).b().Inputs(0U, 27U);  // i <= X
4389             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(14U);
4390         }
4391         BASIC_BLOCK(3U, 6U, 3U)
4392         {
4393             INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);
4394             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 13U, 27U).SrcVregs({0U, 1U, 2U, 3U});
4395             INST(16U, Opcode::NullCheck).ref().Inputs(13U, 7U);
4396             INST(17U, Opcode::LenArray).s32().Inputs(16U);
4397             INST(8U, Opcode::BoundsCheck).s32().Inputs(17U, 4U, 7U);
4398             INST(9U, Opcode::LoadArray).s32().Inputs(16U, 8U);  // load a[i]
4399             INST(18U, Opcode::Add).s32().Inputs(4U, 2U);
4400             INST(19U, Opcode::BoundsCheck).s32().Inputs(17U, 18U, 7U);
4401             INST(20U, Opcode::StoreArray).s32().Inputs(16U, 19U, 9U);                 // a[i + 3] = a[i]
4402             INST(10U, Opcode::Add).s32().Inputs(4U, 1U);                              // i += 8
4403             INST(5U, Opcode::Compare).CC(ConditionCode::CC_GT).b().Inputs(10U, 27U);  // i <= X
4404             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
4405         }
4406         BASIC_BLOCK(6U, 1U)
4407         {
4408             INST(26U, Opcode::Phi).s32().Inputs(0U, 10U);
4409             INST(12U, Opcode::Return).s32().Inputs(26U);
4410         }
4411     }
4412 }
4413 
TEST_F(ChecksEliminationTest,LoopWithBigStepLE)4414 TEST_F(ChecksEliminationTest, LoopWithBigStepLE)
4415 {
4416     BuildGraphLoopWithBigStepLE();
4417     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
4418     auto graph1 = CreateEmptyGraph();
4419     GRAPH(graph1)
4420     {
4421         CONSTANT(0U, 2U);  // initial
4422         CONSTANT(1U, 8U);  // increment
4423         CONSTANT(2U, 3U);
4424         PARAMETER(13U, 0U).ref();  // Array
4425         PARAMETER(27U, 1U).s32();  // X
4426         CONSTANT(42U, 0x7ffffff7U);
4427 
4428         BASIC_BLOCK(2U, 6U, 3U)
4429         {
4430             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
4431             INST(44U, Opcode::Compare).Inputs(42U, 27U).CC(CC_LT).b();
4432             INST(45U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(44U, 30U);
4433             INST(33U, Opcode::NullCheck).ref().Inputs(13U, 30U).SetFlag(inst_flags::CAN_DEOPTIMIZE);
4434             INST(31U, Opcode::LenArray).s32().Inputs(33U);
4435             INST(36U, Opcode::Sub).s32().Inputs(27U, 0U);
4436             INST(37U, Opcode::Mod).s32().Inputs(36U, 1U);
4437             INST(38U, Opcode::Sub).s32().Inputs(27U, 37U);
4438             INST(39U, Opcode::Sub).s32().Inputs(31U, 2U);
4439             INST(40U, Opcode::Compare).b().CC(CC_LE).Inputs(39U, 38U);
4440             // DeoptimizeIf len - 3 <= X - (X - 2) % 8
4441             INST(41U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(40U, 30U);
4442             INST(14U, Opcode::Compare).CC(ConditionCode::CC_GT).b().Inputs(0U, 27U);  // i <= X
4443             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(14U);
4444         }
4445         BASIC_BLOCK(3U, 6U, 3U)
4446         {
4447             INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);
4448             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 13U, 27U).SrcVregs({0U, 1U, 2U, 3U});
4449             INST(16U, Opcode::NOP);
4450             INST(17U, Opcode::LenArray).s32().Inputs(33U);
4451             INST(8U, Opcode::NOP);
4452             INST(9U, Opcode::LoadArray).s32().Inputs(33U, 4U);  // load a[i]
4453             INST(18U, Opcode::Add).s32().Inputs(4U, 2U);
4454             INST(19U, Opcode::NOP);
4455             INST(20U, Opcode::StoreArray).s32().Inputs(33U, 18U, 9U);                 // a[i + 3] = a[i]
4456             INST(10U, Opcode::Add).s32().Inputs(4U, 1U);                              // i += 8
4457             INST(5U, Opcode::Compare).CC(ConditionCode::CC_GT).b().Inputs(10U, 27U);  // i <= X
4458             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
4459         }
4460         BASIC_BLOCK(6U, 1U)
4461         {
4462             INST(26U, Opcode::Phi).s32().Inputs(0U, 10U);
4463             INST(12U, Opcode::Return).s32().Inputs(26U);
4464         }
4465     }
4466     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
4467 }
4468 
BuildGraphLoopWithBigStepLT()4469 void ChecksEliminationTest::BuildGraphLoopWithBigStepLT()
4470 {
4471     GRAPH(GetGraph())
4472     {
4473         CONSTANT(0U, 2U);  // initial
4474         CONSTANT(1U, 8U);  // increment
4475         CONSTANT(2U, 3U);
4476         PARAMETER(13U, 0U).ref();  // Array
4477         PARAMETER(27U, 1U).s32();  // X
4478         BASIC_BLOCK(2U, 6U, 3U)
4479         {
4480             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
4481             INST(14U, Opcode::Compare).CC(ConditionCode::CC_GE).b().Inputs(0U, 27U);  // i < X
4482             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(14U);
4483         }
4484         BASIC_BLOCK(3U, 6U, 3U)
4485         {
4486             INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);
4487             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 13U, 27U).SrcVregs({0U, 1U, 2U, 3U});
4488             INST(16U, Opcode::NullCheck).ref().Inputs(13U, 7U);
4489             INST(17U, Opcode::LenArray).s32().Inputs(16U);
4490             INST(8U, Opcode::BoundsCheck).s32().Inputs(17U, 4U, 7U);
4491             INST(9U, Opcode::LoadArray).s32().Inputs(16U, 8U);  // load a[i]
4492             INST(18U, Opcode::Add).s32().Inputs(4U, 2U);
4493             INST(19U, Opcode::BoundsCheck).s32().Inputs(17U, 18U, 7U);
4494             INST(20U, Opcode::StoreArray).s32().Inputs(16U, 19U, 9U);                 // a[i + 3] = a[i]
4495             INST(10U, Opcode::Add).s32().Inputs(4U, 1U);                              // i += 8
4496             INST(5U, Opcode::Compare).CC(ConditionCode::CC_GE).b().Inputs(10U, 27U);  // i < X
4497             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
4498         }
4499         BASIC_BLOCK(6U, 1U)
4500         {
4501             INST(26U, Opcode::Phi).s32().Inputs(0U, 10U);
4502             INST(12U, Opcode::Return).s32().Inputs(26U);
4503         }
4504     }
4505 }
4506 
TEST_F(ChecksEliminationTest,LoopWithBigStepLT)4507 TEST_F(ChecksEliminationTest, LoopWithBigStepLT)
4508 {
4509     BuildGraphLoopWithBigStepLT();
4510     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
4511     auto graph1 = CreateEmptyGraph();
4512     GRAPH(graph1)
4513     {
4514         CONSTANT(0U, 2U);  // initial
4515         CONSTANT(1U, 8U);  // increment
4516         CONSTANT(2U, 3U);
4517         PARAMETER(13U, 0U).ref();  // Array
4518         PARAMETER(27U, 1U).s32();  // X
4519         CONSTANT(43U, 1U);
4520         CONSTANT(42U, 0x7ffffff8U);
4521 
4522         BASIC_BLOCK(2U, 6U, 3U)
4523         {
4524             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
4525             INST(44U, Opcode::Compare).Inputs(42U, 27U).CC(CC_LT).b();
4526             INST(45U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(44U, 30U);
4527             INST(33U, Opcode::NullCheck).ref().Inputs(13U, 30U).SetFlag(inst_flags::CAN_DEOPTIMIZE);
4528             INST(31U, Opcode::LenArray).s32().Inputs(33U);
4529             INST(35U, Opcode::Add).s32().Inputs(0U, 43U);
4530             INST(36U, Opcode::Sub).s32().Inputs(27U, 35U);
4531             INST(37U, Opcode::Mod).s32().Inputs(36U, 1U);
4532             INST(38U, Opcode::Sub).s32().Inputs(27U, 37U);
4533             INST(39U, Opcode::Sub).s32().Inputs(31U, 2U);
4534             INST(40U, Opcode::Compare).b().CC(CC_LT).Inputs(39U, 38U);
4535             // DeoptimizeIf len - 3 < X - (X - (2 + 1)) % 8
4536             INST(41U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(40U, 30U);
4537             INST(14U, Opcode::Compare).CC(ConditionCode::CC_GE).b().Inputs(0U, 27U);  // i < X
4538             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(14U);
4539         }
4540         BASIC_BLOCK(3U, 6U, 3U)
4541         {
4542             INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);
4543             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 13U, 27U).SrcVregs({0U, 1U, 2U, 3U});
4544             INST(16U, Opcode::NOP);
4545             INST(17U, Opcode::LenArray).s32().Inputs(33U);
4546             INST(8U, Opcode::NOP);
4547             INST(9U, Opcode::LoadArray).s32().Inputs(33U, 4U);  // load a[i]
4548             INST(18U, Opcode::Add).s32().Inputs(4U, 2U);
4549             INST(19U, Opcode::NOP);
4550             INST(20U, Opcode::StoreArray).s32().Inputs(33U, 18U, 9U);                 // a[i + 3] = a[i]
4551             INST(10U, Opcode::Add).s32().Inputs(4U, 1U);                              // i += 8
4552             INST(5U, Opcode::Compare).CC(ConditionCode::CC_GE).b().Inputs(10U, 27U);  // i < X
4553             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
4554         }
4555         BASIC_BLOCK(6U, 1U)
4556         {
4557             INST(26U, Opcode::Phi).s32().Inputs(0U, 10U);
4558             INST(12U, Opcode::Return).s32().Inputs(26U);
4559         }
4560     }
4561     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
4562 }
4563 
BuildGraphLoopWithBoundsCheckUnderIfGE()4564 void ChecksEliminationTest::BuildGraphLoopWithBoundsCheckUnderIfGE()
4565 {
4566     GRAPH(GetGraph())
4567     {
4568         CONSTANT(0U, 0U);  // initial
4569         CONSTANT(1U, 1U);  // increment
4570         CONSTANT(3U, 3U);
4571         PARAMETER(2U, 0U).ref();  // array
4572         PARAMETER(4U, 1U).s32();  // X
4573 
4574         BASIC_BLOCK(2U, 3U)
4575         {
4576             INST(5U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
4577             INST(6U, Opcode::NullCheck).ref().Inputs(2U, 5U);
4578             INST(7U, Opcode::LenArray).s32().Inputs(6U);
4579 
4580             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
4581         }
4582 
4583         BASIC_BLOCK(3U, 4U, 8U)
4584         {
4585             INST(8U, Opcode::Phi).s32().Inputs(0U, 24U);             // i
4586             INST(25U, Opcode::Phi).s32().Inputs(0U, 23U);            // sum
4587             INST(9U, Opcode::Compare).CC(CC_LT).b().Inputs(8U, 4U);  // i < X
4588             INST(10U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(9U);
4589         }
4590         BASIC_BLOCK(4U, 5U, 6U)
4591         {
4592             INST(14U, Opcode::Compare).CC(CC_LE).b().Inputs(3U, 8U);  // 3 <= i
4593             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(14U);
4594         }
4595         BASIC_BLOCK(5U, 7U)
4596         {
4597             INST(16U, Opcode::Sub).s32().Inputs(8U, 3U);
4598             INST(27U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
4599             INST(17U, Opcode::BoundsCheck).s32().Inputs(7U, 16U, 27U);
4600             INST(18U, Opcode::LoadArray).s32().Inputs(6U, 17U);  // a[i - 3]
4601         }
4602         BASIC_BLOCK(6U, 7U)
4603         {
4604             INST(19U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
4605             INST(20U, Opcode::BoundsCheck).s32().Inputs(7U, 8U, 19U);
4606             INST(21U, Opcode::LoadArray).s32().Inputs(6U, 20U);  // a[i]
4607         }
4608         BASIC_BLOCK(7U, 3U)
4609         {
4610             INST(22U, Opcode::Phi).s32().Inputs(18U, 21U);
4611             INST(23U, Opcode::Add).s32().Inputs(25U, 22U);
4612             INST(24U, Opcode::Add).s32().Inputs(8U, 1U);
4613         }
4614         BASIC_BLOCK(8U, 1U)
4615         {
4616             INST(26U, Opcode::Return).s32().Inputs(25U);
4617         }
4618     }
4619 }
4620 
4621 // Lower bound is correct in each branch based on BoundsAnalysis, build deoptimize only for upper bound
TEST_F(ChecksEliminationTest,LoopWithBoundsCheckUnderIfGE)4622 TEST_F(ChecksEliminationTest, LoopWithBoundsCheckUnderIfGE)
4623 {
4624     BuildGraphLoopWithBoundsCheckUnderIfGE();
4625     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
4626     auto graph1 = CreateEmptyGraph();
4627     GRAPH(graph1)
4628     {
4629         CONSTANT(0U, 0U);  // initial
4630         CONSTANT(1U, 1U);  // increment
4631         CONSTANT(3U, 3U);
4632         PARAMETER(2U, 0U).ref();  // array
4633         PARAMETER(4U, 1U).s32();  // X
4634 
4635         BASIC_BLOCK(2U, 3U)
4636         {
4637             INST(5U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
4638             INST(6U, Opcode::NullCheck).ref().Inputs(2U, 5U);
4639             INST(7U, Opcode::LenArray).s32().Inputs(6U);
4640 
4641             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
4642             INST(31U, Opcode::Compare).b().CC(CC_LT).Inputs(7U, 4U);
4643             INST(32U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(31U, 30U);
4644         }
4645 
4646         BASIC_BLOCK(3U, 4U, 8U)
4647         {
4648             INST(8U, Opcode::Phi).s32().Inputs(0U, 24U);             // i
4649             INST(25U, Opcode::Phi).s32().Inputs(0U, 23U);            // sum
4650             INST(9U, Opcode::Compare).CC(CC_LT).b().Inputs(8U, 4U);  // i < X
4651             INST(10U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(9U);
4652         }
4653         BASIC_BLOCK(4U, 5U, 6U)
4654         {
4655             INST(14U, Opcode::Compare).CC(CC_LE).b().Inputs(3U, 8U);  // 3 <= i
4656             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(14U);
4657         }
4658         BASIC_BLOCK(5U, 7U)
4659         {
4660             INST(16U, Opcode::Sub).s32().Inputs(8U, 3U);
4661             INST(27U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
4662             INST(17U, Opcode::NOP);
4663             INST(18U, Opcode::LoadArray).s32().Inputs(6U, 16U);  // a[i - 3]
4664         }
4665         BASIC_BLOCK(6U, 7U)
4666         {
4667             INST(19U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
4668             INST(20U, Opcode::NOP);
4669             INST(21U, Opcode::LoadArray).s32().Inputs(6U, 8U);  // a[i]
4670         }
4671         BASIC_BLOCK(7U, 3U)
4672         {
4673             INST(22U, Opcode::Phi).s32().Inputs(18U, 21U);
4674             INST(23U, Opcode::Add).s32().Inputs(25U, 22U);
4675             INST(24U, Opcode::Add).s32().Inputs(8U, 1U);
4676         }
4677         BASIC_BLOCK(8U, 1U)
4678         {
4679             INST(26U, Opcode::Return).s32().Inputs(25U);
4680         }
4681     }
4682     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
4683 }
4684 
BuildGraphLoopWithBoundsCheckUnderIfLT()4685 void ChecksEliminationTest::BuildGraphLoopWithBoundsCheckUnderIfLT()
4686 {
4687     GRAPH(GetGraph())
4688     {
4689         CONSTANT(0U, 0U);  // initial
4690         CONSTANT(1U, 1U);  // increment
4691         CONSTANT(3U, 3U);
4692         PARAMETER(2U, 0U).ref();  // array
4693         PARAMETER(4U, 1U).s32();  // X
4694 
4695         BASIC_BLOCK(2U, 3U, 8U)
4696         {
4697             INST(5U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
4698             INST(6U, Opcode::NullCheck).ref().Inputs(2U, 5U);
4699             INST(7U, Opcode::LenArray).s32().Inputs(6U);
4700 
4701             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
4702             INST(31U, Opcode::Compare).CC(CC_LT).b().Inputs(4U, 7U);  // X < len_array
4703             INST(32U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(31U);
4704         }
4705 
4706         BASIC_BLOCK(3U, 4U, 8U)
4707         {
4708             INST(8U, Opcode::Phi).s32().Inputs(4U, 24U);             // i = X
4709             INST(25U, Opcode::Phi).s32().Inputs(0U, 23U);            // sum
4710             INST(9U, Opcode::Compare).CC(CC_LT).b().Inputs(8U, 7U);  // i < len_array
4711             INST(10U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(9U);
4712         }
4713         BASIC_BLOCK(4U, 5U, 6U)
4714         {
4715             INST(13U, Opcode::Add).s32().Inputs(8U, 3U);
4716             INST(14U, Opcode::Compare).CC(CC_LT).b().Inputs(13U, 7U);  // i + 3 < len_array
4717             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(14U);
4718         }
4719         BASIC_BLOCK(5U, 6U)
4720         {
4721             INST(20U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
4722             INST(17U, Opcode::BoundsCheck).s32().Inputs(7U, 13U, 20U);
4723             INST(18U, Opcode::LoadArray).s32().Inputs(6U, 17U);
4724             INST(19U, Opcode::Mul).s32().Inputs(8U, 18U);  // i * a[i + 3]
4725         }
4726         BASIC_BLOCK(6U, 3U)
4727         {
4728             INST(22U, Opcode::Phi).s32().Inputs(8U, 19U);
4729             INST(23U, Opcode::Add).s32().Inputs(25U, 22U);
4730             INST(24U, Opcode::Add).s32().Inputs(8U, 1U);
4731         }
4732         BASIC_BLOCK(8U, 1U)
4733         {
4734             INST(26U, Opcode::Phi).s32().Inputs(0U, 25U);
4735             INST(27U, Opcode::Return).s32().Inputs(26U);
4736         }
4737     }
4738 }
4739 
4740 // Upper bound is correct in each branch based on BoundsAnalysis, build deoptimize only for lower bound
TEST_F(ChecksEliminationTest,LoopWithBoundsCheckUnderIfLT)4741 TEST_F(ChecksEliminationTest, LoopWithBoundsCheckUnderIfLT)
4742 {
4743     BuildGraphLoopWithBoundsCheckUnderIfLT();
4744     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
4745     auto graph1 = CreateEmptyGraph();
4746     GRAPH(graph1)
4747     {
4748         CONSTANT(0U, 0U);  // initial
4749         CONSTANT(1U, 1U);  // increment
4750         CONSTANT(3U, 3U);
4751         PARAMETER(2U, 0U).ref();  // array
4752         PARAMETER(4U, 1U).s32();  // X
4753 
4754         BASIC_BLOCK(2U, 3U, 8U)
4755         {
4756             INST(5U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
4757             INST(6U, Opcode::NullCheck).ref().Inputs(2U, 5U);
4758             INST(7U, Opcode::LenArray).s32().Inputs(6U);
4759 
4760             INST(30U, Opcode::SaveStateDeoptimize).Inputs(0U).SrcVregs({0U});
4761             INST(33U, Opcode::Add).s32().Inputs(4U, 3U);
4762             INST(34U, Opcode::Compare).b().CC(CC_LT).Inputs(33U, 0U);  // X + 3 < 0
4763             INST(35U, Opcode::DeoptimizeIf).DeoptimizeType(DeoptimizeType::BOUNDS_CHECK).Inputs(34U, 30U);
4764             INST(31U, Opcode::Compare).CC(CC_LT).b().Inputs(4U, 7U);  // X < len_array
4765             INST(32U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(31U);
4766         }
4767         BASIC_BLOCK(3U, 4U, 8U)
4768         {
4769             INST(8U, Opcode::Phi).s32().Inputs(4U, 24U);             // i = X
4770             INST(25U, Opcode::Phi).s32().Inputs(0U, 23U);            // sum
4771             INST(9U, Opcode::Compare).CC(CC_LT).b().Inputs(8U, 7U);  // i < len_array
4772             INST(10U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(9U);
4773         }
4774         BASIC_BLOCK(4U, 5U, 6U)
4775         {
4776             INST(13U, Opcode::Add).s32().Inputs(8U, 3U);
4777             INST(14U, Opcode::Compare).CC(CC_LT).b().Inputs(13U, 7U);  // i + 3 < len_array
4778             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(14U);
4779         }
4780         BASIC_BLOCK(5U, 6U)
4781         {
4782             INST(20U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
4783             INST(17U, Opcode::NOP);
4784             INST(18U, Opcode::LoadArray).s32().Inputs(6U, 13U);
4785             INST(19U, Opcode::Mul).s32().Inputs(8U, 18U);  // i * a[i + 3]
4786         }
4787         BASIC_BLOCK(6U, 3U)
4788         {
4789             INST(22U, Opcode::Phi).s32().Inputs(8U, 19U);
4790             INST(23U, Opcode::Add).s32().Inputs(25U, 22U);
4791             INST(24U, Opcode::Add).s32().Inputs(8U, 1U);
4792         }
4793         BASIC_BLOCK(8U, 1U)
4794         {
4795             INST(26U, Opcode::Phi).s32().Inputs(0U, 25U);
4796             INST(27U, Opcode::Return).s32().Inputs(26U);
4797         }
4798     }
4799     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph1));
4800 }
4801 
TEST_F(ChecksEliminationTest,DeoptTest)4802 TEST_F(ChecksEliminationTest, DeoptTest)
4803 {
4804     GRAPH(GetGraph())
4805     {
4806         CONSTANT(0U, 0U);
4807         CONSTANT(1U, nullptr);
4808         BASIC_BLOCK(2U, 1U)
4809         {
4810             INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
4811             INST(3U, Opcode::NullCheck).ref().Inputs(1U, 2U);
4812             INST(4U, Opcode::ZeroCheck).s32().Inputs(0U, 2U);
4813             INST(5U, Opcode::ReturnVoid).v0id();
4814         }
4815     }
4816     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
4817     auto graph = CreateEmptyGraph();
4818     GRAPH(graph)
4819     {
4820         CONSTANT(0U, 0U);
4821         CONSTANT(1U, nullptr);
4822         BASIC_BLOCK(2U, 1U)
4823         {
4824             INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
4825             INST(3U, Opcode::Deoptimize).DeoptimizeType(DeoptimizeType::NULL_CHECK).Inputs(2U);
4826         }
4827     }
4828 }
4829 
TEST_F(ChecksEliminationTest,CheckCastEqualInputs)4830 TEST_F(ChecksEliminationTest, CheckCastEqualInputs)
4831 {
4832     // Check Elimination for CheckCast is applied.
4833     GRAPH(GetGraph())
4834     {
4835         PARAMETER(0U, 0U).ref();
4836         BASIC_BLOCK(2U, 1U)
4837         {
4838             INST(1U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
4839             INST(2U, Opcode::LoadClass).ref().Inputs(1U).TypeId(1U);
4840             INST(3U, Opcode::CheckCast).TypeId(1U).Inputs(0U, 2U, 1U);
4841             INST(4U, Opcode::CheckCast).TypeId(1U).Inputs(0U, 2U, 1U);
4842             INST(5U, Opcode::Return).ref().Inputs(0U);
4843         }
4844     }
4845     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
4846     auto graph = CreateEmptyGraph();
4847     GRAPH(graph)
4848     {
4849         PARAMETER(0U, 0U).ref();
4850         BASIC_BLOCK(2U, 1U)
4851         {
4852             INST(1U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
4853             INST(2U, Opcode::LoadClass).ref().Inputs(1U).TypeId(1U);
4854             INST(3U, Opcode::CheckCast).TypeId(1U).Inputs(0U, 2U, 1U);
4855             INST(4U, Opcode::NOP);
4856             INST(5U, Opcode::Return).ref().Inputs(0U);
4857         }
4858     }
4859     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
4860 }
4861 
TEST_F(ChecksEliminationTest,CheckCastDifferentInputs)4862 TEST_F(ChecksEliminationTest, CheckCastDifferentInputs)
4863 {
4864     // Check Elimination for CheckCast is not applied.
4865     GRAPH(GetGraph())
4866     {
4867         PARAMETER(0U, 0U).ref();
4868         PARAMETER(1U, 1U).ref();
4869         BASIC_BLOCK(2U, 1U)
4870         {
4871             INST(8U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
4872             INST(2U, Opcode::LoadClass).ref().Inputs(8U).TypeId(1U);
4873             INST(3U, Opcode::LoadClass).ref().Inputs(8U).TypeId(2U);
4874             INST(4U, Opcode::CheckCast).TypeId(1U).Inputs(0U, 2U, 8U);
4875             INST(5U, Opcode::CheckCast).TypeId(2U).Inputs(0U, 3U, 8U);
4876             INST(6U, Opcode::CheckCast).TypeId(2U).Inputs(1U, 3U, 8U);
4877             INST(7U, Opcode::Return).ref().Inputs(0U);
4878         }
4879     }
4880     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
4881     ASSERT_FALSE(GetGraph()->RunPass<ChecksElimination>());
4882     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
4883 }
4884 
BuildGraphCheckCastAfterIsInstance()4885 void ChecksEliminationTest::BuildGraphCheckCastAfterIsInstance()
4886 {
4887     GRAPH(GetGraph())
4888     {
4889         PARAMETER(0U, 0U).ref();
4890         CONSTANT(9U, nullptr);
4891         BASIC_BLOCK(2U, 3U, 4U)
4892         {
4893             INST(1U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
4894             INST(2U, Opcode::LoadClass).ref().Inputs(1U).TypeId(1U);
4895             INST(3U, Opcode::IsInstance).b().Inputs(0U, 2U).TypeId(1U);
4896             INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_EQ).Imm(0U).Inputs(3U);
4897         }
4898 
4899         BASIC_BLOCK(4U, 1U)
4900         {
4901             INST(5U, Opcode::CheckCast).TypeId(1U).Inputs(0U, 2U, 1U);
4902             INST(6U, Opcode::LoadClass).ref().Inputs(1U).TypeId(2U);
4903             INST(7U, Opcode::CheckCast).TypeId(2U).Inputs(0U, 2U, 1U);
4904             INST(8U, Opcode::Return).ref().Inputs(0U);
4905         }
4906 
4907         BASIC_BLOCK(3U, 1U)
4908         {
4909             INST(10U, Opcode::Return).ref().Inputs(9U);
4910         }
4911     }
4912 }
4913 
TEST_F(ChecksEliminationTest,CheckCastAfterIsInstance)4914 TEST_F(ChecksEliminationTest, CheckCastAfterIsInstance)
4915 {
4916     // CheckCast after successful IsInstance can be removed.
4917     BuildGraphCheckCastAfterIsInstance();
4918 
4919     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
4920     ASSERT_TRUE(INS(7U).CastToCheckCast()->GetOmitNullCheck());
4921 
4922     auto graph = CreateEmptyGraph();
4923     GRAPH(graph)
4924     {
4925         PARAMETER(0U, 0U).ref();
4926         CONSTANT(9U, nullptr);
4927         BASIC_BLOCK(2U, 3U, 4U)
4928         {
4929             INST(1U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
4930             INST(2U, Opcode::LoadClass).ref().Inputs(1U).TypeId(1U);
4931             INST(3U, Opcode::IsInstance).b().Inputs(0U, 2U).TypeId(1U);
4932             INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_EQ).Imm(0U).Inputs(3U);
4933         }
4934 
4935         BASIC_BLOCK(4U, 1U)
4936         {
4937             INST(5U, Opcode::NOP);
4938             INST(6U, Opcode::LoadClass).ref().Inputs(1U).TypeId(2U);
4939             INST(7U, Opcode::CheckCast).TypeId(2U).Inputs(0U, 2U, 1U);
4940             INST(8U, Opcode::Return).ref().Inputs(0U);
4941         }
4942 
4943         BASIC_BLOCK(3U, 1U)
4944         {
4945             INST(10U, Opcode::Return).ref().Inputs(9U);
4946         }
4947     }
4948     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
4949 }
4950 
TEST_F(ChecksEliminationTest,CheckCastAfterIsInstanceTriangleCase)4951 TEST_F(ChecksEliminationTest, CheckCastAfterIsInstanceTriangleCase)
4952 {
4953     // CheckCast cannot be removed because dominating IsInstance can be false.
4954     GRAPH(GetGraph())
4955     {
4956         PARAMETER(0U, 0U).ref();
4957         CONSTANT(9U, nullptr);
4958         BASIC_BLOCK(2U, 3U, 4U)
4959         {
4960             INST(1U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
4961             INST(2U, Opcode::LoadClass).ref().Inputs(1U).TypeId(1U);
4962             INST(3U, Opcode::IsInstance).b().Inputs(0U, 2U).TypeId(1U);
4963             INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_EQ).Imm(0U).Inputs(3U);
4964         }
4965 
4966         BASIC_BLOCK(3U, 4U) {}
4967 
4968         BASIC_BLOCK(4U, 1U)
4969         {
4970             INST(5U, Opcode::Phi).ref().Inputs({{2U, 9U}, {3U, 0U}});
4971             INST(6U, Opcode::CheckCast).TypeId(1U).Inputs(0U, 2U, 1U);
4972             INST(7U, Opcode::Return).ref().Inputs(5U);
4973         }
4974     }
4975     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
4976     ASSERT_FALSE(GetGraph()->RunPass<ChecksElimination>());
4977     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
4978 }
4979 
TEST_F(ChecksEliminationTest,CheckCastAfterIsInstanceDiamondCase)4980 TEST_F(ChecksEliminationTest, CheckCastAfterIsInstanceDiamondCase)
4981 {
4982     // CheckCast cannot be removed because dominating IsInstance can be false.
4983     GRAPH(GetGraph())
4984     {
4985         PARAMETER(0U, 0U).ref();
4986         CONSTANT(9U, nullptr);
4987         BASIC_BLOCK(2U, 3U, 4U)
4988         {
4989             INST(1U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
4990             INST(2U, Opcode::LoadClass).ref().Inputs(1U).TypeId(1U);
4991             INST(3U, Opcode::IsInstance).b().Inputs(0U, 2U).TypeId(1U);
4992             INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_EQ).Imm(0U).Inputs(3U);
4993         }
4994 
4995         BASIC_BLOCK(3U, 5U) {}
4996 
4997         BASIC_BLOCK(4U, 5U) {}
4998 
4999         BASIC_BLOCK(5U, 1U)
5000         {
5001             INST(5U, Opcode::Phi).ref().Inputs({{3U, 9U}, {4U, 0U}});
5002             INST(6U, Opcode::CheckCast).TypeId(1U).Inputs(0U, 2U, 1U);
5003             INST(7U, Opcode::Return).ref().Inputs(5U);
5004         }
5005     }
5006     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
5007     ASSERT_FALSE(GetGraph()->RunPass<ChecksElimination>());
5008     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
5009 }
5010 
BuildHoistCheckCastGraph()5011 void ChecksEliminationTest::BuildHoistCheckCastGraph()
5012 {
5013     GRAPH(GetGraph())
5014     {
5015         CONSTANT(0U, 0U);  // initial
5016         CONSTANT(1U, 1U);  // increment
5017         CONSTANT(2U, 10U);
5018         PARAMETER(3U, 0U).ref();
5019         BASIC_BLOCK(2U, 3U, 5U)
5020         {
5021             INST(21U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
5022             INST(22U, Opcode::LoadClass).ref().Inputs(21U).TypeId(1U);
5023             INST(20U, Opcode::SaveStateDeoptimize).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
5024             INST(5U, Opcode::Compare).SrcType(DataType::INT32).CC(CC_LT).b().Inputs(0U, 2U);  // 0 < 10
5025             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
5026         }
5027         BASIC_BLOCK(3U, 3U, 5U)
5028         {
5029             INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);  // i
5030             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
5031             INST(8U, Opcode::CheckCast).ref().Inputs(3U, 22U, 7U).TypeId(1U);
5032             INST(9U, Opcode::LoadObject).ref().Inputs(3U);
5033             INST(23U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U, 9U).SrcVregs({0U, 1U, 2U, 3U, 4U});
5034             INST(11U, Opcode::CheckCast).ref().Inputs(9U, 22U, 23U).TypeId(1U);
5035 
5036             INST(10U, Opcode::Add).s32().Inputs(4U, 1U);               // i++
5037             INST(13U, Opcode::Compare).CC(CC_LT).b().Inputs(10U, 2U);  // i < 10
5038             INST(14U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(13U);
5039         }
5040         BASIC_BLOCK(5U, 1U)
5041         {
5042             INST(12U, Opcode::ReturnVoid).v0id();
5043         }
5044     }
5045 }
5046 
TEST_F(ChecksEliminationTest,HoistCheckCastTest)5047 TEST_F(ChecksEliminationTest, HoistCheckCastTest)
5048 {
5049     BuildHoistCheckCastGraph();
5050     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
5051     auto graph = CreateEmptyGraph();
5052     GRAPH(graph)
5053     {
5054         CONSTANT(0U, 0U);  // initial
5055         CONSTANT(1U, 1U);  // increment
5056         CONSTANT(2U, 10U);
5057         PARAMETER(3U, 0U).ref();
5058         BASIC_BLOCK(2U, 3U, 5U)
5059         {
5060             INST(21U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
5061             INST(22U, Opcode::LoadClass).ref().Inputs(21U).TypeId(1U);
5062             INST(20U, Opcode::SaveStateDeoptimize).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
5063             INST(8U, Opcode::CheckCast).ref().Inputs(3U, 22U, 20U).TypeId(1U).SetFlag(inst_flags::CAN_DEOPTIMIZE);
5064             INST(5U, Opcode::Compare).SrcType(DataType::INT32).CC(CC_LT).b().Inputs(0U, 2U);  // 0 < 10
5065             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
5066         }
5067         BASIC_BLOCK(3U, 3U, 5U)
5068         {
5069             INST(4U, Opcode::Phi).s32().Inputs(0U, 10U);  // i
5070             INST(7U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U).SrcVregs({0U, 1U, 2U, 3U});
5071             INST(9U, Opcode::LoadObject).ref().Inputs(3U);
5072             INST(23U, Opcode::SaveState).Inputs(0U, 1U, 2U, 3U, 9U).SrcVregs({0U, 1U, 2U, 3U, 4U});
5073             INST(11U, Opcode::CheckCast).ref().Inputs(9U, 22U, 23U).TypeId(1U);
5074 
5075             INST(10U, Opcode::Add).s32().Inputs(4U, 1U);               // i++
5076             INST(13U, Opcode::Compare).CC(CC_LT).b().Inputs(10U, 2U);  // i < 10
5077             INST(14U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(13U);
5078         }
5079         BASIC_BLOCK(5U, 1U)
5080         {
5081             INST(12U, Opcode::ReturnVoid).v0id();
5082         }
5083     }
5084     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
5085 }
5086 
TEST_F(ChecksEliminationTest,NullCheckAfterIsInstance)5087 TEST_F(ChecksEliminationTest, NullCheckAfterIsInstance)
5088 {
5089     // NullCheck after successful IsInstance can be removed.
5090     GRAPH(GetGraph())
5091     {
5092         PARAMETER(0U, 0U).ref();
5093         CONSTANT(9U, nullptr);
5094         BASIC_BLOCK(2U, 3U, 4U)
5095         {
5096             INST(1U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
5097             INST(2U, Opcode::LoadClass).ref().Inputs(1U).TypeId(1U);
5098             INST(3U, Opcode::IsInstance).b().Inputs(0U, 2U).TypeId(1U);
5099             INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_EQ).Imm(0U).Inputs(3U);
5100         }
5101 
5102         BASIC_BLOCK(4U, 1U)
5103         {
5104             INST(5U, Opcode::NullCheck).ref().Inputs(0U, 1U);
5105             INST(6U, Opcode::Return).ref().Inputs(5U);
5106         }
5107 
5108         BASIC_BLOCK(3U, 1U)
5109         {
5110             INST(10U, Opcode::Return).ref().Inputs(9U);
5111         }
5112     }
5113     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
5114 
5115     auto graph = CreateEmptyGraph();
5116     GRAPH(graph)
5117     {
5118         PARAMETER(0U, 0U).ref();
5119         CONSTANT(9U, nullptr);
5120         BASIC_BLOCK(2U, 3U, 4U)
5121         {
5122             INST(1U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
5123             INST(2U, Opcode::LoadClass).ref().Inputs(1U).TypeId(1U);
5124             INST(3U, Opcode::IsInstance).b().Inputs(0U, 2U).TypeId(1U);
5125             INST(4U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_EQ).Imm(0U).Inputs(3U);
5126         }
5127 
5128         BASIC_BLOCK(4U, 1U)
5129         {
5130             INST(5U, Opcode::NOP);
5131             INST(6U, Opcode::Return).ref().Inputs(0U);
5132         }
5133 
5134         BASIC_BLOCK(3U, 1U)
5135         {
5136             INST(10U, Opcode::Return).ref().Inputs(9U);
5137         }
5138     }
5139     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), graph));
5140 }
5141 
TEST_F(ChecksEliminationTest,OmitNullCheck)5142 TEST_F(ChecksEliminationTest, OmitNullCheck)
5143 {
5144     // Check Elimination for NullCheck is applied.
5145     GRAPH(GetGraph())
5146     {
5147         PARAMETER(0U, 0U).ref();
5148         CONSTANT(1U, 10U);
5149         BASIC_BLOCK(2U, 1U)
5150         {
5151             INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
5152             INST(3U, Opcode::NullCheck).ref().Inputs(0U, 2U);
5153             INST(4U, Opcode::LoadArray).s32().Inputs(3U, 1U);
5154             INST(5U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
5155             INST(6U, Opcode::LoadClass).ref().Inputs(5U);
5156             INST(7U, Opcode::CheckCast).TypeId(1U).Inputs(0U, 6U, 5U);
5157             INST(8U, Opcode::LoadClass).ref().Inputs(5U);
5158             INST(9U, Opcode::IsInstance).TypeId(2U).b().Inputs(0U, 8U, 5U);
5159             INST(10U, Opcode::Return).b().Inputs(9U);
5160         }
5161     }
5162     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
5163     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
5164     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
5165     ASSERT_TRUE(INS(7U).CastToCheckCast()->GetOmitNullCheck());
5166     ASSERT_TRUE(INS(9U).CastToIsInstance()->GetOmitNullCheck());
5167 }
5168 
TEST_F(ChecksEliminationTest,DoNotOmitNullCheck)5169 TEST_F(ChecksEliminationTest, DoNotOmitNullCheck)
5170 {
5171     // NullCheck inside CheckCast and IsInstance cannot be omitted. NullCheck doesn't dominate them.
5172     GRAPH(GetGraph())
5173     {
5174         PARAMETER(0U, 0U).ref();
5175         CONSTANT(1U, 10U);
5176 
5177         BASIC_BLOCK(2U, 3U, 4U)
5178         {
5179             INST(2U, Opcode::Compare).b().SrcType(DataType::Type::INT64).Inputs(1U, 1U);
5180             INST(3U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(2U);
5181         }
5182 
5183         BASIC_BLOCK(3U, 5U)
5184         {
5185             INST(4U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
5186             INST(5U, Opcode::NullCheck).ref().Inputs(0U, 4U);
5187             INST(6U, Opcode::LoadArray).s32().Inputs(5U, 1U);
5188         }
5189 
5190         BASIC_BLOCK(4U, 5U)
5191         {
5192             INST(7U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
5193             INST(8U, Opcode::LoadClass).TypeId(1U).ref().Inputs(7U);
5194             INST(9U, Opcode::CheckCast).TypeId(1U).Inputs(0U, 8U, 7U);
5195             INST(10U, Opcode::LoadClass).TypeId(2U).ref().Inputs(7U);
5196             INST(11U, Opcode::IsInstance).TypeId(2U).b().Inputs(0U, 10U, 7U);
5197         }
5198 
5199         BASIC_BLOCK(5U, 1U)
5200         {
5201             INST(12U, Opcode::Phi).s32().Inputs(6U, 1U);
5202             INST(13U, Opcode::Return).s32().Inputs(12U);
5203         }
5204     }
5205     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
5206     ASSERT_FALSE(GetGraph()->RunPass<ChecksElimination>());
5207     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
5208     ASSERT_FALSE(INS(9U).CastToCheckCast()->GetOmitNullCheck());
5209     ASSERT_FALSE(INS(11U).CastToIsInstance()->GetOmitNullCheck());
5210 }
5211 
5212 // NOTE(schernykh): It's possible to remove boundschecks from this test, but BoundsAnalysis must be upgrade for
5213 // it.
TEST_F(ChecksEliminationTest,OptimizeBoundsCheckElimination)5214 TEST_F(ChecksEliminationTest, OptimizeBoundsCheckElimination)
5215 {
5216     GRAPH(GetGraph())
5217     {
5218         CONSTANT(0U, 0U);
5219         CONSTANT(14U, 1U);
5220         PARAMETER(1U, 0U).s32();
5221         PARAMETER(2U, 1U).s32();
5222         BASIC_BLOCK(2U, 6U, 3U)
5223         {
5224             INST(43U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
5225             INST(44U, Opcode::LoadAndInitClass).ref().Inputs().TypeId(68U);
5226             INST(3U, Opcode::NewArray).ref().Inputs(44U, 1U, 43U);
5227             INST(4U, Opcode::Compare).b().SrcType(DataType::Type::INT32).CC(CC_LT).Inputs(2U, 0U);
5228             INST(5U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(4U);
5229         }
5230         BASIC_BLOCK(3U, 6U, 4U)
5231         {
5232             INST(6U, Opcode::Compare).b().SrcType(DataType::Type::INT32).CC(CC_GE).Inputs(2U, 1U);
5233             INST(7U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(6U);
5234         }
5235         BASIC_BLOCK(4U, 6U, 5U)
5236         {
5237             INST(8U, Opcode::Add).s32().Inputs(2U, 14U);
5238             INST(9U, Opcode::Compare).b().SrcType(DataType::Type::INT32).CC(CC_GE).Inputs(8U, 1U);
5239             INST(10U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(9U);
5240         }
5241         BASIC_BLOCK(5U, 6U)
5242         {
5243             INST(11U, Opcode::SaveState).Inputs(0U, 1U, 2U).SrcVregs({0U, 1U, 2U});
5244             INST(12U, Opcode::BoundsCheck).s32().Inputs(1U, 8U, 11U);
5245             INST(13U, Opcode::StoreArray).s32().Inputs(3U, 8U, 0U);
5246         }
5247         BASIC_BLOCK(6U, 1U)
5248         {
5249             INST(15U, Opcode::ReturnVoid).v0id();
5250         }
5251     }
5252     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
5253     ASSERT_FALSE(GetGraph()->RunPass<ChecksElimination>());
5254     ASSERT_TRUE(GraphComparator().Compare(GetGraph(), clone));
5255 }
5256 
TEST_F(ChecksEliminationTest,BoundsCheckEqualInputs)5257 TEST_F(ChecksEliminationTest, BoundsCheckEqualInputs)
5258 {
5259     GRAPH(GetGraph())
5260     {
5261         PARAMETER(1U, 2U).s32();
5262         PARAMETER(2U, 3U).s32();
5263         CONSTANT(3U, 10U);
5264         BASIC_BLOCK(2U, 1U)
5265         {
5266             INST(4U, Opcode::SaveState).Inputs(1U, 2U).SrcVregs({1U, 2U});
5267             INST(44U, Opcode::LoadAndInitClass).ref().Inputs().TypeId(68U);
5268             INST(5U, Opcode::NewArray).ref().Inputs(44U, 3U, 4U);
5269             INST(6U, Opcode::BoundsCheck).s32().Inputs(3U, 1U, 4U);
5270             INST(7U, Opcode::StoreArray).s32().Inputs(5U, 6U, 3U);
5271 
5272             INST(14U, Opcode::SaveState).Inputs(1U, 2U).SrcVregs({1U, 2U});
5273             INST(15U, Opcode::NewArray).ref().Inputs(44U, 2U, 14U);
5274             INST(16U, Opcode::BoundsCheck).s32().Inputs(2U, 3U, 14U);
5275             INST(17U, Opcode::StoreArray).s32().Inputs(15U, 16U, 3U);
5276 
5277             INST(18U, Opcode::ReturnVoid).v0id();
5278         }
5279     }
5280     auto clone = GraphCloner(GetGraph(), GetGraph()->GetAllocator(), GetGraph()->GetLocalAllocator()).CloneGraph();
5281     ASSERT_FALSE(GetGraph()->RunPass<ChecksElimination>());
5282     ASSERT_TRUE(GraphComparator().Compare(clone, GetGraph()));
5283 }
5284 
5285 // dominated checks
TEST_F(ChecksEliminationTest,AddSubOverflowCheckDom)5286 TEST_F(ChecksEliminationTest, AddSubOverflowCheckDom)
5287 {
5288     GRAPH(GetGraph())
5289     {
5290         PARAMETER(0U, 0U).s32();
5291         PARAMETER(1U, 1U).s32();
5292         BASIC_BLOCK(2U, -1L)
5293         {
5294             INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5295             INST(3U, Opcode::AddOverflowCheck).s32().Inputs(0U, 1U, 2U);  // main
5296 
5297             INST(4U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5298             INST(5U, Opcode::AddOverflowCheck).s32().Inputs(0U, 1U, 4U);  // redundant
5299 
5300             INST(6U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5301             INST(7U, Opcode::AddOverflowCheck).s32().Inputs(1U, 0U, 6U);  // redundant, swapped inputs
5302 
5303             INST(8U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5304             INST(9U, Opcode::SubOverflowCheck).s32().Inputs(0U, 1U, 8U);  // main
5305 
5306             INST(10U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5307             INST(11U, Opcode::SubOverflowCheck).s32().Inputs(0U, 1U, 10U);  // redundant
5308 
5309             INST(12U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5310             INST(13U, Opcode::SubOverflowCheck).s32().Inputs(1U, 0U, 12U);  // not redundant, swapped inputs
5311 
5312             INST(14U, Opcode::ReturnVoid).v0id();
5313         }
5314     }
5315     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
5316     ASSERT_TRUE(GetGraph()->RunPass<Cleanup>());
5317     auto graph = CreateEmptyGraph();
5318     GRAPH(graph)
5319     {
5320         PARAMETER(0U, 0U).s32();
5321         PARAMETER(1U, 1U).s32();
5322         BASIC_BLOCK(2U, -1L)
5323         {
5324             INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5325             INST(3U, Opcode::AddOverflowCheck).s32().Inputs(0U, 1U, 2U);  // main
5326 
5327             INST(8U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5328             INST(9U, Opcode::SubOverflowCheck).s32().Inputs(0U, 1U, 8U);  // main
5329 
5330             INST(12U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5331             INST(13U, Opcode::SubOverflowCheck).s32().Inputs(1U, 0U, 12U);  // not redundant, swapped inputs
5332 
5333             INST(14U, Opcode::ReturnVoid).v0id();
5334         }
5335     }
5336     ASSERT_TRUE(GraphComparator().Compare(graph, GetGraph()));
5337 }
5338 
BuildGraphOverflowCheckOptimize()5339 void ChecksEliminationTest::BuildGraphOverflowCheckOptimize()
5340 {
5341     GRAPH(GetGraph())
5342     {
5343         PARAMETER(0U, 0U).s32();
5344         PARAMETER(1U, 1U).s32();
5345         CONSTANT(6U, 6U);
5346         CONSTANT(1000U, 0U);
5347         CONSTANT(13U, INT32_MAX);
5348         CONSTANT(14U, INT32_MIN);
5349         BASIC_BLOCK(2U, 3U, 4U)
5350         {
5351             INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5352             INST(3U, Opcode::AddOverflowCheck).s32().Inputs(0U, 1U, 2U);  // maybe overflow
5353 
5354             INST(4U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5355             INST(5U, Opcode::SubOverflowCheck).s32().Inputs(0U, 1U, 4U);  // maybe overflow
5356 
5357             INST(20U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5358             INST(30U, Opcode::AddOverflowCheck).s32().Inputs(0U, 6U, 20U);  // maybe overflow
5359 
5360             INST(40U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5361             INST(50U, Opcode::SubOverflowCheck).s32().Inputs(0U, 6U, 40U);  // maybe overflow
5362 
5363             INST(7U, Opcode::Div).s32().Inputs(0U, 6U);
5364             INST(8U, Opcode::Div).s32().Inputs(1U, 6U);
5365 
5366             INST(9U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5367             INST(10U, Opcode::AddOverflowCheck).s32().Inputs(7U, 8U, 9U);  // can't overflow
5368 
5369             INST(11U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5370             INST(12U, Opcode::SubOverflowCheck).s32().Inputs(7U, 8U, 11U);  // can't overflow
5371 
5372             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(1000U);
5373         }
5374         BASIC_BLOCK(3U, 5U)
5375         {
5376             INST(16U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5377             INST(17U, Opcode::AddOverflowCheck).s32().Inputs(13U, 6U, 16U);  // must overflow
5378         }
5379         BASIC_BLOCK(4U, 5U)
5380         {
5381             INST(18U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5382             INST(19U, Opcode::SubOverflowCheck).s32().Inputs(14U, 6U, 18U);  // must overflow
5383         }
5384         BASIC_BLOCK(5U, -1L)
5385         {
5386             INST(100U, Opcode::ReturnVoid).v0id();
5387         }
5388     }
5389 }
5390 
TEST_F(ChecksEliminationTest,OverflowCheckOptimize)5391 TEST_F(ChecksEliminationTest, OverflowCheckOptimize)
5392 {
5393     BuildGraphOverflowCheckOptimize();
5394     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
5395     auto graph = CreateEmptyGraph();
5396     GRAPH(graph)
5397     {
5398         PARAMETER(0U, 0U).s32();
5399         PARAMETER(1U, 1U).s32();
5400         CONSTANT(6U, 6U);
5401         CONSTANT(1000U, 0U);
5402         CONSTANT(13U, INT32_MAX);
5403         CONSTANT(14U, INT32_MIN);
5404         BASIC_BLOCK(2U, 3U, 4U)
5405         {
5406             INST(2U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5407             INST(3U, Opcode::AddOverflowCheck).s32().Inputs(0U, 1U, 2U);  // maybe overflow
5408 
5409             INST(4U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5410             INST(5U, Opcode::SubOverflowCheck).s32().Inputs(0U, 1U, 4U);  // maybe overflow
5411 
5412             INST(20U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5413             INST(30U, Opcode::AddOverflowCheck).s32().Inputs(0U, 6U, 20U);  // maybe overflow
5414 
5415             INST(40U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5416             INST(50U, Opcode::SubOverflowCheck).s32().Inputs(0U, 6U, 40U);  // maybe overflow
5417 
5418             INST(7U, Opcode::Div).s32().Inputs(0U, 6U);
5419             INST(8U, Opcode::Div).s32().Inputs(1U, 6U);
5420 
5421             INST(9U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5422             INST(10U, Opcode::Add).s32().Inputs(7U, 8U);
5423 
5424             INST(11U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5425             INST(12U, Opcode::Sub).s32().Inputs(7U, 8U);
5426 
5427             INST(15U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(1000U);
5428         }
5429         BASIC_BLOCK(3U, -1L)
5430         {
5431             INST(16U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5432             INST(17U, Opcode::Deoptimize).DeoptimizeType(DeoptimizeType::OVERFLOW).Inputs(16U);  // must overflow
5433         }
5434         BASIC_BLOCK(4U, -1L)
5435         {
5436             INST(18U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({1U, 2U});
5437             INST(19U, Opcode::Deoptimize).DeoptimizeType(DeoptimizeType::OVERFLOW).Inputs(18U);  // must overflow
5438         }
5439     }
5440     ASSERT_TRUE(GraphComparator().Compare(graph, GetGraph()));
5441 }
5442 
TEST_F(ChecksEliminationTest,LoopWithOverflowCheck)5443 TEST_F(ChecksEliminationTest, LoopWithOverflowCheck)
5444 {
5445     GRAPH(GetGraph())
5446     {
5447         PARAMETER(0U, 0U).s32();
5448         PARAMETER(1U, 1U).s32();
5449         CONSTANT(2U, 0U);
5450         BASIC_BLOCK(2U, 3U)
5451         {
5452             INST(3U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
5453         }
5454         BASIC_BLOCK(3U, 3U, 4U)
5455         {
5456             INST(4U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
5457             INST(5U, Opcode::AddOverflowCheck).s32().Inputs(0U, 1U, 4U);
5458             INST(6U, Opcode::SubOverflowCheck).s32().Inputs(0U, 1U, 4U);
5459             INST(7U, Opcode::IfImm).SrcType(DataType::BOOL).Inputs(2U).Imm(0U);
5460         }
5461         BASIC_BLOCK(4U, 1U)
5462         {
5463             INST(8U, Opcode::ReturnVoid).v0id();
5464         }
5465     }
5466     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
5467     auto graph = CreateEmptyGraph();
5468     GRAPH(graph)
5469     {
5470         PARAMETER(0U, 0U).s32();
5471         PARAMETER(1U, 1U).s32();
5472         CONSTANT(2U, 0U);
5473         BASIC_BLOCK(2U, 3U)
5474         {
5475             INST(3U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
5476             INST(5U, Opcode::SubOverflowCheck).s32().Inputs(0U, 1U, 3U);
5477             INST(6U, Opcode::AddOverflowCheck).s32().Inputs(0U, 1U, 3U);
5478         }
5479         BASIC_BLOCK(3U, 3U, 4U)
5480         {
5481             INST(4U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
5482             INST(7U, Opcode::IfImm).SrcType(DataType::BOOL).Inputs(2U).Imm(0U);
5483         }
5484         BASIC_BLOCK(4U, 1U)
5485         {
5486             INST(8U, Opcode::ReturnVoid).v0id();
5487         }
5488     }
5489     ASSERT_TRUE(GraphComparator().Compare(graph, GetGraph()));
5490 }
5491 
TEST_F(ChecksEliminationTest,LoopWithAddOverflowCheck)5492 TEST_F(ChecksEliminationTest, LoopWithAddOverflowCheck)
5493 {
5494     GRAPH(GetGraph())
5495     {
5496         PARAMETER(0U, 0U).s32();
5497         CONSTANT(1U, 1U);
5498         CONSTANT(10U, 10U);
5499 
5500         BASIC_BLOCK(2U, 3U, 4U)
5501         {
5502             INST(2U, Opcode::Phi).s32().Inputs(1U, 4U);
5503             INST(6U, Opcode::Compare).b().Inputs(2U, 10U).CC(CC_LT);
5504             INST(5U, Opcode::IfImm).SrcType(DataType::BOOL).Inputs(6U).Imm(0U).CC(CC_NE);
5505         }
5506         BASIC_BLOCK(3U, 2U)
5507         {
5508             INST(3U, Opcode::SaveState).Inputs(0U, 1U, 10U).SrcVregs({0U, 1U, 10U});
5509             INST(4U, Opcode::AddOverflowCheck).s32().Inputs(2U, 1U, 3U);  // can't be overflow
5510         }
5511         BASIC_BLOCK(4U, 1U)
5512         {
5513             INST(7U, Opcode::Return).s32().Inputs(2U);
5514         }
5515     }
5516     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
5517     auto graph = CreateEmptyGraph();
5518     GRAPH(graph)
5519     {
5520         PARAMETER(0U, 0U).s32();
5521         CONSTANT(1U, 1U);
5522         CONSTANT(10U, 10U);
5523 
5524         BASIC_BLOCK(2U, 3U, 4U)
5525         {
5526             INST(2U, Opcode::Phi).s32().Inputs(1U, 4U);
5527             INST(6U, Opcode::Compare).b().Inputs(2U, 10U).CC(CC_LT);
5528             INST(5U, Opcode::IfImm).SrcType(DataType::BOOL).Inputs(6U).Imm(0U).CC(CC_NE);
5529         }
5530         BASIC_BLOCK(3U, 2U)
5531         {
5532             INST(3U, Opcode::SaveState).Inputs(0U, 1U, 10U).SrcVregs({0U, 1U, 10U});
5533             INST(4U, Opcode::Add).s32().Inputs(2U, 1U);
5534         }
5535         BASIC_BLOCK(4U, 1U)
5536         {
5537             INST(7U, Opcode::Return).s32().Inputs(2U);
5538         }
5539     }
5540     ASSERT_TRUE(GraphComparator().Compare(graph, GetGraph()));
5541 }
5542 
TEST_F(ChecksEliminationTest,LoopWithSubOverflowCheck)5543 TEST_F(ChecksEliminationTest, LoopWithSubOverflowCheck)
5544 {
5545     GRAPH(GetGraph())
5546     {
5547         PARAMETER(0U, 0U).s32();
5548         CONSTANT(1U, 1U);
5549         CONSTANT(10U, 10U);
5550 
5551         BASIC_BLOCK(2U, 3U, 4U)
5552         {
5553             INST(2U, Opcode::Phi).s32().Inputs(10U, 4U);
5554             INST(6U, Opcode::Compare).b().Inputs(2U, 1U).CC(CC_GT);
5555             INST(5U, Opcode::IfImm).SrcType(DataType::BOOL).Inputs(6U).Imm(0U).CC(CC_NE);
5556         }
5557         BASIC_BLOCK(3U, 2U)
5558         {
5559             INST(3U, Opcode::SaveState).Inputs(0U, 1U, 10U).SrcVregs({0U, 1U, 10U});
5560             INST(4U, Opcode::SubOverflowCheck).s32().Inputs(2U, 1U, 3U);  // can't be overflow
5561         }
5562         BASIC_BLOCK(4U, 1U)
5563         {
5564             INST(7U, Opcode::Return).s32().Inputs(2U);
5565         }
5566     }
5567     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
5568     auto graph = CreateEmptyGraph();
5569     GRAPH(graph)
5570     {
5571         PARAMETER(0U, 0U).s32();
5572         CONSTANT(1U, 1U);
5573         CONSTANT(10U, 10U);
5574 
5575         BASIC_BLOCK(2U, 3U, 4U)
5576         {
5577             INST(2U, Opcode::Phi).s32().Inputs(10U, 4U);
5578             INST(6U, Opcode::Compare).b().Inputs(2U, 1U).CC(CC_GT);
5579             INST(5U, Opcode::IfImm).SrcType(DataType::BOOL).Inputs(6U).Imm(0U).CC(CC_NE);
5580         }
5581         BASIC_BLOCK(3U, 2U)
5582         {
5583             INST(3U, Opcode::SaveState).Inputs(0U, 1U, 10U).SrcVregs({0U, 1U, 10U});
5584             INST(4U, Opcode::Sub).s32().Inputs(2U, 1U);
5585         }
5586         BASIC_BLOCK(4U, 1U)
5587         {
5588             INST(7U, Opcode::Return).s32().Inputs(2U);
5589         }
5590     }
5591     ASSERT_TRUE(GraphComparator().Compare(graph, GetGraph()));
5592 }
5593 
TEST_F(ChecksEliminationTest,AndWithAddOverFlowCheck)5594 TEST_F(ChecksEliminationTest, AndWithAddOverFlowCheck)
5595 {
5596     GRAPH(GetGraph())
5597     {
5598         PARAMETER(0U, 0U).s64();
5599         PARAMETER(1U, 1U).s64();
5600         CONSTANT(2U, 0x3U);
5601         BASIC_BLOCK(2U, -1L)
5602         {
5603             INST(3U, Opcode::And).s32().Inputs(0U, 2U);
5604             INST(4U, Opcode::And).s32().Inputs(1U, 2U);
5605             INST(5U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
5606             INST(6U, Opcode::AddOverflowCheck).s32().Inputs(3U, 4U, 5U);
5607             INST(7U, Opcode::Return).s32().Inputs(6U);
5608         }
5609     }
5610     ASSERT_TRUE(GetGraph()->RunPass<ChecksElimination>());
5611     auto graph = CreateEmptyGraph();
5612     GRAPH(graph)
5613     {
5614         PARAMETER(0U, 0U).s64();
5615         PARAMETER(1U, 1U).s64();
5616         CONSTANT(2U, 0x3U);
5617         BASIC_BLOCK(2U, -1L)
5618         {
5619             INST(3U, Opcode::And).s32().Inputs(0U, 2U);
5620             INST(4U, Opcode::And).s32().Inputs(1U, 2U);
5621             INST(5U, Opcode::SaveState).Inputs(0U, 1U).SrcVregs({0U, 1U});
5622             INST(6U, Opcode::Add).s32().Inputs(3U, 4U);
5623             INST(7U, Opcode::Return).s32().Inputs(6U);
5624         }
5625     }
5626     ASSERT_TRUE(GraphComparator().Compare(graph, GetGraph()));
5627 }
5628 
5629 // Must Deoptimize
TEST_F(ChecksEliminationTest,NegOverflowAndZeroCheck1)5630 TEST_F(ChecksEliminationTest, NegOverflowAndZeroCheck1)
5631 {
5632     for (auto cnst : {0, INT32_MIN}) {
5633         auto graph1 = CreateEmptyGraph();
5634         GRAPH(graph1)
5635         {
5636             CONSTANT(0U, cnst);
5637             BASIC_BLOCK(2U, -1L)
5638             {
5639                 INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
5640                 INST(6U, Opcode::NegOverflowAndZeroCheck).s32().Inputs(0U, 5U);
5641                 INST(7U, Opcode::Return).s32().Inputs(6U);
5642             }
5643         }
5644         ASSERT_TRUE(graph1->RunPass<ChecksElimination>());
5645         auto graph2 = CreateEmptyGraph();
5646         GRAPH(graph2)
5647         {
5648             CONSTANT(0U, cnst);
5649             BASIC_BLOCK(2U, -1L)
5650             {
5651                 INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
5652                 INST(6U, Opcode::Deoptimize).DeoptimizeType(DeoptimizeType::OVERFLOW).Inputs(5U);
5653             }
5654         }
5655         ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
5656     }
5657 }
5658 
5659 // Remove dominated check
TEST_F(ChecksEliminationTest,NegOverflowAndZeroCheck2)5660 TEST_F(ChecksEliminationTest, NegOverflowAndZeroCheck2)
5661 {
5662     auto graph1 = CreateEmptyGraph();
5663     GRAPH(graph1)
5664     {
5665         PARAMETER(0U, 0U).u32();
5666         BASIC_BLOCK(2U, -1L)
5667         {
5668             INST(3U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
5669             INST(4U, Opcode::NegOverflowAndZeroCheck).s32().Inputs(0U, 3U);
5670             INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
5671             INST(6U, Opcode::NegOverflowAndZeroCheck).s32().Inputs(0U, 5U);
5672             INST(7U, Opcode::CallStatic).s32().InputsAutoType(4U, 6U, 3U);
5673             INST(8U, Opcode::Return).s32().Inputs(7U);
5674         }
5675     }
5676     ASSERT_TRUE(graph1->RunPass<ChecksElimination>());
5677     ASSERT_TRUE(graph1->RunPass<Cleanup>());
5678     auto graph2 = CreateEmptyGraph();
5679     GRAPH(graph2)
5680     {
5681         PARAMETER(0U, 0U).u32();
5682         BASIC_BLOCK(2U, -1L)
5683         {
5684             INST(3U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
5685             INST(4U, Opcode::NegOverflowAndZeroCheck).s32().Inputs(0U, 3U);
5686             INST(7U, Opcode::CallStatic).s32().InputsAutoType(4U, 4U, 3U);
5687             INST(8U, Opcode::Return).s32().Inputs(7U);
5688         }
5689     }
5690     ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
5691 }
5692 
5693 // Replace by Neg
TEST_F(ChecksEliminationTest,NegOverflowAndZeroCheck3)5694 TEST_F(ChecksEliminationTest, NegOverflowAndZeroCheck3)
5695 {
5696     auto graph1 = CreateEmptyGraph();
5697     GRAPH(graph1)
5698     {
5699         CONSTANT(0U, 1U);
5700         BASIC_BLOCK(2U, -1L)
5701         {
5702             INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
5703             INST(6U, Opcode::NegOverflowAndZeroCheck).s32().Inputs(0U, 5U);
5704             INST(7U, Opcode::Return).s32().Inputs(6U);
5705         }
5706     }
5707     ASSERT_TRUE(graph1->RunPass<ChecksElimination>());
5708     auto graph2 = CreateEmptyGraph();
5709     GRAPH(graph2)
5710     {
5711         CONSTANT(0U, 1U);
5712         BASIC_BLOCK(2U, -1L)
5713         {
5714             INST(5U, Opcode::SaveState).Inputs(0U).SrcVregs({0U});
5715             INST(6U, Opcode::Neg).s32().Inputs(0U);
5716             INST(7U, Opcode::Return).s32().Inputs(6U);
5717         }
5718     }
5719     ASSERT_TRUE(GraphComparator().Compare(graph1, graph2));
5720 }
5721 
TEST_F(ChecksEliminationTest,OsrMode)5722 TEST_F(ChecksEliminationTest, OsrMode)
5723 {
5724     auto osrGraph = CreateOsrGraph();
5725     GRAPH(osrGraph)
5726     {
5727         PARAMETER(0U, 0U).u32();
5728         PARAMETER(42U, 1U).ref();
5729         CONSTANT(1U, 0U);
5730         CONSTANT(2U, 1U);
5731 
5732         BASIC_BLOCK(2U, 3U)
5733         {
5734             INST(15U, Opcode::SaveState).Inputs(42U).SrcVregs({42U});
5735             INST(16U, Opcode::NullCheck).ref().Inputs(42U, 15U);
5736             INST(17U, Opcode::LenArray).s32().Inputs(16U);
5737         }
5738         BASIC_BLOCK(3U, 5U, 4U)
5739         {
5740             INST(3U, Opcode::Phi).s32().Inputs(0U, 7U);
5741             INST(4U, Opcode::SaveStateOsr).Inputs(3U, 42U).SrcVregs({1U, 42U});
5742             INST(5U, Opcode::Compare).b().SrcType(DataType::Type::INT32).CC(CC_LE).Inputs(3U, 1U);
5743             INST(6U, Opcode::IfImm).SrcType(DataType::BOOL).CC(CC_NE).Imm(0U).Inputs(5U);
5744         }
5745         BASIC_BLOCK(4U, 3U)
5746         {
5747             INST(7U, Opcode::Sub).s32().Inputs(3U, 2U);
5748             INST(8U, Opcode::SaveState).Inputs(42U).SrcVregs({42U});
5749             INST(9U, Opcode::NullCheck).ref().Inputs(42U, 8U);
5750             INST(10U, Opcode::LenArray).s32().Inputs(9U);
5751         }
5752         BASIC_BLOCK(5U, 6U)
5753         {
5754             INST(11U, Opcode::SaveState).Inputs(42U).SrcVregs({42U});
5755             INST(12U, Opcode::NullCheck).ref().Inputs(42U, 11U);
5756             INST(13U, Opcode::LenArray).s32().Inputs(12U);
5757         }
5758         BASIC_BLOCK(6U, -1L)
5759         {
5760             INST(14U, Opcode::Return).u32().Inputs(3U);
5761         }
5762     }
5763     ASSERT_FALSE(osrGraph->RunPass<ChecksElimination>());
5764 }
5765 
5766 // NOLINTEND(readability-magic-numbers)
5767 
5768 }  // namespace ark::compiler
5769