blob: 4701bddd48aa08f30a4bb5a802cd205970872508 [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
Mathieu Chartierb666f482015-02-18 14:33:14 -080017#include "base/arena_allocator.h"
Mingyao Yangf384f882014-10-22 16:08:18 -070018#include "bounds_check_elimination.h"
19#include "builder.h"
20#include "gvn.h"
Mingyao Yang0304e182015-01-30 16:41:29 -080021#include "instruction_simplifier.h"
Mingyao Yangf384f882014-10-22 16:08:18 -070022#include "nodes.h"
23#include "optimizing_unit_test.h"
Nicolas Geoffray827eedb2015-01-26 15:18:36 +000024#include "side_effects_analysis.h"
Mingyao Yangf384f882014-10-22 16:08:18 -070025
26#include "gtest/gtest.h"
27
28namespace art {
29
Mingyao Yang0304e182015-01-30 16:41:29 -080030static void RunSimplifierAndGvn(HGraph* graph) {
31 InstructionSimplifier simplify(graph);
32 simplify.Run();
Nicolas Geoffraye6f17152015-01-26 15:13:47 +000033 SideEffectsAnalysis side_effects(graph);
34 side_effects.Run();
Nicolas Geoffray827eedb2015-01-26 15:18:36 +000035 GVNOptimization(graph, side_effects).Run();
Nicolas Geoffraye6f17152015-01-26 15:13:47 +000036}
37
Mingyao Yangf384f882014-10-22 16:08:18 -070038// if (i < 0) { array[i] = 1; // Can't eliminate. }
39// else if (i >= array.length) { array[i] = 1; // Can't eliminate. }
40// else { array[i] = 1; // Can eliminate. }
41TEST(BoundsCheckEliminationTest, NarrowingRangeArrayBoundsElimination) {
42 ArenaPool pool;
43 ArenaAllocator allocator(&pool);
44
Nicolas Geoffray0a23d742015-05-07 11:57:35 +010045 HGraph* graph = CreateGraph(&allocator);
Mark Mendell1152c922015-04-24 17:06:35 -040046 graph->SetHasBoundsChecks(true);
Mingyao Yangf384f882014-10-22 16:08:18 -070047
48 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
49 graph->AddBlock(entry);
50 graph->SetEntryBlock(entry);
51 HInstruction* parameter1 = new (&allocator)
52 HParameterValue(0, Primitive::kPrimNot); // array
53 HInstruction* parameter2 = new (&allocator)
54 HParameterValue(0, Primitive::kPrimInt); // i
Mingyao Yangf384f882014-10-22 16:08:18 -070055 entry->AddInstruction(parameter1);
56 entry->AddInstruction(parameter2);
David Brazdil8d5b8b22015-03-24 10:51:52 +000057
58 HInstruction* constant_1 = graph->GetIntConstant(1);
59 HInstruction* constant_0 = graph->GetIntConstant(0);
Mingyao Yangf384f882014-10-22 16:08:18 -070060
61 HBasicBlock* block1 = new (&allocator) HBasicBlock(graph);
62 graph->AddBlock(block1);
63 HInstruction* cmp = new (&allocator) HGreaterThanOrEqual(parameter2, constant_0);
64 HIf* if_inst = new (&allocator) HIf(cmp);
65 block1->AddInstruction(cmp);
66 block1->AddInstruction(if_inst);
67 entry->AddSuccessor(block1);
68
69 HBasicBlock* block2 = new (&allocator) HBasicBlock(graph);
70 graph->AddBlock(block2);
71 HNullCheck* null_check = new (&allocator) HNullCheck(parameter1, 0);
72 HArrayLength* array_length = new (&allocator) HArrayLength(null_check);
73 HBoundsCheck* bounds_check2 = new (&allocator)
74 HBoundsCheck(parameter2, array_length, 0);
75 HArraySet* array_set = new (&allocator) HArraySet(
76 null_check, bounds_check2, constant_1, Primitive::kPrimInt, 0);
77 block2->AddInstruction(null_check);
78 block2->AddInstruction(array_length);
79 block2->AddInstruction(bounds_check2);
80 block2->AddInstruction(array_set);
81
82 HBasicBlock* block3 = new (&allocator) HBasicBlock(graph);
83 graph->AddBlock(block3);
84 null_check = new (&allocator) HNullCheck(parameter1, 0);
85 array_length = new (&allocator) HArrayLength(null_check);
86 cmp = new (&allocator) HLessThan(parameter2, array_length);
87 if_inst = new (&allocator) HIf(cmp);
88 block3->AddInstruction(null_check);
89 block3->AddInstruction(array_length);
90 block3->AddInstruction(cmp);
91 block3->AddInstruction(if_inst);
92
93 HBasicBlock* block4 = new (&allocator) HBasicBlock(graph);
94 graph->AddBlock(block4);
95 null_check = new (&allocator) HNullCheck(parameter1, 0);
96 array_length = new (&allocator) HArrayLength(null_check);
97 HBoundsCheck* bounds_check4 = new (&allocator)
98 HBoundsCheck(parameter2, array_length, 0);
99 array_set = new (&allocator) HArraySet(
100 null_check, bounds_check4, constant_1, Primitive::kPrimInt, 0);
101 block4->AddInstruction(null_check);
102 block4->AddInstruction(array_length);
103 block4->AddInstruction(bounds_check4);
104 block4->AddInstruction(array_set);
105
106 HBasicBlock* block5 = new (&allocator) HBasicBlock(graph);
107 graph->AddBlock(block5);
108 null_check = new (&allocator) HNullCheck(parameter1, 0);
109 array_length = new (&allocator) HArrayLength(null_check);
110 HBoundsCheck* bounds_check5 = new (&allocator)
111 HBoundsCheck(parameter2, array_length, 0);
112 array_set = new (&allocator) HArraySet(
113 null_check, bounds_check5, constant_1, Primitive::kPrimInt, 0);
114 block5->AddInstruction(null_check);
115 block5->AddInstruction(array_length);
116 block5->AddInstruction(bounds_check5);
117 block5->AddInstruction(array_set);
118
119 HBasicBlock* exit = new (&allocator) HBasicBlock(graph);
120 graph->AddBlock(exit);
121 block2->AddSuccessor(exit);
122 block4->AddSuccessor(exit);
123 block5->AddSuccessor(exit);
124 exit->AddInstruction(new (&allocator) HExit());
125
126 block1->AddSuccessor(block3); // True successor
127 block1->AddSuccessor(block2); // False successor
128
129 block3->AddSuccessor(block5); // True successor
130 block3->AddSuccessor(block4); // False successor
131
132 graph->BuildDominatorTree();
Mingyao Yang0304e182015-01-30 16:41:29 -0800133 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700134 BoundsCheckElimination bounds_check_elimination(graph);
135 bounds_check_elimination.Run();
136 ASSERT_FALSE(IsRemoved(bounds_check2));
137 ASSERT_FALSE(IsRemoved(bounds_check4));
138 ASSERT_TRUE(IsRemoved(bounds_check5));
139}
140
141// if (i > 0) {
142// // Positive number plus MAX_INT will overflow and be negative.
143// int j = i + Integer.MAX_VALUE;
144// if (j < array.length) array[j] = 1; // Can't eliminate.
145// }
146TEST(BoundsCheckEliminationTest, OverflowArrayBoundsElimination) {
147 ArenaPool pool;
148 ArenaAllocator allocator(&pool);
149
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100150 HGraph* graph = CreateGraph(&allocator);
Mark Mendell1152c922015-04-24 17:06:35 -0400151 graph->SetHasBoundsChecks(true);
Mingyao Yangf384f882014-10-22 16:08:18 -0700152
153 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
154 graph->AddBlock(entry);
155 graph->SetEntryBlock(entry);
156 HInstruction* parameter1 = new (&allocator)
157 HParameterValue(0, Primitive::kPrimNot); // array
158 HInstruction* parameter2 = new (&allocator)
159 HParameterValue(0, Primitive::kPrimInt); // i
Mingyao Yangf384f882014-10-22 16:08:18 -0700160 entry->AddInstruction(parameter1);
161 entry->AddInstruction(parameter2);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000162
163 HInstruction* constant_1 = graph->GetIntConstant(1);
164 HInstruction* constant_0 = graph->GetIntConstant(0);
165 HInstruction* constant_max_int = graph->GetIntConstant(INT_MAX);
Mingyao Yangf384f882014-10-22 16:08:18 -0700166
167 HBasicBlock* block1 = new (&allocator) HBasicBlock(graph);
168 graph->AddBlock(block1);
169 HInstruction* cmp = new (&allocator) HLessThanOrEqual(parameter2, constant_0);
170 HIf* if_inst = new (&allocator) HIf(cmp);
171 block1->AddInstruction(cmp);
172 block1->AddInstruction(if_inst);
173 entry->AddSuccessor(block1);
174
175 HBasicBlock* block2 = new (&allocator) HBasicBlock(graph);
176 graph->AddBlock(block2);
177 HInstruction* add = new (&allocator) HAdd(Primitive::kPrimInt, parameter2, constant_max_int);
178 HNullCheck* null_check = new (&allocator) HNullCheck(parameter1, 0);
179 HArrayLength* array_length = new (&allocator) HArrayLength(null_check);
180 HInstruction* cmp2 = new (&allocator) HGreaterThanOrEqual(add, array_length);
181 if_inst = new (&allocator) HIf(cmp2);
182 block2->AddInstruction(add);
183 block2->AddInstruction(null_check);
184 block2->AddInstruction(array_length);
185 block2->AddInstruction(cmp2);
186 block2->AddInstruction(if_inst);
187
188 HBasicBlock* block3 = new (&allocator) HBasicBlock(graph);
189 graph->AddBlock(block3);
190 HBoundsCheck* bounds_check = new (&allocator)
191 HBoundsCheck(add, array_length, 0);
192 HArraySet* array_set = new (&allocator) HArraySet(
193 null_check, bounds_check, constant_1, Primitive::kPrimInt, 0);
194 block3->AddInstruction(bounds_check);
195 block3->AddInstruction(array_set);
196
197 HBasicBlock* exit = new (&allocator) HBasicBlock(graph);
198 graph->AddBlock(exit);
199 exit->AddInstruction(new (&allocator) HExit());
Andreas Gampe0418b5b2014-12-04 17:24:50 -0800200 block1->AddSuccessor(exit); // true successor
201 block1->AddSuccessor(block2); // false successor
202 block2->AddSuccessor(exit); // true successor
203 block2->AddSuccessor(block3); // false successor
Mingyao Yangf384f882014-10-22 16:08:18 -0700204 block3->AddSuccessor(exit);
205
206 graph->BuildDominatorTree();
Mingyao Yang0304e182015-01-30 16:41:29 -0800207 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700208 BoundsCheckElimination bounds_check_elimination(graph);
209 bounds_check_elimination.Run();
210 ASSERT_FALSE(IsRemoved(bounds_check));
211}
212
213// if (i < array.length) {
214// int j = i - Integer.MAX_VALUE;
215// j = j - Integer.MAX_VALUE; // j is (i+2) after substracting MAX_INT twice
216// if (j > 0) array[j] = 1; // Can't eliminate.
217// }
218TEST(BoundsCheckEliminationTest, UnderflowArrayBoundsElimination) {
219 ArenaPool pool;
220 ArenaAllocator allocator(&pool);
221
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100222 HGraph* graph = CreateGraph(&allocator);
Mark Mendell1152c922015-04-24 17:06:35 -0400223 graph->SetHasBoundsChecks(true);
Mingyao Yangf384f882014-10-22 16:08:18 -0700224
225 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
226 graph->AddBlock(entry);
227 graph->SetEntryBlock(entry);
228 HInstruction* parameter1 = new (&allocator)
229 HParameterValue(0, Primitive::kPrimNot); // array
230 HInstruction* parameter2 = new (&allocator)
231 HParameterValue(0, Primitive::kPrimInt); // i
Mingyao Yangf384f882014-10-22 16:08:18 -0700232 entry->AddInstruction(parameter1);
233 entry->AddInstruction(parameter2);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000234
235 HInstruction* constant_1 = graph->GetIntConstant(1);
236 HInstruction* constant_0 = graph->GetIntConstant(0);
237 HInstruction* constant_max_int = graph->GetIntConstant(INT_MAX);
Mingyao Yangf384f882014-10-22 16:08:18 -0700238
239 HBasicBlock* block1 = new (&allocator) HBasicBlock(graph);
240 graph->AddBlock(block1);
241 HNullCheck* null_check = new (&allocator) HNullCheck(parameter1, 0);
242 HArrayLength* array_length = new (&allocator) HArrayLength(null_check);
243 HInstruction* cmp = new (&allocator) HGreaterThanOrEqual(parameter2, array_length);
244 HIf* if_inst = new (&allocator) HIf(cmp);
245 block1->AddInstruction(null_check);
246 block1->AddInstruction(array_length);
247 block1->AddInstruction(cmp);
248 block1->AddInstruction(if_inst);
249 entry->AddSuccessor(block1);
250
251 HBasicBlock* block2 = new (&allocator) HBasicBlock(graph);
252 graph->AddBlock(block2);
253 HInstruction* sub1 = new (&allocator) HSub(Primitive::kPrimInt, parameter2, constant_max_int);
254 HInstruction* sub2 = new (&allocator) HSub(Primitive::kPrimInt, sub1, constant_max_int);
255 HInstruction* cmp2 = new (&allocator) HLessThanOrEqual(sub2, constant_0);
256 if_inst = new (&allocator) HIf(cmp2);
257 block2->AddInstruction(sub1);
258 block2->AddInstruction(sub2);
259 block2->AddInstruction(cmp2);
260 block2->AddInstruction(if_inst);
261
262 HBasicBlock* block3 = new (&allocator) HBasicBlock(graph);
263 graph->AddBlock(block3);
264 HBoundsCheck* bounds_check = new (&allocator)
265 HBoundsCheck(sub2, array_length, 0);
266 HArraySet* array_set = new (&allocator) HArraySet(
267 null_check, bounds_check, constant_1, Primitive::kPrimInt, 0);
268 block3->AddInstruction(bounds_check);
269 block3->AddInstruction(array_set);
270
271 HBasicBlock* exit = new (&allocator) HBasicBlock(graph);
272 graph->AddBlock(exit);
273 exit->AddInstruction(new (&allocator) HExit());
Andreas Gampe0418b5b2014-12-04 17:24:50 -0800274 block1->AddSuccessor(exit); // true successor
275 block1->AddSuccessor(block2); // false successor
276 block2->AddSuccessor(exit); // true successor
277 block2->AddSuccessor(block3); // false successor
Mingyao Yangf384f882014-10-22 16:08:18 -0700278 block3->AddSuccessor(exit);
279
280 graph->BuildDominatorTree();
Mingyao Yang0304e182015-01-30 16:41:29 -0800281 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700282 BoundsCheckElimination bounds_check_elimination(graph);
283 bounds_check_elimination.Run();
284 ASSERT_FALSE(IsRemoved(bounds_check));
285}
286
Andreas Gampe0ba62732015-03-24 02:39:46 +0000287// array[6] = 1; // Can't eliminate.
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700288// array[5] = 1; // Can eliminate.
289// array[4] = 1; // Can eliminate.
Mingyao Yangf384f882014-10-22 16:08:18 -0700290TEST(BoundsCheckEliminationTest, ConstantArrayBoundsElimination) {
291 ArenaPool pool;
292 ArenaAllocator allocator(&pool);
293
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100294 HGraph* graph = CreateGraph(&allocator);
Mark Mendell1152c922015-04-24 17:06:35 -0400295 graph->SetHasBoundsChecks(true);
Mingyao Yangf384f882014-10-22 16:08:18 -0700296
297 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
298 graph->AddBlock(entry);
299 graph->SetEntryBlock(entry);
300 HInstruction* parameter = new (&allocator) HParameterValue(0, Primitive::kPrimNot);
Mingyao Yangf384f882014-10-22 16:08:18 -0700301 entry->AddInstruction(parameter);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000302
303 HInstruction* constant_5 = graph->GetIntConstant(5);
304 HInstruction* constant_4 = graph->GetIntConstant(4);
305 HInstruction* constant_6 = graph->GetIntConstant(6);
306 HInstruction* constant_1 = graph->GetIntConstant(1);
Mingyao Yangf384f882014-10-22 16:08:18 -0700307
308 HBasicBlock* block = new (&allocator) HBasicBlock(graph);
309 graph->AddBlock(block);
310 entry->AddSuccessor(block);
311
312 HNullCheck* null_check = new (&allocator) HNullCheck(parameter, 0);
313 HArrayLength* array_length = new (&allocator) HArrayLength(null_check);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700314 HBoundsCheck* bounds_check6 = new (&allocator)
315 HBoundsCheck(constant_6, array_length, 0);
316 HInstruction* array_set = new (&allocator) HArraySet(
317 null_check, bounds_check6, constant_1, Primitive::kPrimInt, 0);
318 block->AddInstruction(null_check);
319 block->AddInstruction(array_length);
320 block->AddInstruction(bounds_check6);
321 block->AddInstruction(array_set);
322
323 null_check = new (&allocator) HNullCheck(parameter, 0);
324 array_length = new (&allocator) HArrayLength(null_check);
Mingyao Yangf384f882014-10-22 16:08:18 -0700325 HBoundsCheck* bounds_check5 = new (&allocator)
326 HBoundsCheck(constant_5, array_length, 0);
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700327 array_set = new (&allocator) HArraySet(
Mingyao Yangf384f882014-10-22 16:08:18 -0700328 null_check, bounds_check5, constant_1, Primitive::kPrimInt, 0);
329 block->AddInstruction(null_check);
330 block->AddInstruction(array_length);
331 block->AddInstruction(bounds_check5);
332 block->AddInstruction(array_set);
333
334 null_check = new (&allocator) HNullCheck(parameter, 0);
335 array_length = new (&allocator) HArrayLength(null_check);
336 HBoundsCheck* bounds_check4 = new (&allocator)
337 HBoundsCheck(constant_4, array_length, 0);
338 array_set = new (&allocator) HArraySet(
339 null_check, bounds_check4, constant_1, Primitive::kPrimInt, 0);
340 block->AddInstruction(null_check);
341 block->AddInstruction(array_length);
342 block->AddInstruction(bounds_check4);
343 block->AddInstruction(array_set);
344
Mingyao Yangf384f882014-10-22 16:08:18 -0700345 block->AddInstruction(new (&allocator) HGoto());
346
347 HBasicBlock* exit = new (&allocator) HBasicBlock(graph);
348 graph->AddBlock(exit);
349 block->AddSuccessor(exit);
350 exit->AddInstruction(new (&allocator) HExit());
351
352 graph->BuildDominatorTree();
Mingyao Yang0304e182015-01-30 16:41:29 -0800353 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700354 BoundsCheckElimination bounds_check_elimination(graph);
355 bounds_check_elimination.Run();
Andreas Gampe0ba62732015-03-24 02:39:46 +0000356 ASSERT_FALSE(IsRemoved(bounds_check6));
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700357 ASSERT_TRUE(IsRemoved(bounds_check5));
358 ASSERT_TRUE(IsRemoved(bounds_check4));
Mingyao Yangf384f882014-10-22 16:08:18 -0700359}
360
361// for (int i=initial; i<array.length; i+=increment) { array[i] = 10; }
362static HGraph* BuildSSAGraph1(ArenaAllocator* allocator,
363 HInstruction** bounds_check,
364 int initial,
365 int increment,
366 IfCondition cond = kCondGE) {
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100367 HGraph* graph = CreateGraph(allocator);
Mark Mendell1152c922015-04-24 17:06:35 -0400368 graph->SetHasBoundsChecks(true);
Mingyao Yangf384f882014-10-22 16:08:18 -0700369
370 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
371 graph->AddBlock(entry);
372 graph->SetEntryBlock(entry);
373 HInstruction* parameter = new (allocator) HParameterValue(0, Primitive::kPrimNot);
Mingyao Yangf384f882014-10-22 16:08:18 -0700374 entry->AddInstruction(parameter);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000375
376 HInstruction* constant_initial = graph->GetIntConstant(initial);
377 HInstruction* constant_increment = graph->GetIntConstant(increment);
378 HInstruction* constant_10 = graph->GetIntConstant(10);
Mingyao Yangf384f882014-10-22 16:08:18 -0700379
380 HBasicBlock* block = new (allocator) HBasicBlock(graph);
381 graph->AddBlock(block);
382 entry->AddSuccessor(block);
383 block->AddInstruction(new (allocator) HGoto());
384
385 HBasicBlock* loop_header = new (allocator) HBasicBlock(graph);
386 HBasicBlock* loop_body = new (allocator) HBasicBlock(graph);
387 HBasicBlock* exit = new (allocator) HBasicBlock(graph);
388
389 graph->AddBlock(loop_header);
390 graph->AddBlock(loop_body);
391 graph->AddBlock(exit);
392 block->AddSuccessor(loop_header);
393 loop_header->AddSuccessor(exit); // true successor
394 loop_header->AddSuccessor(loop_body); // false successor
395 loop_body->AddSuccessor(loop_header);
396
397 HPhi* phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt);
Mingyao Yangf384f882014-10-22 16:08:18 -0700398 HInstruction* null_check = new (allocator) HNullCheck(parameter, 0);
399 HInstruction* array_length = new (allocator) HArrayLength(null_check);
400 HInstruction* cmp = nullptr;
401 if (cond == kCondGE) {
402 cmp = new (allocator) HGreaterThanOrEqual(phi, array_length);
403 } else {
404 DCHECK(cond == kCondGT);
405 cmp = new (allocator) HGreaterThan(phi, array_length);
406 }
407 HInstruction* if_inst = new (allocator) HIf(cmp);
408 loop_header->AddPhi(phi);
409 loop_header->AddInstruction(null_check);
410 loop_header->AddInstruction(array_length);
411 loop_header->AddInstruction(cmp);
412 loop_header->AddInstruction(if_inst);
David Brazdil1abb4192015-02-17 18:33:36 +0000413 phi->AddInput(constant_initial);
Mingyao Yangf384f882014-10-22 16:08:18 -0700414
415 null_check = new (allocator) HNullCheck(parameter, 0);
416 array_length = new (allocator) HArrayLength(null_check);
417 *bounds_check = new (allocator) HBoundsCheck(phi, array_length, 0);
418 HInstruction* array_set = new (allocator) HArraySet(
419 null_check, *bounds_check, constant_10, Primitive::kPrimInt, 0);
420
421 HInstruction* add = new (allocator) HAdd(Primitive::kPrimInt, phi, constant_increment);
422 loop_body->AddInstruction(null_check);
423 loop_body->AddInstruction(array_length);
424 loop_body->AddInstruction(*bounds_check);
425 loop_body->AddInstruction(array_set);
426 loop_body->AddInstruction(add);
427 loop_body->AddInstruction(new (allocator) HGoto());
428 phi->AddInput(add);
429
430 exit->AddInstruction(new (allocator) HExit());
431
432 return graph;
433}
434
435TEST(BoundsCheckEliminationTest, LoopArrayBoundsElimination1) {
436 ArenaPool pool;
437 ArenaAllocator allocator(&pool);
438
439 // for (int i=0; i<array.length; i++) { array[i] = 10; // Can eliminate with gvn. }
440 HInstruction* bounds_check = nullptr;
441 HGraph* graph = BuildSSAGraph1(&allocator, &bounds_check, 0, 1);
442 graph->BuildDominatorTree();
Mingyao Yang3584bce2015-05-19 16:01:59 -0700443 graph->AnalyzeNaturalLoops();
444 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700445 BoundsCheckElimination bounds_check_elimination(graph);
446 bounds_check_elimination.Run();
Mingyao Yangf384f882014-10-22 16:08:18 -0700447 ASSERT_TRUE(IsRemoved(bounds_check));
448
449 // for (int i=1; i<array.length; i++) { array[i] = 10; // Can eliminate. }
450 graph = BuildSSAGraph1(&allocator, &bounds_check, 1, 1);
451 graph->BuildDominatorTree();
Mingyao Yang3584bce2015-05-19 16:01:59 -0700452 graph->AnalyzeNaturalLoops();
Mingyao Yang0304e182015-01-30 16:41:29 -0800453 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700454 BoundsCheckElimination bounds_check_elimination_with_initial_1(graph);
455 bounds_check_elimination_with_initial_1.Run();
456 ASSERT_TRUE(IsRemoved(bounds_check));
457
458 // for (int i=-1; i<array.length; i++) { array[i] = 10; // Can't eliminate. }
459 graph = BuildSSAGraph1(&allocator, &bounds_check, -1, 1);
460 graph->BuildDominatorTree();
Mingyao Yang3584bce2015-05-19 16:01:59 -0700461 graph->AnalyzeNaturalLoops();
Mingyao Yang0304e182015-01-30 16:41:29 -0800462 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700463 BoundsCheckElimination bounds_check_elimination_with_initial_minus_1(graph);
464 bounds_check_elimination_with_initial_minus_1.Run();
465 ASSERT_FALSE(IsRemoved(bounds_check));
466
467 // for (int i=0; i<=array.length; i++) { array[i] = 10; // Can't eliminate. }
468 graph = BuildSSAGraph1(&allocator, &bounds_check, 0, 1, kCondGT);
469 graph->BuildDominatorTree();
Mingyao Yang3584bce2015-05-19 16:01:59 -0700470 graph->AnalyzeNaturalLoops();
Mingyao Yang0304e182015-01-30 16:41:29 -0800471 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700472 BoundsCheckElimination bounds_check_elimination_with_greater_than(graph);
473 bounds_check_elimination_with_greater_than.Run();
474 ASSERT_FALSE(IsRemoved(bounds_check));
475
476 // for (int i=0; i<array.length; i += 2) {
477 // array[i] = 10; // Can't eliminate due to overflow concern. }
478 graph = BuildSSAGraph1(&allocator, &bounds_check, 0, 2);
479 graph->BuildDominatorTree();
Mingyao Yang3584bce2015-05-19 16:01:59 -0700480 graph->AnalyzeNaturalLoops();
Mingyao Yang0304e182015-01-30 16:41:29 -0800481 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700482 BoundsCheckElimination bounds_check_elimination_with_increment_2(graph);
483 bounds_check_elimination_with_increment_2.Run();
484 ASSERT_FALSE(IsRemoved(bounds_check));
485
486 // for (int i=1; i<array.length; i += 2) { array[i] = 10; // Can eliminate. }
487 graph = BuildSSAGraph1(&allocator, &bounds_check, 1, 2);
488 graph->BuildDominatorTree();
Mingyao Yang3584bce2015-05-19 16:01:59 -0700489 graph->AnalyzeNaturalLoops();
Mingyao Yang0304e182015-01-30 16:41:29 -0800490 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700491 BoundsCheckElimination bounds_check_elimination_with_increment_2_from_1(graph);
492 bounds_check_elimination_with_increment_2_from_1.Run();
493 ASSERT_TRUE(IsRemoved(bounds_check));
494}
495
496// for (int i=array.length; i>0; i+=increment) { array[i-1] = 10; }
497static HGraph* BuildSSAGraph2(ArenaAllocator* allocator,
498 HInstruction** bounds_check,
499 int initial,
500 int increment = -1,
501 IfCondition cond = kCondLE) {
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100502 HGraph* graph = CreateGraph(allocator);
Mark Mendell1152c922015-04-24 17:06:35 -0400503 graph->SetHasBoundsChecks(true);
Mingyao Yangf384f882014-10-22 16:08:18 -0700504
505 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
506 graph->AddBlock(entry);
507 graph->SetEntryBlock(entry);
508 HInstruction* parameter = new (allocator) HParameterValue(0, Primitive::kPrimNot);
Mingyao Yangf384f882014-10-22 16:08:18 -0700509 entry->AddInstruction(parameter);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000510
511 HInstruction* constant_initial = graph->GetIntConstant(initial);
512 HInstruction* constant_increment = graph->GetIntConstant(increment);
513 HInstruction* constant_minus_1 = graph->GetIntConstant(-1);
514 HInstruction* constant_10 = graph->GetIntConstant(10);
Mingyao Yangf384f882014-10-22 16:08:18 -0700515
516 HBasicBlock* block = new (allocator) HBasicBlock(graph);
517 graph->AddBlock(block);
518 entry->AddSuccessor(block);
519 HInstruction* null_check = new (allocator) HNullCheck(parameter, 0);
520 HInstruction* array_length = new (allocator) HArrayLength(null_check);
521 block->AddInstruction(null_check);
522 block->AddInstruction(array_length);
523 block->AddInstruction(new (allocator) HGoto());
524
525 HBasicBlock* loop_header = new (allocator) HBasicBlock(graph);
526 HBasicBlock* loop_body = new (allocator) HBasicBlock(graph);
527 HBasicBlock* exit = new (allocator) HBasicBlock(graph);
528
529 graph->AddBlock(loop_header);
530 graph->AddBlock(loop_body);
531 graph->AddBlock(exit);
532 block->AddSuccessor(loop_header);
533 loop_header->AddSuccessor(exit); // true successor
534 loop_header->AddSuccessor(loop_body); // false successor
535 loop_body->AddSuccessor(loop_header);
536
537 HPhi* phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt);
Mingyao Yangf384f882014-10-22 16:08:18 -0700538 HInstruction* cmp = nullptr;
539 if (cond == kCondLE) {
540 cmp = new (allocator) HLessThanOrEqual(phi, constant_initial);
541 } else {
542 DCHECK(cond == kCondLT);
543 cmp = new (allocator) HLessThan(phi, constant_initial);
544 }
545 HInstruction* if_inst = new (allocator) HIf(cmp);
546 loop_header->AddPhi(phi);
547 loop_header->AddInstruction(cmp);
548 loop_header->AddInstruction(if_inst);
David Brazdil1abb4192015-02-17 18:33:36 +0000549 phi->AddInput(array_length);
Mingyao Yangf384f882014-10-22 16:08:18 -0700550
551 HInstruction* add = new (allocator) HAdd(Primitive::kPrimInt, phi, constant_minus_1);
552 null_check = new (allocator) HNullCheck(parameter, 0);
553 array_length = new (allocator) HArrayLength(null_check);
554 *bounds_check = new (allocator) HBoundsCheck(add, array_length, 0);
555 HInstruction* array_set = new (allocator) HArraySet(
556 null_check, *bounds_check, constant_10, Primitive::kPrimInt, 0);
557 HInstruction* add_phi = new (allocator) HAdd(Primitive::kPrimInt, phi, constant_increment);
558 loop_body->AddInstruction(add);
559 loop_body->AddInstruction(null_check);
560 loop_body->AddInstruction(array_length);
561 loop_body->AddInstruction(*bounds_check);
562 loop_body->AddInstruction(array_set);
563 loop_body->AddInstruction(add_phi);
564 loop_body->AddInstruction(new (allocator) HGoto());
565 phi->AddInput(add);
566
567 exit->AddInstruction(new (allocator) HExit());
568
569 return graph;
570}
571
572TEST(BoundsCheckEliminationTest, LoopArrayBoundsElimination2) {
573 ArenaPool pool;
574 ArenaAllocator allocator(&pool);
575
576 // for (int i=array.length; i>0; i--) { array[i-1] = 10; // Can eliminate with gvn. }
577 HInstruction* bounds_check = nullptr;
578 HGraph* graph = BuildSSAGraph2(&allocator, &bounds_check, 0);
579 graph->BuildDominatorTree();
Mingyao Yang3584bce2015-05-19 16:01:59 -0700580 graph->AnalyzeNaturalLoops();
581 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700582 BoundsCheckElimination bounds_check_elimination(graph);
583 bounds_check_elimination.Run();
Mingyao Yangf384f882014-10-22 16:08:18 -0700584 ASSERT_TRUE(IsRemoved(bounds_check));
585
586 // for (int i=array.length; i>1; i--) { array[i-1] = 10; // Can eliminate. }
587 graph = BuildSSAGraph2(&allocator, &bounds_check, 1);
588 graph->BuildDominatorTree();
Mingyao Yang3584bce2015-05-19 16:01:59 -0700589 graph->AnalyzeNaturalLoops();
Mingyao Yang0304e182015-01-30 16:41:29 -0800590 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700591 BoundsCheckElimination bounds_check_elimination_with_initial_1(graph);
592 bounds_check_elimination_with_initial_1.Run();
593 ASSERT_TRUE(IsRemoved(bounds_check));
594
595 // for (int i=array.length; i>-1; i--) { array[i-1] = 10; // Can't eliminate. }
596 graph = BuildSSAGraph2(&allocator, &bounds_check, -1);
597 graph->BuildDominatorTree();
Mingyao Yang3584bce2015-05-19 16:01:59 -0700598 graph->AnalyzeNaturalLoops();
Mingyao Yang0304e182015-01-30 16:41:29 -0800599 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700600 BoundsCheckElimination bounds_check_elimination_with_initial_minus_1(graph);
601 bounds_check_elimination_with_initial_minus_1.Run();
602 ASSERT_FALSE(IsRemoved(bounds_check));
603
604 // for (int i=array.length; i>=0; i--) { array[i-1] = 10; // Can't eliminate. }
605 graph = BuildSSAGraph2(&allocator, &bounds_check, 0, -1, kCondLT);
606 graph->BuildDominatorTree();
Mingyao Yang3584bce2015-05-19 16:01:59 -0700607 graph->AnalyzeNaturalLoops();
Mingyao Yang0304e182015-01-30 16:41:29 -0800608 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700609 BoundsCheckElimination bounds_check_elimination_with_less_than(graph);
610 bounds_check_elimination_with_less_than.Run();
611 ASSERT_FALSE(IsRemoved(bounds_check));
612
613 // for (int i=array.length; i>0; i-=2) { array[i-1] = 10; // Can eliminate. }
614 graph = BuildSSAGraph2(&allocator, &bounds_check, 0, -2);
615 graph->BuildDominatorTree();
Mingyao Yang3584bce2015-05-19 16:01:59 -0700616 graph->AnalyzeNaturalLoops();
Mingyao Yang0304e182015-01-30 16:41:29 -0800617 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700618 BoundsCheckElimination bounds_check_elimination_increment_minus_2(graph);
619 bounds_check_elimination_increment_minus_2.Run();
620 ASSERT_TRUE(IsRemoved(bounds_check));
621}
622
Mingyao Yang8c8bad82015-02-09 18:13:26 -0800623// int[] array = new int[10];
Mingyao Yangf384f882014-10-22 16:08:18 -0700624// for (int i=0; i<10; i+=increment) { array[i] = 10; }
625static HGraph* BuildSSAGraph3(ArenaAllocator* allocator,
626 HInstruction** bounds_check,
627 int initial,
628 int increment,
629 IfCondition cond) {
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100630 HGraph* graph = CreateGraph(allocator);
Mark Mendell1152c922015-04-24 17:06:35 -0400631 graph->SetHasBoundsChecks(true);
Mingyao Yangf384f882014-10-22 16:08:18 -0700632
633 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
634 graph->AddBlock(entry);
635 graph->SetEntryBlock(entry);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000636
637 HInstruction* constant_10 = graph->GetIntConstant(10);
638 HInstruction* constant_initial = graph->GetIntConstant(initial);
639 HInstruction* constant_increment = graph->GetIntConstant(increment);
Mingyao Yangf384f882014-10-22 16:08:18 -0700640
641 HBasicBlock* block = new (allocator) HBasicBlock(graph);
642 graph->AddBlock(block);
643 entry->AddSuccessor(block);
Nicolas Geoffray69aa6012015-06-09 10:34:25 +0100644 HInstruction* new_array = new (allocator) HNewArray(
645 constant_10,
646 graph->GetCurrentMethod(),
647 0,
648 Primitive::kPrimInt,
649 graph->GetDexFile(),
650 kQuickAllocArray);
Mingyao Yangf384f882014-10-22 16:08:18 -0700651 block->AddInstruction(new_array);
652 block->AddInstruction(new (allocator) HGoto());
653
654 HBasicBlock* loop_header = new (allocator) HBasicBlock(graph);
655 HBasicBlock* loop_body = new (allocator) HBasicBlock(graph);
656 HBasicBlock* exit = new (allocator) HBasicBlock(graph);
657
658 graph->AddBlock(loop_header);
659 graph->AddBlock(loop_body);
660 graph->AddBlock(exit);
661 block->AddSuccessor(loop_header);
662 loop_header->AddSuccessor(exit); // true successor
663 loop_header->AddSuccessor(loop_body); // false successor
664 loop_body->AddSuccessor(loop_header);
665
666 HPhi* phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt);
Mingyao Yangf384f882014-10-22 16:08:18 -0700667 HInstruction* cmp = nullptr;
668 if (cond == kCondGE) {
669 cmp = new (allocator) HGreaterThanOrEqual(phi, constant_10);
670 } else {
671 DCHECK(cond == kCondGT);
672 cmp = new (allocator) HGreaterThan(phi, constant_10);
673 }
674 HInstruction* if_inst = new (allocator) HIf(cmp);
675 loop_header->AddPhi(phi);
676 loop_header->AddInstruction(cmp);
677 loop_header->AddInstruction(if_inst);
David Brazdil1abb4192015-02-17 18:33:36 +0000678 phi->AddInput(constant_initial);
Mingyao Yangf384f882014-10-22 16:08:18 -0700679
680 HNullCheck* null_check = new (allocator) HNullCheck(new_array, 0);
681 HArrayLength* array_length = new (allocator) HArrayLength(null_check);
682 *bounds_check = new (allocator) HBoundsCheck(phi, array_length, 0);
683 HInstruction* array_set = new (allocator) HArraySet(
684 null_check, *bounds_check, constant_10, Primitive::kPrimInt, 0);
685 HInstruction* add = new (allocator) HAdd(Primitive::kPrimInt, phi, constant_increment);
686 loop_body->AddInstruction(null_check);
687 loop_body->AddInstruction(array_length);
688 loop_body->AddInstruction(*bounds_check);
689 loop_body->AddInstruction(array_set);
690 loop_body->AddInstruction(add);
691 loop_body->AddInstruction(new (allocator) HGoto());
692 phi->AddInput(add);
693
694 exit->AddInstruction(new (allocator) HExit());
695
696 return graph;
697}
698
699TEST(BoundsCheckEliminationTest, LoopArrayBoundsElimination3) {
700 ArenaPool pool;
701 ArenaAllocator allocator(&pool);
702
Mingyao Yang8c8bad82015-02-09 18:13:26 -0800703 // int[] array = new int[10];
Mingyao Yangf384f882014-10-22 16:08:18 -0700704 // for (int i=0; i<10; i++) { array[i] = 10; // Can eliminate. }
705 HInstruction* bounds_check = nullptr;
706 HGraph* graph = BuildSSAGraph3(&allocator, &bounds_check, 0, 1, kCondGE);
707 graph->BuildDominatorTree();
Mingyao Yang3584bce2015-05-19 16:01:59 -0700708 graph->AnalyzeNaturalLoops();
Mingyao Yang0304e182015-01-30 16:41:29 -0800709 RunSimplifierAndGvn(graph);
Mingyao Yang3584bce2015-05-19 16:01:59 -0700710 BoundsCheckElimination bounds_check_elimination(graph);
711 bounds_check_elimination.Run();
Mingyao Yangf384f882014-10-22 16:08:18 -0700712 ASSERT_TRUE(IsRemoved(bounds_check));
713
Mingyao Yang8c8bad82015-02-09 18:13:26 -0800714 // int[] array = new int[10];
Mingyao Yangf384f882014-10-22 16:08:18 -0700715 // for (int i=1; i<10; i++) { array[i] = 10; // Can eliminate. }
716 graph = BuildSSAGraph3(&allocator, &bounds_check, 1, 1, kCondGE);
717 graph->BuildDominatorTree();
Mingyao Yang3584bce2015-05-19 16:01:59 -0700718 graph->AnalyzeNaturalLoops();
Mingyao Yang0304e182015-01-30 16:41:29 -0800719 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700720 BoundsCheckElimination bounds_check_elimination_with_initial_1(graph);
721 bounds_check_elimination_with_initial_1.Run();
722 ASSERT_TRUE(IsRemoved(bounds_check));
723
Mingyao Yang8c8bad82015-02-09 18:13:26 -0800724 // int[] array = new int[10];
Mingyao Yangf384f882014-10-22 16:08:18 -0700725 // for (int i=0; i<=10; i++) { array[i] = 10; // Can't eliminate. }
726 graph = BuildSSAGraph3(&allocator, &bounds_check, 0, 1, kCondGT);
727 graph->BuildDominatorTree();
Mingyao Yang3584bce2015-05-19 16:01:59 -0700728 graph->AnalyzeNaturalLoops();
Mingyao Yang0304e182015-01-30 16:41:29 -0800729 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700730 BoundsCheckElimination bounds_check_elimination_with_greater_than(graph);
731 bounds_check_elimination_with_greater_than.Run();
732 ASSERT_FALSE(IsRemoved(bounds_check));
733
Mingyao Yang8c8bad82015-02-09 18:13:26 -0800734 // int[] array = new int[10];
Mingyao Yangf384f882014-10-22 16:08:18 -0700735 // for (int i=1; i<10; i+=8) { array[i] = 10; // Can eliminate. }
736 graph = BuildSSAGraph3(&allocator, &bounds_check, 1, 8, kCondGE);
737 graph->BuildDominatorTree();
Mingyao Yang3584bce2015-05-19 16:01:59 -0700738 graph->AnalyzeNaturalLoops();
Mingyao Yang0304e182015-01-30 16:41:29 -0800739 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700740 BoundsCheckElimination bounds_check_elimination_increment_8(graph);
741 bounds_check_elimination_increment_8.Run();
742 ASSERT_TRUE(IsRemoved(bounds_check));
743}
744
745// for (int i=initial; i<array.length; i++) { array[array.length-i-1] = 10; }
746static HGraph* BuildSSAGraph4(ArenaAllocator* allocator,
747 HInstruction** bounds_check,
748 int initial,
749 IfCondition cond = kCondGE) {
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100750 HGraph* graph = CreateGraph(allocator);
Mark Mendell1152c922015-04-24 17:06:35 -0400751 graph->SetHasBoundsChecks(true);
Mingyao Yangf384f882014-10-22 16:08:18 -0700752
753 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
754 graph->AddBlock(entry);
755 graph->SetEntryBlock(entry);
756 HInstruction* parameter = new (allocator) HParameterValue(0, Primitive::kPrimNot);
Mingyao Yangf384f882014-10-22 16:08:18 -0700757 entry->AddInstruction(parameter);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000758
759 HInstruction* constant_initial = graph->GetIntConstant(initial);
760 HInstruction* constant_1 = graph->GetIntConstant(1);
761 HInstruction* constant_10 = graph->GetIntConstant(10);
762 HInstruction* constant_minus_1 = graph->GetIntConstant(-1);
Mingyao Yangf384f882014-10-22 16:08:18 -0700763
764 HBasicBlock* block = new (allocator) HBasicBlock(graph);
765 graph->AddBlock(block);
766 entry->AddSuccessor(block);
767 block->AddInstruction(new (allocator) HGoto());
768
769 HBasicBlock* loop_header = new (allocator) HBasicBlock(graph);
770 HBasicBlock* loop_body = new (allocator) HBasicBlock(graph);
771 HBasicBlock* exit = new (allocator) HBasicBlock(graph);
772
773 graph->AddBlock(loop_header);
774 graph->AddBlock(loop_body);
775 graph->AddBlock(exit);
776 block->AddSuccessor(loop_header);
777 loop_header->AddSuccessor(exit); // true successor
778 loop_header->AddSuccessor(loop_body); // false successor
779 loop_body->AddSuccessor(loop_header);
780
781 HPhi* phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt);
Mingyao Yangf384f882014-10-22 16:08:18 -0700782 HInstruction* null_check = new (allocator) HNullCheck(parameter, 0);
783 HInstruction* array_length = new (allocator) HArrayLength(null_check);
784 HInstruction* cmp = nullptr;
785 if (cond == kCondGE) {
786 cmp = new (allocator) HGreaterThanOrEqual(phi, array_length);
787 } else if (cond == kCondGT) {
788 cmp = new (allocator) HGreaterThan(phi, array_length);
789 }
790 HInstruction* if_inst = new (allocator) HIf(cmp);
791 loop_header->AddPhi(phi);
792 loop_header->AddInstruction(null_check);
793 loop_header->AddInstruction(array_length);
794 loop_header->AddInstruction(cmp);
795 loop_header->AddInstruction(if_inst);
David Brazdil1abb4192015-02-17 18:33:36 +0000796 phi->AddInput(constant_initial);
Mingyao Yangf384f882014-10-22 16:08:18 -0700797
798 null_check = new (allocator) HNullCheck(parameter, 0);
799 array_length = new (allocator) HArrayLength(null_check);
800 HInstruction* sub = new (allocator) HSub(Primitive::kPrimInt, array_length, phi);
801 HInstruction* add_minus_1 = new (allocator)
802 HAdd(Primitive::kPrimInt, sub, constant_minus_1);
803 *bounds_check = new (allocator) HBoundsCheck(add_minus_1, array_length, 0);
804 HInstruction* array_set = new (allocator) HArraySet(
805 null_check, *bounds_check, constant_10, Primitive::kPrimInt, 0);
806 HInstruction* add = new (allocator) HAdd(Primitive::kPrimInt, phi, constant_1);
807 loop_body->AddInstruction(null_check);
808 loop_body->AddInstruction(array_length);
809 loop_body->AddInstruction(sub);
810 loop_body->AddInstruction(add_minus_1);
811 loop_body->AddInstruction(*bounds_check);
812 loop_body->AddInstruction(array_set);
813 loop_body->AddInstruction(add);
814 loop_body->AddInstruction(new (allocator) HGoto());
815 phi->AddInput(add);
816
817 exit->AddInstruction(new (allocator) HExit());
818
819 return graph;
820}
821
822TEST(BoundsCheckEliminationTest, LoopArrayBoundsElimination4) {
823 ArenaPool pool;
824 ArenaAllocator allocator(&pool);
825
826 // for (int i=0; i<array.length; i++) { array[array.length-i-1] = 10; // Can eliminate with gvn. }
827 HInstruction* bounds_check = nullptr;
828 HGraph* graph = BuildSSAGraph4(&allocator, &bounds_check, 0);
829 graph->BuildDominatorTree();
Mingyao Yang3584bce2015-05-19 16:01:59 -0700830 graph->AnalyzeNaturalLoops();
831 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700832 BoundsCheckElimination bounds_check_elimination(graph);
833 bounds_check_elimination.Run();
Mingyao Yangf384f882014-10-22 16:08:18 -0700834 ASSERT_TRUE(IsRemoved(bounds_check));
835
836 // for (int i=1; i<array.length; i++) { array[array.length-i-1] = 10; // Can eliminate. }
837 graph = BuildSSAGraph4(&allocator, &bounds_check, 1);
838 graph->BuildDominatorTree();
Mingyao Yang3584bce2015-05-19 16:01:59 -0700839 graph->AnalyzeNaturalLoops();
Mingyao Yang0304e182015-01-30 16:41:29 -0800840 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700841 BoundsCheckElimination bounds_check_elimination_with_initial_1(graph);
842 bounds_check_elimination_with_initial_1.Run();
843 ASSERT_TRUE(IsRemoved(bounds_check));
844
845 // for (int i=0; i<=array.length; i++) { array[array.length-i] = 10; // Can't eliminate. }
846 graph = BuildSSAGraph4(&allocator, &bounds_check, 0, kCondGT);
847 graph->BuildDominatorTree();
Mingyao Yang3584bce2015-05-19 16:01:59 -0700848 graph->AnalyzeNaturalLoops();
Mingyao Yang0304e182015-01-30 16:41:29 -0800849 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700850 BoundsCheckElimination bounds_check_elimination_with_greater_than(graph);
851 bounds_check_elimination_with_greater_than.Run();
852 ASSERT_FALSE(IsRemoved(bounds_check));
853}
854
855// Bubble sort:
856// (Every array access bounds-check can be eliminated.)
857// for (int i=0; i<array.length-1; i++) {
858// for (int j=0; j<array.length-i-1; j++) {
859// if (array[j] > array[j+1]) {
860// int temp = array[j+1];
861// array[j+1] = array[j];
862// array[j] = temp;
863// }
864// }
865// }
866TEST(BoundsCheckEliminationTest, BubbleSortArrayBoundsElimination) {
867 ArenaPool pool;
868 ArenaAllocator allocator(&pool);
869
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100870 HGraph* graph = CreateGraph(&allocator);
Mark Mendell1152c922015-04-24 17:06:35 -0400871 graph->SetHasBoundsChecks(true);
Mingyao Yangf384f882014-10-22 16:08:18 -0700872
873 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
874 graph->AddBlock(entry);
875 graph->SetEntryBlock(entry);
876 HInstruction* parameter = new (&allocator) HParameterValue(0, Primitive::kPrimNot);
Mingyao Yangf384f882014-10-22 16:08:18 -0700877 entry->AddInstruction(parameter);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000878
879 HInstruction* constant_0 = graph->GetIntConstant(0);
880 HInstruction* constant_minus_1 = graph->GetIntConstant(-1);
881 HInstruction* constant_1 = graph->GetIntConstant(1);
Mingyao Yangf384f882014-10-22 16:08:18 -0700882
883 HBasicBlock* block = new (&allocator) HBasicBlock(graph);
884 graph->AddBlock(block);
885 entry->AddSuccessor(block);
886 block->AddInstruction(new (&allocator) HGoto());
887
888 HBasicBlock* exit = new (&allocator) HBasicBlock(graph);
889 graph->AddBlock(exit);
890 exit->AddInstruction(new (&allocator) HExit());
891
892 HBasicBlock* outer_header = new (&allocator) HBasicBlock(graph);
893 graph->AddBlock(outer_header);
894 HPhi* phi_i = new (&allocator) HPhi(&allocator, 0, 0, Primitive::kPrimInt);
Mingyao Yangf384f882014-10-22 16:08:18 -0700895 HNullCheck* null_check = new (&allocator) HNullCheck(parameter, 0);
896 HArrayLength* array_length = new (&allocator) HArrayLength(null_check);
897 HAdd* add = new (&allocator) HAdd(Primitive::kPrimInt, array_length, constant_minus_1);
898 HInstruction* cmp = new (&allocator) HGreaterThanOrEqual(phi_i, add);
899 HIf* if_inst = new (&allocator) HIf(cmp);
900 outer_header->AddPhi(phi_i);
901 outer_header->AddInstruction(null_check);
902 outer_header->AddInstruction(array_length);
903 outer_header->AddInstruction(add);
904 outer_header->AddInstruction(cmp);
905 outer_header->AddInstruction(if_inst);
David Brazdil1abb4192015-02-17 18:33:36 +0000906 phi_i->AddInput(constant_0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700907
908 HBasicBlock* inner_header = new (&allocator) HBasicBlock(graph);
909 graph->AddBlock(inner_header);
910 HPhi* phi_j = new (&allocator) HPhi(&allocator, 0, 0, Primitive::kPrimInt);
Mingyao Yangf384f882014-10-22 16:08:18 -0700911 null_check = new (&allocator) HNullCheck(parameter, 0);
912 array_length = new (&allocator) HArrayLength(null_check);
913 HSub* sub = new (&allocator) HSub(Primitive::kPrimInt, array_length, phi_i);
914 add = new (&allocator) HAdd(Primitive::kPrimInt, sub, constant_minus_1);
915 cmp = new (&allocator) HGreaterThanOrEqual(phi_j, add);
916 if_inst = new (&allocator) HIf(cmp);
917 inner_header->AddPhi(phi_j);
918 inner_header->AddInstruction(null_check);
919 inner_header->AddInstruction(array_length);
920 inner_header->AddInstruction(sub);
921 inner_header->AddInstruction(add);
922 inner_header->AddInstruction(cmp);
923 inner_header->AddInstruction(if_inst);
David Brazdil1abb4192015-02-17 18:33:36 +0000924 phi_j->AddInput(constant_0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700925
926 HBasicBlock* inner_body_compare = new (&allocator) HBasicBlock(graph);
927 graph->AddBlock(inner_body_compare);
928 null_check = new (&allocator) HNullCheck(parameter, 0);
929 array_length = new (&allocator) HArrayLength(null_check);
930 HBoundsCheck* bounds_check1 = new (&allocator) HBoundsCheck(phi_j, array_length, 0);
931 HArrayGet* array_get_j = new (&allocator)
932 HArrayGet(null_check, bounds_check1, Primitive::kPrimInt);
933 inner_body_compare->AddInstruction(null_check);
934 inner_body_compare->AddInstruction(array_length);
935 inner_body_compare->AddInstruction(bounds_check1);
936 inner_body_compare->AddInstruction(array_get_j);
937 HInstruction* j_plus_1 = new (&allocator) HAdd(Primitive::kPrimInt, phi_j, constant_1);
938 null_check = new (&allocator) HNullCheck(parameter, 0);
939 array_length = new (&allocator) HArrayLength(null_check);
940 HBoundsCheck* bounds_check2 = new (&allocator) HBoundsCheck(j_plus_1, array_length, 0);
941 HArrayGet* array_get_j_plus_1 = new (&allocator)
942 HArrayGet(null_check, bounds_check2, Primitive::kPrimInt);
943 cmp = new (&allocator) HGreaterThanOrEqual(array_get_j, array_get_j_plus_1);
944 if_inst = new (&allocator) HIf(cmp);
945 inner_body_compare->AddInstruction(j_plus_1);
946 inner_body_compare->AddInstruction(null_check);
947 inner_body_compare->AddInstruction(array_length);
948 inner_body_compare->AddInstruction(bounds_check2);
949 inner_body_compare->AddInstruction(array_get_j_plus_1);
950 inner_body_compare->AddInstruction(cmp);
951 inner_body_compare->AddInstruction(if_inst);
952
953 HBasicBlock* inner_body_swap = new (&allocator) HBasicBlock(graph);
954 graph->AddBlock(inner_body_swap);
955 j_plus_1 = new (&allocator) HAdd(Primitive::kPrimInt, phi_j, constant_1);
956 // temp = array[j+1]
957 null_check = new (&allocator) HNullCheck(parameter, 0);
958 array_length = new (&allocator) HArrayLength(null_check);
959 HInstruction* bounds_check3 = new (&allocator) HBoundsCheck(j_plus_1, array_length, 0);
960 array_get_j_plus_1 = new (&allocator)
961 HArrayGet(null_check, bounds_check3, Primitive::kPrimInt);
962 inner_body_swap->AddInstruction(j_plus_1);
963 inner_body_swap->AddInstruction(null_check);
964 inner_body_swap->AddInstruction(array_length);
965 inner_body_swap->AddInstruction(bounds_check3);
966 inner_body_swap->AddInstruction(array_get_j_plus_1);
967 // array[j+1] = array[j]
968 null_check = new (&allocator) HNullCheck(parameter, 0);
969 array_length = new (&allocator) HArrayLength(null_check);
970 HInstruction* bounds_check4 = new (&allocator) HBoundsCheck(phi_j, array_length, 0);
971 array_get_j = new (&allocator)
972 HArrayGet(null_check, bounds_check4, Primitive::kPrimInt);
973 inner_body_swap->AddInstruction(null_check);
974 inner_body_swap->AddInstruction(array_length);
975 inner_body_swap->AddInstruction(bounds_check4);
976 inner_body_swap->AddInstruction(array_get_j);
977 null_check = new (&allocator) HNullCheck(parameter, 0);
978 array_length = new (&allocator) HArrayLength(null_check);
979 HInstruction* bounds_check5 = new (&allocator) HBoundsCheck(j_plus_1, array_length, 0);
980 HArraySet* array_set_j_plus_1 = new (&allocator)
981 HArraySet(null_check, bounds_check5, array_get_j, Primitive::kPrimInt, 0);
982 inner_body_swap->AddInstruction(null_check);
983 inner_body_swap->AddInstruction(array_length);
984 inner_body_swap->AddInstruction(bounds_check5);
985 inner_body_swap->AddInstruction(array_set_j_plus_1);
986 // array[j] = temp
987 null_check = new (&allocator) HNullCheck(parameter, 0);
988 array_length = new (&allocator) HArrayLength(null_check);
989 HInstruction* bounds_check6 = new (&allocator) HBoundsCheck(phi_j, array_length, 0);
990 HArraySet* array_set_j = new (&allocator)
991 HArraySet(null_check, bounds_check6, array_get_j_plus_1, Primitive::kPrimInt, 0);
992 inner_body_swap->AddInstruction(null_check);
993 inner_body_swap->AddInstruction(array_length);
994 inner_body_swap->AddInstruction(bounds_check6);
995 inner_body_swap->AddInstruction(array_set_j);
996 inner_body_swap->AddInstruction(new (&allocator) HGoto());
997
998 HBasicBlock* inner_body_add = new (&allocator) HBasicBlock(graph);
999 graph->AddBlock(inner_body_add);
1000 add = new (&allocator) HAdd(Primitive::kPrimInt, phi_j, constant_1);
1001 inner_body_add->AddInstruction(add);
1002 inner_body_add->AddInstruction(new (&allocator) HGoto());
1003 phi_j->AddInput(add);
1004
1005 HBasicBlock* outer_body_add = new (&allocator) HBasicBlock(graph);
1006 graph->AddBlock(outer_body_add);
1007 add = new (&allocator) HAdd(Primitive::kPrimInt, phi_i, constant_1);
1008 outer_body_add->AddInstruction(add);
1009 outer_body_add->AddInstruction(new (&allocator) HGoto());
1010 phi_i->AddInput(add);
1011
1012 block->AddSuccessor(outer_header);
1013 outer_header->AddSuccessor(exit);
1014 outer_header->AddSuccessor(inner_header);
1015 inner_header->AddSuccessor(outer_body_add);
1016 inner_header->AddSuccessor(inner_body_compare);
1017 inner_body_compare->AddSuccessor(inner_body_add);
1018 inner_body_compare->AddSuccessor(inner_body_swap);
1019 inner_body_swap->AddSuccessor(inner_body_add);
1020 inner_body_add->AddSuccessor(inner_header);
1021 outer_body_add->AddSuccessor(outer_header);
1022
1023 graph->BuildDominatorTree();
Mingyao Yang3584bce2015-05-19 16:01:59 -07001024 graph->AnalyzeNaturalLoops();
Mingyao Yang0304e182015-01-30 16:41:29 -08001025 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -07001026 // gvn should remove the same bounds check.
1027 ASSERT_FALSE(IsRemoved(bounds_check1));
1028 ASSERT_FALSE(IsRemoved(bounds_check2));
1029 ASSERT_TRUE(IsRemoved(bounds_check3));
1030 ASSERT_TRUE(IsRemoved(bounds_check4));
1031 ASSERT_TRUE(IsRemoved(bounds_check5));
1032 ASSERT_TRUE(IsRemoved(bounds_check6));
1033
1034 BoundsCheckElimination bounds_check_elimination(graph);
1035 bounds_check_elimination.Run();
1036 ASSERT_TRUE(IsRemoved(bounds_check1));
1037 ASSERT_TRUE(IsRemoved(bounds_check2));
1038 ASSERT_TRUE(IsRemoved(bounds_check3));
1039 ASSERT_TRUE(IsRemoved(bounds_check4));
1040 ASSERT_TRUE(IsRemoved(bounds_check5));
1041 ASSERT_TRUE(IsRemoved(bounds_check6));
1042}
1043
1044} // namespace art