blob: 929a9e7fe7b85367c11389cc55d1176ccec9bee5 [file] [log] [blame]
Mingyao Yangf384f882014-10-22 16:08:18 -07001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "bounds_check_elimination.h"
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070018
19#include "base/arena_allocator.h"
Vladimir Markoe2727152019-10-10 10:46:42 +010020#include "base/macros.h"
Mingyao Yangf384f882014-10-22 16:08:18 -070021#include "builder.h"
22#include "gvn.h"
Aart Bik22af3be2015-09-10 12:50:58 -070023#include "induction_var_analysis.h"
Mingyao Yang0304e182015-01-30 16:41:29 -080024#include "instruction_simplifier.h"
Mingyao Yangf384f882014-10-22 16:08:18 -070025#include "nodes.h"
26#include "optimizing_unit_test.h"
Nicolas Geoffray827eedb2015-01-26 15:18:36 +000027#include "side_effects_analysis.h"
Mingyao Yangf384f882014-10-22 16:08:18 -070028
29#include "gtest/gtest.h"
30
Vladimir Markoe2727152019-10-10 10:46:42 +010031namespace art HIDDEN {
Mingyao Yangf384f882014-10-22 16:08:18 -070032
Aart Bik22af3be2015-09-10 12:50:58 -070033/**
34 * Fixture class for the BoundsCheckElimination tests.
35 */
Vladimir Markoca6fff82017-10-03 14:49:14 +010036class BoundsCheckEliminationTest : public OptimizingUnitTest {
Aart Bik22af3be2015-09-10 12:50:58 -070037 public:
Vladimir Markoca6fff82017-10-03 14:49:14 +010038 BoundsCheckEliminationTest() : graph_(CreateGraph()) {
Aart Bik22af3be2015-09-10 12:50:58 -070039 graph_->SetHasBoundsChecks(true);
40 }
41
42 ~BoundsCheckEliminationTest() { }
43
44 void RunBCE() {
45 graph_->BuildDominatorTree();
Aart Bik22af3be2015-09-10 12:50:58 -070046
Andreas Gampe3db70682018-12-26 15:12:03 -080047 InstructionSimplifier(graph_, /* codegen= */ nullptr).Run();
Aart Bik22af3be2015-09-10 12:50:58 -070048
49 SideEffectsAnalysis side_effects(graph_);
50 side_effects.Run();
51
52 GVNOptimization(graph_, side_effects).Run();
53
54 HInductionVarAnalysis induction(graph_);
55 induction.Run();
56
Aart Bik4a342772015-11-30 10:17:46 -080057 BoundsCheckElimination(graph_, side_effects, &induction).Run();
Aart Bik22af3be2015-09-10 12:50:58 -070058 }
59
Aart Bik22af3be2015-09-10 12:50:58 -070060 HGraph* graph_;
61};
62
Nicolas Geoffraye6f17152015-01-26 15:13:47 +000063
Mingyao Yangf384f882014-10-22 16:08:18 -070064// if (i < 0) { array[i] = 1; // Can't eliminate. }
65// else if (i >= array.length) { array[i] = 1; // Can't eliminate. }
66// else { array[i] = 1; // Can eliminate. }
Aart Bik22af3be2015-09-10 12:50:58 -070067TEST_F(BoundsCheckEliminationTest, NarrowingRangeArrayBoundsElimination) {
Vladimir Markoca6fff82017-10-03 14:49:14 +010068 HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -070069 graph_->AddBlock(entry);
70 graph_->SetEntryBlock(entry);
Vladimir Markoca6fff82017-10-03 14:49:14 +010071 HInstruction* parameter1 = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010072 graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference); // array
Vladimir Markoca6fff82017-10-03 14:49:14 +010073 HInstruction* parameter2 = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010074 graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32); // i
Mingyao Yangf384f882014-10-22 16:08:18 -070075 entry->AddInstruction(parameter1);
76 entry->AddInstruction(parameter2);
David Brazdil8d5b8b22015-03-24 10:51:52 +000077
Aart Bik22af3be2015-09-10 12:50:58 -070078 HInstruction* constant_1 = graph_->GetIntConstant(1);
79 HInstruction* constant_0 = graph_->GetIntConstant(0);
Mingyao Yangf384f882014-10-22 16:08:18 -070080
Vladimir Markoca6fff82017-10-03 14:49:14 +010081 HBasicBlock* block1 = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -070082 graph_->AddBlock(block1);
Vladimir Markoca6fff82017-10-03 14:49:14 +010083 HInstruction* cmp = new (GetAllocator()) HGreaterThanOrEqual(parameter2, constant_0);
84 HIf* if_inst = new (GetAllocator()) HIf(cmp);
Mingyao Yangf384f882014-10-22 16:08:18 -070085 block1->AddInstruction(cmp);
86 block1->AddInstruction(if_inst);
87 entry->AddSuccessor(block1);
88
Vladimir Markoca6fff82017-10-03 14:49:14 +010089 HBasicBlock* block2 = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -070090 graph_->AddBlock(block2);
Vladimir Markoca6fff82017-10-03 14:49:14 +010091 HNullCheck* null_check = new (GetAllocator()) HNullCheck(parameter1, 0);
92 HArrayLength* array_length = new (GetAllocator()) HArrayLength(null_check, 0);
93 HBoundsCheck* bounds_check2 = new (GetAllocator())
Mingyao Yangf384f882014-10-22 16:08:18 -070094 HBoundsCheck(parameter2, array_length, 0);
Vladimir Markoca6fff82017-10-03 14:49:14 +010095 HArraySet* array_set = new (GetAllocator()) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010096 null_check, bounds_check2, constant_1, DataType::Type::kInt32, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -070097 block2->AddInstruction(null_check);
98 block2->AddInstruction(array_length);
99 block2->AddInstruction(bounds_check2);
100 block2->AddInstruction(array_set);
101
Vladimir Markoca6fff82017-10-03 14:49:14 +0100102 HBasicBlock* block3 = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700103 graph_->AddBlock(block3);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100104 null_check = new (GetAllocator()) HNullCheck(parameter1, 0);
105 array_length = new (GetAllocator()) HArrayLength(null_check, 0);
106 cmp = new (GetAllocator()) HLessThan(parameter2, array_length);
107 if_inst = new (GetAllocator()) HIf(cmp);
Mingyao Yangf384f882014-10-22 16:08:18 -0700108 block3->AddInstruction(null_check);
109 block3->AddInstruction(array_length);
110 block3->AddInstruction(cmp);
111 block3->AddInstruction(if_inst);
112
Vladimir Markoca6fff82017-10-03 14:49:14 +0100113 HBasicBlock* block4 = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700114 graph_->AddBlock(block4);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100115 null_check = new (GetAllocator()) HNullCheck(parameter1, 0);
116 array_length = new (GetAllocator()) HArrayLength(null_check, 0);
117 HBoundsCheck* bounds_check4 = new (GetAllocator())
Mingyao Yangf384f882014-10-22 16:08:18 -0700118 HBoundsCheck(parameter2, array_length, 0);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100119 array_set = new (GetAllocator()) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100120 null_check, bounds_check4, constant_1, DataType::Type::kInt32, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700121 block4->AddInstruction(null_check);
122 block4->AddInstruction(array_length);
123 block4->AddInstruction(bounds_check4);
124 block4->AddInstruction(array_set);
125
Vladimir Markoca6fff82017-10-03 14:49:14 +0100126 HBasicBlock* block5 = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700127 graph_->AddBlock(block5);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100128 null_check = new (GetAllocator()) HNullCheck(parameter1, 0);
129 array_length = new (GetAllocator()) HArrayLength(null_check, 0);
130 HBoundsCheck* bounds_check5 = new (GetAllocator())
Mingyao Yangf384f882014-10-22 16:08:18 -0700131 HBoundsCheck(parameter2, array_length, 0);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100132 array_set = new (GetAllocator()) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100133 null_check, bounds_check5, constant_1, DataType::Type::kInt32, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700134 block5->AddInstruction(null_check);
135 block5->AddInstruction(array_length);
136 block5->AddInstruction(bounds_check5);
137 block5->AddInstruction(array_set);
138
Vladimir Markoca6fff82017-10-03 14:49:14 +0100139 HBasicBlock* exit = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700140 graph_->AddBlock(exit);
Mingyao Yangf384f882014-10-22 16:08:18 -0700141 block2->AddSuccessor(exit);
142 block4->AddSuccessor(exit);
143 block5->AddSuccessor(exit);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100144 exit->AddInstruction(new (GetAllocator()) HExit());
Mingyao Yangf384f882014-10-22 16:08:18 -0700145
146 block1->AddSuccessor(block3); // True successor
147 block1->AddSuccessor(block2); // False successor
148
149 block3->AddSuccessor(block5); // True successor
150 block3->AddSuccessor(block4); // False successor
151
Aart Bik22af3be2015-09-10 12:50:58 -0700152 RunBCE();
153
Mingyao Yangf384f882014-10-22 16:08:18 -0700154 ASSERT_FALSE(IsRemoved(bounds_check2));
155 ASSERT_FALSE(IsRemoved(bounds_check4));
156 ASSERT_TRUE(IsRemoved(bounds_check5));
157}
158
159// if (i > 0) {
160// // Positive number plus MAX_INT will overflow and be negative.
161// int j = i + Integer.MAX_VALUE;
162// if (j < array.length) array[j] = 1; // Can't eliminate.
163// }
Aart Bik22af3be2015-09-10 12:50:58 -0700164TEST_F(BoundsCheckEliminationTest, OverflowArrayBoundsElimination) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100165 HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700166 graph_->AddBlock(entry);
167 graph_->SetEntryBlock(entry);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100168 HInstruction* parameter1 = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100169 graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference); // array
Vladimir Markoca6fff82017-10-03 14:49:14 +0100170 HInstruction* parameter2 = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100171 graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32); // i
Mingyao Yangf384f882014-10-22 16:08:18 -0700172 entry->AddInstruction(parameter1);
173 entry->AddInstruction(parameter2);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000174
Aart Bik22af3be2015-09-10 12:50:58 -0700175 HInstruction* constant_1 = graph_->GetIntConstant(1);
176 HInstruction* constant_0 = graph_->GetIntConstant(0);
177 HInstruction* constant_max_int = graph_->GetIntConstant(INT_MAX);
Mingyao Yangf384f882014-10-22 16:08:18 -0700178
Vladimir Markoca6fff82017-10-03 14:49:14 +0100179 HBasicBlock* block1 = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700180 graph_->AddBlock(block1);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100181 HInstruction* cmp = new (GetAllocator()) HLessThanOrEqual(parameter2, constant_0);
182 HIf* if_inst = new (GetAllocator()) HIf(cmp);
Mingyao Yangf384f882014-10-22 16:08:18 -0700183 block1->AddInstruction(cmp);
184 block1->AddInstruction(if_inst);
185 entry->AddSuccessor(block1);
186
Vladimir Markoca6fff82017-10-03 14:49:14 +0100187 HBasicBlock* block2 = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700188 graph_->AddBlock(block2);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100189 HInstruction* add =
190 new (GetAllocator()) HAdd(DataType::Type::kInt32, parameter2, constant_max_int);
191 HNullCheck* null_check = new (GetAllocator()) HNullCheck(parameter1, 0);
192 HArrayLength* array_length = new (GetAllocator()) HArrayLength(null_check, 0);
193 HInstruction* cmp2 = new (GetAllocator()) HGreaterThanOrEqual(add, array_length);
194 if_inst = new (GetAllocator()) HIf(cmp2);
Mingyao Yangf384f882014-10-22 16:08:18 -0700195 block2->AddInstruction(add);
196 block2->AddInstruction(null_check);
197 block2->AddInstruction(array_length);
198 block2->AddInstruction(cmp2);
199 block2->AddInstruction(if_inst);
200
Vladimir Markoca6fff82017-10-03 14:49:14 +0100201 HBasicBlock* block3 = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700202 graph_->AddBlock(block3);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100203 HBoundsCheck* bounds_check = new (GetAllocator())
Mingyao Yangf384f882014-10-22 16:08:18 -0700204 HBoundsCheck(add, array_length, 0);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100205 HArraySet* array_set = new (GetAllocator()) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100206 null_check, bounds_check, constant_1, DataType::Type::kInt32, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700207 block3->AddInstruction(bounds_check);
208 block3->AddInstruction(array_set);
209
Vladimir Markoca6fff82017-10-03 14:49:14 +0100210 HBasicBlock* exit = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700211 graph_->AddBlock(exit);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100212 exit->AddInstruction(new (GetAllocator()) HExit());
Andreas Gampe0418b5b2014-12-04 17:24:50 -0800213 block1->AddSuccessor(exit); // true successor
214 block1->AddSuccessor(block2); // false successor
215 block2->AddSuccessor(exit); // true successor
216 block2->AddSuccessor(block3); // false successor
Mingyao Yangf384f882014-10-22 16:08:18 -0700217 block3->AddSuccessor(exit);
218
Aart Bik22af3be2015-09-10 12:50:58 -0700219 RunBCE();
220
Mingyao Yangf384f882014-10-22 16:08:18 -0700221 ASSERT_FALSE(IsRemoved(bounds_check));
222}
223
224// if (i < array.length) {
225// int j = i - Integer.MAX_VALUE;
Aart Bik22af3be2015-09-10 12:50:58 -0700226// j = j - Integer.MAX_VALUE; // j is (i+2) after subtracting MAX_INT twice
Mingyao Yangf384f882014-10-22 16:08:18 -0700227// if (j > 0) array[j] = 1; // Can't eliminate.
228// }
Aart Bik22af3be2015-09-10 12:50:58 -0700229TEST_F(BoundsCheckEliminationTest, UnderflowArrayBoundsElimination) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100230 HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700231 graph_->AddBlock(entry);
232 graph_->SetEntryBlock(entry);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100233 HInstruction* parameter1 = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100234 graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference); // array
Vladimir Markoca6fff82017-10-03 14:49:14 +0100235 HInstruction* parameter2 = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100236 graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32); // i
Mingyao Yangf384f882014-10-22 16:08:18 -0700237 entry->AddInstruction(parameter1);
238 entry->AddInstruction(parameter2);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000239
Aart Bik22af3be2015-09-10 12:50:58 -0700240 HInstruction* constant_1 = graph_->GetIntConstant(1);
241 HInstruction* constant_0 = graph_->GetIntConstant(0);
242 HInstruction* constant_max_int = graph_->GetIntConstant(INT_MAX);
Mingyao Yangf384f882014-10-22 16:08:18 -0700243
Vladimir Markoca6fff82017-10-03 14:49:14 +0100244 HBasicBlock* block1 = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700245 graph_->AddBlock(block1);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100246 HNullCheck* null_check = new (GetAllocator()) HNullCheck(parameter1, 0);
247 HArrayLength* array_length = new (GetAllocator()) HArrayLength(null_check, 0);
248 HInstruction* cmp = new (GetAllocator()) HGreaterThanOrEqual(parameter2, array_length);
249 HIf* if_inst = new (GetAllocator()) HIf(cmp);
Mingyao Yangf384f882014-10-22 16:08:18 -0700250 block1->AddInstruction(null_check);
251 block1->AddInstruction(array_length);
252 block1->AddInstruction(cmp);
253 block1->AddInstruction(if_inst);
254 entry->AddSuccessor(block1);
255
Vladimir Markoca6fff82017-10-03 14:49:14 +0100256 HBasicBlock* block2 = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700257 graph_->AddBlock(block2);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100258 HInstruction* sub1 =
259 new (GetAllocator()) HSub(DataType::Type::kInt32, parameter2, constant_max_int);
260 HInstruction* sub2 = new (GetAllocator()) HSub(DataType::Type::kInt32, sub1, constant_max_int);
261 HInstruction* cmp2 = new (GetAllocator()) HLessThanOrEqual(sub2, constant_0);
262 if_inst = new (GetAllocator()) HIf(cmp2);
Mingyao Yangf384f882014-10-22 16:08:18 -0700263 block2->AddInstruction(sub1);
264 block2->AddInstruction(sub2);
265 block2->AddInstruction(cmp2);
266 block2->AddInstruction(if_inst);
267
Vladimir Markoca6fff82017-10-03 14:49:14 +0100268 HBasicBlock* block3 = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700269 graph_->AddBlock(block3);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100270 HBoundsCheck* bounds_check = new (GetAllocator())
Mingyao Yangf384f882014-10-22 16:08:18 -0700271 HBoundsCheck(sub2, array_length, 0);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100272 HArraySet* array_set = new (GetAllocator()) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100273 null_check, bounds_check, constant_1, DataType::Type::kInt32, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700274 block3->AddInstruction(bounds_check);
275 block3->AddInstruction(array_set);
276
Vladimir Markoca6fff82017-10-03 14:49:14 +0100277 HBasicBlock* exit = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700278 graph_->AddBlock(exit);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100279 exit->AddInstruction(new (GetAllocator()) HExit());
Andreas Gampe0418b5b2014-12-04 17:24:50 -0800280 block1->AddSuccessor(exit); // true successor
281 block1->AddSuccessor(block2); // false successor
282 block2->AddSuccessor(exit); // true successor
283 block2->AddSuccessor(block3); // false successor
Mingyao Yangf384f882014-10-22 16:08:18 -0700284 block3->AddSuccessor(exit);
285
Aart Bik22af3be2015-09-10 12:50:58 -0700286 RunBCE();
287
Mingyao Yangf384f882014-10-22 16:08:18 -0700288 ASSERT_FALSE(IsRemoved(bounds_check));
289}
290
Andreas Gampe0ba62732015-03-24 02:39:46 +0000291// array[6] = 1; // Can't eliminate.
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700292// array[5] = 1; // Can eliminate.
293// array[4] = 1; // Can eliminate.
Aart Bik22af3be2015-09-10 12:50:58 -0700294TEST_F(BoundsCheckEliminationTest, ConstantArrayBoundsElimination) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100295 HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700296 graph_->AddBlock(entry);
297 graph_->SetEntryBlock(entry);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100298 HInstruction* parameter = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100299 graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
Mingyao Yangf384f882014-10-22 16:08:18 -0700300 entry->AddInstruction(parameter);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000301
Aart Bik22af3be2015-09-10 12:50:58 -0700302 HInstruction* constant_5 = graph_->GetIntConstant(5);
303 HInstruction* constant_4 = graph_->GetIntConstant(4);
304 HInstruction* constant_6 = graph_->GetIntConstant(6);
305 HInstruction* constant_1 = graph_->GetIntConstant(1);
Mingyao Yangf384f882014-10-22 16:08:18 -0700306
Vladimir Markoca6fff82017-10-03 14:49:14 +0100307 HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700308 graph_->AddBlock(block);
Mingyao Yangf384f882014-10-22 16:08:18 -0700309 entry->AddSuccessor(block);
310
Vladimir Markoca6fff82017-10-03 14:49:14 +0100311 HNullCheck* null_check = new (GetAllocator()) HNullCheck(parameter, 0);
312 HArrayLength* array_length = new (GetAllocator()) HArrayLength(null_check, 0);
313 HBoundsCheck* bounds_check6 = new (GetAllocator())
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700314 HBoundsCheck(constant_6, array_length, 0);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100315 HInstruction* array_set = new (GetAllocator()) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100316 null_check, bounds_check6, constant_1, DataType::Type::kInt32, 0);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700317 block->AddInstruction(null_check);
318 block->AddInstruction(array_length);
319 block->AddInstruction(bounds_check6);
320 block->AddInstruction(array_set);
321
Vladimir Markoca6fff82017-10-03 14:49:14 +0100322 null_check = new (GetAllocator()) HNullCheck(parameter, 0);
323 array_length = new (GetAllocator()) HArrayLength(null_check, 0);
324 HBoundsCheck* bounds_check5 = new (GetAllocator())
Mingyao Yangf384f882014-10-22 16:08:18 -0700325 HBoundsCheck(constant_5, array_length, 0);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100326 array_set = new (GetAllocator()) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100327 null_check, bounds_check5, constant_1, DataType::Type::kInt32, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700328 block->AddInstruction(null_check);
329 block->AddInstruction(array_length);
330 block->AddInstruction(bounds_check5);
331 block->AddInstruction(array_set);
332
Vladimir Markoca6fff82017-10-03 14:49:14 +0100333 null_check = new (GetAllocator()) HNullCheck(parameter, 0);
334 array_length = new (GetAllocator()) HArrayLength(null_check, 0);
335 HBoundsCheck* bounds_check4 = new (GetAllocator())
Mingyao Yangf384f882014-10-22 16:08:18 -0700336 HBoundsCheck(constant_4, array_length, 0);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100337 array_set = new (GetAllocator()) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100338 null_check, bounds_check4, constant_1, DataType::Type::kInt32, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700339 block->AddInstruction(null_check);
340 block->AddInstruction(array_length);
341 block->AddInstruction(bounds_check4);
342 block->AddInstruction(array_set);
343
Vladimir Markoca6fff82017-10-03 14:49:14 +0100344 block->AddInstruction(new (GetAllocator()) HGoto());
Mingyao Yangf384f882014-10-22 16:08:18 -0700345
Vladimir Markoca6fff82017-10-03 14:49:14 +0100346 HBasicBlock* exit = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700347 graph_->AddBlock(exit);
Mingyao Yangf384f882014-10-22 16:08:18 -0700348 block->AddSuccessor(exit);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100349 exit->AddInstruction(new (GetAllocator()) HExit());
Mingyao Yangf384f882014-10-22 16:08:18 -0700350
Aart Bik22af3be2015-09-10 12:50:58 -0700351 RunBCE();
352
Andreas Gampe0ba62732015-03-24 02:39:46 +0000353 ASSERT_FALSE(IsRemoved(bounds_check6));
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700354 ASSERT_TRUE(IsRemoved(bounds_check5));
355 ASSERT_TRUE(IsRemoved(bounds_check4));
Mingyao Yangf384f882014-10-22 16:08:18 -0700356}
357
358// for (int i=initial; i<array.length; i+=increment) { array[i] = 10; }
Aart Bik22af3be2015-09-10 12:50:58 -0700359static HInstruction* BuildSSAGraph1(HGraph* graph,
360 ArenaAllocator* allocator,
361 int initial,
362 int increment,
363 IfCondition cond = kCondGE) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700364 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
365 graph->AddBlock(entry);
366 graph->SetEntryBlock(entry);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000367 HInstruction* parameter = new (allocator) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100368 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
Mingyao Yangf384f882014-10-22 16:08:18 -0700369 entry->AddInstruction(parameter);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000370
371 HInstruction* constant_initial = graph->GetIntConstant(initial);
372 HInstruction* constant_increment = graph->GetIntConstant(increment);
373 HInstruction* constant_10 = graph->GetIntConstant(10);
Mingyao Yangf384f882014-10-22 16:08:18 -0700374
375 HBasicBlock* block = new (allocator) HBasicBlock(graph);
376 graph->AddBlock(block);
377 entry->AddSuccessor(block);
378 block->AddInstruction(new (allocator) HGoto());
379
380 HBasicBlock* loop_header = new (allocator) HBasicBlock(graph);
381 HBasicBlock* loop_body = new (allocator) HBasicBlock(graph);
382 HBasicBlock* exit = new (allocator) HBasicBlock(graph);
383
384 graph->AddBlock(loop_header);
385 graph->AddBlock(loop_body);
386 graph->AddBlock(exit);
387 block->AddSuccessor(loop_header);
388 loop_header->AddSuccessor(exit); // true successor
389 loop_header->AddSuccessor(loop_body); // false successor
390 loop_body->AddSuccessor(loop_header);
391
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100392 HPhi* phi = new (allocator) HPhi(allocator, 0, 0, DataType::Type::kInt32);
Mingyao Yangf384f882014-10-22 16:08:18 -0700393 HInstruction* null_check = new (allocator) HNullCheck(parameter, 0);
Calin Juravle154746b2015-10-06 15:46:54 +0100394 HInstruction* array_length = new (allocator) HArrayLength(null_check, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700395 HInstruction* cmp = nullptr;
396 if (cond == kCondGE) {
397 cmp = new (allocator) HGreaterThanOrEqual(phi, array_length);
398 } else {
399 DCHECK(cond == kCondGT);
400 cmp = new (allocator) HGreaterThan(phi, array_length);
401 }
402 HInstruction* if_inst = new (allocator) HIf(cmp);
403 loop_header->AddPhi(phi);
404 loop_header->AddInstruction(null_check);
405 loop_header->AddInstruction(array_length);
406 loop_header->AddInstruction(cmp);
407 loop_header->AddInstruction(if_inst);
David Brazdil1abb4192015-02-17 18:33:36 +0000408 phi->AddInput(constant_initial);
Mingyao Yangf384f882014-10-22 16:08:18 -0700409
410 null_check = new (allocator) HNullCheck(parameter, 0);
Calin Juravle154746b2015-10-06 15:46:54 +0100411 array_length = new (allocator) HArrayLength(null_check, 0);
Aart Bik22af3be2015-09-10 12:50:58 -0700412 HInstruction* bounds_check = new (allocator) HBoundsCheck(phi, array_length, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700413 HInstruction* array_set = new (allocator) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100414 null_check, bounds_check, constant_10, DataType::Type::kInt32, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700415
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100416 HInstruction* add = new (allocator) HAdd(DataType::Type::kInt32, phi, constant_increment);
Mingyao Yangf384f882014-10-22 16:08:18 -0700417 loop_body->AddInstruction(null_check);
418 loop_body->AddInstruction(array_length);
Aart Bik22af3be2015-09-10 12:50:58 -0700419 loop_body->AddInstruction(bounds_check);
Mingyao Yangf384f882014-10-22 16:08:18 -0700420 loop_body->AddInstruction(array_set);
421 loop_body->AddInstruction(add);
422 loop_body->AddInstruction(new (allocator) HGoto());
423 phi->AddInput(add);
424
425 exit->AddInstruction(new (allocator) HExit());
426
Aart Bik22af3be2015-09-10 12:50:58 -0700427 return bounds_check;
Mingyao Yangf384f882014-10-22 16:08:18 -0700428}
429
Aart Bik22af3be2015-09-10 12:50:58 -0700430TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination1a) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700431 // for (int i=0; i<array.length; i++) { array[i] = 10; // Can eliminate with gvn. }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100432 HInstruction* bounds_check = BuildSSAGraph1(graph_, GetAllocator(), 0, 1);
Aart Bik22af3be2015-09-10 12:50:58 -0700433 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700434 ASSERT_TRUE(IsRemoved(bounds_check));
Aart Bik22af3be2015-09-10 12:50:58 -0700435}
Mingyao Yangf384f882014-10-22 16:08:18 -0700436
Aart Bik22af3be2015-09-10 12:50:58 -0700437TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination1b) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700438 // for (int i=1; i<array.length; i++) { array[i] = 10; // Can eliminate. }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100439 HInstruction* bounds_check = BuildSSAGraph1(graph_, GetAllocator(), 1, 1);
Aart Bik22af3be2015-09-10 12:50:58 -0700440 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700441 ASSERT_TRUE(IsRemoved(bounds_check));
Aart Bik22af3be2015-09-10 12:50:58 -0700442}
Mingyao Yangf384f882014-10-22 16:08:18 -0700443
Aart Bik22af3be2015-09-10 12:50:58 -0700444TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination1c) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700445 // for (int i=-1; i<array.length; i++) { array[i] = 10; // Can't eliminate. }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100446 HInstruction* bounds_check = BuildSSAGraph1(graph_, GetAllocator(), -1, 1);
Aart Bik22af3be2015-09-10 12:50:58 -0700447 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700448 ASSERT_FALSE(IsRemoved(bounds_check));
Aart Bik22af3be2015-09-10 12:50:58 -0700449}
Mingyao Yangf384f882014-10-22 16:08:18 -0700450
Aart Bik22af3be2015-09-10 12:50:58 -0700451TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination1d) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700452 // for (int i=0; i<=array.length; i++) { array[i] = 10; // Can't eliminate. }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100453 HInstruction* bounds_check = BuildSSAGraph1(graph_, GetAllocator(), 0, 1, kCondGT);
Aart Bik22af3be2015-09-10 12:50:58 -0700454 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700455 ASSERT_FALSE(IsRemoved(bounds_check));
Aart Bik22af3be2015-09-10 12:50:58 -0700456}
Mingyao Yangf384f882014-10-22 16:08:18 -0700457
Aart Bik22af3be2015-09-10 12:50:58 -0700458TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination1e) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700459 // for (int i=0; i<array.length; i += 2) {
460 // array[i] = 10; // Can't eliminate due to overflow concern. }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100461 HInstruction* bounds_check = BuildSSAGraph1(graph_, GetAllocator(), 0, 2);
Aart Bik22af3be2015-09-10 12:50:58 -0700462 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700463 ASSERT_FALSE(IsRemoved(bounds_check));
Aart Bik22af3be2015-09-10 12:50:58 -0700464}
Mingyao Yangf384f882014-10-22 16:08:18 -0700465
Aart Bik22af3be2015-09-10 12:50:58 -0700466TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination1f) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700467 // for (int i=1; i<array.length; i += 2) { array[i] = 10; // Can eliminate. }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100468 HInstruction* bounds_check = BuildSSAGraph1(graph_, GetAllocator(), 1, 2);
Aart Bik22af3be2015-09-10 12:50:58 -0700469 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700470 ASSERT_TRUE(IsRemoved(bounds_check));
471}
472
473// for (int i=array.length; i>0; i+=increment) { array[i-1] = 10; }
Aart Bik22af3be2015-09-10 12:50:58 -0700474static HInstruction* BuildSSAGraph2(HGraph *graph,
475 ArenaAllocator* allocator,
476 int initial,
477 int increment = -1,
478 IfCondition cond = kCondLE) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700479 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
480 graph->AddBlock(entry);
481 graph->SetEntryBlock(entry);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000482 HInstruction* parameter = new (allocator) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100483 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
Mingyao Yangf384f882014-10-22 16:08:18 -0700484 entry->AddInstruction(parameter);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000485
486 HInstruction* constant_initial = graph->GetIntConstant(initial);
487 HInstruction* constant_increment = graph->GetIntConstant(increment);
488 HInstruction* constant_minus_1 = graph->GetIntConstant(-1);
489 HInstruction* constant_10 = graph->GetIntConstant(10);
Mingyao Yangf384f882014-10-22 16:08:18 -0700490
491 HBasicBlock* block = new (allocator) HBasicBlock(graph);
492 graph->AddBlock(block);
493 entry->AddSuccessor(block);
494 HInstruction* null_check = new (allocator) HNullCheck(parameter, 0);
Calin Juravle154746b2015-10-06 15:46:54 +0100495 HInstruction* array_length = new (allocator) HArrayLength(null_check, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700496 block->AddInstruction(null_check);
497 block->AddInstruction(array_length);
498 block->AddInstruction(new (allocator) HGoto());
499
500 HBasicBlock* loop_header = new (allocator) HBasicBlock(graph);
501 HBasicBlock* loop_body = new (allocator) HBasicBlock(graph);
502 HBasicBlock* exit = new (allocator) HBasicBlock(graph);
503
504 graph->AddBlock(loop_header);
505 graph->AddBlock(loop_body);
506 graph->AddBlock(exit);
507 block->AddSuccessor(loop_header);
508 loop_header->AddSuccessor(exit); // true successor
509 loop_header->AddSuccessor(loop_body); // false successor
510 loop_body->AddSuccessor(loop_header);
511
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100512 HPhi* phi = new (allocator) HPhi(allocator, 0, 0, DataType::Type::kInt32);
Mingyao Yangf384f882014-10-22 16:08:18 -0700513 HInstruction* cmp = nullptr;
514 if (cond == kCondLE) {
515 cmp = new (allocator) HLessThanOrEqual(phi, constant_initial);
516 } else {
517 DCHECK(cond == kCondLT);
518 cmp = new (allocator) HLessThan(phi, constant_initial);
519 }
520 HInstruction* if_inst = new (allocator) HIf(cmp);
521 loop_header->AddPhi(phi);
522 loop_header->AddInstruction(cmp);
523 loop_header->AddInstruction(if_inst);
David Brazdil1abb4192015-02-17 18:33:36 +0000524 phi->AddInput(array_length);
Mingyao Yangf384f882014-10-22 16:08:18 -0700525
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100526 HInstruction* add = new (allocator) HAdd(DataType::Type::kInt32, phi, constant_minus_1);
Mingyao Yangf384f882014-10-22 16:08:18 -0700527 null_check = new (allocator) HNullCheck(parameter, 0);
Calin Juravle154746b2015-10-06 15:46:54 +0100528 array_length = new (allocator) HArrayLength(null_check, 0);
Aart Bik22af3be2015-09-10 12:50:58 -0700529 HInstruction* bounds_check = new (allocator) HBoundsCheck(add, array_length, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700530 HInstruction* array_set = new (allocator) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100531 null_check, bounds_check, constant_10, DataType::Type::kInt32, 0);
532 HInstruction* add_phi = new (allocator) HAdd(DataType::Type::kInt32, phi, constant_increment);
Mingyao Yangf384f882014-10-22 16:08:18 -0700533 loop_body->AddInstruction(add);
534 loop_body->AddInstruction(null_check);
535 loop_body->AddInstruction(array_length);
Aart Bik22af3be2015-09-10 12:50:58 -0700536 loop_body->AddInstruction(bounds_check);
Mingyao Yangf384f882014-10-22 16:08:18 -0700537 loop_body->AddInstruction(array_set);
538 loop_body->AddInstruction(add_phi);
539 loop_body->AddInstruction(new (allocator) HGoto());
540 phi->AddInput(add);
541
542 exit->AddInstruction(new (allocator) HExit());
543
Aart Bik22af3be2015-09-10 12:50:58 -0700544 return bounds_check;
Mingyao Yangf384f882014-10-22 16:08:18 -0700545}
546
Aart Bik22af3be2015-09-10 12:50:58 -0700547TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination2a) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700548 // for (int i=array.length; i>0; i--) { array[i-1] = 10; // Can eliminate with gvn. }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100549 HInstruction* bounds_check = BuildSSAGraph2(graph_, GetAllocator(), 0);
Aart Bik22af3be2015-09-10 12:50:58 -0700550 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700551 ASSERT_TRUE(IsRemoved(bounds_check));
Aart Bik22af3be2015-09-10 12:50:58 -0700552}
Mingyao Yangf384f882014-10-22 16:08:18 -0700553
Aart Bik22af3be2015-09-10 12:50:58 -0700554TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination2b) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700555 // for (int i=array.length; i>1; i--) { array[i-1] = 10; // Can eliminate. }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100556 HInstruction* bounds_check = BuildSSAGraph2(graph_, GetAllocator(), 1);
Aart Bik22af3be2015-09-10 12:50:58 -0700557 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700558 ASSERT_TRUE(IsRemoved(bounds_check));
Aart Bik22af3be2015-09-10 12:50:58 -0700559}
Mingyao Yangf384f882014-10-22 16:08:18 -0700560
Aart Bik22af3be2015-09-10 12:50:58 -0700561TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination2c) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700562 // for (int i=array.length; i>-1; i--) { array[i-1] = 10; // Can't eliminate. }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100563 HInstruction* bounds_check = BuildSSAGraph2(graph_, GetAllocator(), -1);
Aart Bik22af3be2015-09-10 12:50:58 -0700564 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700565 ASSERT_FALSE(IsRemoved(bounds_check));
Aart Bik22af3be2015-09-10 12:50:58 -0700566}
Mingyao Yangf384f882014-10-22 16:08:18 -0700567
Aart Bik22af3be2015-09-10 12:50:58 -0700568TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination2d) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700569 // for (int i=array.length; i>=0; i--) { array[i-1] = 10; // Can't eliminate. }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100570 HInstruction* bounds_check = BuildSSAGraph2(graph_, GetAllocator(), 0, -1, kCondLT);
Aart Bik22af3be2015-09-10 12:50:58 -0700571 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700572 ASSERT_FALSE(IsRemoved(bounds_check));
Aart Bik22af3be2015-09-10 12:50:58 -0700573}
Mingyao Yangf384f882014-10-22 16:08:18 -0700574
Aart Bik22af3be2015-09-10 12:50:58 -0700575TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination2e) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700576 // for (int i=array.length; i>0; i-=2) { array[i-1] = 10; // Can eliminate. }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100577 HInstruction* bounds_check = BuildSSAGraph2(graph_, GetAllocator(), 0, -2);
Aart Bik22af3be2015-09-10 12:50:58 -0700578 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700579 ASSERT_TRUE(IsRemoved(bounds_check));
580}
581
Mingyao Yang8c8bad82015-02-09 18:13:26 -0800582// int[] array = new int[10];
Mingyao Yangf384f882014-10-22 16:08:18 -0700583// for (int i=0; i<10; i+=increment) { array[i] = 10; }
Aart Bik22af3be2015-09-10 12:50:58 -0700584static HInstruction* BuildSSAGraph3(HGraph* graph,
585 ArenaAllocator* allocator,
586 int initial,
587 int increment,
588 IfCondition cond) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700589 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
590 graph->AddBlock(entry);
591 graph->SetEntryBlock(entry);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000592
593 HInstruction* constant_10 = graph->GetIntConstant(10);
594 HInstruction* constant_initial = graph->GetIntConstant(initial);
595 HInstruction* constant_increment = graph->GetIntConstant(increment);
Mingyao Yangf384f882014-10-22 16:08:18 -0700596
597 HBasicBlock* block = new (allocator) HBasicBlock(graph);
598 graph->AddBlock(block);
599 entry->AddSuccessor(block);
Nicolas Geoffraye761bcc2017-01-19 08:59:37 +0000600 // We pass a bogus constant for the class to avoid mocking one.
Nicolas Geoffray69aa6012015-06-09 10:34:25 +0100601 HInstruction* new_array = new (allocator) HNewArray(
Vladimir Markob5461632018-10-15 14:24:21 +0100602 /* cls= */ constant_10,
603 /* length= */ constant_10,
604 /* dex_pc= */ 0,
605 /* component_size_shift= */ 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700606 block->AddInstruction(new_array);
607 block->AddInstruction(new (allocator) HGoto());
608
609 HBasicBlock* loop_header = new (allocator) HBasicBlock(graph);
610 HBasicBlock* loop_body = new (allocator) HBasicBlock(graph);
611 HBasicBlock* exit = new (allocator) HBasicBlock(graph);
612
613 graph->AddBlock(loop_header);
614 graph->AddBlock(loop_body);
615 graph->AddBlock(exit);
616 block->AddSuccessor(loop_header);
617 loop_header->AddSuccessor(exit); // true successor
618 loop_header->AddSuccessor(loop_body); // false successor
619 loop_body->AddSuccessor(loop_header);
620
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100621 HPhi* phi = new (allocator) HPhi(allocator, 0, 0, DataType::Type::kInt32);
Mingyao Yangf384f882014-10-22 16:08:18 -0700622 HInstruction* cmp = nullptr;
623 if (cond == kCondGE) {
624 cmp = new (allocator) HGreaterThanOrEqual(phi, constant_10);
625 } else {
626 DCHECK(cond == kCondGT);
627 cmp = new (allocator) HGreaterThan(phi, constant_10);
628 }
629 HInstruction* if_inst = new (allocator) HIf(cmp);
630 loop_header->AddPhi(phi);
631 loop_header->AddInstruction(cmp);
632 loop_header->AddInstruction(if_inst);
David Brazdil1abb4192015-02-17 18:33:36 +0000633 phi->AddInput(constant_initial);
Mingyao Yangf384f882014-10-22 16:08:18 -0700634
635 HNullCheck* null_check = new (allocator) HNullCheck(new_array, 0);
Calin Juravle154746b2015-10-06 15:46:54 +0100636 HArrayLength* array_length = new (allocator) HArrayLength(null_check, 0);
Aart Bik22af3be2015-09-10 12:50:58 -0700637 HInstruction* bounds_check = new (allocator) HBoundsCheck(phi, array_length, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700638 HInstruction* array_set = new (allocator) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100639 null_check, bounds_check, constant_10, DataType::Type::kInt32, 0);
640 HInstruction* add = new (allocator) HAdd(DataType::Type::kInt32, phi, constant_increment);
Mingyao Yangf384f882014-10-22 16:08:18 -0700641 loop_body->AddInstruction(null_check);
642 loop_body->AddInstruction(array_length);
Aart Bik22af3be2015-09-10 12:50:58 -0700643 loop_body->AddInstruction(bounds_check);
Mingyao Yangf384f882014-10-22 16:08:18 -0700644 loop_body->AddInstruction(array_set);
645 loop_body->AddInstruction(add);
646 loop_body->AddInstruction(new (allocator) HGoto());
647 phi->AddInput(add);
648
649 exit->AddInstruction(new (allocator) HExit());
650
Aart Bik22af3be2015-09-10 12:50:58 -0700651 return bounds_check;
Mingyao Yangf384f882014-10-22 16:08:18 -0700652}
653
Aart Bik22af3be2015-09-10 12:50:58 -0700654TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination3a) {
Mingyao Yang8c8bad82015-02-09 18:13:26 -0800655 // int[] array = new int[10];
Mingyao Yangf384f882014-10-22 16:08:18 -0700656 // for (int i=0; i<10; i++) { array[i] = 10; // Can eliminate. }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100657 HInstruction* bounds_check = BuildSSAGraph3(graph_, GetAllocator(), 0, 1, kCondGE);
Aart Bik22af3be2015-09-10 12:50:58 -0700658 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700659 ASSERT_TRUE(IsRemoved(bounds_check));
Aart Bik22af3be2015-09-10 12:50:58 -0700660}
Mingyao Yangf384f882014-10-22 16:08:18 -0700661
Aart Bik22af3be2015-09-10 12:50:58 -0700662TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination3b) {
Mingyao Yang8c8bad82015-02-09 18:13:26 -0800663 // int[] array = new int[10];
Mingyao Yangf384f882014-10-22 16:08:18 -0700664 // for (int i=1; i<10; i++) { array[i] = 10; // Can eliminate. }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100665 HInstruction* bounds_check = BuildSSAGraph3(graph_, GetAllocator(), 1, 1, kCondGE);
Aart Bik22af3be2015-09-10 12:50:58 -0700666 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700667 ASSERT_TRUE(IsRemoved(bounds_check));
Aart Bik22af3be2015-09-10 12:50:58 -0700668}
Mingyao Yangf384f882014-10-22 16:08:18 -0700669
Aart Bik22af3be2015-09-10 12:50:58 -0700670TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination3c) {
Mingyao Yang8c8bad82015-02-09 18:13:26 -0800671 // int[] array = new int[10];
Mingyao Yangf384f882014-10-22 16:08:18 -0700672 // for (int i=0; i<=10; i++) { array[i] = 10; // Can't eliminate. }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100673 HInstruction* bounds_check = BuildSSAGraph3(graph_, GetAllocator(), 0, 1, kCondGT);
Aart Bik22af3be2015-09-10 12:50:58 -0700674 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700675 ASSERT_FALSE(IsRemoved(bounds_check));
Aart Bik22af3be2015-09-10 12:50:58 -0700676}
Mingyao Yangf384f882014-10-22 16:08:18 -0700677
Aart Bik22af3be2015-09-10 12:50:58 -0700678TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination3d) {
Mingyao Yang8c8bad82015-02-09 18:13:26 -0800679 // int[] array = new int[10];
Mingyao Yangf384f882014-10-22 16:08:18 -0700680 // for (int i=1; i<10; i+=8) { array[i] = 10; // Can eliminate. }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100681 HInstruction* bounds_check = BuildSSAGraph3(graph_, GetAllocator(), 1, 8, kCondGE);
Aart Bik22af3be2015-09-10 12:50:58 -0700682 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700683 ASSERT_TRUE(IsRemoved(bounds_check));
684}
685
686// for (int i=initial; i<array.length; i++) { array[array.length-i-1] = 10; }
Aart Bik22af3be2015-09-10 12:50:58 -0700687static HInstruction* BuildSSAGraph4(HGraph* graph,
688 ArenaAllocator* allocator,
689 int initial,
690 IfCondition cond = kCondGE) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700691 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
692 graph->AddBlock(entry);
693 graph->SetEntryBlock(entry);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000694 HInstruction* parameter = new (allocator) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100695 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
Mingyao Yangf384f882014-10-22 16:08:18 -0700696 entry->AddInstruction(parameter);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000697
698 HInstruction* constant_initial = graph->GetIntConstant(initial);
699 HInstruction* constant_1 = graph->GetIntConstant(1);
700 HInstruction* constant_10 = graph->GetIntConstant(10);
701 HInstruction* constant_minus_1 = graph->GetIntConstant(-1);
Mingyao Yangf384f882014-10-22 16:08:18 -0700702
703 HBasicBlock* block = new (allocator) HBasicBlock(graph);
704 graph->AddBlock(block);
705 entry->AddSuccessor(block);
706 block->AddInstruction(new (allocator) HGoto());
707
708 HBasicBlock* loop_header = new (allocator) HBasicBlock(graph);
709 HBasicBlock* loop_body = new (allocator) HBasicBlock(graph);
710 HBasicBlock* exit = new (allocator) HBasicBlock(graph);
711
712 graph->AddBlock(loop_header);
713 graph->AddBlock(loop_body);
714 graph->AddBlock(exit);
715 block->AddSuccessor(loop_header);
716 loop_header->AddSuccessor(exit); // true successor
717 loop_header->AddSuccessor(loop_body); // false successor
718 loop_body->AddSuccessor(loop_header);
719
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100720 HPhi* phi = new (allocator) HPhi(allocator, 0, 0, DataType::Type::kInt32);
Mingyao Yangf384f882014-10-22 16:08:18 -0700721 HInstruction* null_check = new (allocator) HNullCheck(parameter, 0);
Calin Juravle154746b2015-10-06 15:46:54 +0100722 HInstruction* array_length = new (allocator) HArrayLength(null_check, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700723 HInstruction* cmp = nullptr;
724 if (cond == kCondGE) {
725 cmp = new (allocator) HGreaterThanOrEqual(phi, array_length);
726 } else if (cond == kCondGT) {
727 cmp = new (allocator) HGreaterThan(phi, array_length);
728 }
729 HInstruction* if_inst = new (allocator) HIf(cmp);
730 loop_header->AddPhi(phi);
731 loop_header->AddInstruction(null_check);
732 loop_header->AddInstruction(array_length);
733 loop_header->AddInstruction(cmp);
734 loop_header->AddInstruction(if_inst);
David Brazdil1abb4192015-02-17 18:33:36 +0000735 phi->AddInput(constant_initial);
Mingyao Yangf384f882014-10-22 16:08:18 -0700736
737 null_check = new (allocator) HNullCheck(parameter, 0);
Calin Juravle154746b2015-10-06 15:46:54 +0100738 array_length = new (allocator) HArrayLength(null_check, 0);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100739 HInstruction* sub = new (allocator) HSub(DataType::Type::kInt32, array_length, phi);
Mingyao Yangf384f882014-10-22 16:08:18 -0700740 HInstruction* add_minus_1 = new (allocator)
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100741 HAdd(DataType::Type::kInt32, sub, constant_minus_1);
Aart Bik22af3be2015-09-10 12:50:58 -0700742 HInstruction* bounds_check = new (allocator) HBoundsCheck(add_minus_1, array_length, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700743 HInstruction* array_set = new (allocator) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100744 null_check, bounds_check, constant_10, DataType::Type::kInt32, 0);
745 HInstruction* add = new (allocator) HAdd(DataType::Type::kInt32, phi, constant_1);
Mingyao Yangf384f882014-10-22 16:08:18 -0700746 loop_body->AddInstruction(null_check);
747 loop_body->AddInstruction(array_length);
748 loop_body->AddInstruction(sub);
749 loop_body->AddInstruction(add_minus_1);
Aart Bik22af3be2015-09-10 12:50:58 -0700750 loop_body->AddInstruction(bounds_check);
Mingyao Yangf384f882014-10-22 16:08:18 -0700751 loop_body->AddInstruction(array_set);
752 loop_body->AddInstruction(add);
753 loop_body->AddInstruction(new (allocator) HGoto());
754 phi->AddInput(add);
755
756 exit->AddInstruction(new (allocator) HExit());
757
Aart Bik22af3be2015-09-10 12:50:58 -0700758 return bounds_check;
Mingyao Yangf384f882014-10-22 16:08:18 -0700759}
760
Aart Bik22af3be2015-09-10 12:50:58 -0700761TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination4a) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700762 // for (int i=0; i<array.length; i++) { array[array.length-i-1] = 10; // Can eliminate with gvn. }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100763 HInstruction* bounds_check = BuildSSAGraph4(graph_, GetAllocator(), 0);
Aart Bik22af3be2015-09-10 12:50:58 -0700764 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700765 ASSERT_TRUE(IsRemoved(bounds_check));
Aart Bik22af3be2015-09-10 12:50:58 -0700766}
Mingyao Yangf384f882014-10-22 16:08:18 -0700767
Aart Bik22af3be2015-09-10 12:50:58 -0700768TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination4b) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700769 // for (int i=1; i<array.length; i++) { array[array.length-i-1] = 10; // Can eliminate. }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100770 HInstruction* bounds_check = BuildSSAGraph4(graph_, GetAllocator(), 1);
Aart Bik22af3be2015-09-10 12:50:58 -0700771 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700772 ASSERT_TRUE(IsRemoved(bounds_check));
Aart Bik22af3be2015-09-10 12:50:58 -0700773}
Mingyao Yangf384f882014-10-22 16:08:18 -0700774
Aart Bik22af3be2015-09-10 12:50:58 -0700775TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination4c) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700776 // for (int i=0; i<=array.length; i++) { array[array.length-i] = 10; // Can't eliminate. }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100777 HInstruction* bounds_check = BuildSSAGraph4(graph_, GetAllocator(), 0, kCondGT);
Aart Bik22af3be2015-09-10 12:50:58 -0700778 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700779 ASSERT_FALSE(IsRemoved(bounds_check));
780}
781
782// Bubble sort:
783// (Every array access bounds-check can be eliminated.)
784// for (int i=0; i<array.length-1; i++) {
785// for (int j=0; j<array.length-i-1; j++) {
786// if (array[j] > array[j+1]) {
787// int temp = array[j+1];
788// array[j+1] = array[j];
789// array[j] = temp;
790// }
791// }
792// }
Aart Bik22af3be2015-09-10 12:50:58 -0700793TEST_F(BoundsCheckEliminationTest, BubbleSortArrayBoundsElimination) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100794 HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700795 graph_->AddBlock(entry);
796 graph_->SetEntryBlock(entry);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100797 HInstruction* parameter = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100798 graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
Mingyao Yangf384f882014-10-22 16:08:18 -0700799 entry->AddInstruction(parameter);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000800
Aart Bik22af3be2015-09-10 12:50:58 -0700801 HInstruction* constant_0 = graph_->GetIntConstant(0);
802 HInstruction* constant_minus_1 = graph_->GetIntConstant(-1);
803 HInstruction* constant_1 = graph_->GetIntConstant(1);
Mingyao Yangf384f882014-10-22 16:08:18 -0700804
Vladimir Markoca6fff82017-10-03 14:49:14 +0100805 HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700806 graph_->AddBlock(block);
Mingyao Yangf384f882014-10-22 16:08:18 -0700807 entry->AddSuccessor(block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100808 block->AddInstruction(new (GetAllocator()) HGoto());
Mingyao Yangf384f882014-10-22 16:08:18 -0700809
Vladimir Markoca6fff82017-10-03 14:49:14 +0100810 HBasicBlock* exit = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700811 graph_->AddBlock(exit);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100812 exit->AddInstruction(new (GetAllocator()) HExit());
Mingyao Yangf384f882014-10-22 16:08:18 -0700813
Vladimir Markoca6fff82017-10-03 14:49:14 +0100814 HBasicBlock* outer_header = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700815 graph_->AddBlock(outer_header);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100816 HPhi* phi_i = new (GetAllocator()) HPhi(GetAllocator(), 0, 0, DataType::Type::kInt32);
817 HNullCheck* null_check = new (GetAllocator()) HNullCheck(parameter, 0);
818 HArrayLength* array_length = new (GetAllocator()) HArrayLength(null_check, 0);
819 HAdd* add = new (GetAllocator()) HAdd(DataType::Type::kInt32, array_length, constant_minus_1);
820 HInstruction* cmp = new (GetAllocator()) HGreaterThanOrEqual(phi_i, add);
821 HIf* if_inst = new (GetAllocator()) HIf(cmp);
Mingyao Yangf384f882014-10-22 16:08:18 -0700822 outer_header->AddPhi(phi_i);
823 outer_header->AddInstruction(null_check);
824 outer_header->AddInstruction(array_length);
825 outer_header->AddInstruction(add);
826 outer_header->AddInstruction(cmp);
827 outer_header->AddInstruction(if_inst);
David Brazdil1abb4192015-02-17 18:33:36 +0000828 phi_i->AddInput(constant_0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700829
Vladimir Markoca6fff82017-10-03 14:49:14 +0100830 HBasicBlock* inner_header = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700831 graph_->AddBlock(inner_header);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100832 HPhi* phi_j = new (GetAllocator()) HPhi(GetAllocator(), 0, 0, DataType::Type::kInt32);
833 null_check = new (GetAllocator()) HNullCheck(parameter, 0);
834 array_length = new (GetAllocator()) HArrayLength(null_check, 0);
835 HSub* sub = new (GetAllocator()) HSub(DataType::Type::kInt32, array_length, phi_i);
836 add = new (GetAllocator()) HAdd(DataType::Type::kInt32, sub, constant_minus_1);
837 cmp = new (GetAllocator()) HGreaterThanOrEqual(phi_j, add);
838 if_inst = new (GetAllocator()) HIf(cmp);
Mingyao Yangf384f882014-10-22 16:08:18 -0700839 inner_header->AddPhi(phi_j);
840 inner_header->AddInstruction(null_check);
841 inner_header->AddInstruction(array_length);
842 inner_header->AddInstruction(sub);
843 inner_header->AddInstruction(add);
844 inner_header->AddInstruction(cmp);
845 inner_header->AddInstruction(if_inst);
David Brazdil1abb4192015-02-17 18:33:36 +0000846 phi_j->AddInput(constant_0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700847
Vladimir Markoca6fff82017-10-03 14:49:14 +0100848 HBasicBlock* inner_body_compare = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700849 graph_->AddBlock(inner_body_compare);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100850 null_check = new (GetAllocator()) HNullCheck(parameter, 0);
851 array_length = new (GetAllocator()) HArrayLength(null_check, 0);
852 HBoundsCheck* bounds_check1 = new (GetAllocator()) HBoundsCheck(phi_j, array_length, 0);
853 HArrayGet* array_get_j = new (GetAllocator())
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100854 HArrayGet(null_check, bounds_check1, DataType::Type::kInt32, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700855 inner_body_compare->AddInstruction(null_check);
856 inner_body_compare->AddInstruction(array_length);
857 inner_body_compare->AddInstruction(bounds_check1);
858 inner_body_compare->AddInstruction(array_get_j);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100859 HInstruction* j_plus_1 = new (GetAllocator()) HAdd(DataType::Type::kInt32, phi_j, constant_1);
860 null_check = new (GetAllocator()) HNullCheck(parameter, 0);
861 array_length = new (GetAllocator()) HArrayLength(null_check, 0);
862 HBoundsCheck* bounds_check2 = new (GetAllocator()) HBoundsCheck(j_plus_1, array_length, 0);
863 HArrayGet* array_get_j_plus_1 = new (GetAllocator())
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100864 HArrayGet(null_check, bounds_check2, DataType::Type::kInt32, 0);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100865 cmp = new (GetAllocator()) HGreaterThanOrEqual(array_get_j, array_get_j_plus_1);
866 if_inst = new (GetAllocator()) HIf(cmp);
Mingyao Yangf384f882014-10-22 16:08:18 -0700867 inner_body_compare->AddInstruction(j_plus_1);
868 inner_body_compare->AddInstruction(null_check);
869 inner_body_compare->AddInstruction(array_length);
870 inner_body_compare->AddInstruction(bounds_check2);
871 inner_body_compare->AddInstruction(array_get_j_plus_1);
872 inner_body_compare->AddInstruction(cmp);
873 inner_body_compare->AddInstruction(if_inst);
874
Vladimir Markoca6fff82017-10-03 14:49:14 +0100875 HBasicBlock* inner_body_swap = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700876 graph_->AddBlock(inner_body_swap);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100877 j_plus_1 = new (GetAllocator()) HAdd(DataType::Type::kInt32, phi_j, constant_1);
Mingyao Yangf384f882014-10-22 16:08:18 -0700878 // temp = array[j+1]
Vladimir Markoca6fff82017-10-03 14:49:14 +0100879 null_check = new (GetAllocator()) HNullCheck(parameter, 0);
880 array_length = new (GetAllocator()) HArrayLength(null_check, 0);
881 HInstruction* bounds_check3 = new (GetAllocator()) HBoundsCheck(j_plus_1, array_length, 0);
882 array_get_j_plus_1 = new (GetAllocator())
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100883 HArrayGet(null_check, bounds_check3, DataType::Type::kInt32, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700884 inner_body_swap->AddInstruction(j_plus_1);
885 inner_body_swap->AddInstruction(null_check);
886 inner_body_swap->AddInstruction(array_length);
887 inner_body_swap->AddInstruction(bounds_check3);
888 inner_body_swap->AddInstruction(array_get_j_plus_1);
889 // array[j+1] = array[j]
Vladimir Markoca6fff82017-10-03 14:49:14 +0100890 null_check = new (GetAllocator()) HNullCheck(parameter, 0);
891 array_length = new (GetAllocator()) HArrayLength(null_check, 0);
892 HInstruction* bounds_check4 = new (GetAllocator()) HBoundsCheck(phi_j, array_length, 0);
893 array_get_j = new (GetAllocator())
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100894 HArrayGet(null_check, bounds_check4, DataType::Type::kInt32, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700895 inner_body_swap->AddInstruction(null_check);
896 inner_body_swap->AddInstruction(array_length);
897 inner_body_swap->AddInstruction(bounds_check4);
898 inner_body_swap->AddInstruction(array_get_j);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100899 null_check = new (GetAllocator()) HNullCheck(parameter, 0);
900 array_length = new (GetAllocator()) HArrayLength(null_check, 0);
901 HInstruction* bounds_check5 = new (GetAllocator()) HBoundsCheck(j_plus_1, array_length, 0);
902 HArraySet* array_set_j_plus_1 = new (GetAllocator())
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100903 HArraySet(null_check, bounds_check5, array_get_j, DataType::Type::kInt32, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700904 inner_body_swap->AddInstruction(null_check);
905 inner_body_swap->AddInstruction(array_length);
906 inner_body_swap->AddInstruction(bounds_check5);
907 inner_body_swap->AddInstruction(array_set_j_plus_1);
908 // array[j] = temp
Vladimir Markoca6fff82017-10-03 14:49:14 +0100909 null_check = new (GetAllocator()) HNullCheck(parameter, 0);
910 array_length = new (GetAllocator()) HArrayLength(null_check, 0);
911 HInstruction* bounds_check6 = new (GetAllocator()) HBoundsCheck(phi_j, array_length, 0);
912 HArraySet* array_set_j = new (GetAllocator())
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100913 HArraySet(null_check, bounds_check6, array_get_j_plus_1, DataType::Type::kInt32, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700914 inner_body_swap->AddInstruction(null_check);
915 inner_body_swap->AddInstruction(array_length);
916 inner_body_swap->AddInstruction(bounds_check6);
917 inner_body_swap->AddInstruction(array_set_j);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100918 inner_body_swap->AddInstruction(new (GetAllocator()) HGoto());
Mingyao Yangf384f882014-10-22 16:08:18 -0700919
Vladimir Markoca6fff82017-10-03 14:49:14 +0100920 HBasicBlock* inner_body_add = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700921 graph_->AddBlock(inner_body_add);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100922 add = new (GetAllocator()) HAdd(DataType::Type::kInt32, phi_j, constant_1);
Mingyao Yangf384f882014-10-22 16:08:18 -0700923 inner_body_add->AddInstruction(add);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100924 inner_body_add->AddInstruction(new (GetAllocator()) HGoto());
Mingyao Yangf384f882014-10-22 16:08:18 -0700925 phi_j->AddInput(add);
926
Vladimir Markoca6fff82017-10-03 14:49:14 +0100927 HBasicBlock* outer_body_add = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700928 graph_->AddBlock(outer_body_add);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100929 add = new (GetAllocator()) HAdd(DataType::Type::kInt32, phi_i, constant_1);
Mingyao Yangf384f882014-10-22 16:08:18 -0700930 outer_body_add->AddInstruction(add);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100931 outer_body_add->AddInstruction(new (GetAllocator()) HGoto());
Mingyao Yangf384f882014-10-22 16:08:18 -0700932 phi_i->AddInput(add);
933
934 block->AddSuccessor(outer_header);
935 outer_header->AddSuccessor(exit);
936 outer_header->AddSuccessor(inner_header);
937 inner_header->AddSuccessor(outer_body_add);
938 inner_header->AddSuccessor(inner_body_compare);
939 inner_body_compare->AddSuccessor(inner_body_add);
940 inner_body_compare->AddSuccessor(inner_body_swap);
941 inner_body_swap->AddSuccessor(inner_body_add);
942 inner_body_add->AddSuccessor(inner_header);
943 outer_body_add->AddSuccessor(outer_header);
944
Aart Bik22af3be2015-09-10 12:50:58 -0700945 RunBCE(); // gvn removes same bounds check already
Mingyao Yangf384f882014-10-22 16:08:18 -0700946
Mingyao Yangf384f882014-10-22 16:08:18 -0700947 ASSERT_TRUE(IsRemoved(bounds_check1));
948 ASSERT_TRUE(IsRemoved(bounds_check2));
949 ASSERT_TRUE(IsRemoved(bounds_check3));
950 ASSERT_TRUE(IsRemoved(bounds_check4));
951 ASSERT_TRUE(IsRemoved(bounds_check5));
952 ASSERT_TRUE(IsRemoved(bounds_check6));
953}
954
xueliang.zhonga22cae72017-06-26 17:49:48 +0100955// int[] array = new int[10];
956// for (int i=0; i<200; i++) {
957// array[i%10] = 10; // Can eliminate
958// array[i%1] = 10; // Can eliminate
959// array[i%200] = 10; // Cannot eliminate
960// array[i%-10] = 10; // Can eliminate
961// array[i%array.length] = 10; // Can eliminate
962// array[param_i%10] = 10; // Can't eliminate, when param_i < 0
963// }
964TEST_F(BoundsCheckEliminationTest, ModArrayBoundsElimination) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100965 HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph_);
xueliang.zhonga22cae72017-06-26 17:49:48 +0100966 graph_->AddBlock(entry);
967 graph_->SetEntryBlock(entry);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100968 HInstruction* param_i = new (GetAllocator())
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100969 HParameterValue(graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
xueliang.zhonga22cae72017-06-26 17:49:48 +0100970 entry->AddInstruction(param_i);
971
972 HInstruction* constant_0 = graph_->GetIntConstant(0);
973 HInstruction* constant_1 = graph_->GetIntConstant(1);
974 HInstruction* constant_10 = graph_->GetIntConstant(10);
975 HInstruction* constant_200 = graph_->GetIntConstant(200);
976 HInstruction* constant_minus_10 = graph_->GetIntConstant(-10);
977
Vladimir Markoca6fff82017-10-03 14:49:14 +0100978 HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph_);
xueliang.zhonga22cae72017-06-26 17:49:48 +0100979 graph_->AddBlock(block);
980 entry->AddSuccessor(block);
981 // We pass a bogus constant for the class to avoid mocking one.
Vladimir Markob5461632018-10-15 14:24:21 +0100982 HInstruction* new_array = new (GetAllocator()) HNewArray(
983 /* cls= */ constant_10,
984 /* length= */ constant_10,
985 /* dex_pc= */ 0,
986 /* component_size_shift= */ 0);
xueliang.zhonga22cae72017-06-26 17:49:48 +0100987 block->AddInstruction(new_array);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100988 block->AddInstruction(new (GetAllocator()) HGoto());
xueliang.zhonga22cae72017-06-26 17:49:48 +0100989
Vladimir Markoca6fff82017-10-03 14:49:14 +0100990 HBasicBlock* loop_header = new (GetAllocator()) HBasicBlock(graph_);
991 HBasicBlock* loop_body = new (GetAllocator()) HBasicBlock(graph_);
992 HBasicBlock* exit = new (GetAllocator()) HBasicBlock(graph_);
xueliang.zhonga22cae72017-06-26 17:49:48 +0100993
994 graph_->AddBlock(loop_header);
995 graph_->AddBlock(loop_body);
996 graph_->AddBlock(exit);
997 block->AddSuccessor(loop_header);
998 loop_header->AddSuccessor(exit); // true successor
999 loop_header->AddSuccessor(loop_body); // false successor
1000 loop_body->AddSuccessor(loop_header);
1001
Vladimir Markoca6fff82017-10-03 14:49:14 +01001002 HPhi* phi = new (GetAllocator()) HPhi(GetAllocator(), 0, 0, DataType::Type::kInt32);
1003 HInstruction* cmp = new (GetAllocator()) HGreaterThanOrEqual(phi, constant_200);
1004 HInstruction* if_inst = new (GetAllocator()) HIf(cmp);
xueliang.zhonga22cae72017-06-26 17:49:48 +01001005 loop_header->AddPhi(phi);
1006 loop_header->AddInstruction(cmp);
1007 loop_header->AddInstruction(if_inst);
1008 phi->AddInput(constant_0);
1009
1010 //////////////////////////////////////////////////////////////////////////////////
1011 // LOOP BODY:
1012 // array[i % 10] = 10;
Vladimir Markoca6fff82017-10-03 14:49:14 +01001013 HRem* i_mod_10 = new (GetAllocator()) HRem(DataType::Type::kInt32, phi, constant_10, 0);
1014 HBoundsCheck* bounds_check_i_mod_10 = new (GetAllocator()) HBoundsCheck(i_mod_10, constant_10, 0);
1015 HInstruction* array_set = new (GetAllocator()) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001016 new_array, bounds_check_i_mod_10, constant_10, DataType::Type::kInt32, 0);
xueliang.zhonga22cae72017-06-26 17:49:48 +01001017 loop_body->AddInstruction(i_mod_10);
1018 loop_body->AddInstruction(bounds_check_i_mod_10);
1019 loop_body->AddInstruction(array_set);
1020
1021 // array[i % 1] = 10;
Vladimir Markoca6fff82017-10-03 14:49:14 +01001022 HRem* i_mod_1 = new (GetAllocator()) HRem(DataType::Type::kInt32, phi, constant_1, 0);
1023 HBoundsCheck* bounds_check_i_mod_1 = new (GetAllocator()) HBoundsCheck(i_mod_1, constant_10, 0);
1024 array_set = new (GetAllocator()) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001025 new_array, bounds_check_i_mod_1, constant_10, DataType::Type::kInt32, 0);
xueliang.zhonga22cae72017-06-26 17:49:48 +01001026 loop_body->AddInstruction(i_mod_1);
1027 loop_body->AddInstruction(bounds_check_i_mod_1);
1028 loop_body->AddInstruction(array_set);
1029
1030 // array[i % 200] = 10;
Vladimir Markoca6fff82017-10-03 14:49:14 +01001031 HRem* i_mod_200 = new (GetAllocator()) HRem(DataType::Type::kInt32, phi, constant_1, 0);
1032 HBoundsCheck* bounds_check_i_mod_200 = new (GetAllocator()) HBoundsCheck(
1033 i_mod_200, constant_10, 0);
1034 array_set = new (GetAllocator()) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001035 new_array, bounds_check_i_mod_200, constant_10, DataType::Type::kInt32, 0);
xueliang.zhonga22cae72017-06-26 17:49:48 +01001036 loop_body->AddInstruction(i_mod_200);
1037 loop_body->AddInstruction(bounds_check_i_mod_200);
1038 loop_body->AddInstruction(array_set);
1039
1040 // array[i % -10] = 10;
Vladimir Markoca6fff82017-10-03 14:49:14 +01001041 HRem* i_mod_minus_10 = new (GetAllocator()) HRem(
1042 DataType::Type::kInt32, phi, constant_minus_10, 0);
1043 HBoundsCheck* bounds_check_i_mod_minus_10 = new (GetAllocator()) HBoundsCheck(
xueliang.zhonga22cae72017-06-26 17:49:48 +01001044 i_mod_minus_10, constant_10, 0);
Vladimir Markoca6fff82017-10-03 14:49:14 +01001045 array_set = new (GetAllocator()) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001046 new_array, bounds_check_i_mod_minus_10, constant_10, DataType::Type::kInt32, 0);
xueliang.zhonga22cae72017-06-26 17:49:48 +01001047 loop_body->AddInstruction(i_mod_minus_10);
1048 loop_body->AddInstruction(bounds_check_i_mod_minus_10);
1049 loop_body->AddInstruction(array_set);
1050
1051 // array[i%array.length] = 10;
Vladimir Markoca6fff82017-10-03 14:49:14 +01001052 HNullCheck* null_check = new (GetAllocator()) HNullCheck(new_array, 0);
1053 HArrayLength* array_length = new (GetAllocator()) HArrayLength(null_check, 0);
1054 HRem* i_mod_array_length = new (GetAllocator()) HRem(
1055 DataType::Type::kInt32, phi, array_length, 0);
1056 HBoundsCheck* bounds_check_i_mod_array_len = new (GetAllocator()) HBoundsCheck(
xueliang.zhonga22cae72017-06-26 17:49:48 +01001057 i_mod_array_length, array_length, 0);
Vladimir Markoca6fff82017-10-03 14:49:14 +01001058 array_set = new (GetAllocator()) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001059 null_check, bounds_check_i_mod_array_len, constant_10, DataType::Type::kInt32, 0);
xueliang.zhonga22cae72017-06-26 17:49:48 +01001060 loop_body->AddInstruction(null_check);
1061 loop_body->AddInstruction(array_length);
1062 loop_body->AddInstruction(i_mod_array_length);
1063 loop_body->AddInstruction(bounds_check_i_mod_array_len);
1064 loop_body->AddInstruction(array_set);
1065
1066 // array[param_i % 10] = 10;
Vladimir Markoca6fff82017-10-03 14:49:14 +01001067 HRem* param_i_mod_10 = new (GetAllocator()) HRem(DataType::Type::kInt32, param_i, constant_10, 0);
1068 HBoundsCheck* bounds_check_param_i_mod_10 = new (GetAllocator()) HBoundsCheck(
xueliang.zhonga22cae72017-06-26 17:49:48 +01001069 param_i_mod_10, constant_10, 0);
Vladimir Markoca6fff82017-10-03 14:49:14 +01001070 array_set = new (GetAllocator()) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001071 new_array, bounds_check_param_i_mod_10, constant_10, DataType::Type::kInt32, 0);
xueliang.zhonga22cae72017-06-26 17:49:48 +01001072 loop_body->AddInstruction(param_i_mod_10);
1073 loop_body->AddInstruction(bounds_check_param_i_mod_10);
1074 loop_body->AddInstruction(array_set);
1075
1076 // array[param_i%array.length] = 10;
Vladimir Markoca6fff82017-10-03 14:49:14 +01001077 null_check = new (GetAllocator()) HNullCheck(new_array, 0);
1078 array_length = new (GetAllocator()) HArrayLength(null_check, 0);
1079 HRem* param_i_mod_array_length = new (GetAllocator()) HRem(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001080 DataType::Type::kInt32, param_i, array_length, 0);
Vladimir Markoca6fff82017-10-03 14:49:14 +01001081 HBoundsCheck* bounds_check_param_i_mod_array_len = new (GetAllocator()) HBoundsCheck(
xueliang.zhonga22cae72017-06-26 17:49:48 +01001082 param_i_mod_array_length, array_length, 0);
Vladimir Markoca6fff82017-10-03 14:49:14 +01001083 array_set = new (GetAllocator()) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001084 null_check, bounds_check_param_i_mod_array_len, constant_10, DataType::Type::kInt32, 0);
xueliang.zhonga22cae72017-06-26 17:49:48 +01001085 loop_body->AddInstruction(null_check);
1086 loop_body->AddInstruction(array_length);
1087 loop_body->AddInstruction(param_i_mod_array_length);
1088 loop_body->AddInstruction(bounds_check_param_i_mod_array_len);
1089 loop_body->AddInstruction(array_set);
1090
1091 // i++;
Vladimir Markoca6fff82017-10-03 14:49:14 +01001092 HInstruction* add = new (GetAllocator()) HAdd(DataType::Type::kInt32, phi, constant_1);
xueliang.zhonga22cae72017-06-26 17:49:48 +01001093 loop_body->AddInstruction(add);
Vladimir Markoca6fff82017-10-03 14:49:14 +01001094 loop_body->AddInstruction(new (GetAllocator()) HGoto());
xueliang.zhonga22cae72017-06-26 17:49:48 +01001095 phi->AddInput(add);
1096 //////////////////////////////////////////////////////////////////////////////////
1097
Vladimir Markoca6fff82017-10-03 14:49:14 +01001098 exit->AddInstruction(new (GetAllocator()) HExit());
xueliang.zhonga22cae72017-06-26 17:49:48 +01001099
1100 RunBCE();
1101
1102 ASSERT_TRUE(IsRemoved(bounds_check_i_mod_10));
1103 ASSERT_TRUE(IsRemoved(bounds_check_i_mod_1));
1104 ASSERT_TRUE(IsRemoved(bounds_check_i_mod_200));
1105 ASSERT_TRUE(IsRemoved(bounds_check_i_mod_minus_10));
1106 ASSERT_TRUE(IsRemoved(bounds_check_i_mod_array_len));
1107 ASSERT_FALSE(IsRemoved(bounds_check_param_i_mod_10));
1108}
1109
Mingyao Yangf384f882014-10-22 16:08:18 -07001110} // namespace art