blob: 851838c4b81bd80b3a5fd8535e425753d8d2490f [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"
Mingyao Yangf384f882014-10-22 16:08:18 -070020#include "builder.h"
21#include "gvn.h"
Aart Bik22af3be2015-09-10 12:50:58 -070022#include "induction_var_analysis.h"
Mingyao Yang0304e182015-01-30 16:41:29 -080023#include "instruction_simplifier.h"
Mingyao Yangf384f882014-10-22 16:08:18 -070024#include "nodes.h"
25#include "optimizing_unit_test.h"
Nicolas Geoffray827eedb2015-01-26 15:18:36 +000026#include "side_effects_analysis.h"
Mingyao Yangf384f882014-10-22 16:08:18 -070027
28#include "gtest/gtest.h"
29
30namespace art {
31
Aart Bik22af3be2015-09-10 12:50:58 -070032/**
33 * Fixture class for the BoundsCheckElimination tests.
34 */
35class BoundsCheckEliminationTest : public testing::Test {
36 public:
37 BoundsCheckEliminationTest() : pool_(), allocator_(&pool_) {
38 graph_ = CreateGraph(&allocator_);
39 graph_->SetHasBoundsChecks(true);
40 }
41
42 ~BoundsCheckEliminationTest() { }
43
44 void RunBCE() {
45 graph_->BuildDominatorTree();
Aart Bik22af3be2015-09-10 12:50:58 -070046
Vladimir Marko65979462017-05-19 17:25:12 +010047 InstructionSimplifier(graph_, /* codegen */ nullptr, /* driver */ 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
60 ArenaPool pool_;
61 ArenaAllocator allocator_;
62 HGraph* graph_;
63};
64
Nicolas Geoffraye6f17152015-01-26 15:13:47 +000065
Mingyao Yangf384f882014-10-22 16:08:18 -070066// if (i < 0) { array[i] = 1; // Can't eliminate. }
67// else if (i >= array.length) { array[i] = 1; // Can't eliminate. }
68// else { array[i] = 1; // Can eliminate. }
Aart Bik22af3be2015-09-10 12:50:58 -070069TEST_F(BoundsCheckEliminationTest, NarrowingRangeArrayBoundsElimination) {
70 HBasicBlock* entry = new (&allocator_) HBasicBlock(graph_);
71 graph_->AddBlock(entry);
72 graph_->SetEntryBlock(entry);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010073 HInstruction* parameter1 = new (&allocator_) HParameterValue(
74 graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference); // array
75 HInstruction* parameter2 = new (&allocator_) HParameterValue(
76 graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32); // i
Mingyao Yangf384f882014-10-22 16:08:18 -070077 entry->AddInstruction(parameter1);
78 entry->AddInstruction(parameter2);
David Brazdil8d5b8b22015-03-24 10:51:52 +000079
Aart Bik22af3be2015-09-10 12:50:58 -070080 HInstruction* constant_1 = graph_->GetIntConstant(1);
81 HInstruction* constant_0 = graph_->GetIntConstant(0);
Mingyao Yangf384f882014-10-22 16:08:18 -070082
Aart Bik22af3be2015-09-10 12:50:58 -070083 HBasicBlock* block1 = new (&allocator_) HBasicBlock(graph_);
84 graph_->AddBlock(block1);
85 HInstruction* cmp = new (&allocator_) HGreaterThanOrEqual(parameter2, constant_0);
86 HIf* if_inst = new (&allocator_) HIf(cmp);
Mingyao Yangf384f882014-10-22 16:08:18 -070087 block1->AddInstruction(cmp);
88 block1->AddInstruction(if_inst);
89 entry->AddSuccessor(block1);
90
Aart Bik22af3be2015-09-10 12:50:58 -070091 HBasicBlock* block2 = new (&allocator_) HBasicBlock(graph_);
92 graph_->AddBlock(block2);
93 HNullCheck* null_check = new (&allocator_) HNullCheck(parameter1, 0);
Calin Juravle154746b2015-10-06 15:46:54 +010094 HArrayLength* array_length = new (&allocator_) HArrayLength(null_check, 0);
Aart Bik22af3be2015-09-10 12:50:58 -070095 HBoundsCheck* bounds_check2 = new (&allocator_)
Mingyao Yangf384f882014-10-22 16:08:18 -070096 HBoundsCheck(parameter2, array_length, 0);
Aart Bik22af3be2015-09-10 12:50:58 -070097 HArraySet* array_set = new (&allocator_) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010098 null_check, bounds_check2, constant_1, DataType::Type::kInt32, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -070099 block2->AddInstruction(null_check);
100 block2->AddInstruction(array_length);
101 block2->AddInstruction(bounds_check2);
102 block2->AddInstruction(array_set);
103
Aart Bik22af3be2015-09-10 12:50:58 -0700104 HBasicBlock* block3 = new (&allocator_) HBasicBlock(graph_);
105 graph_->AddBlock(block3);
106 null_check = new (&allocator_) HNullCheck(parameter1, 0);
Calin Juravle154746b2015-10-06 15:46:54 +0100107 array_length = new (&allocator_) HArrayLength(null_check, 0);
Aart Bik22af3be2015-09-10 12:50:58 -0700108 cmp = new (&allocator_) HLessThan(parameter2, array_length);
109 if_inst = new (&allocator_) HIf(cmp);
Mingyao Yangf384f882014-10-22 16:08:18 -0700110 block3->AddInstruction(null_check);
111 block3->AddInstruction(array_length);
112 block3->AddInstruction(cmp);
113 block3->AddInstruction(if_inst);
114
Aart Bik22af3be2015-09-10 12:50:58 -0700115 HBasicBlock* block4 = new (&allocator_) HBasicBlock(graph_);
116 graph_->AddBlock(block4);
117 null_check = new (&allocator_) HNullCheck(parameter1, 0);
Calin Juravle154746b2015-10-06 15:46:54 +0100118 array_length = new (&allocator_) HArrayLength(null_check, 0);
Aart Bik22af3be2015-09-10 12:50:58 -0700119 HBoundsCheck* bounds_check4 = new (&allocator_)
Mingyao Yangf384f882014-10-22 16:08:18 -0700120 HBoundsCheck(parameter2, array_length, 0);
Aart Bik22af3be2015-09-10 12:50:58 -0700121 array_set = new (&allocator_) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100122 null_check, bounds_check4, constant_1, DataType::Type::kInt32, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700123 block4->AddInstruction(null_check);
124 block4->AddInstruction(array_length);
125 block4->AddInstruction(bounds_check4);
126 block4->AddInstruction(array_set);
127
Aart Bik22af3be2015-09-10 12:50:58 -0700128 HBasicBlock* block5 = new (&allocator_) HBasicBlock(graph_);
129 graph_->AddBlock(block5);
130 null_check = new (&allocator_) HNullCheck(parameter1, 0);
Calin Juravle154746b2015-10-06 15:46:54 +0100131 array_length = new (&allocator_) HArrayLength(null_check, 0);
Aart Bik22af3be2015-09-10 12:50:58 -0700132 HBoundsCheck* bounds_check5 = new (&allocator_)
Mingyao Yangf384f882014-10-22 16:08:18 -0700133 HBoundsCheck(parameter2, array_length, 0);
Aart Bik22af3be2015-09-10 12:50:58 -0700134 array_set = new (&allocator_) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100135 null_check, bounds_check5, constant_1, DataType::Type::kInt32, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700136 block5->AddInstruction(null_check);
137 block5->AddInstruction(array_length);
138 block5->AddInstruction(bounds_check5);
139 block5->AddInstruction(array_set);
140
Aart Bik22af3be2015-09-10 12:50:58 -0700141 HBasicBlock* exit = new (&allocator_) HBasicBlock(graph_);
142 graph_->AddBlock(exit);
Mingyao Yangf384f882014-10-22 16:08:18 -0700143 block2->AddSuccessor(exit);
144 block4->AddSuccessor(exit);
145 block5->AddSuccessor(exit);
Aart Bik22af3be2015-09-10 12:50:58 -0700146 exit->AddInstruction(new (&allocator_) HExit());
Mingyao Yangf384f882014-10-22 16:08:18 -0700147
148 block1->AddSuccessor(block3); // True successor
149 block1->AddSuccessor(block2); // False successor
150
151 block3->AddSuccessor(block5); // True successor
152 block3->AddSuccessor(block4); // False successor
153
Aart Bik22af3be2015-09-10 12:50:58 -0700154 RunBCE();
155
Mingyao Yangf384f882014-10-22 16:08:18 -0700156 ASSERT_FALSE(IsRemoved(bounds_check2));
157 ASSERT_FALSE(IsRemoved(bounds_check4));
158 ASSERT_TRUE(IsRemoved(bounds_check5));
159}
160
161// if (i > 0) {
162// // Positive number plus MAX_INT will overflow and be negative.
163// int j = i + Integer.MAX_VALUE;
164// if (j < array.length) array[j] = 1; // Can't eliminate.
165// }
Aart Bik22af3be2015-09-10 12:50:58 -0700166TEST_F(BoundsCheckEliminationTest, OverflowArrayBoundsElimination) {
167 HBasicBlock* entry = new (&allocator_) HBasicBlock(graph_);
168 graph_->AddBlock(entry);
169 graph_->SetEntryBlock(entry);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100170 HInstruction* parameter1 = new (&allocator_) HParameterValue(
171 graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference); // array
172 HInstruction* parameter2 = new (&allocator_) HParameterValue(
173 graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32); // i
Mingyao Yangf384f882014-10-22 16:08:18 -0700174 entry->AddInstruction(parameter1);
175 entry->AddInstruction(parameter2);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000176
Aart Bik22af3be2015-09-10 12:50:58 -0700177 HInstruction* constant_1 = graph_->GetIntConstant(1);
178 HInstruction* constant_0 = graph_->GetIntConstant(0);
179 HInstruction* constant_max_int = graph_->GetIntConstant(INT_MAX);
Mingyao Yangf384f882014-10-22 16:08:18 -0700180
Aart Bik22af3be2015-09-10 12:50:58 -0700181 HBasicBlock* block1 = new (&allocator_) HBasicBlock(graph_);
182 graph_->AddBlock(block1);
183 HInstruction* cmp = new (&allocator_) HLessThanOrEqual(parameter2, constant_0);
184 HIf* if_inst = new (&allocator_) HIf(cmp);
Mingyao Yangf384f882014-10-22 16:08:18 -0700185 block1->AddInstruction(cmp);
186 block1->AddInstruction(if_inst);
187 entry->AddSuccessor(block1);
188
Aart Bik22af3be2015-09-10 12:50:58 -0700189 HBasicBlock* block2 = new (&allocator_) HBasicBlock(graph_);
190 graph_->AddBlock(block2);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100191 HInstruction* add = new (&allocator_) HAdd(DataType::Type::kInt32, parameter2, constant_max_int);
Aart Bik22af3be2015-09-10 12:50:58 -0700192 HNullCheck* null_check = new (&allocator_) HNullCheck(parameter1, 0);
Calin Juravle154746b2015-10-06 15:46:54 +0100193 HArrayLength* array_length = new (&allocator_) HArrayLength(null_check, 0);
Aart Bik22af3be2015-09-10 12:50:58 -0700194 HInstruction* cmp2 = new (&allocator_) HGreaterThanOrEqual(add, array_length);
195 if_inst = new (&allocator_) HIf(cmp2);
Mingyao Yangf384f882014-10-22 16:08:18 -0700196 block2->AddInstruction(add);
197 block2->AddInstruction(null_check);
198 block2->AddInstruction(array_length);
199 block2->AddInstruction(cmp2);
200 block2->AddInstruction(if_inst);
201
Aart Bik22af3be2015-09-10 12:50:58 -0700202 HBasicBlock* block3 = new (&allocator_) HBasicBlock(graph_);
203 graph_->AddBlock(block3);
204 HBoundsCheck* bounds_check = new (&allocator_)
Mingyao Yangf384f882014-10-22 16:08:18 -0700205 HBoundsCheck(add, array_length, 0);
Aart Bik22af3be2015-09-10 12:50:58 -0700206 HArraySet* array_set = new (&allocator_) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100207 null_check, bounds_check, constant_1, DataType::Type::kInt32, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700208 block3->AddInstruction(bounds_check);
209 block3->AddInstruction(array_set);
210
Aart Bik22af3be2015-09-10 12:50:58 -0700211 HBasicBlock* exit = new (&allocator_) HBasicBlock(graph_);
212 graph_->AddBlock(exit);
213 exit->AddInstruction(new (&allocator_) HExit());
Andreas Gampe0418b5b2014-12-04 17:24:50 -0800214 block1->AddSuccessor(exit); // true successor
215 block1->AddSuccessor(block2); // false successor
216 block2->AddSuccessor(exit); // true successor
217 block2->AddSuccessor(block3); // false successor
Mingyao Yangf384f882014-10-22 16:08:18 -0700218 block3->AddSuccessor(exit);
219
Aart Bik22af3be2015-09-10 12:50:58 -0700220 RunBCE();
221
Mingyao Yangf384f882014-10-22 16:08:18 -0700222 ASSERT_FALSE(IsRemoved(bounds_check));
223}
224
225// if (i < array.length) {
226// int j = i - Integer.MAX_VALUE;
Aart Bik22af3be2015-09-10 12:50:58 -0700227// j = j - Integer.MAX_VALUE; // j is (i+2) after subtracting MAX_INT twice
Mingyao Yangf384f882014-10-22 16:08:18 -0700228// if (j > 0) array[j] = 1; // Can't eliminate.
229// }
Aart Bik22af3be2015-09-10 12:50:58 -0700230TEST_F(BoundsCheckEliminationTest, UnderflowArrayBoundsElimination) {
231 HBasicBlock* entry = new (&allocator_) HBasicBlock(graph_);
232 graph_->AddBlock(entry);
233 graph_->SetEntryBlock(entry);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100234 HInstruction* parameter1 = new (&allocator_) HParameterValue(
235 graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference); // array
236 HInstruction* parameter2 = new (&allocator_) HParameterValue(
237 graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32); // i
Mingyao Yangf384f882014-10-22 16:08:18 -0700238 entry->AddInstruction(parameter1);
239 entry->AddInstruction(parameter2);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000240
Aart Bik22af3be2015-09-10 12:50:58 -0700241 HInstruction* constant_1 = graph_->GetIntConstant(1);
242 HInstruction* constant_0 = graph_->GetIntConstant(0);
243 HInstruction* constant_max_int = graph_->GetIntConstant(INT_MAX);
Mingyao Yangf384f882014-10-22 16:08:18 -0700244
Aart Bik22af3be2015-09-10 12:50:58 -0700245 HBasicBlock* block1 = new (&allocator_) HBasicBlock(graph_);
246 graph_->AddBlock(block1);
247 HNullCheck* null_check = new (&allocator_) HNullCheck(parameter1, 0);
Calin Juravle154746b2015-10-06 15:46:54 +0100248 HArrayLength* array_length = new (&allocator_) HArrayLength(null_check, 0);
Aart Bik22af3be2015-09-10 12:50:58 -0700249 HInstruction* cmp = new (&allocator_) HGreaterThanOrEqual(parameter2, array_length);
250 HIf* if_inst = new (&allocator_) HIf(cmp);
Mingyao Yangf384f882014-10-22 16:08:18 -0700251 block1->AddInstruction(null_check);
252 block1->AddInstruction(array_length);
253 block1->AddInstruction(cmp);
254 block1->AddInstruction(if_inst);
255 entry->AddSuccessor(block1);
256
Aart Bik22af3be2015-09-10 12:50:58 -0700257 HBasicBlock* block2 = new (&allocator_) HBasicBlock(graph_);
258 graph_->AddBlock(block2);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100259 HInstruction* sub1 = new (&allocator_) HSub(DataType::Type::kInt32, parameter2, constant_max_int);
260 HInstruction* sub2 = new (&allocator_) HSub(DataType::Type::kInt32, sub1, constant_max_int);
Aart Bik22af3be2015-09-10 12:50:58 -0700261 HInstruction* cmp2 = new (&allocator_) HLessThanOrEqual(sub2, constant_0);
262 if_inst = new (&allocator_) 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
Aart Bik22af3be2015-09-10 12:50:58 -0700268 HBasicBlock* block3 = new (&allocator_) HBasicBlock(graph_);
269 graph_->AddBlock(block3);
270 HBoundsCheck* bounds_check = new (&allocator_)
Mingyao Yangf384f882014-10-22 16:08:18 -0700271 HBoundsCheck(sub2, array_length, 0);
Aart Bik22af3be2015-09-10 12:50:58 -0700272 HArraySet* array_set = new (&allocator_) 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
Aart Bik22af3be2015-09-10 12:50:58 -0700277 HBasicBlock* exit = new (&allocator_) HBasicBlock(graph_);
278 graph_->AddBlock(exit);
279 exit->AddInstruction(new (&allocator_) 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) {
295 HBasicBlock* entry = new (&allocator_) HBasicBlock(graph_);
296 graph_->AddBlock(entry);
297 graph_->SetEntryBlock(entry);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000298 HInstruction* parameter = new (&allocator_) 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
Aart Bik22af3be2015-09-10 12:50:58 -0700307 HBasicBlock* block = new (&allocator_) HBasicBlock(graph_);
308 graph_->AddBlock(block);
Mingyao Yangf384f882014-10-22 16:08:18 -0700309 entry->AddSuccessor(block);
310
Aart Bik22af3be2015-09-10 12:50:58 -0700311 HNullCheck* null_check = new (&allocator_) HNullCheck(parameter, 0);
Calin Juravle154746b2015-10-06 15:46:54 +0100312 HArrayLength* array_length = new (&allocator_) HArrayLength(null_check, 0);
Aart Bik22af3be2015-09-10 12:50:58 -0700313 HBoundsCheck* bounds_check6 = new (&allocator_)
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700314 HBoundsCheck(constant_6, array_length, 0);
Aart Bik22af3be2015-09-10 12:50:58 -0700315 HInstruction* array_set = new (&allocator_) 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
Aart Bik22af3be2015-09-10 12:50:58 -0700322 null_check = new (&allocator_) HNullCheck(parameter, 0);
Calin Juravle154746b2015-10-06 15:46:54 +0100323 array_length = new (&allocator_) HArrayLength(null_check, 0);
Aart Bik22af3be2015-09-10 12:50:58 -0700324 HBoundsCheck* bounds_check5 = new (&allocator_)
Mingyao Yangf384f882014-10-22 16:08:18 -0700325 HBoundsCheck(constant_5, array_length, 0);
Aart Bik22af3be2015-09-10 12:50:58 -0700326 array_set = new (&allocator_) 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
Aart Bik22af3be2015-09-10 12:50:58 -0700333 null_check = new (&allocator_) HNullCheck(parameter, 0);
Calin Juravle154746b2015-10-06 15:46:54 +0100334 array_length = new (&allocator_) HArrayLength(null_check, 0);
Aart Bik22af3be2015-09-10 12:50:58 -0700335 HBoundsCheck* bounds_check4 = new (&allocator_)
Mingyao Yangf384f882014-10-22 16:08:18 -0700336 HBoundsCheck(constant_4, array_length, 0);
Aart Bik22af3be2015-09-10 12:50:58 -0700337 array_set = new (&allocator_) 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
Aart Bik22af3be2015-09-10 12:50:58 -0700344 block->AddInstruction(new (&allocator_) HGoto());
Mingyao Yangf384f882014-10-22 16:08:18 -0700345
Aart Bik22af3be2015-09-10 12:50:58 -0700346 HBasicBlock* exit = new (&allocator_) HBasicBlock(graph_);
347 graph_->AddBlock(exit);
Mingyao Yangf384f882014-10-22 16:08:18 -0700348 block->AddSuccessor(exit);
Aart Bik22af3be2015-09-10 12:50:58 -0700349 exit->AddInstruction(new (&allocator_) 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. }
Aart Bik22af3be2015-09-10 12:50:58 -0700432 HInstruction* bounds_check = BuildSSAGraph1(graph_, &allocator_, 0, 1);
433 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. }
Aart Bik22af3be2015-09-10 12:50:58 -0700439 HInstruction* bounds_check = BuildSSAGraph1(graph_, &allocator_, 1, 1);
440 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. }
Aart Bik22af3be2015-09-10 12:50:58 -0700446 HInstruction* bounds_check = BuildSSAGraph1(graph_, &allocator_, -1, 1);
447 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. }
Aart Bik22af3be2015-09-10 12:50:58 -0700453 HInstruction* bounds_check = BuildSSAGraph1(graph_, &allocator_, 0, 1, kCondGT);
454 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. }
Aart Bik22af3be2015-09-10 12:50:58 -0700461 HInstruction* bounds_check = BuildSSAGraph1(graph_, &allocator_, 0, 2);
462 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. }
Aart Bik22af3be2015-09-10 12:50:58 -0700468 HInstruction* bounds_check = BuildSSAGraph1(graph_, &allocator_, 1, 2);
469 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. }
Aart Bik22af3be2015-09-10 12:50:58 -0700549 HInstruction* bounds_check = BuildSSAGraph2(graph_, &allocator_, 0);
550 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. }
Aart Bik22af3be2015-09-10 12:50:58 -0700556 HInstruction* bounds_check = BuildSSAGraph2(graph_, &allocator_, 1);
557 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. }
Aart Bik22af3be2015-09-10 12:50:58 -0700563 HInstruction* bounds_check = BuildSSAGraph2(graph_, &allocator_, -1);
564 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. }
Aart Bik22af3be2015-09-10 12:50:58 -0700570 HInstruction* bounds_check = BuildSSAGraph2(graph_, &allocator_, 0, -1, kCondLT);
571 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. }
Aart Bik22af3be2015-09-10 12:50:58 -0700577 HInstruction* bounds_check = BuildSSAGraph2(graph_, &allocator_, 0, -2);
578 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(
602 constant_10,
Nicolas Geoffraye761bcc2017-01-19 08:59:37 +0000603 constant_10,
604 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700605 block->AddInstruction(new_array);
606 block->AddInstruction(new (allocator) HGoto());
607
608 HBasicBlock* loop_header = new (allocator) HBasicBlock(graph);
609 HBasicBlock* loop_body = new (allocator) HBasicBlock(graph);
610 HBasicBlock* exit = new (allocator) HBasicBlock(graph);
611
612 graph->AddBlock(loop_header);
613 graph->AddBlock(loop_body);
614 graph->AddBlock(exit);
615 block->AddSuccessor(loop_header);
616 loop_header->AddSuccessor(exit); // true successor
617 loop_header->AddSuccessor(loop_body); // false successor
618 loop_body->AddSuccessor(loop_header);
619
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100620 HPhi* phi = new (allocator) HPhi(allocator, 0, 0, DataType::Type::kInt32);
Mingyao Yangf384f882014-10-22 16:08:18 -0700621 HInstruction* cmp = nullptr;
622 if (cond == kCondGE) {
623 cmp = new (allocator) HGreaterThanOrEqual(phi, constant_10);
624 } else {
625 DCHECK(cond == kCondGT);
626 cmp = new (allocator) HGreaterThan(phi, constant_10);
627 }
628 HInstruction* if_inst = new (allocator) HIf(cmp);
629 loop_header->AddPhi(phi);
630 loop_header->AddInstruction(cmp);
631 loop_header->AddInstruction(if_inst);
David Brazdil1abb4192015-02-17 18:33:36 +0000632 phi->AddInput(constant_initial);
Mingyao Yangf384f882014-10-22 16:08:18 -0700633
634 HNullCheck* null_check = new (allocator) HNullCheck(new_array, 0);
Calin Juravle154746b2015-10-06 15:46:54 +0100635 HArrayLength* array_length = new (allocator) HArrayLength(null_check, 0);
Aart Bik22af3be2015-09-10 12:50:58 -0700636 HInstruction* bounds_check = new (allocator) HBoundsCheck(phi, array_length, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700637 HInstruction* array_set = new (allocator) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100638 null_check, bounds_check, constant_10, DataType::Type::kInt32, 0);
639 HInstruction* add = new (allocator) HAdd(DataType::Type::kInt32, phi, constant_increment);
Mingyao Yangf384f882014-10-22 16:08:18 -0700640 loop_body->AddInstruction(null_check);
641 loop_body->AddInstruction(array_length);
Aart Bik22af3be2015-09-10 12:50:58 -0700642 loop_body->AddInstruction(bounds_check);
Mingyao Yangf384f882014-10-22 16:08:18 -0700643 loop_body->AddInstruction(array_set);
644 loop_body->AddInstruction(add);
645 loop_body->AddInstruction(new (allocator) HGoto());
646 phi->AddInput(add);
647
648 exit->AddInstruction(new (allocator) HExit());
649
Aart Bik22af3be2015-09-10 12:50:58 -0700650 return bounds_check;
Mingyao Yangf384f882014-10-22 16:08:18 -0700651}
652
Aart Bik22af3be2015-09-10 12:50:58 -0700653TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination3a) {
Mingyao Yang8c8bad82015-02-09 18:13:26 -0800654 // int[] array = new int[10];
Mingyao Yangf384f882014-10-22 16:08:18 -0700655 // for (int i=0; i<10; i++) { array[i] = 10; // Can eliminate. }
Aart Bik22af3be2015-09-10 12:50:58 -0700656 HInstruction* bounds_check = BuildSSAGraph3(graph_, &allocator_, 0, 1, kCondGE);
657 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700658 ASSERT_TRUE(IsRemoved(bounds_check));
Aart Bik22af3be2015-09-10 12:50:58 -0700659}
Mingyao Yangf384f882014-10-22 16:08:18 -0700660
Aart Bik22af3be2015-09-10 12:50:58 -0700661TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination3b) {
Mingyao Yang8c8bad82015-02-09 18:13:26 -0800662 // int[] array = new int[10];
Mingyao Yangf384f882014-10-22 16:08:18 -0700663 // for (int i=1; i<10; i++) { array[i] = 10; // Can eliminate. }
Aart Bik22af3be2015-09-10 12:50:58 -0700664 HInstruction* bounds_check = BuildSSAGraph3(graph_, &allocator_, 1, 1, kCondGE);
665 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700666 ASSERT_TRUE(IsRemoved(bounds_check));
Aart Bik22af3be2015-09-10 12:50:58 -0700667}
Mingyao Yangf384f882014-10-22 16:08:18 -0700668
Aart Bik22af3be2015-09-10 12:50:58 -0700669TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination3c) {
Mingyao Yang8c8bad82015-02-09 18:13:26 -0800670 // int[] array = new int[10];
Mingyao Yangf384f882014-10-22 16:08:18 -0700671 // for (int i=0; i<=10; i++) { array[i] = 10; // Can't eliminate. }
Aart Bik22af3be2015-09-10 12:50:58 -0700672 HInstruction* bounds_check = BuildSSAGraph3(graph_, &allocator_, 0, 1, kCondGT);
673 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700674 ASSERT_FALSE(IsRemoved(bounds_check));
Aart Bik22af3be2015-09-10 12:50:58 -0700675}
Mingyao Yangf384f882014-10-22 16:08:18 -0700676
Aart Bik22af3be2015-09-10 12:50:58 -0700677TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination3d) {
Mingyao Yang8c8bad82015-02-09 18:13:26 -0800678 // int[] array = new int[10];
Mingyao Yangf384f882014-10-22 16:08:18 -0700679 // for (int i=1; i<10; i+=8) { array[i] = 10; // Can eliminate. }
Aart Bik22af3be2015-09-10 12:50:58 -0700680 HInstruction* bounds_check = BuildSSAGraph3(graph_, &allocator_, 1, 8, kCondGE);
681 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700682 ASSERT_TRUE(IsRemoved(bounds_check));
683}
684
685// for (int i=initial; i<array.length; i++) { array[array.length-i-1] = 10; }
Aart Bik22af3be2015-09-10 12:50:58 -0700686static HInstruction* BuildSSAGraph4(HGraph* graph,
687 ArenaAllocator* allocator,
688 int initial,
689 IfCondition cond = kCondGE) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700690 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
691 graph->AddBlock(entry);
692 graph->SetEntryBlock(entry);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000693 HInstruction* parameter = new (allocator) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100694 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
Mingyao Yangf384f882014-10-22 16:08:18 -0700695 entry->AddInstruction(parameter);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000696
697 HInstruction* constant_initial = graph->GetIntConstant(initial);
698 HInstruction* constant_1 = graph->GetIntConstant(1);
699 HInstruction* constant_10 = graph->GetIntConstant(10);
700 HInstruction* constant_minus_1 = graph->GetIntConstant(-1);
Mingyao Yangf384f882014-10-22 16:08:18 -0700701
702 HBasicBlock* block = new (allocator) HBasicBlock(graph);
703 graph->AddBlock(block);
704 entry->AddSuccessor(block);
705 block->AddInstruction(new (allocator) HGoto());
706
707 HBasicBlock* loop_header = new (allocator) HBasicBlock(graph);
708 HBasicBlock* loop_body = new (allocator) HBasicBlock(graph);
709 HBasicBlock* exit = new (allocator) HBasicBlock(graph);
710
711 graph->AddBlock(loop_header);
712 graph->AddBlock(loop_body);
713 graph->AddBlock(exit);
714 block->AddSuccessor(loop_header);
715 loop_header->AddSuccessor(exit); // true successor
716 loop_header->AddSuccessor(loop_body); // false successor
717 loop_body->AddSuccessor(loop_header);
718
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100719 HPhi* phi = new (allocator) HPhi(allocator, 0, 0, DataType::Type::kInt32);
Mingyao Yangf384f882014-10-22 16:08:18 -0700720 HInstruction* null_check = new (allocator) HNullCheck(parameter, 0);
Calin Juravle154746b2015-10-06 15:46:54 +0100721 HInstruction* array_length = new (allocator) HArrayLength(null_check, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700722 HInstruction* cmp = nullptr;
723 if (cond == kCondGE) {
724 cmp = new (allocator) HGreaterThanOrEqual(phi, array_length);
725 } else if (cond == kCondGT) {
726 cmp = new (allocator) HGreaterThan(phi, array_length);
727 }
728 HInstruction* if_inst = new (allocator) HIf(cmp);
729 loop_header->AddPhi(phi);
730 loop_header->AddInstruction(null_check);
731 loop_header->AddInstruction(array_length);
732 loop_header->AddInstruction(cmp);
733 loop_header->AddInstruction(if_inst);
David Brazdil1abb4192015-02-17 18:33:36 +0000734 phi->AddInput(constant_initial);
Mingyao Yangf384f882014-10-22 16:08:18 -0700735
736 null_check = new (allocator) HNullCheck(parameter, 0);
Calin Juravle154746b2015-10-06 15:46:54 +0100737 array_length = new (allocator) HArrayLength(null_check, 0);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100738 HInstruction* sub = new (allocator) HSub(DataType::Type::kInt32, array_length, phi);
Mingyao Yangf384f882014-10-22 16:08:18 -0700739 HInstruction* add_minus_1 = new (allocator)
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100740 HAdd(DataType::Type::kInt32, sub, constant_minus_1);
Aart Bik22af3be2015-09-10 12:50:58 -0700741 HInstruction* bounds_check = new (allocator) HBoundsCheck(add_minus_1, array_length, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700742 HInstruction* array_set = new (allocator) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100743 null_check, bounds_check, constant_10, DataType::Type::kInt32, 0);
744 HInstruction* add = new (allocator) HAdd(DataType::Type::kInt32, phi, constant_1);
Mingyao Yangf384f882014-10-22 16:08:18 -0700745 loop_body->AddInstruction(null_check);
746 loop_body->AddInstruction(array_length);
747 loop_body->AddInstruction(sub);
748 loop_body->AddInstruction(add_minus_1);
Aart Bik22af3be2015-09-10 12:50:58 -0700749 loop_body->AddInstruction(bounds_check);
Mingyao Yangf384f882014-10-22 16:08:18 -0700750 loop_body->AddInstruction(array_set);
751 loop_body->AddInstruction(add);
752 loop_body->AddInstruction(new (allocator) HGoto());
753 phi->AddInput(add);
754
755 exit->AddInstruction(new (allocator) HExit());
756
Aart Bik22af3be2015-09-10 12:50:58 -0700757 return bounds_check;
Mingyao Yangf384f882014-10-22 16:08:18 -0700758}
759
Aart Bik22af3be2015-09-10 12:50:58 -0700760TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination4a) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700761 // for (int i=0; i<array.length; i++) { array[array.length-i-1] = 10; // Can eliminate with gvn. }
Aart Bik22af3be2015-09-10 12:50:58 -0700762 HInstruction* bounds_check = BuildSSAGraph4(graph_, &allocator_, 0);
763 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700764 ASSERT_TRUE(IsRemoved(bounds_check));
Aart Bik22af3be2015-09-10 12:50:58 -0700765}
Mingyao Yangf384f882014-10-22 16:08:18 -0700766
Aart Bik22af3be2015-09-10 12:50:58 -0700767TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination4b) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700768 // for (int i=1; i<array.length; i++) { array[array.length-i-1] = 10; // Can eliminate. }
Aart Bik22af3be2015-09-10 12:50:58 -0700769 HInstruction* bounds_check = BuildSSAGraph4(graph_, &allocator_, 1);
770 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700771 ASSERT_TRUE(IsRemoved(bounds_check));
Aart Bik22af3be2015-09-10 12:50:58 -0700772}
Mingyao Yangf384f882014-10-22 16:08:18 -0700773
Aart Bik22af3be2015-09-10 12:50:58 -0700774TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination4c) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700775 // for (int i=0; i<=array.length; i++) { array[array.length-i] = 10; // Can't eliminate. }
Aart Bik22af3be2015-09-10 12:50:58 -0700776 HInstruction* bounds_check = BuildSSAGraph4(graph_, &allocator_, 0, kCondGT);
777 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700778 ASSERT_FALSE(IsRemoved(bounds_check));
779}
780
781// Bubble sort:
782// (Every array access bounds-check can be eliminated.)
783// for (int i=0; i<array.length-1; i++) {
784// for (int j=0; j<array.length-i-1; j++) {
785// if (array[j] > array[j+1]) {
786// int temp = array[j+1];
787// array[j+1] = array[j];
788// array[j] = temp;
789// }
790// }
791// }
Aart Bik22af3be2015-09-10 12:50:58 -0700792TEST_F(BoundsCheckEliminationTest, BubbleSortArrayBoundsElimination) {
793 HBasicBlock* entry = new (&allocator_) HBasicBlock(graph_);
794 graph_->AddBlock(entry);
795 graph_->SetEntryBlock(entry);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000796 HInstruction* parameter = new (&allocator_) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100797 graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
Mingyao Yangf384f882014-10-22 16:08:18 -0700798 entry->AddInstruction(parameter);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000799
Aart Bik22af3be2015-09-10 12:50:58 -0700800 HInstruction* constant_0 = graph_->GetIntConstant(0);
801 HInstruction* constant_minus_1 = graph_->GetIntConstant(-1);
802 HInstruction* constant_1 = graph_->GetIntConstant(1);
Mingyao Yangf384f882014-10-22 16:08:18 -0700803
Aart Bik22af3be2015-09-10 12:50:58 -0700804 HBasicBlock* block = new (&allocator_) HBasicBlock(graph_);
805 graph_->AddBlock(block);
Mingyao Yangf384f882014-10-22 16:08:18 -0700806 entry->AddSuccessor(block);
Aart Bik22af3be2015-09-10 12:50:58 -0700807 block->AddInstruction(new (&allocator_) HGoto());
Mingyao Yangf384f882014-10-22 16:08:18 -0700808
Aart Bik22af3be2015-09-10 12:50:58 -0700809 HBasicBlock* exit = new (&allocator_) HBasicBlock(graph_);
810 graph_->AddBlock(exit);
811 exit->AddInstruction(new (&allocator_) HExit());
Mingyao Yangf384f882014-10-22 16:08:18 -0700812
Aart Bik22af3be2015-09-10 12:50:58 -0700813 HBasicBlock* outer_header = new (&allocator_) HBasicBlock(graph_);
814 graph_->AddBlock(outer_header);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100815 HPhi* phi_i = new (&allocator_) HPhi(&allocator_, 0, 0, DataType::Type::kInt32);
Aart Bik22af3be2015-09-10 12:50:58 -0700816 HNullCheck* null_check = new (&allocator_) HNullCheck(parameter, 0);
Calin Juravle154746b2015-10-06 15:46:54 +0100817 HArrayLength* array_length = new (&allocator_) HArrayLength(null_check, 0);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100818 HAdd* add = new (&allocator_) HAdd(DataType::Type::kInt32, array_length, constant_minus_1);
Aart Bik22af3be2015-09-10 12:50:58 -0700819 HInstruction* cmp = new (&allocator_) HGreaterThanOrEqual(phi_i, add);
820 HIf* if_inst = new (&allocator_) HIf(cmp);
Mingyao Yangf384f882014-10-22 16:08:18 -0700821 outer_header->AddPhi(phi_i);
822 outer_header->AddInstruction(null_check);
823 outer_header->AddInstruction(array_length);
824 outer_header->AddInstruction(add);
825 outer_header->AddInstruction(cmp);
826 outer_header->AddInstruction(if_inst);
David Brazdil1abb4192015-02-17 18:33:36 +0000827 phi_i->AddInput(constant_0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700828
Aart Bik22af3be2015-09-10 12:50:58 -0700829 HBasicBlock* inner_header = new (&allocator_) HBasicBlock(graph_);
830 graph_->AddBlock(inner_header);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100831 HPhi* phi_j = new (&allocator_) HPhi(&allocator_, 0, 0, DataType::Type::kInt32);
Aart Bik22af3be2015-09-10 12:50:58 -0700832 null_check = new (&allocator_) HNullCheck(parameter, 0);
Calin Juravle154746b2015-10-06 15:46:54 +0100833 array_length = new (&allocator_) HArrayLength(null_check, 0);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100834 HSub* sub = new (&allocator_) HSub(DataType::Type::kInt32, array_length, phi_i);
835 add = new (&allocator_) HAdd(DataType::Type::kInt32, sub, constant_minus_1);
Aart Bik22af3be2015-09-10 12:50:58 -0700836 cmp = new (&allocator_) HGreaterThanOrEqual(phi_j, add);
837 if_inst = new (&allocator_) HIf(cmp);
Mingyao Yangf384f882014-10-22 16:08:18 -0700838 inner_header->AddPhi(phi_j);
839 inner_header->AddInstruction(null_check);
840 inner_header->AddInstruction(array_length);
841 inner_header->AddInstruction(sub);
842 inner_header->AddInstruction(add);
843 inner_header->AddInstruction(cmp);
844 inner_header->AddInstruction(if_inst);
David Brazdil1abb4192015-02-17 18:33:36 +0000845 phi_j->AddInput(constant_0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700846
Aart Bik22af3be2015-09-10 12:50:58 -0700847 HBasicBlock* inner_body_compare = new (&allocator_) HBasicBlock(graph_);
848 graph_->AddBlock(inner_body_compare);
849 null_check = new (&allocator_) HNullCheck(parameter, 0);
Calin Juravle154746b2015-10-06 15:46:54 +0100850 array_length = new (&allocator_) HArrayLength(null_check, 0);
Aart Bik22af3be2015-09-10 12:50:58 -0700851 HBoundsCheck* bounds_check1 = new (&allocator_) HBoundsCheck(phi_j, array_length, 0);
852 HArrayGet* array_get_j = new (&allocator_)
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100853 HArrayGet(null_check, bounds_check1, DataType::Type::kInt32, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700854 inner_body_compare->AddInstruction(null_check);
855 inner_body_compare->AddInstruction(array_length);
856 inner_body_compare->AddInstruction(bounds_check1);
857 inner_body_compare->AddInstruction(array_get_j);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100858 HInstruction* j_plus_1 = new (&allocator_) HAdd(DataType::Type::kInt32, phi_j, constant_1);
Aart Bik22af3be2015-09-10 12:50:58 -0700859 null_check = new (&allocator_) HNullCheck(parameter, 0);
Calin Juravle154746b2015-10-06 15:46:54 +0100860 array_length = new (&allocator_) HArrayLength(null_check, 0);
Aart Bik22af3be2015-09-10 12:50:58 -0700861 HBoundsCheck* bounds_check2 = new (&allocator_) HBoundsCheck(j_plus_1, array_length, 0);
862 HArrayGet* array_get_j_plus_1 = new (&allocator_)
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100863 HArrayGet(null_check, bounds_check2, DataType::Type::kInt32, 0);
Aart Bik22af3be2015-09-10 12:50:58 -0700864 cmp = new (&allocator_) HGreaterThanOrEqual(array_get_j, array_get_j_plus_1);
865 if_inst = new (&allocator_) HIf(cmp);
Mingyao Yangf384f882014-10-22 16:08:18 -0700866 inner_body_compare->AddInstruction(j_plus_1);
867 inner_body_compare->AddInstruction(null_check);
868 inner_body_compare->AddInstruction(array_length);
869 inner_body_compare->AddInstruction(bounds_check2);
870 inner_body_compare->AddInstruction(array_get_j_plus_1);
871 inner_body_compare->AddInstruction(cmp);
872 inner_body_compare->AddInstruction(if_inst);
873
Aart Bik22af3be2015-09-10 12:50:58 -0700874 HBasicBlock* inner_body_swap = new (&allocator_) HBasicBlock(graph_);
875 graph_->AddBlock(inner_body_swap);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100876 j_plus_1 = new (&allocator_) HAdd(DataType::Type::kInt32, phi_j, constant_1);
Mingyao Yangf384f882014-10-22 16:08:18 -0700877 // temp = array[j+1]
Aart Bik22af3be2015-09-10 12:50:58 -0700878 null_check = new (&allocator_) HNullCheck(parameter, 0);
Calin Juravle154746b2015-10-06 15:46:54 +0100879 array_length = new (&allocator_) HArrayLength(null_check, 0);
Aart Bik22af3be2015-09-10 12:50:58 -0700880 HInstruction* bounds_check3 = new (&allocator_) HBoundsCheck(j_plus_1, array_length, 0);
881 array_get_j_plus_1 = new (&allocator_)
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100882 HArrayGet(null_check, bounds_check3, DataType::Type::kInt32, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700883 inner_body_swap->AddInstruction(j_plus_1);
884 inner_body_swap->AddInstruction(null_check);
885 inner_body_swap->AddInstruction(array_length);
886 inner_body_swap->AddInstruction(bounds_check3);
887 inner_body_swap->AddInstruction(array_get_j_plus_1);
888 // array[j+1] = array[j]
Aart Bik22af3be2015-09-10 12:50:58 -0700889 null_check = new (&allocator_) HNullCheck(parameter, 0);
Calin Juravle154746b2015-10-06 15:46:54 +0100890 array_length = new (&allocator_) HArrayLength(null_check, 0);
Aart Bik22af3be2015-09-10 12:50:58 -0700891 HInstruction* bounds_check4 = new (&allocator_) HBoundsCheck(phi_j, array_length, 0);
892 array_get_j = new (&allocator_)
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100893 HArrayGet(null_check, bounds_check4, DataType::Type::kInt32, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700894 inner_body_swap->AddInstruction(null_check);
895 inner_body_swap->AddInstruction(array_length);
896 inner_body_swap->AddInstruction(bounds_check4);
897 inner_body_swap->AddInstruction(array_get_j);
Aart Bik22af3be2015-09-10 12:50:58 -0700898 null_check = new (&allocator_) HNullCheck(parameter, 0);
Calin Juravle154746b2015-10-06 15:46:54 +0100899 array_length = new (&allocator_) HArrayLength(null_check, 0);
Aart Bik22af3be2015-09-10 12:50:58 -0700900 HInstruction* bounds_check5 = new (&allocator_) HBoundsCheck(j_plus_1, array_length, 0);
901 HArraySet* array_set_j_plus_1 = new (&allocator_)
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100902 HArraySet(null_check, bounds_check5, array_get_j, DataType::Type::kInt32, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700903 inner_body_swap->AddInstruction(null_check);
904 inner_body_swap->AddInstruction(array_length);
905 inner_body_swap->AddInstruction(bounds_check5);
906 inner_body_swap->AddInstruction(array_set_j_plus_1);
907 // array[j] = temp
Aart Bik22af3be2015-09-10 12:50:58 -0700908 null_check = new (&allocator_) HNullCheck(parameter, 0);
Calin Juravle154746b2015-10-06 15:46:54 +0100909 array_length = new (&allocator_) HArrayLength(null_check, 0);
Aart Bik22af3be2015-09-10 12:50:58 -0700910 HInstruction* bounds_check6 = new (&allocator_) HBoundsCheck(phi_j, array_length, 0);
911 HArraySet* array_set_j = new (&allocator_)
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100912 HArraySet(null_check, bounds_check6, array_get_j_plus_1, DataType::Type::kInt32, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700913 inner_body_swap->AddInstruction(null_check);
914 inner_body_swap->AddInstruction(array_length);
915 inner_body_swap->AddInstruction(bounds_check6);
916 inner_body_swap->AddInstruction(array_set_j);
Aart Bik22af3be2015-09-10 12:50:58 -0700917 inner_body_swap->AddInstruction(new (&allocator_) HGoto());
Mingyao Yangf384f882014-10-22 16:08:18 -0700918
Aart Bik22af3be2015-09-10 12:50:58 -0700919 HBasicBlock* inner_body_add = new (&allocator_) HBasicBlock(graph_);
920 graph_->AddBlock(inner_body_add);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100921 add = new (&allocator_) HAdd(DataType::Type::kInt32, phi_j, constant_1);
Mingyao Yangf384f882014-10-22 16:08:18 -0700922 inner_body_add->AddInstruction(add);
Aart Bik22af3be2015-09-10 12:50:58 -0700923 inner_body_add->AddInstruction(new (&allocator_) HGoto());
Mingyao Yangf384f882014-10-22 16:08:18 -0700924 phi_j->AddInput(add);
925
Aart Bik22af3be2015-09-10 12:50:58 -0700926 HBasicBlock* outer_body_add = new (&allocator_) HBasicBlock(graph_);
927 graph_->AddBlock(outer_body_add);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100928 add = new (&allocator_) HAdd(DataType::Type::kInt32, phi_i, constant_1);
Mingyao Yangf384f882014-10-22 16:08:18 -0700929 outer_body_add->AddInstruction(add);
Aart Bik22af3be2015-09-10 12:50:58 -0700930 outer_body_add->AddInstruction(new (&allocator_) HGoto());
Mingyao Yangf384f882014-10-22 16:08:18 -0700931 phi_i->AddInput(add);
932
933 block->AddSuccessor(outer_header);
934 outer_header->AddSuccessor(exit);
935 outer_header->AddSuccessor(inner_header);
936 inner_header->AddSuccessor(outer_body_add);
937 inner_header->AddSuccessor(inner_body_compare);
938 inner_body_compare->AddSuccessor(inner_body_add);
939 inner_body_compare->AddSuccessor(inner_body_swap);
940 inner_body_swap->AddSuccessor(inner_body_add);
941 inner_body_add->AddSuccessor(inner_header);
942 outer_body_add->AddSuccessor(outer_header);
943
Aart Bik22af3be2015-09-10 12:50:58 -0700944 RunBCE(); // gvn removes same bounds check already
Mingyao Yangf384f882014-10-22 16:08:18 -0700945
Mingyao Yangf384f882014-10-22 16:08:18 -0700946 ASSERT_TRUE(IsRemoved(bounds_check1));
947 ASSERT_TRUE(IsRemoved(bounds_check2));
948 ASSERT_TRUE(IsRemoved(bounds_check3));
949 ASSERT_TRUE(IsRemoved(bounds_check4));
950 ASSERT_TRUE(IsRemoved(bounds_check5));
951 ASSERT_TRUE(IsRemoved(bounds_check6));
952}
953
xueliang.zhonga22cae72017-06-26 17:49:48 +0100954// int[] array = new int[10];
955// for (int i=0; i<200; i++) {
956// array[i%10] = 10; // Can eliminate
957// array[i%1] = 10; // Can eliminate
958// array[i%200] = 10; // Cannot eliminate
959// array[i%-10] = 10; // Can eliminate
960// array[i%array.length] = 10; // Can eliminate
961// array[param_i%10] = 10; // Can't eliminate, when param_i < 0
962// }
963TEST_F(BoundsCheckEliminationTest, ModArrayBoundsElimination) {
964 HBasicBlock* entry = new (&allocator_) HBasicBlock(graph_);
965 graph_->AddBlock(entry);
966 graph_->SetEntryBlock(entry);
967 HInstruction* param_i = new (&allocator_)
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100968 HParameterValue(graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
xueliang.zhonga22cae72017-06-26 17:49:48 +0100969 entry->AddInstruction(param_i);
970
971 HInstruction* constant_0 = graph_->GetIntConstant(0);
972 HInstruction* constant_1 = graph_->GetIntConstant(1);
973 HInstruction* constant_10 = graph_->GetIntConstant(10);
974 HInstruction* constant_200 = graph_->GetIntConstant(200);
975 HInstruction* constant_minus_10 = graph_->GetIntConstant(-10);
976
977 HBasicBlock* block = new (&allocator_) HBasicBlock(graph_);
978 graph_->AddBlock(block);
979 entry->AddSuccessor(block);
980 // We pass a bogus constant for the class to avoid mocking one.
981 HInstruction* new_array = new (&allocator_) HNewArray(constant_10, constant_10, 0);
982 block->AddInstruction(new_array);
983 block->AddInstruction(new (&allocator_) HGoto());
984
985 HBasicBlock* loop_header = new (&allocator_) HBasicBlock(graph_);
986 HBasicBlock* loop_body = new (&allocator_) HBasicBlock(graph_);
987 HBasicBlock* exit = new (&allocator_) HBasicBlock(graph_);
988
989 graph_->AddBlock(loop_header);
990 graph_->AddBlock(loop_body);
991 graph_->AddBlock(exit);
992 block->AddSuccessor(loop_header);
993 loop_header->AddSuccessor(exit); // true successor
994 loop_header->AddSuccessor(loop_body); // false successor
995 loop_body->AddSuccessor(loop_header);
996
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100997 HPhi* phi = new (&allocator_) HPhi(&allocator_, 0, 0, DataType::Type::kInt32);
xueliang.zhonga22cae72017-06-26 17:49:48 +0100998 HInstruction* cmp = new (&allocator_) HGreaterThanOrEqual(phi, constant_200);
999 HInstruction* if_inst = new (&allocator_) HIf(cmp);
1000 loop_header->AddPhi(phi);
1001 loop_header->AddInstruction(cmp);
1002 loop_header->AddInstruction(if_inst);
1003 phi->AddInput(constant_0);
1004
1005 //////////////////////////////////////////////////////////////////////////////////
1006 // LOOP BODY:
1007 // array[i % 10] = 10;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001008 HRem* i_mod_10 = new (&allocator_) HRem(DataType::Type::kInt32, phi, constant_10, 0);
xueliang.zhonga22cae72017-06-26 17:49:48 +01001009 HBoundsCheck* bounds_check_i_mod_10 = new (&allocator_) HBoundsCheck(i_mod_10, constant_10, 0);
1010 HInstruction* array_set = new (&allocator_) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001011 new_array, bounds_check_i_mod_10, constant_10, DataType::Type::kInt32, 0);
xueliang.zhonga22cae72017-06-26 17:49:48 +01001012 loop_body->AddInstruction(i_mod_10);
1013 loop_body->AddInstruction(bounds_check_i_mod_10);
1014 loop_body->AddInstruction(array_set);
1015
1016 // array[i % 1] = 10;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001017 HRem* i_mod_1 = new (&allocator_) HRem(DataType::Type::kInt32, phi, constant_1, 0);
xueliang.zhonga22cae72017-06-26 17:49:48 +01001018 HBoundsCheck* bounds_check_i_mod_1 = new (&allocator_) HBoundsCheck(i_mod_1, constant_10, 0);
1019 array_set = new (&allocator_) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001020 new_array, bounds_check_i_mod_1, constant_10, DataType::Type::kInt32, 0);
xueliang.zhonga22cae72017-06-26 17:49:48 +01001021 loop_body->AddInstruction(i_mod_1);
1022 loop_body->AddInstruction(bounds_check_i_mod_1);
1023 loop_body->AddInstruction(array_set);
1024
1025 // array[i % 200] = 10;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001026 HRem* i_mod_200 = new (&allocator_) HRem(DataType::Type::kInt32, phi, constant_1, 0);
xueliang.zhonga22cae72017-06-26 17:49:48 +01001027 HBoundsCheck* bounds_check_i_mod_200 = new (&allocator_) HBoundsCheck(i_mod_200, constant_10, 0);
1028 array_set = new (&allocator_) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001029 new_array, bounds_check_i_mod_200, constant_10, DataType::Type::kInt32, 0);
xueliang.zhonga22cae72017-06-26 17:49:48 +01001030 loop_body->AddInstruction(i_mod_200);
1031 loop_body->AddInstruction(bounds_check_i_mod_200);
1032 loop_body->AddInstruction(array_set);
1033
1034 // array[i % -10] = 10;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001035 HRem* i_mod_minus_10 = new (&allocator_) HRem(DataType::Type::kInt32, phi, constant_minus_10, 0);
xueliang.zhonga22cae72017-06-26 17:49:48 +01001036 HBoundsCheck* bounds_check_i_mod_minus_10 = new (&allocator_) HBoundsCheck(
1037 i_mod_minus_10, constant_10, 0);
1038 array_set = new (&allocator_) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001039 new_array, bounds_check_i_mod_minus_10, constant_10, DataType::Type::kInt32, 0);
xueliang.zhonga22cae72017-06-26 17:49:48 +01001040 loop_body->AddInstruction(i_mod_minus_10);
1041 loop_body->AddInstruction(bounds_check_i_mod_minus_10);
1042 loop_body->AddInstruction(array_set);
1043
1044 // array[i%array.length] = 10;
1045 HNullCheck* null_check = new (&allocator_) HNullCheck(new_array, 0);
1046 HArrayLength* array_length = new (&allocator_) HArrayLength(null_check, 0);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001047 HRem* i_mod_array_length = new (&allocator_) HRem(DataType::Type::kInt32, phi, array_length, 0);
xueliang.zhonga22cae72017-06-26 17:49:48 +01001048 HBoundsCheck* bounds_check_i_mod_array_len = new (&allocator_) HBoundsCheck(
1049 i_mod_array_length, array_length, 0);
1050 array_set = new (&allocator_) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001051 null_check, bounds_check_i_mod_array_len, constant_10, DataType::Type::kInt32, 0);
xueliang.zhonga22cae72017-06-26 17:49:48 +01001052 loop_body->AddInstruction(null_check);
1053 loop_body->AddInstruction(array_length);
1054 loop_body->AddInstruction(i_mod_array_length);
1055 loop_body->AddInstruction(bounds_check_i_mod_array_len);
1056 loop_body->AddInstruction(array_set);
1057
1058 // array[param_i % 10] = 10;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001059 HRem* param_i_mod_10 = new (&allocator_) HRem(DataType::Type::kInt32, param_i, constant_10, 0);
xueliang.zhonga22cae72017-06-26 17:49:48 +01001060 HBoundsCheck* bounds_check_param_i_mod_10 = new (&allocator_) HBoundsCheck(
1061 param_i_mod_10, constant_10, 0);
1062 array_set = new (&allocator_) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001063 new_array, bounds_check_param_i_mod_10, constant_10, DataType::Type::kInt32, 0);
xueliang.zhonga22cae72017-06-26 17:49:48 +01001064 loop_body->AddInstruction(param_i_mod_10);
1065 loop_body->AddInstruction(bounds_check_param_i_mod_10);
1066 loop_body->AddInstruction(array_set);
1067
1068 // array[param_i%array.length] = 10;
1069 null_check = new (&allocator_) HNullCheck(new_array, 0);
1070 array_length = new (&allocator_) HArrayLength(null_check, 0);
1071 HRem* param_i_mod_array_length = new (&allocator_) HRem(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001072 DataType::Type::kInt32, param_i, array_length, 0);
xueliang.zhonga22cae72017-06-26 17:49:48 +01001073 HBoundsCheck* bounds_check_param_i_mod_array_len = new (&allocator_) HBoundsCheck(
1074 param_i_mod_array_length, array_length, 0);
1075 array_set = new (&allocator_) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001076 null_check, bounds_check_param_i_mod_array_len, constant_10, DataType::Type::kInt32, 0);
xueliang.zhonga22cae72017-06-26 17:49:48 +01001077 loop_body->AddInstruction(null_check);
1078 loop_body->AddInstruction(array_length);
1079 loop_body->AddInstruction(param_i_mod_array_length);
1080 loop_body->AddInstruction(bounds_check_param_i_mod_array_len);
1081 loop_body->AddInstruction(array_set);
1082
1083 // i++;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001084 HInstruction* add = new (&allocator_) HAdd(DataType::Type::kInt32, phi, constant_1);
xueliang.zhonga22cae72017-06-26 17:49:48 +01001085 loop_body->AddInstruction(add);
1086 loop_body->AddInstruction(new (&allocator_) HGoto());
1087 phi->AddInput(add);
1088 //////////////////////////////////////////////////////////////////////////////////
1089
1090 exit->AddInstruction(new (&allocator_) HExit());
1091
1092 RunBCE();
1093
1094 ASSERT_TRUE(IsRemoved(bounds_check_i_mod_10));
1095 ASSERT_TRUE(IsRemoved(bounds_check_i_mod_1));
1096 ASSERT_TRUE(IsRemoved(bounds_check_i_mod_200));
1097 ASSERT_TRUE(IsRemoved(bounds_check_i_mod_minus_10));
1098 ASSERT_TRUE(IsRemoved(bounds_check_i_mod_array_len));
1099 ASSERT_FALSE(IsRemoved(bounds_check_param_i_mod_10));
1100}
1101
Mingyao Yangf384f882014-10-22 16:08:18 -07001102} // namespace art