1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2014 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker *
4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker *
8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker *
10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker */
16*795d594fSAndroid Build Coastguard Worker
17*795d594fSAndroid Build Coastguard Worker #include "bounds_check_elimination.h"
18*795d594fSAndroid Build Coastguard Worker
19*795d594fSAndroid Build Coastguard Worker #include "base/arena_allocator.h"
20*795d594fSAndroid Build Coastguard Worker #include "base/macros.h"
21*795d594fSAndroid Build Coastguard Worker #include "builder.h"
22*795d594fSAndroid Build Coastguard Worker #include "gvn.h"
23*795d594fSAndroid Build Coastguard Worker #include "induction_var_analysis.h"
24*795d594fSAndroid Build Coastguard Worker #include "instruction_simplifier.h"
25*795d594fSAndroid Build Coastguard Worker #include "nodes.h"
26*795d594fSAndroid Build Coastguard Worker #include "optimizing_unit_test.h"
27*795d594fSAndroid Build Coastguard Worker #include "side_effects_analysis.h"
28*795d594fSAndroid Build Coastguard Worker
29*795d594fSAndroid Build Coastguard Worker #include "gtest/gtest.h"
30*795d594fSAndroid Build Coastguard Worker
31*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
32*795d594fSAndroid Build Coastguard Worker
33*795d594fSAndroid Build Coastguard Worker /**
34*795d594fSAndroid Build Coastguard Worker * Fixture class for the BoundsCheckElimination tests.
35*795d594fSAndroid Build Coastguard Worker */
36*795d594fSAndroid Build Coastguard Worker class BoundsCheckEliminationTest : public OptimizingUnitTest {
37*795d594fSAndroid Build Coastguard Worker public:
RunBCE()38*795d594fSAndroid Build Coastguard Worker void RunBCE() {
39*795d594fSAndroid Build Coastguard Worker graph_->SetHasBoundsChecks(true);
40*795d594fSAndroid Build Coastguard Worker graph_->BuildDominatorTree();
41*795d594fSAndroid Build Coastguard Worker
42*795d594fSAndroid Build Coastguard Worker InstructionSimplifier(graph_, /* codegen= */ nullptr).Run();
43*795d594fSAndroid Build Coastguard Worker
44*795d594fSAndroid Build Coastguard Worker SideEffectsAnalysis side_effects(graph_);
45*795d594fSAndroid Build Coastguard Worker side_effects.Run();
46*795d594fSAndroid Build Coastguard Worker
47*795d594fSAndroid Build Coastguard Worker GVNOptimization(graph_, side_effects).Run();
48*795d594fSAndroid Build Coastguard Worker
49*795d594fSAndroid Build Coastguard Worker HInductionVarAnalysis induction(graph_);
50*795d594fSAndroid Build Coastguard Worker induction.Run();
51*795d594fSAndroid Build Coastguard Worker
52*795d594fSAndroid Build Coastguard Worker BoundsCheckElimination(graph_, side_effects, &induction).Run();
53*795d594fSAndroid Build Coastguard Worker }
54*795d594fSAndroid Build Coastguard Worker
55*795d594fSAndroid Build Coastguard Worker HInstruction* BuildSSAGraph1(int initial, int increment, IfCondition cond = kCondGE);
56*795d594fSAndroid Build Coastguard Worker HInstruction* BuildSSAGraph2(int initial, int increment = -1, IfCondition cond = kCondLE);
57*795d594fSAndroid Build Coastguard Worker HInstruction* BuildSSAGraph3(int initial, int increment, IfCondition cond);
58*795d594fSAndroid Build Coastguard Worker HInstruction* BuildSSAGraph4(int initial, IfCondition cond = kCondGE);
59*795d594fSAndroid Build Coastguard Worker };
60*795d594fSAndroid Build Coastguard Worker
61*795d594fSAndroid Build Coastguard Worker
62*795d594fSAndroid Build Coastguard Worker // if (i < 0) { array[i] = 1; // Can't eliminate. }
63*795d594fSAndroid Build Coastguard Worker // else if (i >= array.length) { array[i] = 1; // Can't eliminate. }
64*795d594fSAndroid Build Coastguard Worker // else { array[i] = 1; // Can eliminate. }
TEST_F(BoundsCheckEliminationTest,NarrowingRangeArrayBoundsElimination)65*795d594fSAndroid Build Coastguard Worker TEST_F(BoundsCheckEliminationTest, NarrowingRangeArrayBoundsElimination) {
66*795d594fSAndroid Build Coastguard Worker CreateGraph();
67*795d594fSAndroid Build Coastguard Worker HBasicBlock* entry = AddNewBlock();
68*795d594fSAndroid Build Coastguard Worker graph_->SetEntryBlock(entry);
69*795d594fSAndroid Build Coastguard Worker HInstruction* parameter1 = MakeParam(DataType::Type::kReference); // array
70*795d594fSAndroid Build Coastguard Worker HInstruction* parameter2 = MakeParam(DataType::Type::kInt32); // i
71*795d594fSAndroid Build Coastguard Worker
72*795d594fSAndroid Build Coastguard Worker HInstruction* constant_1 = graph_->GetIntConstant(1);
73*795d594fSAndroid Build Coastguard Worker HInstruction* constant_0 = graph_->GetIntConstant(0);
74*795d594fSAndroid Build Coastguard Worker
75*795d594fSAndroid Build Coastguard Worker HBasicBlock* block1 = AddNewBlock();
76*795d594fSAndroid Build Coastguard Worker HInstruction* cmp = MakeCondition(block1, kCondGE, parameter2, constant_0);
77*795d594fSAndroid Build Coastguard Worker MakeIf(block1, cmp);
78*795d594fSAndroid Build Coastguard Worker entry->AddSuccessor(block1);
79*795d594fSAndroid Build Coastguard Worker
80*795d594fSAndroid Build Coastguard Worker HBasicBlock* block2 = AddNewBlock();
81*795d594fSAndroid Build Coastguard Worker HNullCheck* null_check = MakeNullCheck(block2, parameter1);
82*795d594fSAndroid Build Coastguard Worker HArrayLength* array_length = MakeArrayLength(block2, null_check);
83*795d594fSAndroid Build Coastguard Worker HBoundsCheck* bounds_check2 = MakeBoundsCheck(block2, parameter2, array_length);
84*795d594fSAndroid Build Coastguard Worker MakeArraySet(block2, null_check, bounds_check2, constant_1, DataType::Type::kInt32);
85*795d594fSAndroid Build Coastguard Worker
86*795d594fSAndroid Build Coastguard Worker HBasicBlock* block3 = AddNewBlock();
87*795d594fSAndroid Build Coastguard Worker null_check = MakeNullCheck(block3, parameter1);
88*795d594fSAndroid Build Coastguard Worker array_length = MakeArrayLength(block3, null_check);
89*795d594fSAndroid Build Coastguard Worker cmp = MakeCondition(block3, kCondLT, parameter2, array_length);
90*795d594fSAndroid Build Coastguard Worker MakeIf(block3, cmp);
91*795d594fSAndroid Build Coastguard Worker
92*795d594fSAndroid Build Coastguard Worker HBasicBlock* block4 = AddNewBlock();
93*795d594fSAndroid Build Coastguard Worker null_check = MakeNullCheck(block4, parameter1);
94*795d594fSAndroid Build Coastguard Worker array_length = MakeArrayLength(block4, null_check);
95*795d594fSAndroid Build Coastguard Worker HBoundsCheck* bounds_check4 = MakeBoundsCheck(block4, parameter2, array_length);
96*795d594fSAndroid Build Coastguard Worker MakeArraySet(block4, null_check, bounds_check4, constant_1, DataType::Type::kInt32);
97*795d594fSAndroid Build Coastguard Worker
98*795d594fSAndroid Build Coastguard Worker HBasicBlock* block5 = AddNewBlock();
99*795d594fSAndroid Build Coastguard Worker null_check = MakeNullCheck(block5, parameter1);
100*795d594fSAndroid Build Coastguard Worker array_length = MakeArrayLength(block5, null_check);
101*795d594fSAndroid Build Coastguard Worker HBoundsCheck* bounds_check5 = MakeBoundsCheck(block5, parameter2, array_length);
102*795d594fSAndroid Build Coastguard Worker MakeArraySet(block5, null_check, bounds_check5, constant_1, DataType::Type::kInt32);
103*795d594fSAndroid Build Coastguard Worker
104*795d594fSAndroid Build Coastguard Worker HBasicBlock* exit = AddNewBlock();
105*795d594fSAndroid Build Coastguard Worker block2->AddSuccessor(exit);
106*795d594fSAndroid Build Coastguard Worker block4->AddSuccessor(exit);
107*795d594fSAndroid Build Coastguard Worker block5->AddSuccessor(exit);
108*795d594fSAndroid Build Coastguard Worker MakeExit(exit);
109*795d594fSAndroid Build Coastguard Worker
110*795d594fSAndroid Build Coastguard Worker block1->AddSuccessor(block3); // True successor
111*795d594fSAndroid Build Coastguard Worker block1->AddSuccessor(block2); // False successor
112*795d594fSAndroid Build Coastguard Worker
113*795d594fSAndroid Build Coastguard Worker block3->AddSuccessor(block5); // True successor
114*795d594fSAndroid Build Coastguard Worker block3->AddSuccessor(block4); // False successor
115*795d594fSAndroid Build Coastguard Worker
116*795d594fSAndroid Build Coastguard Worker RunBCE();
117*795d594fSAndroid Build Coastguard Worker
118*795d594fSAndroid Build Coastguard Worker ASSERT_FALSE(IsRemoved(bounds_check2));
119*795d594fSAndroid Build Coastguard Worker ASSERT_FALSE(IsRemoved(bounds_check4));
120*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(IsRemoved(bounds_check5));
121*795d594fSAndroid Build Coastguard Worker }
122*795d594fSAndroid Build Coastguard Worker
123*795d594fSAndroid Build Coastguard Worker // if (i > 0) {
124*795d594fSAndroid Build Coastguard Worker // // Positive number plus MAX_INT will overflow and be negative.
125*795d594fSAndroid Build Coastguard Worker // int j = i + Integer.MAX_VALUE;
126*795d594fSAndroid Build Coastguard Worker // if (j < array.length) array[j] = 1; // Can't eliminate.
127*795d594fSAndroid Build Coastguard Worker // }
TEST_F(BoundsCheckEliminationTest,OverflowArrayBoundsElimination)128*795d594fSAndroid Build Coastguard Worker TEST_F(BoundsCheckEliminationTest, OverflowArrayBoundsElimination) {
129*795d594fSAndroid Build Coastguard Worker CreateGraph();
130*795d594fSAndroid Build Coastguard Worker HBasicBlock* entry = AddNewBlock();
131*795d594fSAndroid Build Coastguard Worker graph_->SetEntryBlock(entry);
132*795d594fSAndroid Build Coastguard Worker HInstruction* parameter1 = MakeParam(DataType::Type::kReference); // array
133*795d594fSAndroid Build Coastguard Worker HInstruction* parameter2 = MakeParam(DataType::Type::kInt32); // i
134*795d594fSAndroid Build Coastguard Worker
135*795d594fSAndroid Build Coastguard Worker HInstruction* constant_1 = graph_->GetIntConstant(1);
136*795d594fSAndroid Build Coastguard Worker HInstruction* constant_0 = graph_->GetIntConstant(0);
137*795d594fSAndroid Build Coastguard Worker HInstruction* constant_max_int = graph_->GetIntConstant(INT_MAX);
138*795d594fSAndroid Build Coastguard Worker
139*795d594fSAndroid Build Coastguard Worker HBasicBlock* block1 = AddNewBlock();
140*795d594fSAndroid Build Coastguard Worker HInstruction* cmp = MakeCondition(block1, kCondLE, parameter2, constant_0);
141*795d594fSAndroid Build Coastguard Worker MakeIf(block1, cmp);
142*795d594fSAndroid Build Coastguard Worker entry->AddSuccessor(block1);
143*795d594fSAndroid Build Coastguard Worker
144*795d594fSAndroid Build Coastguard Worker HBasicBlock* block2 = AddNewBlock();
145*795d594fSAndroid Build Coastguard Worker HInstruction* add = MakeBinOp<HAdd>(block2, DataType::Type::kInt32, parameter2, constant_max_int);
146*795d594fSAndroid Build Coastguard Worker HNullCheck* null_check = MakeNullCheck(block2, parameter1);
147*795d594fSAndroid Build Coastguard Worker HArrayLength* array_length = MakeArrayLength(block2, null_check);
148*795d594fSAndroid Build Coastguard Worker HInstruction* cmp2 = MakeCondition(block2, kCondGE, add, array_length);
149*795d594fSAndroid Build Coastguard Worker MakeIf(block2, cmp2);
150*795d594fSAndroid Build Coastguard Worker
151*795d594fSAndroid Build Coastguard Worker HBasicBlock* block3 = AddNewBlock();
152*795d594fSAndroid Build Coastguard Worker HBoundsCheck* bounds_check = MakeBoundsCheck(block3, add, array_length);
153*795d594fSAndroid Build Coastguard Worker MakeArraySet(block3, null_check, bounds_check, constant_1, DataType::Type::kInt32);
154*795d594fSAndroid Build Coastguard Worker
155*795d594fSAndroid Build Coastguard Worker HBasicBlock* exit = AddNewBlock();
156*795d594fSAndroid Build Coastguard Worker MakeExit(exit);
157*795d594fSAndroid Build Coastguard Worker block1->AddSuccessor(exit); // true successor
158*795d594fSAndroid Build Coastguard Worker block1->AddSuccessor(block2); // false successor
159*795d594fSAndroid Build Coastguard Worker block2->AddSuccessor(exit); // true successor
160*795d594fSAndroid Build Coastguard Worker block2->AddSuccessor(block3); // false successor
161*795d594fSAndroid Build Coastguard Worker block3->AddSuccessor(exit);
162*795d594fSAndroid Build Coastguard Worker
163*795d594fSAndroid Build Coastguard Worker RunBCE();
164*795d594fSAndroid Build Coastguard Worker
165*795d594fSAndroid Build Coastguard Worker ASSERT_FALSE(IsRemoved(bounds_check));
166*795d594fSAndroid Build Coastguard Worker }
167*795d594fSAndroid Build Coastguard Worker
168*795d594fSAndroid Build Coastguard Worker // if (i < array.length) {
169*795d594fSAndroid Build Coastguard Worker // int j = i - Integer.MAX_VALUE;
170*795d594fSAndroid Build Coastguard Worker // j = j - Integer.MAX_VALUE; // j is (i+2) after subtracting MAX_INT twice
171*795d594fSAndroid Build Coastguard Worker // if (j > 0) array[j] = 1; // Can't eliminate.
172*795d594fSAndroid Build Coastguard Worker // }
TEST_F(BoundsCheckEliminationTest,UnderflowArrayBoundsElimination)173*795d594fSAndroid Build Coastguard Worker TEST_F(BoundsCheckEliminationTest, UnderflowArrayBoundsElimination) {
174*795d594fSAndroid Build Coastguard Worker CreateGraph();
175*795d594fSAndroid Build Coastguard Worker HBasicBlock* entry = AddNewBlock();
176*795d594fSAndroid Build Coastguard Worker graph_->SetEntryBlock(entry);
177*795d594fSAndroid Build Coastguard Worker HInstruction* parameter1 = MakeParam(DataType::Type::kReference); // array
178*795d594fSAndroid Build Coastguard Worker HInstruction* parameter2 = MakeParam(DataType::Type::kInt32); // i
179*795d594fSAndroid Build Coastguard Worker
180*795d594fSAndroid Build Coastguard Worker HInstruction* constant_1 = graph_->GetIntConstant(1);
181*795d594fSAndroid Build Coastguard Worker HInstruction* constant_0 = graph_->GetIntConstant(0);
182*795d594fSAndroid Build Coastguard Worker HInstruction* constant_max_int = graph_->GetIntConstant(INT_MAX);
183*795d594fSAndroid Build Coastguard Worker
184*795d594fSAndroid Build Coastguard Worker HBasicBlock* block1 = AddNewBlock();
185*795d594fSAndroid Build Coastguard Worker HNullCheck* null_check = MakeNullCheck(block1, parameter1);
186*795d594fSAndroid Build Coastguard Worker HArrayLength* array_length = MakeArrayLength(block1, null_check);
187*795d594fSAndroid Build Coastguard Worker HInstruction* cmp = MakeCondition(block1, kCondGE, parameter2, array_length);
188*795d594fSAndroid Build Coastguard Worker MakeIf(block1, cmp);
189*795d594fSAndroid Build Coastguard Worker entry->AddSuccessor(block1);
190*795d594fSAndroid Build Coastguard Worker
191*795d594fSAndroid Build Coastguard Worker HBasicBlock* block2 = AddNewBlock();
192*795d594fSAndroid Build Coastguard Worker HInstruction* sub1 =
193*795d594fSAndroid Build Coastguard Worker MakeBinOp<HSub>(block2, DataType::Type::kInt32, parameter2, constant_max_int);
194*795d594fSAndroid Build Coastguard Worker HInstruction* sub2 = MakeBinOp<HSub>(block2, DataType::Type::kInt32, sub1, constant_max_int);
195*795d594fSAndroid Build Coastguard Worker HInstruction* cmp2 = MakeCondition(block2, kCondLE, sub2, constant_0);
196*795d594fSAndroid Build Coastguard Worker MakeIf(block2, cmp2);
197*795d594fSAndroid Build Coastguard Worker
198*795d594fSAndroid Build Coastguard Worker HBasicBlock* block3 = AddNewBlock();
199*795d594fSAndroid Build Coastguard Worker HBoundsCheck* bounds_check = MakeBoundsCheck(block3, sub2, array_length);
200*795d594fSAndroid Build Coastguard Worker MakeArraySet(block3, null_check, bounds_check, constant_1, DataType::Type::kInt32);
201*795d594fSAndroid Build Coastguard Worker
202*795d594fSAndroid Build Coastguard Worker HBasicBlock* exit = AddNewBlock();
203*795d594fSAndroid Build Coastguard Worker MakeExit(exit);
204*795d594fSAndroid Build Coastguard Worker block1->AddSuccessor(exit); // true successor
205*795d594fSAndroid Build Coastguard Worker block1->AddSuccessor(block2); // false successor
206*795d594fSAndroid Build Coastguard Worker block2->AddSuccessor(exit); // true successor
207*795d594fSAndroid Build Coastguard Worker block2->AddSuccessor(block3); // false successor
208*795d594fSAndroid Build Coastguard Worker block3->AddSuccessor(exit);
209*795d594fSAndroid Build Coastguard Worker
210*795d594fSAndroid Build Coastguard Worker RunBCE();
211*795d594fSAndroid Build Coastguard Worker
212*795d594fSAndroid Build Coastguard Worker ASSERT_FALSE(IsRemoved(bounds_check));
213*795d594fSAndroid Build Coastguard Worker }
214*795d594fSAndroid Build Coastguard Worker
215*795d594fSAndroid Build Coastguard Worker // array[6] = 1; // Can't eliminate.
216*795d594fSAndroid Build Coastguard Worker // array[5] = 1; // Can eliminate.
217*795d594fSAndroid Build Coastguard Worker // array[4] = 1; // Can eliminate.
TEST_F(BoundsCheckEliminationTest,ConstantArrayBoundsElimination)218*795d594fSAndroid Build Coastguard Worker TEST_F(BoundsCheckEliminationTest, ConstantArrayBoundsElimination) {
219*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = InitEntryMainExitGraphWithReturnVoid();
220*795d594fSAndroid Build Coastguard Worker
221*795d594fSAndroid Build Coastguard Worker HInstruction* parameter = MakeParam(DataType::Type::kReference);
222*795d594fSAndroid Build Coastguard Worker HInstruction* constant_5 = graph_->GetIntConstant(5);
223*795d594fSAndroid Build Coastguard Worker HInstruction* constant_4 = graph_->GetIntConstant(4);
224*795d594fSAndroid Build Coastguard Worker HInstruction* constant_6 = graph_->GetIntConstant(6);
225*795d594fSAndroid Build Coastguard Worker HInstruction* constant_1 = graph_->GetIntConstant(1);
226*795d594fSAndroid Build Coastguard Worker
227*795d594fSAndroid Build Coastguard Worker HNullCheck* null_check = MakeNullCheck(block, parameter);
228*795d594fSAndroid Build Coastguard Worker HArrayLength* array_length = MakeArrayLength(block, null_check);
229*795d594fSAndroid Build Coastguard Worker HBoundsCheck* bounds_check6 = MakeBoundsCheck(block, constant_6, array_length);
230*795d594fSAndroid Build Coastguard Worker MakeArraySet(block, null_check, bounds_check6, constant_1, DataType::Type::kInt32);
231*795d594fSAndroid Build Coastguard Worker
232*795d594fSAndroid Build Coastguard Worker null_check = MakeNullCheck(block, parameter);
233*795d594fSAndroid Build Coastguard Worker array_length = MakeArrayLength(block, null_check);
234*795d594fSAndroid Build Coastguard Worker HBoundsCheck* bounds_check5 = MakeBoundsCheck(block, constant_5, array_length);
235*795d594fSAndroid Build Coastguard Worker MakeArraySet(block, null_check, bounds_check5, constant_1, DataType::Type::kInt32);
236*795d594fSAndroid Build Coastguard Worker
237*795d594fSAndroid Build Coastguard Worker null_check = MakeNullCheck(block, parameter);
238*795d594fSAndroid Build Coastguard Worker array_length = MakeArrayLength(block, null_check);
239*795d594fSAndroid Build Coastguard Worker HBoundsCheck* bounds_check4 = MakeBoundsCheck(block, constant_4, array_length);
240*795d594fSAndroid Build Coastguard Worker MakeArraySet(block, null_check, bounds_check4, constant_1, DataType::Type::kInt32);
241*795d594fSAndroid Build Coastguard Worker
242*795d594fSAndroid Build Coastguard Worker RunBCE();
243*795d594fSAndroid Build Coastguard Worker
244*795d594fSAndroid Build Coastguard Worker ASSERT_FALSE(IsRemoved(bounds_check6));
245*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(IsRemoved(bounds_check5));
246*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(IsRemoved(bounds_check4));
247*795d594fSAndroid Build Coastguard Worker }
248*795d594fSAndroid Build Coastguard Worker
249*795d594fSAndroid Build Coastguard Worker // for (int i=initial; i<array.length; i+=increment) { array[i] = 10; }
BuildSSAGraph1(int initial,int increment,IfCondition cond)250*795d594fSAndroid Build Coastguard Worker HInstruction* BoundsCheckEliminationTest::BuildSSAGraph1(int initial,
251*795d594fSAndroid Build Coastguard Worker int increment,
252*795d594fSAndroid Build Coastguard Worker IfCondition cond) {
253*795d594fSAndroid Build Coastguard Worker HBasicBlock* return_block = InitEntryMainExitGraphWithReturnVoid();
254*795d594fSAndroid Build Coastguard Worker auto [pre_header, loop_header, loop_body] = CreateWhileLoop(return_block);
255*795d594fSAndroid Build Coastguard Worker
256*795d594fSAndroid Build Coastguard Worker HInstruction* parameter = MakeParam(DataType::Type::kReference);
257*795d594fSAndroid Build Coastguard Worker HInstruction* constant_10 = graph_->GetIntConstant(10);
258*795d594fSAndroid Build Coastguard Worker
259*795d594fSAndroid Build Coastguard Worker auto [phi, add] = MakeLinearLoopVar(loop_header, loop_body, initial, increment);
260*795d594fSAndroid Build Coastguard Worker HInstruction* null_check = MakeNullCheck(loop_header, parameter);
261*795d594fSAndroid Build Coastguard Worker HInstruction* array_length = MakeArrayLength(loop_header, null_check);
262*795d594fSAndroid Build Coastguard Worker DCHECK(cond == kCondGE || cond == kCondGT) << cond;
263*795d594fSAndroid Build Coastguard Worker HInstruction* cmp = MakeCondition(loop_header, cond, phi, array_length);
264*795d594fSAndroid Build Coastguard Worker MakeIf(loop_header, cmp);
265*795d594fSAndroid Build Coastguard Worker
266*795d594fSAndroid Build Coastguard Worker null_check = MakeNullCheck(loop_body, parameter);
267*795d594fSAndroid Build Coastguard Worker array_length = MakeArrayLength(loop_body, null_check);
268*795d594fSAndroid Build Coastguard Worker HInstruction* bounds_check = MakeBoundsCheck(loop_body, phi, array_length);
269*795d594fSAndroid Build Coastguard Worker MakeArraySet(loop_body, null_check, bounds_check, constant_10, DataType::Type::kInt32);
270*795d594fSAndroid Build Coastguard Worker
271*795d594fSAndroid Build Coastguard Worker return bounds_check;
272*795d594fSAndroid Build Coastguard Worker }
273*795d594fSAndroid Build Coastguard Worker
TEST_F(BoundsCheckEliminationTest,LoopArrayBoundsElimination1a)274*795d594fSAndroid Build Coastguard Worker TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination1a) {
275*795d594fSAndroid Build Coastguard Worker // for (int i=0; i<array.length; i++) { array[i] = 10; // Can eliminate with gvn. }
276*795d594fSAndroid Build Coastguard Worker HInstruction* bounds_check = BuildSSAGraph1(0, 1);
277*795d594fSAndroid Build Coastguard Worker RunBCE();
278*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(IsRemoved(bounds_check));
279*795d594fSAndroid Build Coastguard Worker }
280*795d594fSAndroid Build Coastguard Worker
TEST_F(BoundsCheckEliminationTest,LoopArrayBoundsElimination1b)281*795d594fSAndroid Build Coastguard Worker TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination1b) {
282*795d594fSAndroid Build Coastguard Worker // for (int i=1; i<array.length; i++) { array[i] = 10; // Can eliminate. }
283*795d594fSAndroid Build Coastguard Worker HInstruction* bounds_check = BuildSSAGraph1(1, 1);
284*795d594fSAndroid Build Coastguard Worker RunBCE();
285*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(IsRemoved(bounds_check));
286*795d594fSAndroid Build Coastguard Worker }
287*795d594fSAndroid Build Coastguard Worker
TEST_F(BoundsCheckEliminationTest,LoopArrayBoundsElimination1c)288*795d594fSAndroid Build Coastguard Worker TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination1c) {
289*795d594fSAndroid Build Coastguard Worker // for (int i=-1; i<array.length; i++) { array[i] = 10; // Can't eliminate. }
290*795d594fSAndroid Build Coastguard Worker HInstruction* bounds_check = BuildSSAGraph1(-1, 1);
291*795d594fSAndroid Build Coastguard Worker RunBCE();
292*795d594fSAndroid Build Coastguard Worker ASSERT_FALSE(IsRemoved(bounds_check));
293*795d594fSAndroid Build Coastguard Worker }
294*795d594fSAndroid Build Coastguard Worker
TEST_F(BoundsCheckEliminationTest,LoopArrayBoundsElimination1d)295*795d594fSAndroid Build Coastguard Worker TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination1d) {
296*795d594fSAndroid Build Coastguard Worker // for (int i=0; i<=array.length; i++) { array[i] = 10; // Can't eliminate. }
297*795d594fSAndroid Build Coastguard Worker HInstruction* bounds_check = BuildSSAGraph1(0, 1, kCondGT);
298*795d594fSAndroid Build Coastguard Worker RunBCE();
299*795d594fSAndroid Build Coastguard Worker ASSERT_FALSE(IsRemoved(bounds_check));
300*795d594fSAndroid Build Coastguard Worker }
301*795d594fSAndroid Build Coastguard Worker
TEST_F(BoundsCheckEliminationTest,LoopArrayBoundsElimination1e)302*795d594fSAndroid Build Coastguard Worker TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination1e) {
303*795d594fSAndroid Build Coastguard Worker // for (int i=0; i<array.length; i += 2) {
304*795d594fSAndroid Build Coastguard Worker // array[i] = 10; // Can't eliminate due to overflow concern. }
305*795d594fSAndroid Build Coastguard Worker HInstruction* bounds_check = BuildSSAGraph1(0, 2);
306*795d594fSAndroid Build Coastguard Worker RunBCE();
307*795d594fSAndroid Build Coastguard Worker ASSERT_FALSE(IsRemoved(bounds_check));
308*795d594fSAndroid Build Coastguard Worker }
309*795d594fSAndroid Build Coastguard Worker
TEST_F(BoundsCheckEliminationTest,LoopArrayBoundsElimination1f)310*795d594fSAndroid Build Coastguard Worker TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination1f) {
311*795d594fSAndroid Build Coastguard Worker // for (int i=1; i<array.length; i += 2) { array[i] = 10; // Can eliminate. }
312*795d594fSAndroid Build Coastguard Worker HInstruction* bounds_check = BuildSSAGraph1(1, 2);
313*795d594fSAndroid Build Coastguard Worker RunBCE();
314*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(IsRemoved(bounds_check));
315*795d594fSAndroid Build Coastguard Worker }
316*795d594fSAndroid Build Coastguard Worker
317*795d594fSAndroid Build Coastguard Worker // for (int i=array.length; i>0; i+=increment) { array[i-1] = 10; }
BuildSSAGraph2(int initial,int increment,IfCondition cond)318*795d594fSAndroid Build Coastguard Worker HInstruction* BoundsCheckEliminationTest::BuildSSAGraph2(int initial,
319*795d594fSAndroid Build Coastguard Worker int increment,
320*795d594fSAndroid Build Coastguard Worker IfCondition cond) {
321*795d594fSAndroid Build Coastguard Worker HBasicBlock* return_block = InitEntryMainExitGraphWithReturnVoid();
322*795d594fSAndroid Build Coastguard Worker auto [pre_header, loop_header, loop_body] = CreateWhileLoop(return_block);
323*795d594fSAndroid Build Coastguard Worker
324*795d594fSAndroid Build Coastguard Worker HInstruction* parameter = MakeParam(DataType::Type::kReference);
325*795d594fSAndroid Build Coastguard Worker HInstruction* constant_initial = graph_->GetIntConstant(initial);
326*795d594fSAndroid Build Coastguard Worker HInstruction* constant_increment = graph_->GetIntConstant(increment);
327*795d594fSAndroid Build Coastguard Worker HInstruction* constant_minus_1 = graph_->GetIntConstant(-1);
328*795d594fSAndroid Build Coastguard Worker HInstruction* constant_10 = graph_->GetIntConstant(10);
329*795d594fSAndroid Build Coastguard Worker
330*795d594fSAndroid Build Coastguard Worker HInstruction* null_check = MakeNullCheck(pre_header, parameter);
331*795d594fSAndroid Build Coastguard Worker HInstruction* array_length = MakeArrayLength(pre_header, null_check);
332*795d594fSAndroid Build Coastguard Worker
333*795d594fSAndroid Build Coastguard Worker auto [phi, add] = MakeLinearLoopVar(loop_header, loop_body, array_length, constant_minus_1);
334*795d594fSAndroid Build Coastguard Worker DCHECK(cond == kCondLE || cond == kCondLT) << cond;
335*795d594fSAndroid Build Coastguard Worker HInstruction* cmp = MakeCondition(loop_header, cond, phi, constant_initial);
336*795d594fSAndroid Build Coastguard Worker MakeIf(loop_header, cmp);
337*795d594fSAndroid Build Coastguard Worker
338*795d594fSAndroid Build Coastguard Worker null_check = MakeNullCheck(loop_body, parameter);
339*795d594fSAndroid Build Coastguard Worker array_length = MakeArrayLength(loop_body, null_check);
340*795d594fSAndroid Build Coastguard Worker HInstruction* bounds_check = MakeBoundsCheck(loop_body, add, array_length);
341*795d594fSAndroid Build Coastguard Worker MakeArraySet(loop_body, null_check, bounds_check, constant_10, DataType::Type::kInt32);
342*795d594fSAndroid Build Coastguard Worker
343*795d594fSAndroid Build Coastguard Worker return bounds_check;
344*795d594fSAndroid Build Coastguard Worker }
345*795d594fSAndroid Build Coastguard Worker
TEST_F(BoundsCheckEliminationTest,LoopArrayBoundsElimination2a)346*795d594fSAndroid Build Coastguard Worker TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination2a) {
347*795d594fSAndroid Build Coastguard Worker // for (int i=array.length; i>0; i--) { array[i-1] = 10; // Can eliminate with gvn. }
348*795d594fSAndroid Build Coastguard Worker HInstruction* bounds_check = BuildSSAGraph2(0);
349*795d594fSAndroid Build Coastguard Worker RunBCE();
350*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(IsRemoved(bounds_check));
351*795d594fSAndroid Build Coastguard Worker }
352*795d594fSAndroid Build Coastguard Worker
TEST_F(BoundsCheckEliminationTest,LoopArrayBoundsElimination2b)353*795d594fSAndroid Build Coastguard Worker TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination2b) {
354*795d594fSAndroid Build Coastguard Worker // for (int i=array.length; i>1; i--) { array[i-1] = 10; // Can eliminate. }
355*795d594fSAndroid Build Coastguard Worker HInstruction* bounds_check = BuildSSAGraph2(1);
356*795d594fSAndroid Build Coastguard Worker RunBCE();
357*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(IsRemoved(bounds_check));
358*795d594fSAndroid Build Coastguard Worker }
359*795d594fSAndroid Build Coastguard Worker
TEST_F(BoundsCheckEliminationTest,LoopArrayBoundsElimination2c)360*795d594fSAndroid Build Coastguard Worker TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination2c) {
361*795d594fSAndroid Build Coastguard Worker // for (int i=array.length; i>-1; i--) { array[i-1] = 10; // Can't eliminate. }
362*795d594fSAndroid Build Coastguard Worker HInstruction* bounds_check = BuildSSAGraph2(-1);
363*795d594fSAndroid Build Coastguard Worker RunBCE();
364*795d594fSAndroid Build Coastguard Worker ASSERT_FALSE(IsRemoved(bounds_check));
365*795d594fSAndroid Build Coastguard Worker }
366*795d594fSAndroid Build Coastguard Worker
TEST_F(BoundsCheckEliminationTest,LoopArrayBoundsElimination2d)367*795d594fSAndroid Build Coastguard Worker TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination2d) {
368*795d594fSAndroid Build Coastguard Worker // for (int i=array.length; i>=0; i--) { array[i-1] = 10; // Can't eliminate. }
369*795d594fSAndroid Build Coastguard Worker HInstruction* bounds_check = BuildSSAGraph2(0, -1, kCondLT);
370*795d594fSAndroid Build Coastguard Worker RunBCE();
371*795d594fSAndroid Build Coastguard Worker ASSERT_FALSE(IsRemoved(bounds_check));
372*795d594fSAndroid Build Coastguard Worker }
373*795d594fSAndroid Build Coastguard Worker
TEST_F(BoundsCheckEliminationTest,LoopArrayBoundsElimination2e)374*795d594fSAndroid Build Coastguard Worker TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination2e) {
375*795d594fSAndroid Build Coastguard Worker // for (int i=array.length; i>0; i-=2) { array[i-1] = 10; // Can eliminate. }
376*795d594fSAndroid Build Coastguard Worker HInstruction* bounds_check = BuildSSAGraph2(0, -2);
377*795d594fSAndroid Build Coastguard Worker RunBCE();
378*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(IsRemoved(bounds_check));
379*795d594fSAndroid Build Coastguard Worker }
380*795d594fSAndroid Build Coastguard Worker
381*795d594fSAndroid Build Coastguard Worker // int[] array = new int[10];
382*795d594fSAndroid Build Coastguard Worker // for (int i=0; i<10; i+=increment) { array[i] = 10; }
BuildSSAGraph3(int initial,int increment,IfCondition cond)383*795d594fSAndroid Build Coastguard Worker HInstruction* BoundsCheckEliminationTest::BuildSSAGraph3(int initial,
384*795d594fSAndroid Build Coastguard Worker int increment,
385*795d594fSAndroid Build Coastguard Worker IfCondition cond) {
386*795d594fSAndroid Build Coastguard Worker HBasicBlock* return_block = InitEntryMainExitGraphWithReturnVoid();
387*795d594fSAndroid Build Coastguard Worker auto [pre_header, loop_header, loop_body] = CreateWhileLoop(return_block);
388*795d594fSAndroid Build Coastguard Worker
389*795d594fSAndroid Build Coastguard Worker HInstruction* constant_10 = graph_->GetIntConstant(10);
390*795d594fSAndroid Build Coastguard Worker
391*795d594fSAndroid Build Coastguard Worker // We pass a bogus constant for the class to avoid mocking one.
392*795d594fSAndroid Build Coastguard Worker HInstruction* new_array =
393*795d594fSAndroid Build Coastguard Worker MakeNewArray(pre_header, /* cls= */ constant_10, /* length= */ constant_10);
394*795d594fSAndroid Build Coastguard Worker
395*795d594fSAndroid Build Coastguard Worker auto [phi, add] = MakeLinearLoopVar(loop_header, loop_body, initial, increment);
396*795d594fSAndroid Build Coastguard Worker DCHECK(cond == kCondGE || cond == kCondGT) << cond;
397*795d594fSAndroid Build Coastguard Worker HInstruction* cmp = MakeCondition(loop_header, cond, phi, constant_10);
398*795d594fSAndroid Build Coastguard Worker MakeIf(loop_header, cmp);
399*795d594fSAndroid Build Coastguard Worker
400*795d594fSAndroid Build Coastguard Worker HNullCheck* null_check = MakeNullCheck(loop_body, new_array);
401*795d594fSAndroid Build Coastguard Worker HArrayLength* array_length = MakeArrayLength(loop_body, null_check);
402*795d594fSAndroid Build Coastguard Worker HInstruction* bounds_check = MakeBoundsCheck(loop_body, phi, array_length);
403*795d594fSAndroid Build Coastguard Worker MakeArraySet(loop_body, null_check, bounds_check, constant_10, DataType::Type::kInt32);
404*795d594fSAndroid Build Coastguard Worker
405*795d594fSAndroid Build Coastguard Worker return bounds_check;
406*795d594fSAndroid Build Coastguard Worker }
407*795d594fSAndroid Build Coastguard Worker
TEST_F(BoundsCheckEliminationTest,LoopArrayBoundsElimination3a)408*795d594fSAndroid Build Coastguard Worker TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination3a) {
409*795d594fSAndroid Build Coastguard Worker // int[] array = new int[10];
410*795d594fSAndroid Build Coastguard Worker // for (int i=0; i<10; i++) { array[i] = 10; // Can eliminate. }
411*795d594fSAndroid Build Coastguard Worker HInstruction* bounds_check = BuildSSAGraph3(0, 1, kCondGE);
412*795d594fSAndroid Build Coastguard Worker RunBCE();
413*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(IsRemoved(bounds_check));
414*795d594fSAndroid Build Coastguard Worker }
415*795d594fSAndroid Build Coastguard Worker
TEST_F(BoundsCheckEliminationTest,LoopArrayBoundsElimination3b)416*795d594fSAndroid Build Coastguard Worker TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination3b) {
417*795d594fSAndroid Build Coastguard Worker // int[] array = new int[10];
418*795d594fSAndroid Build Coastguard Worker // for (int i=1; i<10; i++) { array[i] = 10; // Can eliminate. }
419*795d594fSAndroid Build Coastguard Worker HInstruction* bounds_check = BuildSSAGraph3(1, 1, kCondGE);
420*795d594fSAndroid Build Coastguard Worker RunBCE();
421*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(IsRemoved(bounds_check));
422*795d594fSAndroid Build Coastguard Worker }
423*795d594fSAndroid Build Coastguard Worker
TEST_F(BoundsCheckEliminationTest,LoopArrayBoundsElimination3c)424*795d594fSAndroid Build Coastguard Worker TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination3c) {
425*795d594fSAndroid Build Coastguard Worker // int[] array = new int[10];
426*795d594fSAndroid Build Coastguard Worker // for (int i=0; i<=10; i++) { array[i] = 10; // Can't eliminate. }
427*795d594fSAndroid Build Coastguard Worker HInstruction* bounds_check = BuildSSAGraph3(0, 1, kCondGT);
428*795d594fSAndroid Build Coastguard Worker RunBCE();
429*795d594fSAndroid Build Coastguard Worker ASSERT_FALSE(IsRemoved(bounds_check));
430*795d594fSAndroid Build Coastguard Worker }
431*795d594fSAndroid Build Coastguard Worker
TEST_F(BoundsCheckEliminationTest,LoopArrayBoundsElimination3d)432*795d594fSAndroid Build Coastguard Worker TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination3d) {
433*795d594fSAndroid Build Coastguard Worker // int[] array = new int[10];
434*795d594fSAndroid Build Coastguard Worker // for (int i=1; i<10; i+=8) { array[i] = 10; // Can eliminate. }
435*795d594fSAndroid Build Coastguard Worker HInstruction* bounds_check = BuildSSAGraph3(1, 8, kCondGE);
436*795d594fSAndroid Build Coastguard Worker RunBCE();
437*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(IsRemoved(bounds_check));
438*795d594fSAndroid Build Coastguard Worker }
439*795d594fSAndroid Build Coastguard Worker
440*795d594fSAndroid Build Coastguard Worker // for (int i=initial; i<array.length; i++) { array[array.length-i-1] = 10; }
BuildSSAGraph4(int initial,IfCondition cond)441*795d594fSAndroid Build Coastguard Worker HInstruction* BoundsCheckEliminationTest::BuildSSAGraph4(int initial, IfCondition cond) {
442*795d594fSAndroid Build Coastguard Worker HBasicBlock* return_block = InitEntryMainExitGraphWithReturnVoid();
443*795d594fSAndroid Build Coastguard Worker auto [pre_header, loop_header, loop_body] = CreateWhileLoop(return_block);
444*795d594fSAndroid Build Coastguard Worker
445*795d594fSAndroid Build Coastguard Worker HInstruction* parameter = MakeParam(DataType::Type::kReference);
446*795d594fSAndroid Build Coastguard Worker HInstruction* constant_10 = graph_->GetIntConstant(10);
447*795d594fSAndroid Build Coastguard Worker HInstruction* constant_minus_1 = graph_->GetIntConstant(-1);
448*795d594fSAndroid Build Coastguard Worker
449*795d594fSAndroid Build Coastguard Worker auto [phi, add] = MakeLinearLoopVar(loop_header, loop_body, initial, /*increment=*/ 1);
450*795d594fSAndroid Build Coastguard Worker HInstruction* null_check = MakeNullCheck(loop_header, parameter);
451*795d594fSAndroid Build Coastguard Worker HInstruction* array_length = MakeArrayLength(loop_header, null_check);
452*795d594fSAndroid Build Coastguard Worker DCHECK(cond == kCondGE || cond == kCondGT) << cond;
453*795d594fSAndroid Build Coastguard Worker HInstruction* cmp = MakeCondition(loop_header, cond, phi, array_length);
454*795d594fSAndroid Build Coastguard Worker MakeIf(loop_header, cmp);
455*795d594fSAndroid Build Coastguard Worker
456*795d594fSAndroid Build Coastguard Worker null_check = MakeNullCheck(loop_body, parameter);
457*795d594fSAndroid Build Coastguard Worker array_length = MakeArrayLength(loop_body, null_check);
458*795d594fSAndroid Build Coastguard Worker HInstruction* sub = MakeBinOp<HSub>(loop_body, DataType::Type::kInt32, array_length, phi);
459*795d594fSAndroid Build Coastguard Worker HInstruction* add_minus_1 =
460*795d594fSAndroid Build Coastguard Worker MakeBinOp<HAdd>(loop_body, DataType::Type::kInt32, sub, constant_minus_1);
461*795d594fSAndroid Build Coastguard Worker HInstruction* bounds_check = MakeBoundsCheck(loop_body, add_minus_1, array_length);
462*795d594fSAndroid Build Coastguard Worker MakeArraySet(loop_body, null_check, bounds_check, constant_10, DataType::Type::kInt32);
463*795d594fSAndroid Build Coastguard Worker
464*795d594fSAndroid Build Coastguard Worker return bounds_check;
465*795d594fSAndroid Build Coastguard Worker }
466*795d594fSAndroid Build Coastguard Worker
TEST_F(BoundsCheckEliminationTest,LoopArrayBoundsElimination4a)467*795d594fSAndroid Build Coastguard Worker TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination4a) {
468*795d594fSAndroid Build Coastguard Worker // for (int i=0; i<array.length; i++) { array[array.length-i-1] = 10; // Can eliminate with gvn. }
469*795d594fSAndroid Build Coastguard Worker HInstruction* bounds_check = BuildSSAGraph4(0);
470*795d594fSAndroid Build Coastguard Worker RunBCE();
471*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(IsRemoved(bounds_check));
472*795d594fSAndroid Build Coastguard Worker }
473*795d594fSAndroid Build Coastguard Worker
TEST_F(BoundsCheckEliminationTest,LoopArrayBoundsElimination4b)474*795d594fSAndroid Build Coastguard Worker TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination4b) {
475*795d594fSAndroid Build Coastguard Worker // for (int i=1; i<array.length; i++) { array[array.length-i-1] = 10; // Can eliminate. }
476*795d594fSAndroid Build Coastguard Worker HInstruction* bounds_check = BuildSSAGraph4(1);
477*795d594fSAndroid Build Coastguard Worker RunBCE();
478*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(IsRemoved(bounds_check));
479*795d594fSAndroid Build Coastguard Worker }
480*795d594fSAndroid Build Coastguard Worker
TEST_F(BoundsCheckEliminationTest,LoopArrayBoundsElimination4c)481*795d594fSAndroid Build Coastguard Worker TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination4c) {
482*795d594fSAndroid Build Coastguard Worker // for (int i=0; i<=array.length; i++) { array[array.length-i] = 10; // Can't eliminate. }
483*795d594fSAndroid Build Coastguard Worker HInstruction* bounds_check = BuildSSAGraph4(0, kCondGT);
484*795d594fSAndroid Build Coastguard Worker RunBCE();
485*795d594fSAndroid Build Coastguard Worker ASSERT_FALSE(IsRemoved(bounds_check));
486*795d594fSAndroid Build Coastguard Worker }
487*795d594fSAndroid Build Coastguard Worker
488*795d594fSAndroid Build Coastguard Worker // Bubble sort:
489*795d594fSAndroid Build Coastguard Worker // (Every array access bounds-check can be eliminated.)
490*795d594fSAndroid Build Coastguard Worker // for (int i=0; i<array.length-1; i++) {
491*795d594fSAndroid Build Coastguard Worker // for (int j=0; j<array.length-i-1; j++) {
492*795d594fSAndroid Build Coastguard Worker // if (array[j] > array[j+1]) {
493*795d594fSAndroid Build Coastguard Worker // int temp = array[j+1];
494*795d594fSAndroid Build Coastguard Worker // array[j+1] = array[j];
495*795d594fSAndroid Build Coastguard Worker // array[j] = temp;
496*795d594fSAndroid Build Coastguard Worker // }
497*795d594fSAndroid Build Coastguard Worker // }
498*795d594fSAndroid Build Coastguard Worker // }
TEST_F(BoundsCheckEliminationTest,BubbleSortArrayBoundsElimination)499*795d594fSAndroid Build Coastguard Worker TEST_F(BoundsCheckEliminationTest, BubbleSortArrayBoundsElimination) {
500*795d594fSAndroid Build Coastguard Worker HBasicBlock* return_block = InitEntryMainExitGraphWithReturnVoid();
501*795d594fSAndroid Build Coastguard Worker auto [outer_pre_header, outer_header, outer_body_add] = CreateWhileLoop(return_block);
502*795d594fSAndroid Build Coastguard Worker auto [inner_pre_header, inner_header, inner_body_add] = CreateWhileLoop(outer_body_add);
503*795d594fSAndroid Build Coastguard Worker auto [inner_body_compare, inner_body_swap, skip_swap] = CreateDiamondPattern(inner_body_add);
504*795d594fSAndroid Build Coastguard Worker
505*795d594fSAndroid Build Coastguard Worker HInstruction* parameter = MakeParam(DataType::Type::kReference);
506*795d594fSAndroid Build Coastguard Worker HInstruction* constant_0 = graph_->GetIntConstant(0);
507*795d594fSAndroid Build Coastguard Worker HInstruction* constant_minus_1 = graph_->GetIntConstant(-1);
508*795d594fSAndroid Build Coastguard Worker HInstruction* constant_1 = graph_->GetIntConstant(1);
509*795d594fSAndroid Build Coastguard Worker
510*795d594fSAndroid Build Coastguard Worker auto [phi_i, add_i] =
511*795d594fSAndroid Build Coastguard Worker MakeLinearLoopVar(outer_header, outer_body_add, /*initial=*/ 0, /*increment=*/ 1);
512*795d594fSAndroid Build Coastguard Worker HNullCheck* null_check = MakeNullCheck(outer_header, parameter);
513*795d594fSAndroid Build Coastguard Worker HArrayLength* array_length = MakeArrayLength(outer_header, null_check);
514*795d594fSAndroid Build Coastguard Worker HAdd* add = MakeBinOp<HAdd>(outer_header, DataType::Type::kInt32, array_length, constant_minus_1);
515*795d594fSAndroid Build Coastguard Worker HInstruction* cmp = MakeCondition(outer_header, kCondGE, phi_i, add);
516*795d594fSAndroid Build Coastguard Worker MakeIf(outer_header, cmp);
517*795d594fSAndroid Build Coastguard Worker
518*795d594fSAndroid Build Coastguard Worker auto [phi_j, add_j] =
519*795d594fSAndroid Build Coastguard Worker MakeLinearLoopVar(inner_header, inner_body_add, /*initial=*/ 0, /*increment=*/ 1);
520*795d594fSAndroid Build Coastguard Worker null_check = MakeNullCheck(inner_header, parameter);
521*795d594fSAndroid Build Coastguard Worker array_length = MakeArrayLength(inner_header, null_check);
522*795d594fSAndroid Build Coastguard Worker HSub* sub = MakeBinOp<HSub>(inner_header, DataType::Type::kInt32, array_length, phi_i);
523*795d594fSAndroid Build Coastguard Worker add = MakeBinOp<HAdd>(inner_header, DataType::Type::kInt32, sub, constant_minus_1);
524*795d594fSAndroid Build Coastguard Worker cmp = MakeCondition(inner_header, kCondGE, phi_j, add);
525*795d594fSAndroid Build Coastguard Worker MakeIf(inner_header, cmp);
526*795d594fSAndroid Build Coastguard Worker
527*795d594fSAndroid Build Coastguard Worker null_check = MakeNullCheck(inner_body_compare, parameter);
528*795d594fSAndroid Build Coastguard Worker array_length = MakeArrayLength(inner_body_compare, null_check);
529*795d594fSAndroid Build Coastguard Worker HBoundsCheck* bounds_check1 = MakeBoundsCheck(inner_body_compare, phi_j, array_length);
530*795d594fSAndroid Build Coastguard Worker HArrayGet* array_get_j =
531*795d594fSAndroid Build Coastguard Worker MakeArrayGet(inner_body_compare, null_check, bounds_check1, DataType::Type::kInt32);
532*795d594fSAndroid Build Coastguard Worker HInstruction* j_plus_1 =
533*795d594fSAndroid Build Coastguard Worker MakeBinOp<HAdd>(inner_body_compare, DataType::Type::kInt32, phi_j, constant_1);
534*795d594fSAndroid Build Coastguard Worker null_check = MakeNullCheck(inner_body_compare, parameter);
535*795d594fSAndroid Build Coastguard Worker array_length = MakeArrayLength(inner_body_compare, null_check);
536*795d594fSAndroid Build Coastguard Worker HBoundsCheck* bounds_check2 = MakeBoundsCheck(inner_body_compare, j_plus_1, array_length);
537*795d594fSAndroid Build Coastguard Worker HArrayGet* array_get_j_plus_1 =
538*795d594fSAndroid Build Coastguard Worker MakeArrayGet(inner_body_compare, null_check, bounds_check2, DataType::Type::kInt32);
539*795d594fSAndroid Build Coastguard Worker cmp = MakeCondition(inner_body_compare, kCondGE, array_get_j, array_get_j_plus_1);
540*795d594fSAndroid Build Coastguard Worker MakeIf(inner_body_compare, cmp);
541*795d594fSAndroid Build Coastguard Worker
542*795d594fSAndroid Build Coastguard Worker j_plus_1 = MakeBinOp<HAdd>(inner_body_swap, DataType::Type::kInt32, phi_j, constant_1);
543*795d594fSAndroid Build Coastguard Worker // temp = array[j+1]
544*795d594fSAndroid Build Coastguard Worker null_check = MakeNullCheck(inner_body_swap, parameter);
545*795d594fSAndroid Build Coastguard Worker array_length = MakeArrayLength(inner_body_swap, null_check);
546*795d594fSAndroid Build Coastguard Worker HInstruction* bounds_check3 = MakeBoundsCheck(inner_body_swap, j_plus_1, array_length);
547*795d594fSAndroid Build Coastguard Worker array_get_j_plus_1 =
548*795d594fSAndroid Build Coastguard Worker MakeArrayGet(inner_body_swap, null_check, bounds_check3, DataType::Type::kInt32);
549*795d594fSAndroid Build Coastguard Worker // array[j+1] = array[j]
550*795d594fSAndroid Build Coastguard Worker null_check = MakeNullCheck(inner_body_swap, parameter);
551*795d594fSAndroid Build Coastguard Worker array_length = MakeArrayLength(inner_body_swap, null_check);
552*795d594fSAndroid Build Coastguard Worker HInstruction* bounds_check4 = MakeBoundsCheck(inner_body_swap, phi_j, array_length);
553*795d594fSAndroid Build Coastguard Worker array_get_j = MakeArrayGet(inner_body_swap, null_check, bounds_check4, DataType::Type::kInt32);
554*795d594fSAndroid Build Coastguard Worker null_check = MakeNullCheck(inner_body_swap, parameter);
555*795d594fSAndroid Build Coastguard Worker array_length = MakeArrayLength(inner_body_swap, null_check);
556*795d594fSAndroid Build Coastguard Worker HInstruction* bounds_check5 = MakeBoundsCheck(inner_body_swap, j_plus_1, array_length);
557*795d594fSAndroid Build Coastguard Worker MakeArraySet(inner_body_swap, null_check, bounds_check5, array_get_j, DataType::Type::kInt32);
558*795d594fSAndroid Build Coastguard Worker // array[j] = temp
559*795d594fSAndroid Build Coastguard Worker null_check = MakeNullCheck(inner_body_swap, parameter);
560*795d594fSAndroid Build Coastguard Worker array_length = MakeArrayLength(inner_body_swap, null_check);
561*795d594fSAndroid Build Coastguard Worker HInstruction* bounds_check6 = MakeBoundsCheck(inner_body_swap, phi_j, array_length);
562*795d594fSAndroid Build Coastguard Worker MakeArraySet(
563*795d594fSAndroid Build Coastguard Worker inner_body_swap, null_check, bounds_check6, array_get_j_plus_1, DataType::Type::kInt32);
564*795d594fSAndroid Build Coastguard Worker
565*795d594fSAndroid Build Coastguard Worker RunBCE(); // gvn removes same bounds check already
566*795d594fSAndroid Build Coastguard Worker
567*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(IsRemoved(bounds_check1));
568*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(IsRemoved(bounds_check2));
569*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(IsRemoved(bounds_check3));
570*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(IsRemoved(bounds_check4));
571*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(IsRemoved(bounds_check5));
572*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(IsRemoved(bounds_check6));
573*795d594fSAndroid Build Coastguard Worker }
574*795d594fSAndroid Build Coastguard Worker
575*795d594fSAndroid Build Coastguard Worker // int[] array = new int[10];
576*795d594fSAndroid Build Coastguard Worker // for (int i=0; i<200; i++) {
577*795d594fSAndroid Build Coastguard Worker // array[i%10] = 10; // Can eliminate
578*795d594fSAndroid Build Coastguard Worker // array[i%1] = 10; // Can eliminate
579*795d594fSAndroid Build Coastguard Worker // array[i%200] = 10; // Cannot eliminate
580*795d594fSAndroid Build Coastguard Worker // array[i%-10] = 10; // Can eliminate
581*795d594fSAndroid Build Coastguard Worker // array[i%array.length] = 10; // Can eliminate
582*795d594fSAndroid Build Coastguard Worker // array[param_i%10] = 10; // Can't eliminate, when param_i < 0
583*795d594fSAndroid Build Coastguard Worker // }
TEST_F(BoundsCheckEliminationTest,ModArrayBoundsElimination)584*795d594fSAndroid Build Coastguard Worker TEST_F(BoundsCheckEliminationTest, ModArrayBoundsElimination) {
585*795d594fSAndroid Build Coastguard Worker HBasicBlock* return_block = InitEntryMainExitGraphWithReturnVoid();
586*795d594fSAndroid Build Coastguard Worker auto [pre_header, loop_header, loop_body] = CreateWhileLoop(return_block);
587*795d594fSAndroid Build Coastguard Worker
588*795d594fSAndroid Build Coastguard Worker HInstruction* param_i = MakeParam(DataType::Type::kInt32);
589*795d594fSAndroid Build Coastguard Worker HInstruction* constant_1 = graph_->GetIntConstant(1);
590*795d594fSAndroid Build Coastguard Worker HInstruction* constant_10 = graph_->GetIntConstant(10);
591*795d594fSAndroid Build Coastguard Worker HInstruction* constant_200 = graph_->GetIntConstant(200);
592*795d594fSAndroid Build Coastguard Worker HInstruction* constant_minus_10 = graph_->GetIntConstant(-10);
593*795d594fSAndroid Build Coastguard Worker
594*795d594fSAndroid Build Coastguard Worker // We pass a bogus constant for the class to avoid mocking one.
595*795d594fSAndroid Build Coastguard Worker HInstruction* new_array =
596*795d594fSAndroid Build Coastguard Worker MakeNewArray(pre_header, /* cls= */ constant_10, /* length= */ constant_10);
597*795d594fSAndroid Build Coastguard Worker
598*795d594fSAndroid Build Coastguard Worker auto [phi, add] = MakeLinearLoopVar(loop_header, loop_body, /*initial=*/ 0, /*increment=*/ 1);
599*795d594fSAndroid Build Coastguard Worker HInstruction* cmp = MakeCondition(loop_header, kCondGE, phi, constant_200);
600*795d594fSAndroid Build Coastguard Worker MakeIf(loop_header, cmp);
601*795d594fSAndroid Build Coastguard Worker
602*795d594fSAndroid Build Coastguard Worker //////////////////////////////////////////////////////////////////////////////////
603*795d594fSAndroid Build Coastguard Worker // LOOP BODY:
604*795d594fSAndroid Build Coastguard Worker // array[i % 10] = 10;
605*795d594fSAndroid Build Coastguard Worker HRem* i_mod_10 = MakeBinOp<HRem>(loop_body, DataType::Type::kInt32, phi, constant_10);
606*795d594fSAndroid Build Coastguard Worker HBoundsCheck* bounds_check_i_mod_10 = MakeBoundsCheck(loop_body, i_mod_10, constant_10);
607*795d594fSAndroid Build Coastguard Worker MakeArraySet(loop_body, new_array, bounds_check_i_mod_10, constant_10, DataType::Type::kInt32);
608*795d594fSAndroid Build Coastguard Worker
609*795d594fSAndroid Build Coastguard Worker // array[i % 1] = 10;
610*795d594fSAndroid Build Coastguard Worker HRem* i_mod_1 = MakeBinOp<HRem>(loop_body, DataType::Type::kInt32, phi, constant_1);
611*795d594fSAndroid Build Coastguard Worker HBoundsCheck* bounds_check_i_mod_1 = MakeBoundsCheck(loop_body, i_mod_1, constant_10);
612*795d594fSAndroid Build Coastguard Worker MakeArraySet(loop_body, new_array, bounds_check_i_mod_1, constant_10, DataType::Type::kInt32);
613*795d594fSAndroid Build Coastguard Worker
614*795d594fSAndroid Build Coastguard Worker // array[i % 200] = 10;
615*795d594fSAndroid Build Coastguard Worker HRem* i_mod_200 = MakeBinOp<HRem>(loop_body, DataType::Type::kInt32, phi, constant_200);
616*795d594fSAndroid Build Coastguard Worker HBoundsCheck* bounds_check_i_mod_200 = MakeBoundsCheck(loop_body, i_mod_200, constant_10);
617*795d594fSAndroid Build Coastguard Worker MakeArraySet(loop_body, new_array, bounds_check_i_mod_200, constant_10, DataType::Type::kInt32);
618*795d594fSAndroid Build Coastguard Worker
619*795d594fSAndroid Build Coastguard Worker // array[i % -10] = 10;
620*795d594fSAndroid Build Coastguard Worker HRem* i_mod_minus_10 = MakeBinOp<HRem>(loop_body, DataType::Type::kInt32, phi, constant_minus_10);
621*795d594fSAndroid Build Coastguard Worker HBoundsCheck* bounds_check_i_mod_minus_10 =
622*795d594fSAndroid Build Coastguard Worker MakeBoundsCheck(loop_body, i_mod_minus_10, constant_10);
623*795d594fSAndroid Build Coastguard Worker MakeArraySet(
624*795d594fSAndroid Build Coastguard Worker loop_body, new_array, bounds_check_i_mod_minus_10, constant_10, DataType::Type::kInt32);
625*795d594fSAndroid Build Coastguard Worker
626*795d594fSAndroid Build Coastguard Worker // array[i%array.length] = 10;
627*795d594fSAndroid Build Coastguard Worker HNullCheck* null_check = MakeNullCheck(loop_body, new_array);
628*795d594fSAndroid Build Coastguard Worker HArrayLength* array_length = MakeArrayLength(loop_body, null_check);
629*795d594fSAndroid Build Coastguard Worker HRem* i_mod_array_length = MakeBinOp<HRem>(loop_body, DataType::Type::kInt32, phi, array_length);
630*795d594fSAndroid Build Coastguard Worker HBoundsCheck* bounds_check_i_mod_array_len =
631*795d594fSAndroid Build Coastguard Worker MakeBoundsCheck(loop_body, i_mod_array_length, array_length);
632*795d594fSAndroid Build Coastguard Worker MakeArraySet(
633*795d594fSAndroid Build Coastguard Worker loop_body, null_check, bounds_check_i_mod_array_len, constant_10, DataType::Type::kInt32);
634*795d594fSAndroid Build Coastguard Worker
635*795d594fSAndroid Build Coastguard Worker // array[param_i % 10] = 10;
636*795d594fSAndroid Build Coastguard Worker HRem* param_i_mod_10 = MakeBinOp<HRem>(loop_body, DataType::Type::kInt32, param_i, constant_10);
637*795d594fSAndroid Build Coastguard Worker HBoundsCheck* bounds_check_param_i_mod_10 =
638*795d594fSAndroid Build Coastguard Worker MakeBoundsCheck(loop_body, param_i_mod_10, constant_10);
639*795d594fSAndroid Build Coastguard Worker MakeArraySet(
640*795d594fSAndroid Build Coastguard Worker loop_body, new_array, bounds_check_param_i_mod_10, constant_10, DataType::Type::kInt32);
641*795d594fSAndroid Build Coastguard Worker
642*795d594fSAndroid Build Coastguard Worker // array[param_i%array.length] = 10;
643*795d594fSAndroid Build Coastguard Worker null_check = MakeNullCheck(loop_body, new_array);
644*795d594fSAndroid Build Coastguard Worker array_length = MakeArrayLength(loop_body, null_check);
645*795d594fSAndroid Build Coastguard Worker HRem* param_i_mod_array_length =
646*795d594fSAndroid Build Coastguard Worker MakeBinOp<HRem>(loop_body, DataType::Type::kInt32, param_i, array_length);
647*795d594fSAndroid Build Coastguard Worker HBoundsCheck* bounds_check_param_i_mod_array_len =
648*795d594fSAndroid Build Coastguard Worker MakeBoundsCheck(loop_body, param_i_mod_array_length, array_length);
649*795d594fSAndroid Build Coastguard Worker MakeArraySet(loop_body,
650*795d594fSAndroid Build Coastguard Worker null_check,
651*795d594fSAndroid Build Coastguard Worker bounds_check_param_i_mod_array_len,
652*795d594fSAndroid Build Coastguard Worker constant_10,
653*795d594fSAndroid Build Coastguard Worker DataType::Type::kInt32);
654*795d594fSAndroid Build Coastguard Worker
655*795d594fSAndroid Build Coastguard Worker //////////////////////////////////////////////////////////////////////////////////
656*795d594fSAndroid Build Coastguard Worker
657*795d594fSAndroid Build Coastguard Worker RunBCE();
658*795d594fSAndroid Build Coastguard Worker
659*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(IsRemoved(bounds_check_i_mod_10));
660*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(IsRemoved(bounds_check_i_mod_1));
661*795d594fSAndroid Build Coastguard Worker ASSERT_FALSE(IsRemoved(bounds_check_i_mod_200));
662*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(IsRemoved(bounds_check_i_mod_minus_10));
663*795d594fSAndroid Build Coastguard Worker ASSERT_TRUE(IsRemoved(bounds_check_i_mod_array_len));
664*795d594fSAndroid Build Coastguard Worker ASSERT_FALSE(IsRemoved(bounds_check_param_i_mod_10));
665*795d594fSAndroid Build Coastguard Worker }
666*795d594fSAndroid Build Coastguard Worker
667*795d594fSAndroid Build Coastguard Worker } // namespace art
668