blob: 163458f75c88c6604ac3b230afdf041fc134f3c2 [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();
443 BoundsCheckElimination bounds_check_elimination(graph);
444 bounds_check_elimination.Run();
445 ASSERT_FALSE(IsRemoved(bounds_check));
446
447 // This time add gvn. Need gvn to eliminate the second
448 // HArrayLength which uses the null check as its input.
449 graph = BuildSSAGraph1(&allocator, &bounds_check, 0, 1);
450 graph->BuildDominatorTree();
Mingyao Yang0304e182015-01-30 16:41:29 -0800451 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700452 BoundsCheckElimination bounds_check_elimination_after_gvn(graph);
453 bounds_check_elimination_after_gvn.Run();
454 ASSERT_TRUE(IsRemoved(bounds_check));
455
456 // for (int i=1; i<array.length; i++) { array[i] = 10; // Can eliminate. }
457 graph = BuildSSAGraph1(&allocator, &bounds_check, 1, 1);
458 graph->BuildDominatorTree();
Mingyao Yang0304e182015-01-30 16:41:29 -0800459 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700460 BoundsCheckElimination bounds_check_elimination_with_initial_1(graph);
461 bounds_check_elimination_with_initial_1.Run();
462 ASSERT_TRUE(IsRemoved(bounds_check));
463
464 // for (int i=-1; i<array.length; i++) { array[i] = 10; // Can't eliminate. }
465 graph = BuildSSAGraph1(&allocator, &bounds_check, -1, 1);
466 graph->BuildDominatorTree();
Mingyao Yang0304e182015-01-30 16:41:29 -0800467 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700468 BoundsCheckElimination bounds_check_elimination_with_initial_minus_1(graph);
469 bounds_check_elimination_with_initial_minus_1.Run();
470 ASSERT_FALSE(IsRemoved(bounds_check));
471
472 // for (int i=0; i<=array.length; i++) { array[i] = 10; // Can't eliminate. }
473 graph = BuildSSAGraph1(&allocator, &bounds_check, 0, 1, kCondGT);
474 graph->BuildDominatorTree();
Mingyao Yang0304e182015-01-30 16:41:29 -0800475 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700476 BoundsCheckElimination bounds_check_elimination_with_greater_than(graph);
477 bounds_check_elimination_with_greater_than.Run();
478 ASSERT_FALSE(IsRemoved(bounds_check));
479
480 // for (int i=0; i<array.length; i += 2) {
481 // array[i] = 10; // Can't eliminate due to overflow concern. }
482 graph = BuildSSAGraph1(&allocator, &bounds_check, 0, 2);
483 graph->BuildDominatorTree();
Mingyao Yang0304e182015-01-30 16:41:29 -0800484 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700485 BoundsCheckElimination bounds_check_elimination_with_increment_2(graph);
486 bounds_check_elimination_with_increment_2.Run();
487 ASSERT_FALSE(IsRemoved(bounds_check));
488
489 // for (int i=1; i<array.length; i += 2) { array[i] = 10; // Can eliminate. }
490 graph = BuildSSAGraph1(&allocator, &bounds_check, 1, 2);
491 graph->BuildDominatorTree();
Mingyao Yang0304e182015-01-30 16:41:29 -0800492 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700493 BoundsCheckElimination bounds_check_elimination_with_increment_2_from_1(graph);
494 bounds_check_elimination_with_increment_2_from_1.Run();
495 ASSERT_TRUE(IsRemoved(bounds_check));
496}
497
498// for (int i=array.length; i>0; i+=increment) { array[i-1] = 10; }
499static HGraph* BuildSSAGraph2(ArenaAllocator* allocator,
500 HInstruction** bounds_check,
501 int initial,
502 int increment = -1,
503 IfCondition cond = kCondLE) {
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100504 HGraph* graph = CreateGraph(allocator);
Mark Mendell1152c922015-04-24 17:06:35 -0400505 graph->SetHasBoundsChecks(true);
Mingyao Yangf384f882014-10-22 16:08:18 -0700506
507 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
508 graph->AddBlock(entry);
509 graph->SetEntryBlock(entry);
510 HInstruction* parameter = new (allocator) HParameterValue(0, Primitive::kPrimNot);
Mingyao Yangf384f882014-10-22 16:08:18 -0700511 entry->AddInstruction(parameter);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000512
513 HInstruction* constant_initial = graph->GetIntConstant(initial);
514 HInstruction* constant_increment = graph->GetIntConstant(increment);
515 HInstruction* constant_minus_1 = graph->GetIntConstant(-1);
516 HInstruction* constant_10 = graph->GetIntConstant(10);
Mingyao Yangf384f882014-10-22 16:08:18 -0700517
518 HBasicBlock* block = new (allocator) HBasicBlock(graph);
519 graph->AddBlock(block);
520 entry->AddSuccessor(block);
521 HInstruction* null_check = new (allocator) HNullCheck(parameter, 0);
522 HInstruction* array_length = new (allocator) HArrayLength(null_check);
523 block->AddInstruction(null_check);
524 block->AddInstruction(array_length);
525 block->AddInstruction(new (allocator) HGoto());
526
527 HBasicBlock* loop_header = new (allocator) HBasicBlock(graph);
528 HBasicBlock* loop_body = new (allocator) HBasicBlock(graph);
529 HBasicBlock* exit = new (allocator) HBasicBlock(graph);
530
531 graph->AddBlock(loop_header);
532 graph->AddBlock(loop_body);
533 graph->AddBlock(exit);
534 block->AddSuccessor(loop_header);
535 loop_header->AddSuccessor(exit); // true successor
536 loop_header->AddSuccessor(loop_body); // false successor
537 loop_body->AddSuccessor(loop_header);
538
539 HPhi* phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt);
Mingyao Yangf384f882014-10-22 16:08:18 -0700540 HInstruction* cmp = nullptr;
541 if (cond == kCondLE) {
542 cmp = new (allocator) HLessThanOrEqual(phi, constant_initial);
543 } else {
544 DCHECK(cond == kCondLT);
545 cmp = new (allocator) HLessThan(phi, constant_initial);
546 }
547 HInstruction* if_inst = new (allocator) HIf(cmp);
548 loop_header->AddPhi(phi);
549 loop_header->AddInstruction(cmp);
550 loop_header->AddInstruction(if_inst);
David Brazdil1abb4192015-02-17 18:33:36 +0000551 phi->AddInput(array_length);
Mingyao Yangf384f882014-10-22 16:08:18 -0700552
553 HInstruction* add = new (allocator) HAdd(Primitive::kPrimInt, phi, constant_minus_1);
554 null_check = new (allocator) HNullCheck(parameter, 0);
555 array_length = new (allocator) HArrayLength(null_check);
556 *bounds_check = new (allocator) HBoundsCheck(add, array_length, 0);
557 HInstruction* array_set = new (allocator) HArraySet(
558 null_check, *bounds_check, constant_10, Primitive::kPrimInt, 0);
559 HInstruction* add_phi = new (allocator) HAdd(Primitive::kPrimInt, phi, constant_increment);
560 loop_body->AddInstruction(add);
561 loop_body->AddInstruction(null_check);
562 loop_body->AddInstruction(array_length);
563 loop_body->AddInstruction(*bounds_check);
564 loop_body->AddInstruction(array_set);
565 loop_body->AddInstruction(add_phi);
566 loop_body->AddInstruction(new (allocator) HGoto());
567 phi->AddInput(add);
568
569 exit->AddInstruction(new (allocator) HExit());
570
571 return graph;
572}
573
574TEST(BoundsCheckEliminationTest, LoopArrayBoundsElimination2) {
575 ArenaPool pool;
576 ArenaAllocator allocator(&pool);
577
578 // for (int i=array.length; i>0; i--) { array[i-1] = 10; // Can eliminate with gvn. }
579 HInstruction* bounds_check = nullptr;
580 HGraph* graph = BuildSSAGraph2(&allocator, &bounds_check, 0);
581 graph->BuildDominatorTree();
582 BoundsCheckElimination bounds_check_elimination(graph);
583 bounds_check_elimination.Run();
584 ASSERT_FALSE(IsRemoved(bounds_check));
585
586 // This time add gvn. Need gvn to eliminate the second
587 // HArrayLength which uses the null check as its input.
588 graph = BuildSSAGraph2(&allocator, &bounds_check, 0);
589 graph->BuildDominatorTree();
Mingyao Yang0304e182015-01-30 16:41:29 -0800590 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700591 BoundsCheckElimination bounds_check_elimination_after_gvn(graph);
592 bounds_check_elimination_after_gvn.Run();
593 ASSERT_TRUE(IsRemoved(bounds_check));
594
595 // for (int i=array.length; i>1; i--) { array[i-1] = 10; // Can eliminate. }
596 graph = BuildSSAGraph2(&allocator, &bounds_check, 1);
597 graph->BuildDominatorTree();
Mingyao Yang0304e182015-01-30 16:41:29 -0800598 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700599 BoundsCheckElimination bounds_check_elimination_with_initial_1(graph);
600 bounds_check_elimination_with_initial_1.Run();
601 ASSERT_TRUE(IsRemoved(bounds_check));
602
603 // for (int i=array.length; i>-1; i--) { array[i-1] = 10; // Can't eliminate. }
604 graph = BuildSSAGraph2(&allocator, &bounds_check, -1);
605 graph->BuildDominatorTree();
Mingyao Yang0304e182015-01-30 16:41:29 -0800606 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700607 BoundsCheckElimination bounds_check_elimination_with_initial_minus_1(graph);
608 bounds_check_elimination_with_initial_minus_1.Run();
609 ASSERT_FALSE(IsRemoved(bounds_check));
610
611 // for (int i=array.length; i>=0; i--) { array[i-1] = 10; // Can't eliminate. }
612 graph = BuildSSAGraph2(&allocator, &bounds_check, 0, -1, kCondLT);
613 graph->BuildDominatorTree();
Mingyao Yang0304e182015-01-30 16:41:29 -0800614 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700615 BoundsCheckElimination bounds_check_elimination_with_less_than(graph);
616 bounds_check_elimination_with_less_than.Run();
617 ASSERT_FALSE(IsRemoved(bounds_check));
618
619 // for (int i=array.length; i>0; i-=2) { array[i-1] = 10; // Can eliminate. }
620 graph = BuildSSAGraph2(&allocator, &bounds_check, 0, -2);
621 graph->BuildDominatorTree();
Mingyao Yang0304e182015-01-30 16:41:29 -0800622 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700623 BoundsCheckElimination bounds_check_elimination_increment_minus_2(graph);
624 bounds_check_elimination_increment_minus_2.Run();
625 ASSERT_TRUE(IsRemoved(bounds_check));
626}
627
Mingyao Yang8c8bad82015-02-09 18:13:26 -0800628// int[] array = new int[10];
Mingyao Yangf384f882014-10-22 16:08:18 -0700629// for (int i=0; i<10; i+=increment) { array[i] = 10; }
630static HGraph* BuildSSAGraph3(ArenaAllocator* allocator,
631 HInstruction** bounds_check,
632 int initial,
633 int increment,
634 IfCondition cond) {
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100635 HGraph* graph = CreateGraph(allocator);
Mark Mendell1152c922015-04-24 17:06:35 -0400636 graph->SetHasBoundsChecks(true);
Mingyao Yangf384f882014-10-22 16:08:18 -0700637
638 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
639 graph->AddBlock(entry);
640 graph->SetEntryBlock(entry);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000641
642 HInstruction* constant_10 = graph->GetIntConstant(10);
643 HInstruction* constant_initial = graph->GetIntConstant(initial);
644 HInstruction* constant_increment = graph->GetIntConstant(increment);
Mingyao Yangf384f882014-10-22 16:08:18 -0700645
646 HBasicBlock* block = new (allocator) HBasicBlock(graph);
647 graph->AddBlock(block);
648 entry->AddSuccessor(block);
649 HInstruction* new_array = new (allocator)
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +0000650 HNewArray(constant_10, 0, Primitive::kPrimInt, 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 Yang0304e182015-01-30 16:41:29 -0800708 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700709 BoundsCheckElimination bounds_check_elimination_after_gvn(graph);
710 bounds_check_elimination_after_gvn.Run();
711 ASSERT_TRUE(IsRemoved(bounds_check));
712
Mingyao Yang8c8bad82015-02-09 18:13:26 -0800713 // int[] array = new int[10];
Mingyao Yangf384f882014-10-22 16:08:18 -0700714 // for (int i=1; i<10; i++) { array[i] = 10; // Can eliminate. }
715 graph = BuildSSAGraph3(&allocator, &bounds_check, 1, 1, kCondGE);
716 graph->BuildDominatorTree();
Mingyao Yang0304e182015-01-30 16:41:29 -0800717 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700718 BoundsCheckElimination bounds_check_elimination_with_initial_1(graph);
719 bounds_check_elimination_with_initial_1.Run();
720 ASSERT_TRUE(IsRemoved(bounds_check));
721
Mingyao Yang8c8bad82015-02-09 18:13:26 -0800722 // int[] array = new int[10];
Mingyao Yangf384f882014-10-22 16:08:18 -0700723 // for (int i=0; i<=10; i++) { array[i] = 10; // Can't eliminate. }
724 graph = BuildSSAGraph3(&allocator, &bounds_check, 0, 1, kCondGT);
725 graph->BuildDominatorTree();
Mingyao Yang0304e182015-01-30 16:41:29 -0800726 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700727 BoundsCheckElimination bounds_check_elimination_with_greater_than(graph);
728 bounds_check_elimination_with_greater_than.Run();
729 ASSERT_FALSE(IsRemoved(bounds_check));
730
Mingyao Yang8c8bad82015-02-09 18:13:26 -0800731 // int[] array = new int[10];
Mingyao Yangf384f882014-10-22 16:08:18 -0700732 // for (int i=1; i<10; i+=8) { array[i] = 10; // Can eliminate. }
733 graph = BuildSSAGraph3(&allocator, &bounds_check, 1, 8, kCondGE);
734 graph->BuildDominatorTree();
Mingyao Yang0304e182015-01-30 16:41:29 -0800735 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700736 BoundsCheckElimination bounds_check_elimination_increment_8(graph);
737 bounds_check_elimination_increment_8.Run();
738 ASSERT_TRUE(IsRemoved(bounds_check));
739}
740
741// for (int i=initial; i<array.length; i++) { array[array.length-i-1] = 10; }
742static HGraph* BuildSSAGraph4(ArenaAllocator* allocator,
743 HInstruction** bounds_check,
744 int initial,
745 IfCondition cond = kCondGE) {
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100746 HGraph* graph = CreateGraph(allocator);
Mark Mendell1152c922015-04-24 17:06:35 -0400747 graph->SetHasBoundsChecks(true);
Mingyao Yangf384f882014-10-22 16:08:18 -0700748
749 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
750 graph->AddBlock(entry);
751 graph->SetEntryBlock(entry);
752 HInstruction* parameter = new (allocator) HParameterValue(0, Primitive::kPrimNot);
Mingyao Yangf384f882014-10-22 16:08:18 -0700753 entry->AddInstruction(parameter);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000754
755 HInstruction* constant_initial = graph->GetIntConstant(initial);
756 HInstruction* constant_1 = graph->GetIntConstant(1);
757 HInstruction* constant_10 = graph->GetIntConstant(10);
758 HInstruction* constant_minus_1 = graph->GetIntConstant(-1);
Mingyao Yangf384f882014-10-22 16:08:18 -0700759
760 HBasicBlock* block = new (allocator) HBasicBlock(graph);
761 graph->AddBlock(block);
762 entry->AddSuccessor(block);
763 block->AddInstruction(new (allocator) HGoto());
764
765 HBasicBlock* loop_header = new (allocator) HBasicBlock(graph);
766 HBasicBlock* loop_body = new (allocator) HBasicBlock(graph);
767 HBasicBlock* exit = new (allocator) HBasicBlock(graph);
768
769 graph->AddBlock(loop_header);
770 graph->AddBlock(loop_body);
771 graph->AddBlock(exit);
772 block->AddSuccessor(loop_header);
773 loop_header->AddSuccessor(exit); // true successor
774 loop_header->AddSuccessor(loop_body); // false successor
775 loop_body->AddSuccessor(loop_header);
776
777 HPhi* phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt);
Mingyao Yangf384f882014-10-22 16:08:18 -0700778 HInstruction* null_check = new (allocator) HNullCheck(parameter, 0);
779 HInstruction* array_length = new (allocator) HArrayLength(null_check);
780 HInstruction* cmp = nullptr;
781 if (cond == kCondGE) {
782 cmp = new (allocator) HGreaterThanOrEqual(phi, array_length);
783 } else if (cond == kCondGT) {
784 cmp = new (allocator) HGreaterThan(phi, array_length);
785 }
786 HInstruction* if_inst = new (allocator) HIf(cmp);
787 loop_header->AddPhi(phi);
788 loop_header->AddInstruction(null_check);
789 loop_header->AddInstruction(array_length);
790 loop_header->AddInstruction(cmp);
791 loop_header->AddInstruction(if_inst);
David Brazdil1abb4192015-02-17 18:33:36 +0000792 phi->AddInput(constant_initial);
Mingyao Yangf384f882014-10-22 16:08:18 -0700793
794 null_check = new (allocator) HNullCheck(parameter, 0);
795 array_length = new (allocator) HArrayLength(null_check);
796 HInstruction* sub = new (allocator) HSub(Primitive::kPrimInt, array_length, phi);
797 HInstruction* add_minus_1 = new (allocator)
798 HAdd(Primitive::kPrimInt, sub, constant_minus_1);
799 *bounds_check = new (allocator) HBoundsCheck(add_minus_1, array_length, 0);
800 HInstruction* array_set = new (allocator) HArraySet(
801 null_check, *bounds_check, constant_10, Primitive::kPrimInt, 0);
802 HInstruction* add = new (allocator) HAdd(Primitive::kPrimInt, phi, constant_1);
803 loop_body->AddInstruction(null_check);
804 loop_body->AddInstruction(array_length);
805 loop_body->AddInstruction(sub);
806 loop_body->AddInstruction(add_minus_1);
807 loop_body->AddInstruction(*bounds_check);
808 loop_body->AddInstruction(array_set);
809 loop_body->AddInstruction(add);
810 loop_body->AddInstruction(new (allocator) HGoto());
811 phi->AddInput(add);
812
813 exit->AddInstruction(new (allocator) HExit());
814
815 return graph;
816}
817
818TEST(BoundsCheckEliminationTest, LoopArrayBoundsElimination4) {
819 ArenaPool pool;
820 ArenaAllocator allocator(&pool);
821
822 // for (int i=0; i<array.length; i++) { array[array.length-i-1] = 10; // Can eliminate with gvn. }
823 HInstruction* bounds_check = nullptr;
824 HGraph* graph = BuildSSAGraph4(&allocator, &bounds_check, 0);
825 graph->BuildDominatorTree();
826 BoundsCheckElimination bounds_check_elimination(graph);
827 bounds_check_elimination.Run();
828 ASSERT_FALSE(IsRemoved(bounds_check));
829
830 // This time add gvn. Need gvn to eliminate the second
831 // HArrayLength which uses the null check as its input.
832 graph = BuildSSAGraph4(&allocator, &bounds_check, 0);
833 graph->BuildDominatorTree();
Mingyao Yang0304e182015-01-30 16:41:29 -0800834 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700835 BoundsCheckElimination bounds_check_elimination_after_gvn(graph);
836 bounds_check_elimination_after_gvn.Run();
837 ASSERT_TRUE(IsRemoved(bounds_check));
838
839 // for (int i=1; i<array.length; i++) { array[array.length-i-1] = 10; // Can eliminate. }
840 graph = BuildSSAGraph4(&allocator, &bounds_check, 1);
841 graph->BuildDominatorTree();
Mingyao Yang0304e182015-01-30 16:41:29 -0800842 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700843 BoundsCheckElimination bounds_check_elimination_with_initial_1(graph);
844 bounds_check_elimination_with_initial_1.Run();
845 ASSERT_TRUE(IsRemoved(bounds_check));
846
847 // for (int i=0; i<=array.length; i++) { array[array.length-i] = 10; // Can't eliminate. }
848 graph = BuildSSAGraph4(&allocator, &bounds_check, 0, kCondGT);
849 graph->BuildDominatorTree();
Mingyao Yang0304e182015-01-30 16:41:29 -0800850 RunSimplifierAndGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700851 BoundsCheckElimination bounds_check_elimination_with_greater_than(graph);
852 bounds_check_elimination_with_greater_than.Run();
853 ASSERT_FALSE(IsRemoved(bounds_check));
854}
855
856// Bubble sort:
857// (Every array access bounds-check can be eliminated.)
858// for (int i=0; i<array.length-1; i++) {
859// for (int j=0; j<array.length-i-1; j++) {
860// if (array[j] > array[j+1]) {
861// int temp = array[j+1];
862// array[j+1] = array[j];
863// array[j] = temp;
864// }
865// }
866// }
867TEST(BoundsCheckEliminationTest, BubbleSortArrayBoundsElimination) {
868 ArenaPool pool;
869 ArenaAllocator allocator(&pool);
870
Nicolas Geoffray0a23d742015-05-07 11:57:35 +0100871 HGraph* graph = CreateGraph(&allocator);
Mark Mendell1152c922015-04-24 17:06:35 -0400872 graph->SetHasBoundsChecks(true);
Mingyao Yangf384f882014-10-22 16:08:18 -0700873
874 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
875 graph->AddBlock(entry);
876 graph->SetEntryBlock(entry);
877 HInstruction* parameter = new (&allocator) HParameterValue(0, Primitive::kPrimNot);
Mingyao Yangf384f882014-10-22 16:08:18 -0700878 entry->AddInstruction(parameter);
David Brazdil8d5b8b22015-03-24 10:51:52 +0000879
880 HInstruction* constant_0 = graph->GetIntConstant(0);
881 HInstruction* constant_minus_1 = graph->GetIntConstant(-1);
882 HInstruction* constant_1 = graph->GetIntConstant(1);
Mingyao Yangf384f882014-10-22 16:08:18 -0700883
884 HBasicBlock* block = new (&allocator) HBasicBlock(graph);
885 graph->AddBlock(block);
886 entry->AddSuccessor(block);
887 block->AddInstruction(new (&allocator) HGoto());
888
889 HBasicBlock* exit = new (&allocator) HBasicBlock(graph);
890 graph->AddBlock(exit);
891 exit->AddInstruction(new (&allocator) HExit());
892
893 HBasicBlock* outer_header = new (&allocator) HBasicBlock(graph);
894 graph->AddBlock(outer_header);
895 HPhi* phi_i = new (&allocator) HPhi(&allocator, 0, 0, Primitive::kPrimInt);
Mingyao Yangf384f882014-10-22 16:08:18 -0700896 HNullCheck* null_check = new (&allocator) HNullCheck(parameter, 0);
897 HArrayLength* array_length = new (&allocator) HArrayLength(null_check);
898 HAdd* add = new (&allocator) HAdd(Primitive::kPrimInt, array_length, constant_minus_1);
899 HInstruction* cmp = new (&allocator) HGreaterThanOrEqual(phi_i, add);
900 HIf* if_inst = new (&allocator) HIf(cmp);
901 outer_header->AddPhi(phi_i);
902 outer_header->AddInstruction(null_check);
903 outer_header->AddInstruction(array_length);
904 outer_header->AddInstruction(add);
905 outer_header->AddInstruction(cmp);
906 outer_header->AddInstruction(if_inst);
David Brazdil1abb4192015-02-17 18:33:36 +0000907 phi_i->AddInput(constant_0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700908
909 HBasicBlock* inner_header = new (&allocator) HBasicBlock(graph);
910 graph->AddBlock(inner_header);
911 HPhi* phi_j = new (&allocator) HPhi(&allocator, 0, 0, Primitive::kPrimInt);
Mingyao Yangf384f882014-10-22 16:08:18 -0700912 null_check = new (&allocator) HNullCheck(parameter, 0);
913 array_length = new (&allocator) HArrayLength(null_check);
914 HSub* sub = new (&allocator) HSub(Primitive::kPrimInt, array_length, phi_i);
915 add = new (&allocator) HAdd(Primitive::kPrimInt, sub, constant_minus_1);
916 cmp = new (&allocator) HGreaterThanOrEqual(phi_j, add);
917 if_inst = new (&allocator) HIf(cmp);
918 inner_header->AddPhi(phi_j);
919 inner_header->AddInstruction(null_check);
920 inner_header->AddInstruction(array_length);
921 inner_header->AddInstruction(sub);
922 inner_header->AddInstruction(add);
923 inner_header->AddInstruction(cmp);
924 inner_header->AddInstruction(if_inst);
David Brazdil1abb4192015-02-17 18:33:36 +0000925 phi_j->AddInput(constant_0);
Mingyao Yangf384f882014-10-22 16:08:18 -0700926
927 HBasicBlock* inner_body_compare = new (&allocator) HBasicBlock(graph);
928 graph->AddBlock(inner_body_compare);
929 null_check = new (&allocator) HNullCheck(parameter, 0);
930 array_length = new (&allocator) HArrayLength(null_check);
931 HBoundsCheck* bounds_check1 = new (&allocator) HBoundsCheck(phi_j, array_length, 0);
932 HArrayGet* array_get_j = new (&allocator)
933 HArrayGet(null_check, bounds_check1, Primitive::kPrimInt);
934 inner_body_compare->AddInstruction(null_check);
935 inner_body_compare->AddInstruction(array_length);
936 inner_body_compare->AddInstruction(bounds_check1);
937 inner_body_compare->AddInstruction(array_get_j);
938 HInstruction* j_plus_1 = new (&allocator) HAdd(Primitive::kPrimInt, phi_j, constant_1);
939 null_check = new (&allocator) HNullCheck(parameter, 0);
940 array_length = new (&allocator) HArrayLength(null_check);
941 HBoundsCheck* bounds_check2 = new (&allocator) HBoundsCheck(j_plus_1, array_length, 0);
942 HArrayGet* array_get_j_plus_1 = new (&allocator)
943 HArrayGet(null_check, bounds_check2, Primitive::kPrimInt);
944 cmp = new (&allocator) HGreaterThanOrEqual(array_get_j, array_get_j_plus_1);
945 if_inst = new (&allocator) HIf(cmp);
946 inner_body_compare->AddInstruction(j_plus_1);
947 inner_body_compare->AddInstruction(null_check);
948 inner_body_compare->AddInstruction(array_length);
949 inner_body_compare->AddInstruction(bounds_check2);
950 inner_body_compare->AddInstruction(array_get_j_plus_1);
951 inner_body_compare->AddInstruction(cmp);
952 inner_body_compare->AddInstruction(if_inst);
953
954 HBasicBlock* inner_body_swap = new (&allocator) HBasicBlock(graph);
955 graph->AddBlock(inner_body_swap);
956 j_plus_1 = new (&allocator) HAdd(Primitive::kPrimInt, phi_j, constant_1);
957 // temp = array[j+1]
958 null_check = new (&allocator) HNullCheck(parameter, 0);
959 array_length = new (&allocator) HArrayLength(null_check);
960 HInstruction* bounds_check3 = new (&allocator) HBoundsCheck(j_plus_1, array_length, 0);
961 array_get_j_plus_1 = new (&allocator)
962 HArrayGet(null_check, bounds_check3, Primitive::kPrimInt);
963 inner_body_swap->AddInstruction(j_plus_1);
964 inner_body_swap->AddInstruction(null_check);
965 inner_body_swap->AddInstruction(array_length);
966 inner_body_swap->AddInstruction(bounds_check3);
967 inner_body_swap->AddInstruction(array_get_j_plus_1);
968 // array[j+1] = array[j]
969 null_check = new (&allocator) HNullCheck(parameter, 0);
970 array_length = new (&allocator) HArrayLength(null_check);
971 HInstruction* bounds_check4 = new (&allocator) HBoundsCheck(phi_j, array_length, 0);
972 array_get_j = new (&allocator)
973 HArrayGet(null_check, bounds_check4, Primitive::kPrimInt);
974 inner_body_swap->AddInstruction(null_check);
975 inner_body_swap->AddInstruction(array_length);
976 inner_body_swap->AddInstruction(bounds_check4);
977 inner_body_swap->AddInstruction(array_get_j);
978 null_check = new (&allocator) HNullCheck(parameter, 0);
979 array_length = new (&allocator) HArrayLength(null_check);
980 HInstruction* bounds_check5 = new (&allocator) HBoundsCheck(j_plus_1, array_length, 0);
981 HArraySet* array_set_j_plus_1 = new (&allocator)
982 HArraySet(null_check, bounds_check5, array_get_j, Primitive::kPrimInt, 0);
983 inner_body_swap->AddInstruction(null_check);
984 inner_body_swap->AddInstruction(array_length);
985 inner_body_swap->AddInstruction(bounds_check5);
986 inner_body_swap->AddInstruction(array_set_j_plus_1);
987 // array[j] = temp
988 null_check = new (&allocator) HNullCheck(parameter, 0);
989 array_length = new (&allocator) HArrayLength(null_check);
990 HInstruction* bounds_check6 = new (&allocator) HBoundsCheck(phi_j, array_length, 0);
991 HArraySet* array_set_j = new (&allocator)
992 HArraySet(null_check, bounds_check6, array_get_j_plus_1, Primitive::kPrimInt, 0);
993 inner_body_swap->AddInstruction(null_check);
994 inner_body_swap->AddInstruction(array_length);
995 inner_body_swap->AddInstruction(bounds_check6);
996 inner_body_swap->AddInstruction(array_set_j);
997 inner_body_swap->AddInstruction(new (&allocator) HGoto());
998
999 HBasicBlock* inner_body_add = new (&allocator) HBasicBlock(graph);
1000 graph->AddBlock(inner_body_add);
1001 add = new (&allocator) HAdd(Primitive::kPrimInt, phi_j, constant_1);
1002 inner_body_add->AddInstruction(add);
1003 inner_body_add->AddInstruction(new (&allocator) HGoto());
1004 phi_j->AddInput(add);
1005
1006 HBasicBlock* outer_body_add = new (&allocator) HBasicBlock(graph);
1007 graph->AddBlock(outer_body_add);
1008 add = new (&allocator) HAdd(Primitive::kPrimInt, phi_i, constant_1);
1009 outer_body_add->AddInstruction(add);
1010 outer_body_add->AddInstruction(new (&allocator) HGoto());
1011 phi_i->AddInput(add);
1012
1013 block->AddSuccessor(outer_header);
1014 outer_header->AddSuccessor(exit);
1015 outer_header->AddSuccessor(inner_header);
1016 inner_header->AddSuccessor(outer_body_add);
1017 inner_header->AddSuccessor(inner_body_compare);
1018 inner_body_compare->AddSuccessor(inner_body_add);
1019 inner_body_compare->AddSuccessor(inner_body_swap);
1020 inner_body_swap->AddSuccessor(inner_body_add);
1021 inner_body_add->AddSuccessor(inner_header);
1022 outer_body_add->AddSuccessor(outer_header);
1023
1024 graph->BuildDominatorTree();
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