blob: 1523478613bb6d72ee0f1bca966c04ee7b48f542 [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 */
Vladimir Markoca6fff82017-10-03 14:49:14 +010035class BoundsCheckEliminationTest : public OptimizingUnitTest {
Aart Bik22af3be2015-09-10 12:50:58 -070036 public:
Vladimir Markoca6fff82017-10-03 14:49:14 +010037 BoundsCheckEliminationTest() : graph_(CreateGraph()) {
Aart Bik22af3be2015-09-10 12:50:58 -070038 graph_->SetHasBoundsChecks(true);
39 }
40
41 ~BoundsCheckEliminationTest() { }
42
43 void RunBCE() {
44 graph_->BuildDominatorTree();
Aart Bik22af3be2015-09-10 12:50:58 -070045
Vladimir Marko65979462017-05-19 17:25:12 +010046 InstructionSimplifier(graph_, /* codegen */ nullptr, /* driver */ nullptr).Run();
Aart Bik22af3be2015-09-10 12:50:58 -070047
48 SideEffectsAnalysis side_effects(graph_);
49 side_effects.Run();
50
51 GVNOptimization(graph_, side_effects).Run();
52
53 HInductionVarAnalysis induction(graph_);
54 induction.Run();
55
Aart Bik4a342772015-11-30 10:17:46 -080056 BoundsCheckElimination(graph_, side_effects, &induction).Run();
Aart Bik22af3be2015-09-10 12:50:58 -070057 }
58
Aart Bik22af3be2015-09-10 12:50:58 -070059 HGraph* graph_;
60};
61
Nicolas Geoffraye6f17152015-01-26 15:13:47 +000062
Mingyao Yangf384f882014-10-22 16:08:18 -070063// if (i < 0) { array[i] = 1; // Can't eliminate. }
64// else if (i >= array.length) { array[i] = 1; // Can't eliminate. }
65// else { array[i] = 1; // Can eliminate. }
Aart Bik22af3be2015-09-10 12:50:58 -070066TEST_F(BoundsCheckEliminationTest, NarrowingRangeArrayBoundsElimination) {
Vladimir Markoca6fff82017-10-03 14:49:14 +010067 HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -070068 graph_->AddBlock(entry);
69 graph_->SetEntryBlock(entry);
Vladimir Markoca6fff82017-10-03 14:49:14 +010070 HInstruction* parameter1 = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010071 graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference); // array
Vladimir Markoca6fff82017-10-03 14:49:14 +010072 HInstruction* parameter2 = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010073 graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32); // i
Mingyao Yangf384f882014-10-22 16:08:18 -070074 entry->AddInstruction(parameter1);
75 entry->AddInstruction(parameter2);
David Brazdil8d5b8b22015-03-24 10:51:52 +000076
Aart Bik22af3be2015-09-10 12:50:58 -070077 HInstruction* constant_1 = graph_->GetIntConstant(1);
78 HInstruction* constant_0 = graph_->GetIntConstant(0);
Mingyao Yangf384f882014-10-22 16:08:18 -070079
Vladimir Markoca6fff82017-10-03 14:49:14 +010080 HBasicBlock* block1 = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -070081 graph_->AddBlock(block1);
Vladimir Markoca6fff82017-10-03 14:49:14 +010082 HInstruction* cmp = new (GetAllocator()) HGreaterThanOrEqual(parameter2, constant_0);
83 HIf* if_inst = new (GetAllocator()) HIf(cmp);
Mingyao Yangf384f882014-10-22 16:08:18 -070084 block1->AddInstruction(cmp);
85 block1->AddInstruction(if_inst);
86 entry->AddSuccessor(block1);
87
Vladimir Markoca6fff82017-10-03 14:49:14 +010088 HBasicBlock* block2 = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -070089 graph_->AddBlock(block2);
Vladimir Markoca6fff82017-10-03 14:49:14 +010090 HNullCheck* null_check = new (GetAllocator()) HNullCheck(parameter1, 0);
91 HArrayLength* array_length = new (GetAllocator()) HArrayLength(null_check, 0);
92 HBoundsCheck* bounds_check2 = new (GetAllocator())
Mingyao Yangf384f882014-10-22 16:08:18 -070093 HBoundsCheck(parameter2, array_length, 0);
Vladimir Markoca6fff82017-10-03 14:49:14 +010094 HArraySet* array_set = new (GetAllocator()) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010095 null_check, bounds_check2, constant_1, DataType::Type::kInt32, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -070096 block2->AddInstruction(null_check);
97 block2->AddInstruction(array_length);
98 block2->AddInstruction(bounds_check2);
99 block2->AddInstruction(array_set);
100
Vladimir Markoca6fff82017-10-03 14:49:14 +0100101 HBasicBlock* block3 = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700102 graph_->AddBlock(block3);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100103 null_check = new (GetAllocator()) HNullCheck(parameter1, 0);
104 array_length = new (GetAllocator()) HArrayLength(null_check, 0);
105 cmp = new (GetAllocator()) HLessThan(parameter2, array_length);
106 if_inst = new (GetAllocator()) HIf(cmp);
Mingyao Yangf384f882014-10-22 16:08:18 -0700107 block3->AddInstruction(null_check);
108 block3->AddInstruction(array_length);
109 block3->AddInstruction(cmp);
110 block3->AddInstruction(if_inst);
111
Vladimir Markoca6fff82017-10-03 14:49:14 +0100112 HBasicBlock* block4 = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700113 graph_->AddBlock(block4);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100114 null_check = new (GetAllocator()) HNullCheck(parameter1, 0);
115 array_length = new (GetAllocator()) HArrayLength(null_check, 0);
116 HBoundsCheck* bounds_check4 = new (GetAllocator())
Mingyao Yangf384f882014-10-22 16:08:18 -0700117 HBoundsCheck(parameter2, array_length, 0);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100118 array_set = new (GetAllocator()) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100119 null_check, bounds_check4, constant_1, DataType::Type::kInt32, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700120 block4->AddInstruction(null_check);
121 block4->AddInstruction(array_length);
122 block4->AddInstruction(bounds_check4);
123 block4->AddInstruction(array_set);
124
Vladimir Markoca6fff82017-10-03 14:49:14 +0100125 HBasicBlock* block5 = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700126 graph_->AddBlock(block5);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100127 null_check = new (GetAllocator()) HNullCheck(parameter1, 0);
128 array_length = new (GetAllocator()) HArrayLength(null_check, 0);
129 HBoundsCheck* bounds_check5 = new (GetAllocator())
Mingyao Yangf384f882014-10-22 16:08:18 -0700130 HBoundsCheck(parameter2, array_length, 0);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100131 array_set = new (GetAllocator()) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100132 null_check, bounds_check5, constant_1, DataType::Type::kInt32, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700133 block5->AddInstruction(null_check);
134 block5->AddInstruction(array_length);
135 block5->AddInstruction(bounds_check5);
136 block5->AddInstruction(array_set);
137
Vladimir Markoca6fff82017-10-03 14:49:14 +0100138 HBasicBlock* exit = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700139 graph_->AddBlock(exit);
Mingyao Yangf384f882014-10-22 16:08:18 -0700140 block2->AddSuccessor(exit);
141 block4->AddSuccessor(exit);
142 block5->AddSuccessor(exit);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100143 exit->AddInstruction(new (GetAllocator()) HExit());
Mingyao Yangf384f882014-10-22 16:08:18 -0700144
145 block1->AddSuccessor(block3); // True successor
146 block1->AddSuccessor(block2); // False successor
147
148 block3->AddSuccessor(block5); // True successor
149 block3->AddSuccessor(block4); // False successor
150
Aart Bik22af3be2015-09-10 12:50:58 -0700151 RunBCE();
152
Mingyao Yangf384f882014-10-22 16:08:18 -0700153 ASSERT_FALSE(IsRemoved(bounds_check2));
154 ASSERT_FALSE(IsRemoved(bounds_check4));
155 ASSERT_TRUE(IsRemoved(bounds_check5));
156}
157
158// if (i > 0) {
159// // Positive number plus MAX_INT will overflow and be negative.
160// int j = i + Integer.MAX_VALUE;
161// if (j < array.length) array[j] = 1; // Can't eliminate.
162// }
Aart Bik22af3be2015-09-10 12:50:58 -0700163TEST_F(BoundsCheckEliminationTest, OverflowArrayBoundsElimination) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100164 HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700165 graph_->AddBlock(entry);
166 graph_->SetEntryBlock(entry);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100167 HInstruction* parameter1 = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100168 graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference); // array
Vladimir Markoca6fff82017-10-03 14:49:14 +0100169 HInstruction* parameter2 = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100170 graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32); // i
Mingyao Yangf384f882014-10-22 16:08:18 -0700171 entry->AddInstruction(parameter1);
172 entry->AddInstruction(parameter2);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000173
Aart Bik22af3be2015-09-10 12:50:58 -0700174 HInstruction* constant_1 = graph_->GetIntConstant(1);
175 HInstruction* constant_0 = graph_->GetIntConstant(0);
176 HInstruction* constant_max_int = graph_->GetIntConstant(INT_MAX);
Mingyao Yangf384f882014-10-22 16:08:18 -0700177
Vladimir Markoca6fff82017-10-03 14:49:14 +0100178 HBasicBlock* block1 = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700179 graph_->AddBlock(block1);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100180 HInstruction* cmp = new (GetAllocator()) HLessThanOrEqual(parameter2, constant_0);
181 HIf* if_inst = new (GetAllocator()) HIf(cmp);
Mingyao Yangf384f882014-10-22 16:08:18 -0700182 block1->AddInstruction(cmp);
183 block1->AddInstruction(if_inst);
184 entry->AddSuccessor(block1);
185
Vladimir Markoca6fff82017-10-03 14:49:14 +0100186 HBasicBlock* block2 = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700187 graph_->AddBlock(block2);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100188 HInstruction* add =
189 new (GetAllocator()) HAdd(DataType::Type::kInt32, parameter2, constant_max_int);
190 HNullCheck* null_check = new (GetAllocator()) HNullCheck(parameter1, 0);
191 HArrayLength* array_length = new (GetAllocator()) HArrayLength(null_check, 0);
192 HInstruction* cmp2 = new (GetAllocator()) HGreaterThanOrEqual(add, array_length);
193 if_inst = new (GetAllocator()) HIf(cmp2);
Mingyao Yangf384f882014-10-22 16:08:18 -0700194 block2->AddInstruction(add);
195 block2->AddInstruction(null_check);
196 block2->AddInstruction(array_length);
197 block2->AddInstruction(cmp2);
198 block2->AddInstruction(if_inst);
199
Vladimir Markoca6fff82017-10-03 14:49:14 +0100200 HBasicBlock* block3 = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700201 graph_->AddBlock(block3);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100202 HBoundsCheck* bounds_check = new (GetAllocator())
Mingyao Yangf384f882014-10-22 16:08:18 -0700203 HBoundsCheck(add, array_length, 0);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100204 HArraySet* array_set = new (GetAllocator()) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100205 null_check, bounds_check, constant_1, DataType::Type::kInt32, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700206 block3->AddInstruction(bounds_check);
207 block3->AddInstruction(array_set);
208
Vladimir Markoca6fff82017-10-03 14:49:14 +0100209 HBasicBlock* exit = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700210 graph_->AddBlock(exit);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100211 exit->AddInstruction(new (GetAllocator()) HExit());
Andreas Gampe0418b5b2014-12-04 17:24:50 -0800212 block1->AddSuccessor(exit); // true successor
213 block1->AddSuccessor(block2); // false successor
214 block2->AddSuccessor(exit); // true successor
215 block2->AddSuccessor(block3); // false successor
Mingyao Yangf384f882014-10-22 16:08:18 -0700216 block3->AddSuccessor(exit);
217
Aart Bik22af3be2015-09-10 12:50:58 -0700218 RunBCE();
219
Mingyao Yangf384f882014-10-22 16:08:18 -0700220 ASSERT_FALSE(IsRemoved(bounds_check));
221}
222
223// if (i < array.length) {
224// int j = i - Integer.MAX_VALUE;
Aart Bik22af3be2015-09-10 12:50:58 -0700225// j = j - Integer.MAX_VALUE; // j is (i+2) after subtracting MAX_INT twice
Mingyao Yangf384f882014-10-22 16:08:18 -0700226// if (j > 0) array[j] = 1; // Can't eliminate.
227// }
Aart Bik22af3be2015-09-10 12:50:58 -0700228TEST_F(BoundsCheckEliminationTest, UnderflowArrayBoundsElimination) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100229 HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700230 graph_->AddBlock(entry);
231 graph_->SetEntryBlock(entry);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100232 HInstruction* parameter1 = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100233 graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference); // array
Vladimir Markoca6fff82017-10-03 14:49:14 +0100234 HInstruction* parameter2 = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100235 graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32); // i
Mingyao Yangf384f882014-10-22 16:08:18 -0700236 entry->AddInstruction(parameter1);
237 entry->AddInstruction(parameter2);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000238
Aart Bik22af3be2015-09-10 12:50:58 -0700239 HInstruction* constant_1 = graph_->GetIntConstant(1);
240 HInstruction* constant_0 = graph_->GetIntConstant(0);
241 HInstruction* constant_max_int = graph_->GetIntConstant(INT_MAX);
Mingyao Yangf384f882014-10-22 16:08:18 -0700242
Vladimir Markoca6fff82017-10-03 14:49:14 +0100243 HBasicBlock* block1 = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700244 graph_->AddBlock(block1);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100245 HNullCheck* null_check = new (GetAllocator()) HNullCheck(parameter1, 0);
246 HArrayLength* array_length = new (GetAllocator()) HArrayLength(null_check, 0);
247 HInstruction* cmp = new (GetAllocator()) HGreaterThanOrEqual(parameter2, array_length);
248 HIf* if_inst = new (GetAllocator()) HIf(cmp);
Mingyao Yangf384f882014-10-22 16:08:18 -0700249 block1->AddInstruction(null_check);
250 block1->AddInstruction(array_length);
251 block1->AddInstruction(cmp);
252 block1->AddInstruction(if_inst);
253 entry->AddSuccessor(block1);
254
Vladimir Markoca6fff82017-10-03 14:49:14 +0100255 HBasicBlock* block2 = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700256 graph_->AddBlock(block2);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100257 HInstruction* sub1 =
258 new (GetAllocator()) HSub(DataType::Type::kInt32, parameter2, constant_max_int);
259 HInstruction* sub2 = new (GetAllocator()) HSub(DataType::Type::kInt32, sub1, constant_max_int);
260 HInstruction* cmp2 = new (GetAllocator()) HLessThanOrEqual(sub2, constant_0);
261 if_inst = new (GetAllocator()) HIf(cmp2);
Mingyao Yangf384f882014-10-22 16:08:18 -0700262 block2->AddInstruction(sub1);
263 block2->AddInstruction(sub2);
264 block2->AddInstruction(cmp2);
265 block2->AddInstruction(if_inst);
266
Vladimir Markoca6fff82017-10-03 14:49:14 +0100267 HBasicBlock* block3 = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700268 graph_->AddBlock(block3);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100269 HBoundsCheck* bounds_check = new (GetAllocator())
Mingyao Yangf384f882014-10-22 16:08:18 -0700270 HBoundsCheck(sub2, array_length, 0);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100271 HArraySet* array_set = new (GetAllocator()) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100272 null_check, bounds_check, constant_1, DataType::Type::kInt32, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700273 block3->AddInstruction(bounds_check);
274 block3->AddInstruction(array_set);
275
Vladimir Markoca6fff82017-10-03 14:49:14 +0100276 HBasicBlock* exit = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700277 graph_->AddBlock(exit);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100278 exit->AddInstruction(new (GetAllocator()) HExit());
Andreas Gampe0418b5b2014-12-04 17:24:50 -0800279 block1->AddSuccessor(exit); // true successor
280 block1->AddSuccessor(block2); // false successor
281 block2->AddSuccessor(exit); // true successor
282 block2->AddSuccessor(block3); // false successor
Mingyao Yangf384f882014-10-22 16:08:18 -0700283 block3->AddSuccessor(exit);
284
Aart Bik22af3be2015-09-10 12:50:58 -0700285 RunBCE();
286
Mingyao Yangf384f882014-10-22 16:08:18 -0700287 ASSERT_FALSE(IsRemoved(bounds_check));
288}
289
Andreas Gampe0ba62732015-03-24 02:39:46 +0000290// array[6] = 1; // Can't eliminate.
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700291// array[5] = 1; // Can eliminate.
292// array[4] = 1; // Can eliminate.
Aart Bik22af3be2015-09-10 12:50:58 -0700293TEST_F(BoundsCheckEliminationTest, ConstantArrayBoundsElimination) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100294 HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700295 graph_->AddBlock(entry);
296 graph_->SetEntryBlock(entry);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100297 HInstruction* parameter = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100298 graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
Mingyao Yangf384f882014-10-22 16:08:18 -0700299 entry->AddInstruction(parameter);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000300
Aart Bik22af3be2015-09-10 12:50:58 -0700301 HInstruction* constant_5 = graph_->GetIntConstant(5);
302 HInstruction* constant_4 = graph_->GetIntConstant(4);
303 HInstruction* constant_6 = graph_->GetIntConstant(6);
304 HInstruction* constant_1 = graph_->GetIntConstant(1);
Mingyao Yangf384f882014-10-22 16:08:18 -0700305
Vladimir Markoca6fff82017-10-03 14:49:14 +0100306 HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700307 graph_->AddBlock(block);
Mingyao Yangf384f882014-10-22 16:08:18 -0700308 entry->AddSuccessor(block);
309
Vladimir Markoca6fff82017-10-03 14:49:14 +0100310 HNullCheck* null_check = new (GetAllocator()) HNullCheck(parameter, 0);
311 HArrayLength* array_length = new (GetAllocator()) HArrayLength(null_check, 0);
312 HBoundsCheck* bounds_check6 = new (GetAllocator())
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700313 HBoundsCheck(constant_6, array_length, 0);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100314 HInstruction* array_set = new (GetAllocator()) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100315 null_check, bounds_check6, constant_1, DataType::Type::kInt32, 0);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700316 block->AddInstruction(null_check);
317 block->AddInstruction(array_length);
318 block->AddInstruction(bounds_check6);
319 block->AddInstruction(array_set);
320
Vladimir Markoca6fff82017-10-03 14:49:14 +0100321 null_check = new (GetAllocator()) HNullCheck(parameter, 0);
322 array_length = new (GetAllocator()) HArrayLength(null_check, 0);
323 HBoundsCheck* bounds_check5 = new (GetAllocator())
Mingyao Yangf384f882014-10-22 16:08:18 -0700324 HBoundsCheck(constant_5, array_length, 0);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100325 array_set = new (GetAllocator()) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100326 null_check, bounds_check5, constant_1, DataType::Type::kInt32, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700327 block->AddInstruction(null_check);
328 block->AddInstruction(array_length);
329 block->AddInstruction(bounds_check5);
330 block->AddInstruction(array_set);
331
Vladimir Markoca6fff82017-10-03 14:49:14 +0100332 null_check = new (GetAllocator()) HNullCheck(parameter, 0);
333 array_length = new (GetAllocator()) HArrayLength(null_check, 0);
334 HBoundsCheck* bounds_check4 = new (GetAllocator())
Mingyao Yangf384f882014-10-22 16:08:18 -0700335 HBoundsCheck(constant_4, array_length, 0);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100336 array_set = new (GetAllocator()) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100337 null_check, bounds_check4, constant_1, DataType::Type::kInt32, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700338 block->AddInstruction(null_check);
339 block->AddInstruction(array_length);
340 block->AddInstruction(bounds_check4);
341 block->AddInstruction(array_set);
342
Vladimir Markoca6fff82017-10-03 14:49:14 +0100343 block->AddInstruction(new (GetAllocator()) HGoto());
Mingyao Yangf384f882014-10-22 16:08:18 -0700344
Vladimir Markoca6fff82017-10-03 14:49:14 +0100345 HBasicBlock* exit = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700346 graph_->AddBlock(exit);
Mingyao Yangf384f882014-10-22 16:08:18 -0700347 block->AddSuccessor(exit);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100348 exit->AddInstruction(new (GetAllocator()) HExit());
Mingyao Yangf384f882014-10-22 16:08:18 -0700349
Aart Bik22af3be2015-09-10 12:50:58 -0700350 RunBCE();
351
Andreas Gampe0ba62732015-03-24 02:39:46 +0000352 ASSERT_FALSE(IsRemoved(bounds_check6));
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700353 ASSERT_TRUE(IsRemoved(bounds_check5));
354 ASSERT_TRUE(IsRemoved(bounds_check4));
Mingyao Yangf384f882014-10-22 16:08:18 -0700355}
356
357// for (int i=initial; i<array.length; i+=increment) { array[i] = 10; }
Aart Bik22af3be2015-09-10 12:50:58 -0700358static HInstruction* BuildSSAGraph1(HGraph* graph,
359 ArenaAllocator* allocator,
360 int initial,
361 int increment,
362 IfCondition cond = kCondGE) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700363 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
364 graph->AddBlock(entry);
365 graph->SetEntryBlock(entry);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000366 HInstruction* parameter = new (allocator) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100367 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
Mingyao Yangf384f882014-10-22 16:08:18 -0700368 entry->AddInstruction(parameter);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000369
370 HInstruction* constant_initial = graph->GetIntConstant(initial);
371 HInstruction* constant_increment = graph->GetIntConstant(increment);
372 HInstruction* constant_10 = graph->GetIntConstant(10);
Mingyao Yangf384f882014-10-22 16:08:18 -0700373
374 HBasicBlock* block = new (allocator) HBasicBlock(graph);
375 graph->AddBlock(block);
376 entry->AddSuccessor(block);
377 block->AddInstruction(new (allocator) HGoto());
378
379 HBasicBlock* loop_header = new (allocator) HBasicBlock(graph);
380 HBasicBlock* loop_body = new (allocator) HBasicBlock(graph);
381 HBasicBlock* exit = new (allocator) HBasicBlock(graph);
382
383 graph->AddBlock(loop_header);
384 graph->AddBlock(loop_body);
385 graph->AddBlock(exit);
386 block->AddSuccessor(loop_header);
387 loop_header->AddSuccessor(exit); // true successor
388 loop_header->AddSuccessor(loop_body); // false successor
389 loop_body->AddSuccessor(loop_header);
390
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100391 HPhi* phi = new (allocator) HPhi(allocator, 0, 0, DataType::Type::kInt32);
Mingyao Yangf384f882014-10-22 16:08:18 -0700392 HInstruction* null_check = new (allocator) HNullCheck(parameter, 0);
Calin Juravle154746b2015-10-06 15:46:54 +0100393 HInstruction* array_length = new (allocator) HArrayLength(null_check, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700394 HInstruction* cmp = nullptr;
395 if (cond == kCondGE) {
396 cmp = new (allocator) HGreaterThanOrEqual(phi, array_length);
397 } else {
398 DCHECK(cond == kCondGT);
399 cmp = new (allocator) HGreaterThan(phi, array_length);
400 }
401 HInstruction* if_inst = new (allocator) HIf(cmp);
402 loop_header->AddPhi(phi);
403 loop_header->AddInstruction(null_check);
404 loop_header->AddInstruction(array_length);
405 loop_header->AddInstruction(cmp);
406 loop_header->AddInstruction(if_inst);
David Brazdil1abb4192015-02-17 18:33:36 +0000407 phi->AddInput(constant_initial);
Mingyao Yangf384f882014-10-22 16:08:18 -0700408
409 null_check = new (allocator) HNullCheck(parameter, 0);
Calin Juravle154746b2015-10-06 15:46:54 +0100410 array_length = new (allocator) HArrayLength(null_check, 0);
Aart Bik22af3be2015-09-10 12:50:58 -0700411 HInstruction* bounds_check = new (allocator) HBoundsCheck(phi, array_length, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700412 HInstruction* array_set = new (allocator) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100413 null_check, bounds_check, constant_10, DataType::Type::kInt32, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700414
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100415 HInstruction* add = new (allocator) HAdd(DataType::Type::kInt32, phi, constant_increment);
Mingyao Yangf384f882014-10-22 16:08:18 -0700416 loop_body->AddInstruction(null_check);
417 loop_body->AddInstruction(array_length);
Aart Bik22af3be2015-09-10 12:50:58 -0700418 loop_body->AddInstruction(bounds_check);
Mingyao Yangf384f882014-10-22 16:08:18 -0700419 loop_body->AddInstruction(array_set);
420 loop_body->AddInstruction(add);
421 loop_body->AddInstruction(new (allocator) HGoto());
422 phi->AddInput(add);
423
424 exit->AddInstruction(new (allocator) HExit());
425
Aart Bik22af3be2015-09-10 12:50:58 -0700426 return bounds_check;
Mingyao Yangf384f882014-10-22 16:08:18 -0700427}
428
Aart Bik22af3be2015-09-10 12:50:58 -0700429TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination1a) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700430 // for (int i=0; i<array.length; i++) { array[i] = 10; // Can eliminate with gvn. }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100431 HInstruction* bounds_check = BuildSSAGraph1(graph_, GetAllocator(), 0, 1);
Aart Bik22af3be2015-09-10 12:50:58 -0700432 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700433 ASSERT_TRUE(IsRemoved(bounds_check));
Aart Bik22af3be2015-09-10 12:50:58 -0700434}
Mingyao Yangf384f882014-10-22 16:08:18 -0700435
Aart Bik22af3be2015-09-10 12:50:58 -0700436TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination1b) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700437 // for (int i=1; i<array.length; i++) { array[i] = 10; // Can eliminate. }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100438 HInstruction* bounds_check = BuildSSAGraph1(graph_, GetAllocator(), 1, 1);
Aart Bik22af3be2015-09-10 12:50:58 -0700439 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700440 ASSERT_TRUE(IsRemoved(bounds_check));
Aart Bik22af3be2015-09-10 12:50:58 -0700441}
Mingyao Yangf384f882014-10-22 16:08:18 -0700442
Aart Bik22af3be2015-09-10 12:50:58 -0700443TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination1c) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700444 // for (int i=-1; i<array.length; i++) { array[i] = 10; // Can't eliminate. }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100445 HInstruction* bounds_check = BuildSSAGraph1(graph_, GetAllocator(), -1, 1);
Aart Bik22af3be2015-09-10 12:50:58 -0700446 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700447 ASSERT_FALSE(IsRemoved(bounds_check));
Aart Bik22af3be2015-09-10 12:50:58 -0700448}
Mingyao Yangf384f882014-10-22 16:08:18 -0700449
Aart Bik22af3be2015-09-10 12:50:58 -0700450TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination1d) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700451 // for (int i=0; i<=array.length; i++) { array[i] = 10; // Can't eliminate. }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100452 HInstruction* bounds_check = BuildSSAGraph1(graph_, GetAllocator(), 0, 1, kCondGT);
Aart Bik22af3be2015-09-10 12:50:58 -0700453 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700454 ASSERT_FALSE(IsRemoved(bounds_check));
Aart Bik22af3be2015-09-10 12:50:58 -0700455}
Mingyao Yangf384f882014-10-22 16:08:18 -0700456
Aart Bik22af3be2015-09-10 12:50:58 -0700457TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination1e) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700458 // for (int i=0; i<array.length; i += 2) {
459 // array[i] = 10; // Can't eliminate due to overflow concern. }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100460 HInstruction* bounds_check = BuildSSAGraph1(graph_, GetAllocator(), 0, 2);
Aart Bik22af3be2015-09-10 12:50:58 -0700461 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700462 ASSERT_FALSE(IsRemoved(bounds_check));
Aart Bik22af3be2015-09-10 12:50:58 -0700463}
Mingyao Yangf384f882014-10-22 16:08:18 -0700464
Aart Bik22af3be2015-09-10 12:50:58 -0700465TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination1f) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700466 // for (int i=1; i<array.length; i += 2) { array[i] = 10; // Can eliminate. }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100467 HInstruction* bounds_check = BuildSSAGraph1(graph_, GetAllocator(), 1, 2);
Aart Bik22af3be2015-09-10 12:50:58 -0700468 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700469 ASSERT_TRUE(IsRemoved(bounds_check));
470}
471
472// for (int i=array.length; i>0; i+=increment) { array[i-1] = 10; }
Aart Bik22af3be2015-09-10 12:50:58 -0700473static HInstruction* BuildSSAGraph2(HGraph *graph,
474 ArenaAllocator* allocator,
475 int initial,
476 int increment = -1,
477 IfCondition cond = kCondLE) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700478 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
479 graph->AddBlock(entry);
480 graph->SetEntryBlock(entry);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000481 HInstruction* parameter = new (allocator) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100482 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
Mingyao Yangf384f882014-10-22 16:08:18 -0700483 entry->AddInstruction(parameter);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000484
485 HInstruction* constant_initial = graph->GetIntConstant(initial);
486 HInstruction* constant_increment = graph->GetIntConstant(increment);
487 HInstruction* constant_minus_1 = graph->GetIntConstant(-1);
488 HInstruction* constant_10 = graph->GetIntConstant(10);
Mingyao Yangf384f882014-10-22 16:08:18 -0700489
490 HBasicBlock* block = new (allocator) HBasicBlock(graph);
491 graph->AddBlock(block);
492 entry->AddSuccessor(block);
493 HInstruction* null_check = new (allocator) HNullCheck(parameter, 0);
Calin Juravle154746b2015-10-06 15:46:54 +0100494 HInstruction* array_length = new (allocator) HArrayLength(null_check, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700495 block->AddInstruction(null_check);
496 block->AddInstruction(array_length);
497 block->AddInstruction(new (allocator) HGoto());
498
499 HBasicBlock* loop_header = new (allocator) HBasicBlock(graph);
500 HBasicBlock* loop_body = new (allocator) HBasicBlock(graph);
501 HBasicBlock* exit = new (allocator) HBasicBlock(graph);
502
503 graph->AddBlock(loop_header);
504 graph->AddBlock(loop_body);
505 graph->AddBlock(exit);
506 block->AddSuccessor(loop_header);
507 loop_header->AddSuccessor(exit); // true successor
508 loop_header->AddSuccessor(loop_body); // false successor
509 loop_body->AddSuccessor(loop_header);
510
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100511 HPhi* phi = new (allocator) HPhi(allocator, 0, 0, DataType::Type::kInt32);
Mingyao Yangf384f882014-10-22 16:08:18 -0700512 HInstruction* cmp = nullptr;
513 if (cond == kCondLE) {
514 cmp = new (allocator) HLessThanOrEqual(phi, constant_initial);
515 } else {
516 DCHECK(cond == kCondLT);
517 cmp = new (allocator) HLessThan(phi, constant_initial);
518 }
519 HInstruction* if_inst = new (allocator) HIf(cmp);
520 loop_header->AddPhi(phi);
521 loop_header->AddInstruction(cmp);
522 loop_header->AddInstruction(if_inst);
David Brazdil1abb4192015-02-17 18:33:36 +0000523 phi->AddInput(array_length);
Mingyao Yangf384f882014-10-22 16:08:18 -0700524
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100525 HInstruction* add = new (allocator) HAdd(DataType::Type::kInt32, phi, constant_minus_1);
Mingyao Yangf384f882014-10-22 16:08:18 -0700526 null_check = new (allocator) HNullCheck(parameter, 0);
Calin Juravle154746b2015-10-06 15:46:54 +0100527 array_length = new (allocator) HArrayLength(null_check, 0);
Aart Bik22af3be2015-09-10 12:50:58 -0700528 HInstruction* bounds_check = new (allocator) HBoundsCheck(add, array_length, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700529 HInstruction* array_set = new (allocator) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100530 null_check, bounds_check, constant_10, DataType::Type::kInt32, 0);
531 HInstruction* add_phi = new (allocator) HAdd(DataType::Type::kInt32, phi, constant_increment);
Mingyao Yangf384f882014-10-22 16:08:18 -0700532 loop_body->AddInstruction(add);
533 loop_body->AddInstruction(null_check);
534 loop_body->AddInstruction(array_length);
Aart Bik22af3be2015-09-10 12:50:58 -0700535 loop_body->AddInstruction(bounds_check);
Mingyao Yangf384f882014-10-22 16:08:18 -0700536 loop_body->AddInstruction(array_set);
537 loop_body->AddInstruction(add_phi);
538 loop_body->AddInstruction(new (allocator) HGoto());
539 phi->AddInput(add);
540
541 exit->AddInstruction(new (allocator) HExit());
542
Aart Bik22af3be2015-09-10 12:50:58 -0700543 return bounds_check;
Mingyao Yangf384f882014-10-22 16:08:18 -0700544}
545
Aart Bik22af3be2015-09-10 12:50:58 -0700546TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination2a) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700547 // for (int i=array.length; i>0; i--) { array[i-1] = 10; // Can eliminate with gvn. }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100548 HInstruction* bounds_check = BuildSSAGraph2(graph_, GetAllocator(), 0);
Aart Bik22af3be2015-09-10 12:50:58 -0700549 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700550 ASSERT_TRUE(IsRemoved(bounds_check));
Aart Bik22af3be2015-09-10 12:50:58 -0700551}
Mingyao Yangf384f882014-10-22 16:08:18 -0700552
Aart Bik22af3be2015-09-10 12:50:58 -0700553TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination2b) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700554 // for (int i=array.length; i>1; i--) { array[i-1] = 10; // Can eliminate. }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100555 HInstruction* bounds_check = BuildSSAGraph2(graph_, GetAllocator(), 1);
Aart Bik22af3be2015-09-10 12:50:58 -0700556 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700557 ASSERT_TRUE(IsRemoved(bounds_check));
Aart Bik22af3be2015-09-10 12:50:58 -0700558}
Mingyao Yangf384f882014-10-22 16:08:18 -0700559
Aart Bik22af3be2015-09-10 12:50:58 -0700560TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination2c) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700561 // for (int i=array.length; i>-1; i--) { array[i-1] = 10; // Can't eliminate. }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100562 HInstruction* bounds_check = BuildSSAGraph2(graph_, GetAllocator(), -1);
Aart Bik22af3be2015-09-10 12:50:58 -0700563 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700564 ASSERT_FALSE(IsRemoved(bounds_check));
Aart Bik22af3be2015-09-10 12:50:58 -0700565}
Mingyao Yangf384f882014-10-22 16:08:18 -0700566
Aart Bik22af3be2015-09-10 12:50:58 -0700567TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination2d) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700568 // for (int i=array.length; i>=0; i--) { array[i-1] = 10; // Can't eliminate. }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100569 HInstruction* bounds_check = BuildSSAGraph2(graph_, GetAllocator(), 0, -1, kCondLT);
Aart Bik22af3be2015-09-10 12:50:58 -0700570 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700571 ASSERT_FALSE(IsRemoved(bounds_check));
Aart Bik22af3be2015-09-10 12:50:58 -0700572}
Mingyao Yangf384f882014-10-22 16:08:18 -0700573
Aart Bik22af3be2015-09-10 12:50:58 -0700574TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination2e) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700575 // for (int i=array.length; i>0; i-=2) { array[i-1] = 10; // Can eliminate. }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100576 HInstruction* bounds_check = BuildSSAGraph2(graph_, GetAllocator(), 0, -2);
Aart Bik22af3be2015-09-10 12:50:58 -0700577 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700578 ASSERT_TRUE(IsRemoved(bounds_check));
579}
580
Mingyao Yang8c8bad82015-02-09 18:13:26 -0800581// int[] array = new int[10];
Mingyao Yangf384f882014-10-22 16:08:18 -0700582// for (int i=0; i<10; i+=increment) { array[i] = 10; }
Aart Bik22af3be2015-09-10 12:50:58 -0700583static HInstruction* BuildSSAGraph3(HGraph* graph,
584 ArenaAllocator* allocator,
585 int initial,
586 int increment,
587 IfCondition cond) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700588 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
589 graph->AddBlock(entry);
590 graph->SetEntryBlock(entry);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000591
592 HInstruction* constant_10 = graph->GetIntConstant(10);
593 HInstruction* constant_initial = graph->GetIntConstant(initial);
594 HInstruction* constant_increment = graph->GetIntConstant(increment);
Mingyao Yangf384f882014-10-22 16:08:18 -0700595
596 HBasicBlock* block = new (allocator) HBasicBlock(graph);
597 graph->AddBlock(block);
598 entry->AddSuccessor(block);
Nicolas Geoffraye761bcc2017-01-19 08:59:37 +0000599 // We pass a bogus constant for the class to avoid mocking one.
Nicolas Geoffray69aa6012015-06-09 10:34:25 +0100600 HInstruction* new_array = new (allocator) HNewArray(
601 constant_10,
Nicolas Geoffraye761bcc2017-01-19 08:59:37 +0000602 constant_10,
603 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700604 block->AddInstruction(new_array);
605 block->AddInstruction(new (allocator) HGoto());
606
607 HBasicBlock* loop_header = new (allocator) HBasicBlock(graph);
608 HBasicBlock* loop_body = new (allocator) HBasicBlock(graph);
609 HBasicBlock* exit = new (allocator) HBasicBlock(graph);
610
611 graph->AddBlock(loop_header);
612 graph->AddBlock(loop_body);
613 graph->AddBlock(exit);
614 block->AddSuccessor(loop_header);
615 loop_header->AddSuccessor(exit); // true successor
616 loop_header->AddSuccessor(loop_body); // false successor
617 loop_body->AddSuccessor(loop_header);
618
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100619 HPhi* phi = new (allocator) HPhi(allocator, 0, 0, DataType::Type::kInt32);
Mingyao Yangf384f882014-10-22 16:08:18 -0700620 HInstruction* cmp = nullptr;
621 if (cond == kCondGE) {
622 cmp = new (allocator) HGreaterThanOrEqual(phi, constant_10);
623 } else {
624 DCHECK(cond == kCondGT);
625 cmp = new (allocator) HGreaterThan(phi, constant_10);
626 }
627 HInstruction* if_inst = new (allocator) HIf(cmp);
628 loop_header->AddPhi(phi);
629 loop_header->AddInstruction(cmp);
630 loop_header->AddInstruction(if_inst);
David Brazdil1abb4192015-02-17 18:33:36 +0000631 phi->AddInput(constant_initial);
Mingyao Yangf384f882014-10-22 16:08:18 -0700632
633 HNullCheck* null_check = new (allocator) HNullCheck(new_array, 0);
Calin Juravle154746b2015-10-06 15:46:54 +0100634 HArrayLength* array_length = new (allocator) HArrayLength(null_check, 0);
Aart Bik22af3be2015-09-10 12:50:58 -0700635 HInstruction* bounds_check = new (allocator) HBoundsCheck(phi, array_length, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700636 HInstruction* array_set = new (allocator) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100637 null_check, bounds_check, constant_10, DataType::Type::kInt32, 0);
638 HInstruction* add = new (allocator) HAdd(DataType::Type::kInt32, phi, constant_increment);
Mingyao Yangf384f882014-10-22 16:08:18 -0700639 loop_body->AddInstruction(null_check);
640 loop_body->AddInstruction(array_length);
Aart Bik22af3be2015-09-10 12:50:58 -0700641 loop_body->AddInstruction(bounds_check);
Mingyao Yangf384f882014-10-22 16:08:18 -0700642 loop_body->AddInstruction(array_set);
643 loop_body->AddInstruction(add);
644 loop_body->AddInstruction(new (allocator) HGoto());
645 phi->AddInput(add);
646
647 exit->AddInstruction(new (allocator) HExit());
648
Aart Bik22af3be2015-09-10 12:50:58 -0700649 return bounds_check;
Mingyao Yangf384f882014-10-22 16:08:18 -0700650}
651
Aart Bik22af3be2015-09-10 12:50:58 -0700652TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination3a) {
Mingyao Yang8c8bad82015-02-09 18:13:26 -0800653 // int[] array = new int[10];
Mingyao Yangf384f882014-10-22 16:08:18 -0700654 // for (int i=0; i<10; i++) { array[i] = 10; // Can eliminate. }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100655 HInstruction* bounds_check = BuildSSAGraph3(graph_, GetAllocator(), 0, 1, kCondGE);
Aart Bik22af3be2015-09-10 12:50:58 -0700656 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700657 ASSERT_TRUE(IsRemoved(bounds_check));
Aart Bik22af3be2015-09-10 12:50:58 -0700658}
Mingyao Yangf384f882014-10-22 16:08:18 -0700659
Aart Bik22af3be2015-09-10 12:50:58 -0700660TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination3b) {
Mingyao Yang8c8bad82015-02-09 18:13:26 -0800661 // int[] array = new int[10];
Mingyao Yangf384f882014-10-22 16:08:18 -0700662 // for (int i=1; i<10; i++) { array[i] = 10; // Can eliminate. }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100663 HInstruction* bounds_check = BuildSSAGraph3(graph_, GetAllocator(), 1, 1, kCondGE);
Aart Bik22af3be2015-09-10 12:50:58 -0700664 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700665 ASSERT_TRUE(IsRemoved(bounds_check));
Aart Bik22af3be2015-09-10 12:50:58 -0700666}
Mingyao Yangf384f882014-10-22 16:08:18 -0700667
Aart Bik22af3be2015-09-10 12:50:58 -0700668TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination3c) {
Mingyao Yang8c8bad82015-02-09 18:13:26 -0800669 // int[] array = new int[10];
Mingyao Yangf384f882014-10-22 16:08:18 -0700670 // for (int i=0; i<=10; i++) { array[i] = 10; // Can't eliminate. }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100671 HInstruction* bounds_check = BuildSSAGraph3(graph_, GetAllocator(), 0, 1, kCondGT);
Aart Bik22af3be2015-09-10 12:50:58 -0700672 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700673 ASSERT_FALSE(IsRemoved(bounds_check));
Aart Bik22af3be2015-09-10 12:50:58 -0700674}
Mingyao Yangf384f882014-10-22 16:08:18 -0700675
Aart Bik22af3be2015-09-10 12:50:58 -0700676TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination3d) {
Mingyao Yang8c8bad82015-02-09 18:13:26 -0800677 // int[] array = new int[10];
Mingyao Yangf384f882014-10-22 16:08:18 -0700678 // for (int i=1; i<10; i+=8) { array[i] = 10; // Can eliminate. }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100679 HInstruction* bounds_check = BuildSSAGraph3(graph_, GetAllocator(), 1, 8, kCondGE);
Aart Bik22af3be2015-09-10 12:50:58 -0700680 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700681 ASSERT_TRUE(IsRemoved(bounds_check));
682}
683
684// for (int i=initial; i<array.length; i++) { array[array.length-i-1] = 10; }
Aart Bik22af3be2015-09-10 12:50:58 -0700685static HInstruction* BuildSSAGraph4(HGraph* graph,
686 ArenaAllocator* allocator,
687 int initial,
688 IfCondition cond = kCondGE) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700689 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
690 graph->AddBlock(entry);
691 graph->SetEntryBlock(entry);
Calin Juravlee6e3bea2015-10-14 13:53:10 +0000692 HInstruction* parameter = new (allocator) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100693 graph->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
Mingyao Yangf384f882014-10-22 16:08:18 -0700694 entry->AddInstruction(parameter);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000695
696 HInstruction* constant_initial = graph->GetIntConstant(initial);
697 HInstruction* constant_1 = graph->GetIntConstant(1);
698 HInstruction* constant_10 = graph->GetIntConstant(10);
699 HInstruction* constant_minus_1 = graph->GetIntConstant(-1);
Mingyao Yangf384f882014-10-22 16:08:18 -0700700
701 HBasicBlock* block = new (allocator) HBasicBlock(graph);
702 graph->AddBlock(block);
703 entry->AddSuccessor(block);
704 block->AddInstruction(new (allocator) HGoto());
705
706 HBasicBlock* loop_header = new (allocator) HBasicBlock(graph);
707 HBasicBlock* loop_body = new (allocator) HBasicBlock(graph);
708 HBasicBlock* exit = new (allocator) HBasicBlock(graph);
709
710 graph->AddBlock(loop_header);
711 graph->AddBlock(loop_body);
712 graph->AddBlock(exit);
713 block->AddSuccessor(loop_header);
714 loop_header->AddSuccessor(exit); // true successor
715 loop_header->AddSuccessor(loop_body); // false successor
716 loop_body->AddSuccessor(loop_header);
717
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100718 HPhi* phi = new (allocator) HPhi(allocator, 0, 0, DataType::Type::kInt32);
Mingyao Yangf384f882014-10-22 16:08:18 -0700719 HInstruction* null_check = new (allocator) HNullCheck(parameter, 0);
Calin Juravle154746b2015-10-06 15:46:54 +0100720 HInstruction* array_length = new (allocator) HArrayLength(null_check, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700721 HInstruction* cmp = nullptr;
722 if (cond == kCondGE) {
723 cmp = new (allocator) HGreaterThanOrEqual(phi, array_length);
724 } else if (cond == kCondGT) {
725 cmp = new (allocator) HGreaterThan(phi, array_length);
726 }
727 HInstruction* if_inst = new (allocator) HIf(cmp);
728 loop_header->AddPhi(phi);
729 loop_header->AddInstruction(null_check);
730 loop_header->AddInstruction(array_length);
731 loop_header->AddInstruction(cmp);
732 loop_header->AddInstruction(if_inst);
David Brazdil1abb4192015-02-17 18:33:36 +0000733 phi->AddInput(constant_initial);
Mingyao Yangf384f882014-10-22 16:08:18 -0700734
735 null_check = new (allocator) HNullCheck(parameter, 0);
Calin Juravle154746b2015-10-06 15:46:54 +0100736 array_length = new (allocator) HArrayLength(null_check, 0);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100737 HInstruction* sub = new (allocator) HSub(DataType::Type::kInt32, array_length, phi);
Mingyao Yangf384f882014-10-22 16:08:18 -0700738 HInstruction* add_minus_1 = new (allocator)
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100739 HAdd(DataType::Type::kInt32, sub, constant_minus_1);
Aart Bik22af3be2015-09-10 12:50:58 -0700740 HInstruction* bounds_check = new (allocator) HBoundsCheck(add_minus_1, array_length, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700741 HInstruction* array_set = new (allocator) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100742 null_check, bounds_check, constant_10, DataType::Type::kInt32, 0);
743 HInstruction* add = new (allocator) HAdd(DataType::Type::kInt32, phi, constant_1);
Mingyao Yangf384f882014-10-22 16:08:18 -0700744 loop_body->AddInstruction(null_check);
745 loop_body->AddInstruction(array_length);
746 loop_body->AddInstruction(sub);
747 loop_body->AddInstruction(add_minus_1);
Aart Bik22af3be2015-09-10 12:50:58 -0700748 loop_body->AddInstruction(bounds_check);
Mingyao Yangf384f882014-10-22 16:08:18 -0700749 loop_body->AddInstruction(array_set);
750 loop_body->AddInstruction(add);
751 loop_body->AddInstruction(new (allocator) HGoto());
752 phi->AddInput(add);
753
754 exit->AddInstruction(new (allocator) HExit());
755
Aart Bik22af3be2015-09-10 12:50:58 -0700756 return bounds_check;
Mingyao Yangf384f882014-10-22 16:08:18 -0700757}
758
Aart Bik22af3be2015-09-10 12:50:58 -0700759TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination4a) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700760 // 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 +0100761 HInstruction* bounds_check = BuildSSAGraph4(graph_, GetAllocator(), 0);
Aart Bik22af3be2015-09-10 12:50:58 -0700762 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700763 ASSERT_TRUE(IsRemoved(bounds_check));
Aart Bik22af3be2015-09-10 12:50:58 -0700764}
Mingyao Yangf384f882014-10-22 16:08:18 -0700765
Aart Bik22af3be2015-09-10 12:50:58 -0700766TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination4b) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700767 // for (int i=1; i<array.length; i++) { array[array.length-i-1] = 10; // Can eliminate. }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100768 HInstruction* bounds_check = BuildSSAGraph4(graph_, GetAllocator(), 1);
Aart Bik22af3be2015-09-10 12:50:58 -0700769 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700770 ASSERT_TRUE(IsRemoved(bounds_check));
Aart Bik22af3be2015-09-10 12:50:58 -0700771}
Mingyao Yangf384f882014-10-22 16:08:18 -0700772
Aart Bik22af3be2015-09-10 12:50:58 -0700773TEST_F(BoundsCheckEliminationTest, LoopArrayBoundsElimination4c) {
Mingyao Yangf384f882014-10-22 16:08:18 -0700774 // for (int i=0; i<=array.length; i++) { array[array.length-i] = 10; // Can't eliminate. }
Vladimir Markoca6fff82017-10-03 14:49:14 +0100775 HInstruction* bounds_check = BuildSSAGraph4(graph_, GetAllocator(), 0, kCondGT);
Aart Bik22af3be2015-09-10 12:50:58 -0700776 RunBCE();
Mingyao Yangf384f882014-10-22 16:08:18 -0700777 ASSERT_FALSE(IsRemoved(bounds_check));
778}
779
780// Bubble sort:
781// (Every array access bounds-check can be eliminated.)
782// for (int i=0; i<array.length-1; i++) {
783// for (int j=0; j<array.length-i-1; j++) {
784// if (array[j] > array[j+1]) {
785// int temp = array[j+1];
786// array[j+1] = array[j];
787// array[j] = temp;
788// }
789// }
790// }
Aart Bik22af3be2015-09-10 12:50:58 -0700791TEST_F(BoundsCheckEliminationTest, BubbleSortArrayBoundsElimination) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100792 HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700793 graph_->AddBlock(entry);
794 graph_->SetEntryBlock(entry);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100795 HInstruction* parameter = new (GetAllocator()) HParameterValue(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100796 graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kReference);
Mingyao Yangf384f882014-10-22 16:08:18 -0700797 entry->AddInstruction(parameter);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000798
Aart Bik22af3be2015-09-10 12:50:58 -0700799 HInstruction* constant_0 = graph_->GetIntConstant(0);
800 HInstruction* constant_minus_1 = graph_->GetIntConstant(-1);
801 HInstruction* constant_1 = graph_->GetIntConstant(1);
Mingyao Yangf384f882014-10-22 16:08:18 -0700802
Vladimir Markoca6fff82017-10-03 14:49:14 +0100803 HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700804 graph_->AddBlock(block);
Mingyao Yangf384f882014-10-22 16:08:18 -0700805 entry->AddSuccessor(block);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100806 block->AddInstruction(new (GetAllocator()) HGoto());
Mingyao Yangf384f882014-10-22 16:08:18 -0700807
Vladimir Markoca6fff82017-10-03 14:49:14 +0100808 HBasicBlock* exit = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700809 graph_->AddBlock(exit);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100810 exit->AddInstruction(new (GetAllocator()) HExit());
Mingyao Yangf384f882014-10-22 16:08:18 -0700811
Vladimir Markoca6fff82017-10-03 14:49:14 +0100812 HBasicBlock* outer_header = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700813 graph_->AddBlock(outer_header);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100814 HPhi* phi_i = new (GetAllocator()) HPhi(GetAllocator(), 0, 0, DataType::Type::kInt32);
815 HNullCheck* null_check = new (GetAllocator()) HNullCheck(parameter, 0);
816 HArrayLength* array_length = new (GetAllocator()) HArrayLength(null_check, 0);
817 HAdd* add = new (GetAllocator()) HAdd(DataType::Type::kInt32, array_length, constant_minus_1);
818 HInstruction* cmp = new (GetAllocator()) HGreaterThanOrEqual(phi_i, add);
819 HIf* if_inst = new (GetAllocator()) HIf(cmp);
Mingyao Yangf384f882014-10-22 16:08:18 -0700820 outer_header->AddPhi(phi_i);
821 outer_header->AddInstruction(null_check);
822 outer_header->AddInstruction(array_length);
823 outer_header->AddInstruction(add);
824 outer_header->AddInstruction(cmp);
825 outer_header->AddInstruction(if_inst);
David Brazdil1abb4192015-02-17 18:33:36 +0000826 phi_i->AddInput(constant_0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700827
Vladimir Markoca6fff82017-10-03 14:49:14 +0100828 HBasicBlock* inner_header = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700829 graph_->AddBlock(inner_header);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100830 HPhi* phi_j = new (GetAllocator()) HPhi(GetAllocator(), 0, 0, DataType::Type::kInt32);
831 null_check = new (GetAllocator()) HNullCheck(parameter, 0);
832 array_length = new (GetAllocator()) HArrayLength(null_check, 0);
833 HSub* sub = new (GetAllocator()) HSub(DataType::Type::kInt32, array_length, phi_i);
834 add = new (GetAllocator()) HAdd(DataType::Type::kInt32, sub, constant_minus_1);
835 cmp = new (GetAllocator()) HGreaterThanOrEqual(phi_j, add);
836 if_inst = new (GetAllocator()) HIf(cmp);
Mingyao Yangf384f882014-10-22 16:08:18 -0700837 inner_header->AddPhi(phi_j);
838 inner_header->AddInstruction(null_check);
839 inner_header->AddInstruction(array_length);
840 inner_header->AddInstruction(sub);
841 inner_header->AddInstruction(add);
842 inner_header->AddInstruction(cmp);
843 inner_header->AddInstruction(if_inst);
David Brazdil1abb4192015-02-17 18:33:36 +0000844 phi_j->AddInput(constant_0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700845
Vladimir Markoca6fff82017-10-03 14:49:14 +0100846 HBasicBlock* inner_body_compare = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700847 graph_->AddBlock(inner_body_compare);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100848 null_check = new (GetAllocator()) HNullCheck(parameter, 0);
849 array_length = new (GetAllocator()) HArrayLength(null_check, 0);
850 HBoundsCheck* bounds_check1 = new (GetAllocator()) HBoundsCheck(phi_j, array_length, 0);
851 HArrayGet* array_get_j = new (GetAllocator())
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100852 HArrayGet(null_check, bounds_check1, DataType::Type::kInt32, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700853 inner_body_compare->AddInstruction(null_check);
854 inner_body_compare->AddInstruction(array_length);
855 inner_body_compare->AddInstruction(bounds_check1);
856 inner_body_compare->AddInstruction(array_get_j);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100857 HInstruction* j_plus_1 = new (GetAllocator()) HAdd(DataType::Type::kInt32, phi_j, constant_1);
858 null_check = new (GetAllocator()) HNullCheck(parameter, 0);
859 array_length = new (GetAllocator()) HArrayLength(null_check, 0);
860 HBoundsCheck* bounds_check2 = new (GetAllocator()) HBoundsCheck(j_plus_1, array_length, 0);
861 HArrayGet* array_get_j_plus_1 = new (GetAllocator())
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100862 HArrayGet(null_check, bounds_check2, DataType::Type::kInt32, 0);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100863 cmp = new (GetAllocator()) HGreaterThanOrEqual(array_get_j, array_get_j_plus_1);
864 if_inst = new (GetAllocator()) HIf(cmp);
Mingyao Yangf384f882014-10-22 16:08:18 -0700865 inner_body_compare->AddInstruction(j_plus_1);
866 inner_body_compare->AddInstruction(null_check);
867 inner_body_compare->AddInstruction(array_length);
868 inner_body_compare->AddInstruction(bounds_check2);
869 inner_body_compare->AddInstruction(array_get_j_plus_1);
870 inner_body_compare->AddInstruction(cmp);
871 inner_body_compare->AddInstruction(if_inst);
872
Vladimir Markoca6fff82017-10-03 14:49:14 +0100873 HBasicBlock* inner_body_swap = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700874 graph_->AddBlock(inner_body_swap);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100875 j_plus_1 = new (GetAllocator()) HAdd(DataType::Type::kInt32, phi_j, constant_1);
Mingyao Yangf384f882014-10-22 16:08:18 -0700876 // temp = array[j+1]
Vladimir Markoca6fff82017-10-03 14:49:14 +0100877 null_check = new (GetAllocator()) HNullCheck(parameter, 0);
878 array_length = new (GetAllocator()) HArrayLength(null_check, 0);
879 HInstruction* bounds_check3 = new (GetAllocator()) HBoundsCheck(j_plus_1, array_length, 0);
880 array_get_j_plus_1 = new (GetAllocator())
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100881 HArrayGet(null_check, bounds_check3, DataType::Type::kInt32, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700882 inner_body_swap->AddInstruction(j_plus_1);
883 inner_body_swap->AddInstruction(null_check);
884 inner_body_swap->AddInstruction(array_length);
885 inner_body_swap->AddInstruction(bounds_check3);
886 inner_body_swap->AddInstruction(array_get_j_plus_1);
887 // array[j+1] = array[j]
Vladimir Markoca6fff82017-10-03 14:49:14 +0100888 null_check = new (GetAllocator()) HNullCheck(parameter, 0);
889 array_length = new (GetAllocator()) HArrayLength(null_check, 0);
890 HInstruction* bounds_check4 = new (GetAllocator()) HBoundsCheck(phi_j, array_length, 0);
891 array_get_j = new (GetAllocator())
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100892 HArrayGet(null_check, bounds_check4, DataType::Type::kInt32, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700893 inner_body_swap->AddInstruction(null_check);
894 inner_body_swap->AddInstruction(array_length);
895 inner_body_swap->AddInstruction(bounds_check4);
896 inner_body_swap->AddInstruction(array_get_j);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100897 null_check = new (GetAllocator()) HNullCheck(parameter, 0);
898 array_length = new (GetAllocator()) HArrayLength(null_check, 0);
899 HInstruction* bounds_check5 = new (GetAllocator()) HBoundsCheck(j_plus_1, array_length, 0);
900 HArraySet* array_set_j_plus_1 = new (GetAllocator())
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100901 HArraySet(null_check, bounds_check5, array_get_j, DataType::Type::kInt32, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700902 inner_body_swap->AddInstruction(null_check);
903 inner_body_swap->AddInstruction(array_length);
904 inner_body_swap->AddInstruction(bounds_check5);
905 inner_body_swap->AddInstruction(array_set_j_plus_1);
906 // array[j] = temp
Vladimir Markoca6fff82017-10-03 14:49:14 +0100907 null_check = new (GetAllocator()) HNullCheck(parameter, 0);
908 array_length = new (GetAllocator()) HArrayLength(null_check, 0);
909 HInstruction* bounds_check6 = new (GetAllocator()) HBoundsCheck(phi_j, array_length, 0);
910 HArraySet* array_set_j = new (GetAllocator())
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100911 HArraySet(null_check, bounds_check6, array_get_j_plus_1, DataType::Type::kInt32, 0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700912 inner_body_swap->AddInstruction(null_check);
913 inner_body_swap->AddInstruction(array_length);
914 inner_body_swap->AddInstruction(bounds_check6);
915 inner_body_swap->AddInstruction(array_set_j);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100916 inner_body_swap->AddInstruction(new (GetAllocator()) HGoto());
Mingyao Yangf384f882014-10-22 16:08:18 -0700917
Vladimir Markoca6fff82017-10-03 14:49:14 +0100918 HBasicBlock* inner_body_add = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700919 graph_->AddBlock(inner_body_add);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100920 add = new (GetAllocator()) HAdd(DataType::Type::kInt32, phi_j, constant_1);
Mingyao Yangf384f882014-10-22 16:08:18 -0700921 inner_body_add->AddInstruction(add);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100922 inner_body_add->AddInstruction(new (GetAllocator()) HGoto());
Mingyao Yangf384f882014-10-22 16:08:18 -0700923 phi_j->AddInput(add);
924
Vladimir Markoca6fff82017-10-03 14:49:14 +0100925 HBasicBlock* outer_body_add = new (GetAllocator()) HBasicBlock(graph_);
Aart Bik22af3be2015-09-10 12:50:58 -0700926 graph_->AddBlock(outer_body_add);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100927 add = new (GetAllocator()) HAdd(DataType::Type::kInt32, phi_i, constant_1);
Mingyao Yangf384f882014-10-22 16:08:18 -0700928 outer_body_add->AddInstruction(add);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100929 outer_body_add->AddInstruction(new (GetAllocator()) HGoto());
Mingyao Yangf384f882014-10-22 16:08:18 -0700930 phi_i->AddInput(add);
931
932 block->AddSuccessor(outer_header);
933 outer_header->AddSuccessor(exit);
934 outer_header->AddSuccessor(inner_header);
935 inner_header->AddSuccessor(outer_body_add);
936 inner_header->AddSuccessor(inner_body_compare);
937 inner_body_compare->AddSuccessor(inner_body_add);
938 inner_body_compare->AddSuccessor(inner_body_swap);
939 inner_body_swap->AddSuccessor(inner_body_add);
940 inner_body_add->AddSuccessor(inner_header);
941 outer_body_add->AddSuccessor(outer_header);
942
Aart Bik22af3be2015-09-10 12:50:58 -0700943 RunBCE(); // gvn removes same bounds check already
Mingyao Yangf384f882014-10-22 16:08:18 -0700944
Mingyao Yangf384f882014-10-22 16:08:18 -0700945 ASSERT_TRUE(IsRemoved(bounds_check1));
946 ASSERT_TRUE(IsRemoved(bounds_check2));
947 ASSERT_TRUE(IsRemoved(bounds_check3));
948 ASSERT_TRUE(IsRemoved(bounds_check4));
949 ASSERT_TRUE(IsRemoved(bounds_check5));
950 ASSERT_TRUE(IsRemoved(bounds_check6));
951}
952
xueliang.zhonga22cae72017-06-26 17:49:48 +0100953// int[] array = new int[10];
954// for (int i=0; i<200; i++) {
955// array[i%10] = 10; // Can eliminate
956// array[i%1] = 10; // Can eliminate
957// array[i%200] = 10; // Cannot eliminate
958// array[i%-10] = 10; // Can eliminate
959// array[i%array.length] = 10; // Can eliminate
960// array[param_i%10] = 10; // Can't eliminate, when param_i < 0
961// }
962TEST_F(BoundsCheckEliminationTest, ModArrayBoundsElimination) {
Vladimir Markoca6fff82017-10-03 14:49:14 +0100963 HBasicBlock* entry = new (GetAllocator()) HBasicBlock(graph_);
xueliang.zhonga22cae72017-06-26 17:49:48 +0100964 graph_->AddBlock(entry);
965 graph_->SetEntryBlock(entry);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100966 HInstruction* param_i = new (GetAllocator())
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100967 HParameterValue(graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32);
xueliang.zhonga22cae72017-06-26 17:49:48 +0100968 entry->AddInstruction(param_i);
969
970 HInstruction* constant_0 = graph_->GetIntConstant(0);
971 HInstruction* constant_1 = graph_->GetIntConstant(1);
972 HInstruction* constant_10 = graph_->GetIntConstant(10);
973 HInstruction* constant_200 = graph_->GetIntConstant(200);
974 HInstruction* constant_minus_10 = graph_->GetIntConstant(-10);
975
Vladimir Markoca6fff82017-10-03 14:49:14 +0100976 HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph_);
xueliang.zhonga22cae72017-06-26 17:49:48 +0100977 graph_->AddBlock(block);
978 entry->AddSuccessor(block);
979 // We pass a bogus constant for the class to avoid mocking one.
Vladimir Markoca6fff82017-10-03 14:49:14 +0100980 HInstruction* new_array = new (GetAllocator()) HNewArray(constant_10, constant_10, 0);
xueliang.zhonga22cae72017-06-26 17:49:48 +0100981 block->AddInstruction(new_array);
Vladimir Markoca6fff82017-10-03 14:49:14 +0100982 block->AddInstruction(new (GetAllocator()) HGoto());
xueliang.zhonga22cae72017-06-26 17:49:48 +0100983
Vladimir Markoca6fff82017-10-03 14:49:14 +0100984 HBasicBlock* loop_header = new (GetAllocator()) HBasicBlock(graph_);
985 HBasicBlock* loop_body = new (GetAllocator()) HBasicBlock(graph_);
986 HBasicBlock* exit = new (GetAllocator()) HBasicBlock(graph_);
xueliang.zhonga22cae72017-06-26 17:49:48 +0100987
988 graph_->AddBlock(loop_header);
989 graph_->AddBlock(loop_body);
990 graph_->AddBlock(exit);
991 block->AddSuccessor(loop_header);
992 loop_header->AddSuccessor(exit); // true successor
993 loop_header->AddSuccessor(loop_body); // false successor
994 loop_body->AddSuccessor(loop_header);
995
Vladimir Markoca6fff82017-10-03 14:49:14 +0100996 HPhi* phi = new (GetAllocator()) HPhi(GetAllocator(), 0, 0, DataType::Type::kInt32);
997 HInstruction* cmp = new (GetAllocator()) HGreaterThanOrEqual(phi, constant_200);
998 HInstruction* if_inst = new (GetAllocator()) HIf(cmp);
xueliang.zhonga22cae72017-06-26 17:49:48 +0100999 loop_header->AddPhi(phi);
1000 loop_header->AddInstruction(cmp);
1001 loop_header->AddInstruction(if_inst);
1002 phi->AddInput(constant_0);
1003
1004 //////////////////////////////////////////////////////////////////////////////////
1005 // LOOP BODY:
1006 // array[i % 10] = 10;
Vladimir Markoca6fff82017-10-03 14:49:14 +01001007 HRem* i_mod_10 = new (GetAllocator()) HRem(DataType::Type::kInt32, phi, constant_10, 0);
1008 HBoundsCheck* bounds_check_i_mod_10 = new (GetAllocator()) HBoundsCheck(i_mod_10, constant_10, 0);
1009 HInstruction* array_set = new (GetAllocator()) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001010 new_array, bounds_check_i_mod_10, constant_10, DataType::Type::kInt32, 0);
xueliang.zhonga22cae72017-06-26 17:49:48 +01001011 loop_body->AddInstruction(i_mod_10);
1012 loop_body->AddInstruction(bounds_check_i_mod_10);
1013 loop_body->AddInstruction(array_set);
1014
1015 // array[i % 1] = 10;
Vladimir Markoca6fff82017-10-03 14:49:14 +01001016 HRem* i_mod_1 = new (GetAllocator()) HRem(DataType::Type::kInt32, phi, constant_1, 0);
1017 HBoundsCheck* bounds_check_i_mod_1 = new (GetAllocator()) HBoundsCheck(i_mod_1, constant_10, 0);
1018 array_set = new (GetAllocator()) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001019 new_array, bounds_check_i_mod_1, constant_10, DataType::Type::kInt32, 0);
xueliang.zhonga22cae72017-06-26 17:49:48 +01001020 loop_body->AddInstruction(i_mod_1);
1021 loop_body->AddInstruction(bounds_check_i_mod_1);
1022 loop_body->AddInstruction(array_set);
1023
1024 // array[i % 200] = 10;
Vladimir Markoca6fff82017-10-03 14:49:14 +01001025 HRem* i_mod_200 = new (GetAllocator()) HRem(DataType::Type::kInt32, phi, constant_1, 0);
1026 HBoundsCheck* bounds_check_i_mod_200 = new (GetAllocator()) HBoundsCheck(
1027 i_mod_200, constant_10, 0);
1028 array_set = new (GetAllocator()) 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 Markoca6fff82017-10-03 14:49:14 +01001035 HRem* i_mod_minus_10 = new (GetAllocator()) HRem(
1036 DataType::Type::kInt32, phi, constant_minus_10, 0);
1037 HBoundsCheck* bounds_check_i_mod_minus_10 = new (GetAllocator()) HBoundsCheck(
xueliang.zhonga22cae72017-06-26 17:49:48 +01001038 i_mod_minus_10, constant_10, 0);
Vladimir Markoca6fff82017-10-03 14:49:14 +01001039 array_set = new (GetAllocator()) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001040 new_array, bounds_check_i_mod_minus_10, constant_10, DataType::Type::kInt32, 0);
xueliang.zhonga22cae72017-06-26 17:49:48 +01001041 loop_body->AddInstruction(i_mod_minus_10);
1042 loop_body->AddInstruction(bounds_check_i_mod_minus_10);
1043 loop_body->AddInstruction(array_set);
1044
1045 // array[i%array.length] = 10;
Vladimir Markoca6fff82017-10-03 14:49:14 +01001046 HNullCheck* null_check = new (GetAllocator()) HNullCheck(new_array, 0);
1047 HArrayLength* array_length = new (GetAllocator()) HArrayLength(null_check, 0);
1048 HRem* i_mod_array_length = new (GetAllocator()) HRem(
1049 DataType::Type::kInt32, phi, array_length, 0);
1050 HBoundsCheck* bounds_check_i_mod_array_len = new (GetAllocator()) HBoundsCheck(
xueliang.zhonga22cae72017-06-26 17:49:48 +01001051 i_mod_array_length, array_length, 0);
Vladimir Markoca6fff82017-10-03 14:49:14 +01001052 array_set = new (GetAllocator()) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001053 null_check, bounds_check_i_mod_array_len, constant_10, DataType::Type::kInt32, 0);
xueliang.zhonga22cae72017-06-26 17:49:48 +01001054 loop_body->AddInstruction(null_check);
1055 loop_body->AddInstruction(array_length);
1056 loop_body->AddInstruction(i_mod_array_length);
1057 loop_body->AddInstruction(bounds_check_i_mod_array_len);
1058 loop_body->AddInstruction(array_set);
1059
1060 // array[param_i % 10] = 10;
Vladimir Markoca6fff82017-10-03 14:49:14 +01001061 HRem* param_i_mod_10 = new (GetAllocator()) HRem(DataType::Type::kInt32, param_i, constant_10, 0);
1062 HBoundsCheck* bounds_check_param_i_mod_10 = new (GetAllocator()) HBoundsCheck(
xueliang.zhonga22cae72017-06-26 17:49:48 +01001063 param_i_mod_10, constant_10, 0);
Vladimir Markoca6fff82017-10-03 14:49:14 +01001064 array_set = new (GetAllocator()) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001065 new_array, bounds_check_param_i_mod_10, constant_10, DataType::Type::kInt32, 0);
xueliang.zhonga22cae72017-06-26 17:49:48 +01001066 loop_body->AddInstruction(param_i_mod_10);
1067 loop_body->AddInstruction(bounds_check_param_i_mod_10);
1068 loop_body->AddInstruction(array_set);
1069
1070 // array[param_i%array.length] = 10;
Vladimir Markoca6fff82017-10-03 14:49:14 +01001071 null_check = new (GetAllocator()) HNullCheck(new_array, 0);
1072 array_length = new (GetAllocator()) HArrayLength(null_check, 0);
1073 HRem* param_i_mod_array_length = new (GetAllocator()) HRem(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001074 DataType::Type::kInt32, param_i, array_length, 0);
Vladimir Markoca6fff82017-10-03 14:49:14 +01001075 HBoundsCheck* bounds_check_param_i_mod_array_len = new (GetAllocator()) HBoundsCheck(
xueliang.zhonga22cae72017-06-26 17:49:48 +01001076 param_i_mod_array_length, array_length, 0);
Vladimir Markoca6fff82017-10-03 14:49:14 +01001077 array_set = new (GetAllocator()) HArraySet(
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001078 null_check, bounds_check_param_i_mod_array_len, constant_10, DataType::Type::kInt32, 0);
xueliang.zhonga22cae72017-06-26 17:49:48 +01001079 loop_body->AddInstruction(null_check);
1080 loop_body->AddInstruction(array_length);
1081 loop_body->AddInstruction(param_i_mod_array_length);
1082 loop_body->AddInstruction(bounds_check_param_i_mod_array_len);
1083 loop_body->AddInstruction(array_set);
1084
1085 // i++;
Vladimir Markoca6fff82017-10-03 14:49:14 +01001086 HInstruction* add = new (GetAllocator()) HAdd(DataType::Type::kInt32, phi, constant_1);
xueliang.zhonga22cae72017-06-26 17:49:48 +01001087 loop_body->AddInstruction(add);
Vladimir Markoca6fff82017-10-03 14:49:14 +01001088 loop_body->AddInstruction(new (GetAllocator()) HGoto());
xueliang.zhonga22cae72017-06-26 17:49:48 +01001089 phi->AddInput(add);
1090 //////////////////////////////////////////////////////////////////////////////////
1091
Vladimir Markoca6fff82017-10-03 14:49:14 +01001092 exit->AddInstruction(new (GetAllocator()) HExit());
xueliang.zhonga22cae72017-06-26 17:49:48 +01001093
1094 RunBCE();
1095
1096 ASSERT_TRUE(IsRemoved(bounds_check_i_mod_10));
1097 ASSERT_TRUE(IsRemoved(bounds_check_i_mod_1));
1098 ASSERT_TRUE(IsRemoved(bounds_check_i_mod_200));
1099 ASSERT_TRUE(IsRemoved(bounds_check_i_mod_minus_10));
1100 ASSERT_TRUE(IsRemoved(bounds_check_i_mod_array_len));
1101 ASSERT_FALSE(IsRemoved(bounds_check_param_i_mod_10));
1102}
1103
Mingyao Yangf384f882014-10-22 16:08:18 -07001104} // namespace art