blob: 3dcb08d195fb74a22b7bb1ae38ac1b7bf04a471f [file] [log] [blame]
Mingyao Yangf384f882014-10-22 16:08:18 -07001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "bounds_check_elimination.h"
18#include "builder.h"
19#include "gvn.h"
20#include "nodes.h"
21#include "optimizing_unit_test.h"
Nicolas Geoffray827eedb2015-01-26 15:18:36 +000022#include "side_effects_analysis.h"
Mingyao Yangf384f882014-10-22 16:08:18 -070023#include "utils/arena_allocator.h"
24
25#include "gtest/gtest.h"
26
27namespace art {
28
Nicolas Geoffraye6f17152015-01-26 15:13:47 +000029static void RunGvn(HGraph* graph) {
30 SideEffectsAnalysis side_effects(graph);
31 side_effects.Run();
Nicolas Geoffray827eedb2015-01-26 15:18:36 +000032 GVNOptimization(graph, side_effects).Run();
Nicolas Geoffraye6f17152015-01-26 15:13:47 +000033}
34
Mingyao Yangf384f882014-10-22 16:08:18 -070035// if (i < 0) { array[i] = 1; // Can't eliminate. }
36// else if (i >= array.length) { array[i] = 1; // Can't eliminate. }
37// else { array[i] = 1; // Can eliminate. }
38TEST(BoundsCheckEliminationTest, NarrowingRangeArrayBoundsElimination) {
39 ArenaPool pool;
40 ArenaAllocator allocator(&pool);
41
42 HGraph* graph = new (&allocator) HGraph(&allocator);
43
44 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
45 graph->AddBlock(entry);
46 graph->SetEntryBlock(entry);
47 HInstruction* parameter1 = new (&allocator)
48 HParameterValue(0, Primitive::kPrimNot); // array
49 HInstruction* parameter2 = new (&allocator)
50 HParameterValue(0, Primitive::kPrimInt); // i
51 HInstruction* constant_1 = new (&allocator) HIntConstant(1);
52 HInstruction* constant_0 = new (&allocator) HIntConstant(0);
53 entry->AddInstruction(parameter1);
54 entry->AddInstruction(parameter2);
55 entry->AddInstruction(constant_1);
56 entry->AddInstruction(constant_0);
57
58 HBasicBlock* block1 = new (&allocator) HBasicBlock(graph);
59 graph->AddBlock(block1);
60 HInstruction* cmp = new (&allocator) HGreaterThanOrEqual(parameter2, constant_0);
61 HIf* if_inst = new (&allocator) HIf(cmp);
62 block1->AddInstruction(cmp);
63 block1->AddInstruction(if_inst);
64 entry->AddSuccessor(block1);
65
66 HBasicBlock* block2 = new (&allocator) HBasicBlock(graph);
67 graph->AddBlock(block2);
68 HNullCheck* null_check = new (&allocator) HNullCheck(parameter1, 0);
69 HArrayLength* array_length = new (&allocator) HArrayLength(null_check);
70 HBoundsCheck* bounds_check2 = new (&allocator)
71 HBoundsCheck(parameter2, array_length, 0);
72 HArraySet* array_set = new (&allocator) HArraySet(
73 null_check, bounds_check2, constant_1, Primitive::kPrimInt, 0);
74 block2->AddInstruction(null_check);
75 block2->AddInstruction(array_length);
76 block2->AddInstruction(bounds_check2);
77 block2->AddInstruction(array_set);
78
79 HBasicBlock* block3 = new (&allocator) HBasicBlock(graph);
80 graph->AddBlock(block3);
81 null_check = new (&allocator) HNullCheck(parameter1, 0);
82 array_length = new (&allocator) HArrayLength(null_check);
83 cmp = new (&allocator) HLessThan(parameter2, array_length);
84 if_inst = new (&allocator) HIf(cmp);
85 block3->AddInstruction(null_check);
86 block3->AddInstruction(array_length);
87 block3->AddInstruction(cmp);
88 block3->AddInstruction(if_inst);
89
90 HBasicBlock* block4 = new (&allocator) HBasicBlock(graph);
91 graph->AddBlock(block4);
92 null_check = new (&allocator) HNullCheck(parameter1, 0);
93 array_length = new (&allocator) HArrayLength(null_check);
94 HBoundsCheck* bounds_check4 = new (&allocator)
95 HBoundsCheck(parameter2, array_length, 0);
96 array_set = new (&allocator) HArraySet(
97 null_check, bounds_check4, constant_1, Primitive::kPrimInt, 0);
98 block4->AddInstruction(null_check);
99 block4->AddInstruction(array_length);
100 block4->AddInstruction(bounds_check4);
101 block4->AddInstruction(array_set);
102
103 HBasicBlock* block5 = new (&allocator) HBasicBlock(graph);
104 graph->AddBlock(block5);
105 null_check = new (&allocator) HNullCheck(parameter1, 0);
106 array_length = new (&allocator) HArrayLength(null_check);
107 HBoundsCheck* bounds_check5 = new (&allocator)
108 HBoundsCheck(parameter2, array_length, 0);
109 array_set = new (&allocator) HArraySet(
110 null_check, bounds_check5, constant_1, Primitive::kPrimInt, 0);
111 block5->AddInstruction(null_check);
112 block5->AddInstruction(array_length);
113 block5->AddInstruction(bounds_check5);
114 block5->AddInstruction(array_set);
115
116 HBasicBlock* exit = new (&allocator) HBasicBlock(graph);
117 graph->AddBlock(exit);
118 block2->AddSuccessor(exit);
119 block4->AddSuccessor(exit);
120 block5->AddSuccessor(exit);
121 exit->AddInstruction(new (&allocator) HExit());
122
123 block1->AddSuccessor(block3); // True successor
124 block1->AddSuccessor(block2); // False successor
125
126 block3->AddSuccessor(block5); // True successor
127 block3->AddSuccessor(block4); // False successor
128
129 graph->BuildDominatorTree();
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000130 RunGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700131 BoundsCheckElimination bounds_check_elimination(graph);
132 bounds_check_elimination.Run();
133 ASSERT_FALSE(IsRemoved(bounds_check2));
134 ASSERT_FALSE(IsRemoved(bounds_check4));
135 ASSERT_TRUE(IsRemoved(bounds_check5));
136}
137
138// if (i > 0) {
139// // Positive number plus MAX_INT will overflow and be negative.
140// int j = i + Integer.MAX_VALUE;
141// if (j < array.length) array[j] = 1; // Can't eliminate.
142// }
143TEST(BoundsCheckEliminationTest, OverflowArrayBoundsElimination) {
144 ArenaPool pool;
145 ArenaAllocator allocator(&pool);
146
147 HGraph* graph = new (&allocator) HGraph(&allocator);
148
149 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
150 graph->AddBlock(entry);
151 graph->SetEntryBlock(entry);
152 HInstruction* parameter1 = new (&allocator)
153 HParameterValue(0, Primitive::kPrimNot); // array
154 HInstruction* parameter2 = new (&allocator)
155 HParameterValue(0, Primitive::kPrimInt); // i
156 HInstruction* constant_1 = new (&allocator) HIntConstant(1);
157 HInstruction* constant_0 = new (&allocator) HIntConstant(0);
158 HInstruction* constant_max_int = new (&allocator) HIntConstant(INT_MAX);
159 entry->AddInstruction(parameter1);
160 entry->AddInstruction(parameter2);
161 entry->AddInstruction(constant_1);
162 entry->AddInstruction(constant_0);
163 entry->AddInstruction(constant_max_int);
164
165 HBasicBlock* block1 = new (&allocator) HBasicBlock(graph);
166 graph->AddBlock(block1);
167 HInstruction* cmp = new (&allocator) HLessThanOrEqual(parameter2, constant_0);
168 HIf* if_inst = new (&allocator) HIf(cmp);
169 block1->AddInstruction(cmp);
170 block1->AddInstruction(if_inst);
171 entry->AddSuccessor(block1);
172
173 HBasicBlock* block2 = new (&allocator) HBasicBlock(graph);
174 graph->AddBlock(block2);
175 HInstruction* add = new (&allocator) HAdd(Primitive::kPrimInt, parameter2, constant_max_int);
176 HNullCheck* null_check = new (&allocator) HNullCheck(parameter1, 0);
177 HArrayLength* array_length = new (&allocator) HArrayLength(null_check);
178 HInstruction* cmp2 = new (&allocator) HGreaterThanOrEqual(add, array_length);
179 if_inst = new (&allocator) HIf(cmp2);
180 block2->AddInstruction(add);
181 block2->AddInstruction(null_check);
182 block2->AddInstruction(array_length);
183 block2->AddInstruction(cmp2);
184 block2->AddInstruction(if_inst);
185
186 HBasicBlock* block3 = new (&allocator) HBasicBlock(graph);
187 graph->AddBlock(block3);
188 HBoundsCheck* bounds_check = new (&allocator)
189 HBoundsCheck(add, array_length, 0);
190 HArraySet* array_set = new (&allocator) HArraySet(
191 null_check, bounds_check, constant_1, Primitive::kPrimInt, 0);
192 block3->AddInstruction(bounds_check);
193 block3->AddInstruction(array_set);
194
195 HBasicBlock* exit = new (&allocator) HBasicBlock(graph);
196 graph->AddBlock(exit);
197 exit->AddInstruction(new (&allocator) HExit());
Andreas Gampe0418b5b2014-12-04 17:24:50 -0800198 block1->AddSuccessor(exit); // true successor
199 block1->AddSuccessor(block2); // false successor
200 block2->AddSuccessor(exit); // true successor
201 block2->AddSuccessor(block3); // false successor
Mingyao Yangf384f882014-10-22 16:08:18 -0700202 block3->AddSuccessor(exit);
203
204 graph->BuildDominatorTree();
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000205 RunGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700206 BoundsCheckElimination bounds_check_elimination(graph);
207 bounds_check_elimination.Run();
208 ASSERT_FALSE(IsRemoved(bounds_check));
209}
210
211// if (i < array.length) {
212// int j = i - Integer.MAX_VALUE;
213// j = j - Integer.MAX_VALUE; // j is (i+2) after substracting MAX_INT twice
214// if (j > 0) array[j] = 1; // Can't eliminate.
215// }
216TEST(BoundsCheckEliminationTest, UnderflowArrayBoundsElimination) {
217 ArenaPool pool;
218 ArenaAllocator allocator(&pool);
219
220 HGraph* graph = new (&allocator) HGraph(&allocator);
221
222 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
223 graph->AddBlock(entry);
224 graph->SetEntryBlock(entry);
225 HInstruction* parameter1 = new (&allocator)
226 HParameterValue(0, Primitive::kPrimNot); // array
227 HInstruction* parameter2 = new (&allocator)
228 HParameterValue(0, Primitive::kPrimInt); // i
229 HInstruction* constant_1 = new (&allocator) HIntConstant(1);
230 HInstruction* constant_0 = new (&allocator) HIntConstant(0);
231 HInstruction* constant_max_int = new (&allocator) HIntConstant(INT_MAX);
232 entry->AddInstruction(parameter1);
233 entry->AddInstruction(parameter2);
234 entry->AddInstruction(constant_1);
235 entry->AddInstruction(constant_0);
236 entry->AddInstruction(constant_max_int);
237
238 HBasicBlock* block1 = new (&allocator) HBasicBlock(graph);
239 graph->AddBlock(block1);
240 HNullCheck* null_check = new (&allocator) HNullCheck(parameter1, 0);
241 HArrayLength* array_length = new (&allocator) HArrayLength(null_check);
242 HInstruction* cmp = new (&allocator) HGreaterThanOrEqual(parameter2, array_length);
243 HIf* if_inst = new (&allocator) HIf(cmp);
244 block1->AddInstruction(null_check);
245 block1->AddInstruction(array_length);
246 block1->AddInstruction(cmp);
247 block1->AddInstruction(if_inst);
248 entry->AddSuccessor(block1);
249
250 HBasicBlock* block2 = new (&allocator) HBasicBlock(graph);
251 graph->AddBlock(block2);
252 HInstruction* sub1 = new (&allocator) HSub(Primitive::kPrimInt, parameter2, constant_max_int);
253 HInstruction* sub2 = new (&allocator) HSub(Primitive::kPrimInt, sub1, constant_max_int);
254 HInstruction* cmp2 = new (&allocator) HLessThanOrEqual(sub2, constant_0);
255 if_inst = new (&allocator) HIf(cmp2);
256 block2->AddInstruction(sub1);
257 block2->AddInstruction(sub2);
258 block2->AddInstruction(cmp2);
259 block2->AddInstruction(if_inst);
260
261 HBasicBlock* block3 = new (&allocator) HBasicBlock(graph);
262 graph->AddBlock(block3);
263 HBoundsCheck* bounds_check = new (&allocator)
264 HBoundsCheck(sub2, array_length, 0);
265 HArraySet* array_set = new (&allocator) HArraySet(
266 null_check, bounds_check, constant_1, Primitive::kPrimInt, 0);
267 block3->AddInstruction(bounds_check);
268 block3->AddInstruction(array_set);
269
270 HBasicBlock* exit = new (&allocator) HBasicBlock(graph);
271 graph->AddBlock(exit);
272 exit->AddInstruction(new (&allocator) HExit());
Andreas Gampe0418b5b2014-12-04 17:24:50 -0800273 block1->AddSuccessor(exit); // true successor
274 block1->AddSuccessor(block2); // false successor
275 block2->AddSuccessor(exit); // true successor
276 block2->AddSuccessor(block3); // false successor
Mingyao Yangf384f882014-10-22 16:08:18 -0700277 block3->AddSuccessor(exit);
278
279 graph->BuildDominatorTree();
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000280 RunGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700281 BoundsCheckElimination bounds_check_elimination(graph);
282 bounds_check_elimination.Run();
283 ASSERT_FALSE(IsRemoved(bounds_check));
284}
285
286// array[5] = 1; // Can't eliminate.
287// array[4] = 1; // Can eliminate.
288// array[6] = 1; // Can't eliminate.
289TEST(BoundsCheckEliminationTest, ConstantArrayBoundsElimination) {
290 ArenaPool pool;
291 ArenaAllocator allocator(&pool);
292
293 HGraph* graph = new (&allocator) HGraph(&allocator);
294
295 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
296 graph->AddBlock(entry);
297 graph->SetEntryBlock(entry);
298 HInstruction* parameter = new (&allocator) HParameterValue(0, Primitive::kPrimNot);
299 HInstruction* constant_5 = new (&allocator) HIntConstant(5);
300 HInstruction* constant_4 = new (&allocator) HIntConstant(4);
301 HInstruction* constant_6 = new (&allocator) HIntConstant(6);
302 HInstruction* constant_1 = new (&allocator) HIntConstant(1);
303 entry->AddInstruction(parameter);
304 entry->AddInstruction(constant_5);
305 entry->AddInstruction(constant_4);
306 entry->AddInstruction(constant_6);
307 entry->AddInstruction(constant_1);
308
309 HBasicBlock* block = new (&allocator) HBasicBlock(graph);
310 graph->AddBlock(block);
311 entry->AddSuccessor(block);
312
313 HNullCheck* null_check = new (&allocator) HNullCheck(parameter, 0);
314 HArrayLength* array_length = new (&allocator) HArrayLength(null_check);
315 HBoundsCheck* bounds_check5 = new (&allocator)
316 HBoundsCheck(constant_5, array_length, 0);
317 HInstruction* array_set = new (&allocator) HArraySet(
318 null_check, bounds_check5, constant_1, Primitive::kPrimInt, 0);
319 block->AddInstruction(null_check);
320 block->AddInstruction(array_length);
321 block->AddInstruction(bounds_check5);
322 block->AddInstruction(array_set);
323
324 null_check = new (&allocator) HNullCheck(parameter, 0);
325 array_length = new (&allocator) HArrayLength(null_check);
326 HBoundsCheck* bounds_check4 = new (&allocator)
327 HBoundsCheck(constant_4, array_length, 0);
328 array_set = new (&allocator) HArraySet(
329 null_check, bounds_check4, constant_1, Primitive::kPrimInt, 0);
330 block->AddInstruction(null_check);
331 block->AddInstruction(array_length);
332 block->AddInstruction(bounds_check4);
333 block->AddInstruction(array_set);
334
335 null_check = new (&allocator) HNullCheck(parameter, 0);
336 array_length = new (&allocator) HArrayLength(null_check);
337 HBoundsCheck* bounds_check6 = new (&allocator)
338 HBoundsCheck(constant_6, array_length, 0);
339 array_set = new (&allocator) HArraySet(
340 null_check, bounds_check6, constant_1, Primitive::kPrimInt, 0);
341 block->AddInstruction(null_check);
342 block->AddInstruction(array_length);
343 block->AddInstruction(bounds_check6);
344 block->AddInstruction(array_set);
345
346 block->AddInstruction(new (&allocator) HGoto());
347
348 HBasicBlock* exit = new (&allocator) HBasicBlock(graph);
349 graph->AddBlock(exit);
350 block->AddSuccessor(exit);
351 exit->AddInstruction(new (&allocator) HExit());
352
353 graph->BuildDominatorTree();
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000354 RunGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700355 BoundsCheckElimination bounds_check_elimination(graph);
356 bounds_check_elimination.Run();
357 ASSERT_FALSE(IsRemoved(bounds_check5));
358 ASSERT_TRUE(IsRemoved(bounds_check4));
359 ASSERT_FALSE(IsRemoved(bounds_check6));
360}
361
362// for (int i=initial; i<array.length; i+=increment) { array[i] = 10; }
363static HGraph* BuildSSAGraph1(ArenaAllocator* allocator,
364 HInstruction** bounds_check,
365 int initial,
366 int increment,
367 IfCondition cond = kCondGE) {
368 HGraph* graph = new (allocator) HGraph(allocator);
369
370 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
371 graph->AddBlock(entry);
372 graph->SetEntryBlock(entry);
373 HInstruction* parameter = new (allocator) HParameterValue(0, Primitive::kPrimNot);
374 HInstruction* constant_initial = new (allocator) HIntConstant(initial);
375 HInstruction* constant_increment = new (allocator) HIntConstant(increment);
376 HInstruction* constant_10 = new (allocator) HIntConstant(10);
377 entry->AddInstruction(parameter);
378 entry->AddInstruction(constant_initial);
379 entry->AddInstruction(constant_increment);
380 entry->AddInstruction(constant_10);
381
382 HBasicBlock* block = new (allocator) HBasicBlock(graph);
383 graph->AddBlock(block);
384 entry->AddSuccessor(block);
385 block->AddInstruction(new (allocator) HGoto());
386
387 HBasicBlock* loop_header = new (allocator) HBasicBlock(graph);
388 HBasicBlock* loop_body = new (allocator) HBasicBlock(graph);
389 HBasicBlock* exit = new (allocator) HBasicBlock(graph);
390
391 graph->AddBlock(loop_header);
392 graph->AddBlock(loop_body);
393 graph->AddBlock(exit);
394 block->AddSuccessor(loop_header);
395 loop_header->AddSuccessor(exit); // true successor
396 loop_header->AddSuccessor(loop_body); // false successor
397 loop_body->AddSuccessor(loop_header);
398
399 HPhi* phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt);
400 phi->AddInput(constant_initial);
401 HInstruction* null_check = new (allocator) HNullCheck(parameter, 0);
402 HInstruction* array_length = new (allocator) HArrayLength(null_check);
403 HInstruction* cmp = nullptr;
404 if (cond == kCondGE) {
405 cmp = new (allocator) HGreaterThanOrEqual(phi, array_length);
406 } else {
407 DCHECK(cond == kCondGT);
408 cmp = new (allocator) HGreaterThan(phi, array_length);
409 }
410 HInstruction* if_inst = new (allocator) HIf(cmp);
411 loop_header->AddPhi(phi);
412 loop_header->AddInstruction(null_check);
413 loop_header->AddInstruction(array_length);
414 loop_header->AddInstruction(cmp);
415 loop_header->AddInstruction(if_inst);
416
417 null_check = new (allocator) HNullCheck(parameter, 0);
418 array_length = new (allocator) HArrayLength(null_check);
419 *bounds_check = new (allocator) HBoundsCheck(phi, array_length, 0);
420 HInstruction* array_set = new (allocator) HArraySet(
421 null_check, *bounds_check, constant_10, Primitive::kPrimInt, 0);
422
423 HInstruction* add = new (allocator) HAdd(Primitive::kPrimInt, phi, constant_increment);
424 loop_body->AddInstruction(null_check);
425 loop_body->AddInstruction(array_length);
426 loop_body->AddInstruction(*bounds_check);
427 loop_body->AddInstruction(array_set);
428 loop_body->AddInstruction(add);
429 loop_body->AddInstruction(new (allocator) HGoto());
430 phi->AddInput(add);
431
432 exit->AddInstruction(new (allocator) HExit());
433
434 return graph;
435}
436
437TEST(BoundsCheckEliminationTest, LoopArrayBoundsElimination1) {
438 ArenaPool pool;
439 ArenaAllocator allocator(&pool);
440
441 // for (int i=0; i<array.length; i++) { array[i] = 10; // Can eliminate with gvn. }
442 HInstruction* bounds_check = nullptr;
443 HGraph* graph = BuildSSAGraph1(&allocator, &bounds_check, 0, 1);
444 graph->BuildDominatorTree();
445 BoundsCheckElimination bounds_check_elimination(graph);
446 bounds_check_elimination.Run();
447 ASSERT_FALSE(IsRemoved(bounds_check));
448
449 // This time add gvn. Need gvn to eliminate the second
450 // HArrayLength which uses the null check as its input.
451 graph = BuildSSAGraph1(&allocator, &bounds_check, 0, 1);
452 graph->BuildDominatorTree();
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000453 RunGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700454 BoundsCheckElimination bounds_check_elimination_after_gvn(graph);
455 bounds_check_elimination_after_gvn.Run();
456 ASSERT_TRUE(IsRemoved(bounds_check));
457
458 // for (int i=1; i<array.length; i++) { array[i] = 10; // Can eliminate. }
459 graph = BuildSSAGraph1(&allocator, &bounds_check, 1, 1);
460 graph->BuildDominatorTree();
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000461 RunGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700462 BoundsCheckElimination bounds_check_elimination_with_initial_1(graph);
463 bounds_check_elimination_with_initial_1.Run();
464 ASSERT_TRUE(IsRemoved(bounds_check));
465
466 // for (int i=-1; i<array.length; i++) { array[i] = 10; // Can't eliminate. }
467 graph = BuildSSAGraph1(&allocator, &bounds_check, -1, 1);
468 graph->BuildDominatorTree();
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000469 RunGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700470 BoundsCheckElimination bounds_check_elimination_with_initial_minus_1(graph);
471 bounds_check_elimination_with_initial_minus_1.Run();
472 ASSERT_FALSE(IsRemoved(bounds_check));
473
474 // for (int i=0; i<=array.length; i++) { array[i] = 10; // Can't eliminate. }
475 graph = BuildSSAGraph1(&allocator, &bounds_check, 0, 1, kCondGT);
476 graph->BuildDominatorTree();
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000477 RunGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700478 BoundsCheckElimination bounds_check_elimination_with_greater_than(graph);
479 bounds_check_elimination_with_greater_than.Run();
480 ASSERT_FALSE(IsRemoved(bounds_check));
481
482 // for (int i=0; i<array.length; i += 2) {
483 // array[i] = 10; // Can't eliminate due to overflow concern. }
484 graph = BuildSSAGraph1(&allocator, &bounds_check, 0, 2);
485 graph->BuildDominatorTree();
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000486 RunGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700487 BoundsCheckElimination bounds_check_elimination_with_increment_2(graph);
488 bounds_check_elimination_with_increment_2.Run();
489 ASSERT_FALSE(IsRemoved(bounds_check));
490
491 // for (int i=1; i<array.length; i += 2) { array[i] = 10; // Can eliminate. }
492 graph = BuildSSAGraph1(&allocator, &bounds_check, 1, 2);
493 graph->BuildDominatorTree();
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000494 RunGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700495 BoundsCheckElimination bounds_check_elimination_with_increment_2_from_1(graph);
496 bounds_check_elimination_with_increment_2_from_1.Run();
497 ASSERT_TRUE(IsRemoved(bounds_check));
498}
499
500// for (int i=array.length; i>0; i+=increment) { array[i-1] = 10; }
501static HGraph* BuildSSAGraph2(ArenaAllocator* allocator,
502 HInstruction** bounds_check,
503 int initial,
504 int increment = -1,
505 IfCondition cond = kCondLE) {
506 HGraph* graph = new (allocator) HGraph(allocator);
507
508 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
509 graph->AddBlock(entry);
510 graph->SetEntryBlock(entry);
511 HInstruction* parameter = new (allocator) HParameterValue(0, Primitive::kPrimNot);
512 HInstruction* constant_initial = new (allocator) HIntConstant(initial);
513 HInstruction* constant_increment = new (allocator) HIntConstant(increment);
514 HInstruction* constant_minus_1 = new (allocator) HIntConstant(-1);
515 HInstruction* constant_10 = new (allocator) HIntConstant(10);
516 entry->AddInstruction(parameter);
517 entry->AddInstruction(constant_initial);
518 entry->AddInstruction(constant_increment);
519 entry->AddInstruction(constant_minus_1);
520 entry->AddInstruction(constant_10);
521
522 HBasicBlock* block = new (allocator) HBasicBlock(graph);
523 graph->AddBlock(block);
524 entry->AddSuccessor(block);
525 HInstruction* null_check = new (allocator) HNullCheck(parameter, 0);
526 HInstruction* array_length = new (allocator) HArrayLength(null_check);
527 block->AddInstruction(null_check);
528 block->AddInstruction(array_length);
529 block->AddInstruction(new (allocator) HGoto());
530
531 HBasicBlock* loop_header = new (allocator) HBasicBlock(graph);
532 HBasicBlock* loop_body = new (allocator) HBasicBlock(graph);
533 HBasicBlock* exit = new (allocator) HBasicBlock(graph);
534
535 graph->AddBlock(loop_header);
536 graph->AddBlock(loop_body);
537 graph->AddBlock(exit);
538 block->AddSuccessor(loop_header);
539 loop_header->AddSuccessor(exit); // true successor
540 loop_header->AddSuccessor(loop_body); // false successor
541 loop_body->AddSuccessor(loop_header);
542
543 HPhi* phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt);
544 phi->AddInput(array_length);
545 HInstruction* cmp = nullptr;
546 if (cond == kCondLE) {
547 cmp = new (allocator) HLessThanOrEqual(phi, constant_initial);
548 } else {
549 DCHECK(cond == kCondLT);
550 cmp = new (allocator) HLessThan(phi, constant_initial);
551 }
552 HInstruction* if_inst = new (allocator) HIf(cmp);
553 loop_header->AddPhi(phi);
554 loop_header->AddInstruction(cmp);
555 loop_header->AddInstruction(if_inst);
556
557 HInstruction* add = new (allocator) HAdd(Primitive::kPrimInt, phi, constant_minus_1);
558 null_check = new (allocator) HNullCheck(parameter, 0);
559 array_length = new (allocator) HArrayLength(null_check);
560 *bounds_check = new (allocator) HBoundsCheck(add, array_length, 0);
561 HInstruction* array_set = new (allocator) HArraySet(
562 null_check, *bounds_check, constant_10, Primitive::kPrimInt, 0);
563 HInstruction* add_phi = new (allocator) HAdd(Primitive::kPrimInt, phi, constant_increment);
564 loop_body->AddInstruction(add);
565 loop_body->AddInstruction(null_check);
566 loop_body->AddInstruction(array_length);
567 loop_body->AddInstruction(*bounds_check);
568 loop_body->AddInstruction(array_set);
569 loop_body->AddInstruction(add_phi);
570 loop_body->AddInstruction(new (allocator) HGoto());
571 phi->AddInput(add);
572
573 exit->AddInstruction(new (allocator) HExit());
574
575 return graph;
576}
577
578TEST(BoundsCheckEliminationTest, LoopArrayBoundsElimination2) {
579 ArenaPool pool;
580 ArenaAllocator allocator(&pool);
581
582 // for (int i=array.length; i>0; i--) { array[i-1] = 10; // Can eliminate with gvn. }
583 HInstruction* bounds_check = nullptr;
584 HGraph* graph = BuildSSAGraph2(&allocator, &bounds_check, 0);
585 graph->BuildDominatorTree();
586 BoundsCheckElimination bounds_check_elimination(graph);
587 bounds_check_elimination.Run();
588 ASSERT_FALSE(IsRemoved(bounds_check));
589
590 // This time add gvn. Need gvn to eliminate the second
591 // HArrayLength which uses the null check as its input.
592 graph = BuildSSAGraph2(&allocator, &bounds_check, 0);
593 graph->BuildDominatorTree();
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000594 RunGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700595 BoundsCheckElimination bounds_check_elimination_after_gvn(graph);
596 bounds_check_elimination_after_gvn.Run();
597 ASSERT_TRUE(IsRemoved(bounds_check));
598
599 // for (int i=array.length; i>1; i--) { array[i-1] = 10; // Can eliminate. }
600 graph = BuildSSAGraph2(&allocator, &bounds_check, 1);
601 graph->BuildDominatorTree();
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000602 RunGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700603 BoundsCheckElimination bounds_check_elimination_with_initial_1(graph);
604 bounds_check_elimination_with_initial_1.Run();
605 ASSERT_TRUE(IsRemoved(bounds_check));
606
607 // for (int i=array.length; i>-1; i--) { array[i-1] = 10; // Can't eliminate. }
608 graph = BuildSSAGraph2(&allocator, &bounds_check, -1);
609 graph->BuildDominatorTree();
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000610 RunGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700611 BoundsCheckElimination bounds_check_elimination_with_initial_minus_1(graph);
612 bounds_check_elimination_with_initial_minus_1.Run();
613 ASSERT_FALSE(IsRemoved(bounds_check));
614
615 // for (int i=array.length; i>=0; i--) { array[i-1] = 10; // Can't eliminate. }
616 graph = BuildSSAGraph2(&allocator, &bounds_check, 0, -1, kCondLT);
617 graph->BuildDominatorTree();
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000618 RunGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700619 BoundsCheckElimination bounds_check_elimination_with_less_than(graph);
620 bounds_check_elimination_with_less_than.Run();
621 ASSERT_FALSE(IsRemoved(bounds_check));
622
623 // for (int i=array.length; i>0; i-=2) { array[i-1] = 10; // Can eliminate. }
624 graph = BuildSSAGraph2(&allocator, &bounds_check, 0, -2);
625 graph->BuildDominatorTree();
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000626 RunGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700627 BoundsCheckElimination bounds_check_elimination_increment_minus_2(graph);
628 bounds_check_elimination_increment_minus_2.Run();
629 ASSERT_TRUE(IsRemoved(bounds_check));
630}
631
632// int[] array = new array[10];
633// for (int i=0; i<10; i+=increment) { array[i] = 10; }
634static HGraph* BuildSSAGraph3(ArenaAllocator* allocator,
635 HInstruction** bounds_check,
636 int initial,
637 int increment,
638 IfCondition cond) {
639 HGraph* graph = new (allocator) HGraph(allocator);
640
641 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
642 graph->AddBlock(entry);
643 graph->SetEntryBlock(entry);
644 HInstruction* constant_10 = new (allocator) HIntConstant(10);
645 HInstruction* constant_initial = new (allocator) HIntConstant(initial);
646 HInstruction* constant_increment = new (allocator) HIntConstant(increment);
647 entry->AddInstruction(constant_10);
648 entry->AddInstruction(constant_initial);
649 entry->AddInstruction(constant_increment);
650
651 HBasicBlock* block = new (allocator) HBasicBlock(graph);
652 graph->AddBlock(block);
653 entry->AddSuccessor(block);
654 HInstruction* new_array = new (allocator)
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +0000655 HNewArray(constant_10, 0, Primitive::kPrimInt, kQuickAllocArray);
Mingyao Yangf384f882014-10-22 16:08:18 -0700656 block->AddInstruction(new_array);
657 block->AddInstruction(new (allocator) HGoto());
658
659 HBasicBlock* loop_header = new (allocator) HBasicBlock(graph);
660 HBasicBlock* loop_body = new (allocator) HBasicBlock(graph);
661 HBasicBlock* exit = new (allocator) HBasicBlock(graph);
662
663 graph->AddBlock(loop_header);
664 graph->AddBlock(loop_body);
665 graph->AddBlock(exit);
666 block->AddSuccessor(loop_header);
667 loop_header->AddSuccessor(exit); // true successor
668 loop_header->AddSuccessor(loop_body); // false successor
669 loop_body->AddSuccessor(loop_header);
670
671 HPhi* phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt);
672 phi->AddInput(constant_initial);
673 HInstruction* cmp = nullptr;
674 if (cond == kCondGE) {
675 cmp = new (allocator) HGreaterThanOrEqual(phi, constant_10);
676 } else {
677 DCHECK(cond == kCondGT);
678 cmp = new (allocator) HGreaterThan(phi, constant_10);
679 }
680 HInstruction* if_inst = new (allocator) HIf(cmp);
681 loop_header->AddPhi(phi);
682 loop_header->AddInstruction(cmp);
683 loop_header->AddInstruction(if_inst);
684
685 HNullCheck* null_check = new (allocator) HNullCheck(new_array, 0);
686 HArrayLength* array_length = new (allocator) HArrayLength(null_check);
687 *bounds_check = new (allocator) HBoundsCheck(phi, array_length, 0);
688 HInstruction* array_set = new (allocator) HArraySet(
689 null_check, *bounds_check, constant_10, Primitive::kPrimInt, 0);
690 HInstruction* add = new (allocator) HAdd(Primitive::kPrimInt, phi, constant_increment);
691 loop_body->AddInstruction(null_check);
692 loop_body->AddInstruction(array_length);
693 loop_body->AddInstruction(*bounds_check);
694 loop_body->AddInstruction(array_set);
695 loop_body->AddInstruction(add);
696 loop_body->AddInstruction(new (allocator) HGoto());
697 phi->AddInput(add);
698
699 exit->AddInstruction(new (allocator) HExit());
700
701 return graph;
702}
703
704TEST(BoundsCheckEliminationTest, LoopArrayBoundsElimination3) {
705 ArenaPool pool;
706 ArenaAllocator allocator(&pool);
707
708 // int[] array = new array[10];
709 // for (int i=0; i<10; i++) { array[i] = 10; // Can eliminate. }
710 HInstruction* bounds_check = nullptr;
711 HGraph* graph = BuildSSAGraph3(&allocator, &bounds_check, 0, 1, kCondGE);
712 graph->BuildDominatorTree();
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000713 RunGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700714 BoundsCheckElimination bounds_check_elimination_after_gvn(graph);
715 bounds_check_elimination_after_gvn.Run();
716 ASSERT_TRUE(IsRemoved(bounds_check));
717
718 // int[] array = new array[10];
719 // for (int i=1; i<10; i++) { array[i] = 10; // Can eliminate. }
720 graph = BuildSSAGraph3(&allocator, &bounds_check, 1, 1, kCondGE);
721 graph->BuildDominatorTree();
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000722 RunGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700723 BoundsCheckElimination bounds_check_elimination_with_initial_1(graph);
724 bounds_check_elimination_with_initial_1.Run();
725 ASSERT_TRUE(IsRemoved(bounds_check));
726
727 // int[] array = new array[10];
728 // for (int i=0; i<=10; i++) { array[i] = 10; // Can't eliminate. }
729 graph = BuildSSAGraph3(&allocator, &bounds_check, 0, 1, kCondGT);
730 graph->BuildDominatorTree();
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000731 RunGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700732 BoundsCheckElimination bounds_check_elimination_with_greater_than(graph);
733 bounds_check_elimination_with_greater_than.Run();
734 ASSERT_FALSE(IsRemoved(bounds_check));
735
736 // int[] array = new array[10];
737 // for (int i=1; i<10; i+=8) { array[i] = 10; // Can eliminate. }
738 graph = BuildSSAGraph3(&allocator, &bounds_check, 1, 8, kCondGE);
739 graph->BuildDominatorTree();
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000740 RunGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700741 BoundsCheckElimination bounds_check_elimination_increment_8(graph);
742 bounds_check_elimination_increment_8.Run();
743 ASSERT_TRUE(IsRemoved(bounds_check));
744}
745
746// for (int i=initial; i<array.length; i++) { array[array.length-i-1] = 10; }
747static HGraph* BuildSSAGraph4(ArenaAllocator* allocator,
748 HInstruction** bounds_check,
749 int initial,
750 IfCondition cond = kCondGE) {
751 HGraph* graph = new (allocator) HGraph(allocator);
752
753 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
754 graph->AddBlock(entry);
755 graph->SetEntryBlock(entry);
756 HInstruction* parameter = new (allocator) HParameterValue(0, Primitive::kPrimNot);
757 HInstruction* constant_initial = new (allocator) HIntConstant(initial);
758 HInstruction* constant_1 = new (allocator) HIntConstant(1);
759 HInstruction* constant_10 = new (allocator) HIntConstant(10);
760 HInstruction* constant_minus_1 = new (allocator) HIntConstant(-1);
761 entry->AddInstruction(parameter);
762 entry->AddInstruction(constant_initial);
763 entry->AddInstruction(constant_1);
764 entry->AddInstruction(constant_10);
765 entry->AddInstruction(constant_minus_1);
766
767 HBasicBlock* block = new (allocator) HBasicBlock(graph);
768 graph->AddBlock(block);
769 entry->AddSuccessor(block);
770 block->AddInstruction(new (allocator) HGoto());
771
772 HBasicBlock* loop_header = new (allocator) HBasicBlock(graph);
773 HBasicBlock* loop_body = new (allocator) HBasicBlock(graph);
774 HBasicBlock* exit = new (allocator) HBasicBlock(graph);
775
776 graph->AddBlock(loop_header);
777 graph->AddBlock(loop_body);
778 graph->AddBlock(exit);
779 block->AddSuccessor(loop_header);
780 loop_header->AddSuccessor(exit); // true successor
781 loop_header->AddSuccessor(loop_body); // false successor
782 loop_body->AddSuccessor(loop_header);
783
784 HPhi* phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt);
785 phi->AddInput(constant_initial);
786 HInstruction* null_check = new (allocator) HNullCheck(parameter, 0);
787 HInstruction* array_length = new (allocator) HArrayLength(null_check);
788 HInstruction* cmp = nullptr;
789 if (cond == kCondGE) {
790 cmp = new (allocator) HGreaterThanOrEqual(phi, array_length);
791 } else if (cond == kCondGT) {
792 cmp = new (allocator) HGreaterThan(phi, array_length);
793 }
794 HInstruction* if_inst = new (allocator) HIf(cmp);
795 loop_header->AddPhi(phi);
796 loop_header->AddInstruction(null_check);
797 loop_header->AddInstruction(array_length);
798 loop_header->AddInstruction(cmp);
799 loop_header->AddInstruction(if_inst);
800
801 null_check = new (allocator) HNullCheck(parameter, 0);
802 array_length = new (allocator) HArrayLength(null_check);
803 HInstruction* sub = new (allocator) HSub(Primitive::kPrimInt, array_length, phi);
804 HInstruction* add_minus_1 = new (allocator)
805 HAdd(Primitive::kPrimInt, sub, constant_minus_1);
806 *bounds_check = new (allocator) HBoundsCheck(add_minus_1, array_length, 0);
807 HInstruction* array_set = new (allocator) HArraySet(
808 null_check, *bounds_check, constant_10, Primitive::kPrimInt, 0);
809 HInstruction* add = new (allocator) HAdd(Primitive::kPrimInt, phi, constant_1);
810 loop_body->AddInstruction(null_check);
811 loop_body->AddInstruction(array_length);
812 loop_body->AddInstruction(sub);
813 loop_body->AddInstruction(add_minus_1);
814 loop_body->AddInstruction(*bounds_check);
815 loop_body->AddInstruction(array_set);
816 loop_body->AddInstruction(add);
817 loop_body->AddInstruction(new (allocator) HGoto());
818 phi->AddInput(add);
819
820 exit->AddInstruction(new (allocator) HExit());
821
822 return graph;
823}
824
825TEST(BoundsCheckEliminationTest, LoopArrayBoundsElimination4) {
826 ArenaPool pool;
827 ArenaAllocator allocator(&pool);
828
829 // for (int i=0; i<array.length; i++) { array[array.length-i-1] = 10; // Can eliminate with gvn. }
830 HInstruction* bounds_check = nullptr;
831 HGraph* graph = BuildSSAGraph4(&allocator, &bounds_check, 0);
832 graph->BuildDominatorTree();
833 BoundsCheckElimination bounds_check_elimination(graph);
834 bounds_check_elimination.Run();
835 ASSERT_FALSE(IsRemoved(bounds_check));
836
837 // This time add gvn. Need gvn to eliminate the second
838 // HArrayLength which uses the null check as its input.
839 graph = BuildSSAGraph4(&allocator, &bounds_check, 0);
840 graph->BuildDominatorTree();
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000841 RunGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700842 BoundsCheckElimination bounds_check_elimination_after_gvn(graph);
843 bounds_check_elimination_after_gvn.Run();
844 ASSERT_TRUE(IsRemoved(bounds_check));
845
846 // for (int i=1; i<array.length; i++) { array[array.length-i-1] = 10; // Can eliminate. }
847 graph = BuildSSAGraph4(&allocator, &bounds_check, 1);
848 graph->BuildDominatorTree();
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000849 RunGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700850 BoundsCheckElimination bounds_check_elimination_with_initial_1(graph);
851 bounds_check_elimination_with_initial_1.Run();
852 ASSERT_TRUE(IsRemoved(bounds_check));
853
854 // for (int i=0; i<=array.length; i++) { array[array.length-i] = 10; // Can't eliminate. }
855 graph = BuildSSAGraph4(&allocator, &bounds_check, 0, kCondGT);
856 graph->BuildDominatorTree();
Nicolas Geoffraye6f17152015-01-26 15:13:47 +0000857 RunGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -0700858 BoundsCheckElimination bounds_check_elimination_with_greater_than(graph);
859 bounds_check_elimination_with_greater_than.Run();
860 ASSERT_FALSE(IsRemoved(bounds_check));
861}
862
863// Bubble sort:
864// (Every array access bounds-check can be eliminated.)
865// for (int i=0; i<array.length-1; i++) {
866// for (int j=0; j<array.length-i-1; j++) {
867// if (array[j] > array[j+1]) {
868// int temp = array[j+1];
869// array[j+1] = array[j];
870// array[j] = temp;
871// }
872// }
873// }
874TEST(BoundsCheckEliminationTest, BubbleSortArrayBoundsElimination) {
875 ArenaPool pool;
876 ArenaAllocator allocator(&pool);
877
878 HGraph* graph = new (&allocator) HGraph(&allocator);
879
880 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
881 graph->AddBlock(entry);
882 graph->SetEntryBlock(entry);
883 HInstruction* parameter = new (&allocator) HParameterValue(0, Primitive::kPrimNot);
884 HInstruction* constant_0 = new (&allocator) HIntConstant(0);
885 HInstruction* constant_minus_1 = new (&allocator) HIntConstant(-1);
886 HInstruction* constant_1 = new (&allocator) HIntConstant(1);
887 entry->AddInstruction(parameter);
888 entry->AddInstruction(constant_0);
889 entry->AddInstruction(constant_minus_1);
890 entry->AddInstruction(constant_1);
891
892 HBasicBlock* block = new (&allocator) HBasicBlock(graph);
893 graph->AddBlock(block);
894 entry->AddSuccessor(block);
895 block->AddInstruction(new (&allocator) HGoto());
896
897 HBasicBlock* exit = new (&allocator) HBasicBlock(graph);
898 graph->AddBlock(exit);
899 exit->AddInstruction(new (&allocator) HExit());
900
901 HBasicBlock* outer_header = new (&allocator) HBasicBlock(graph);
902 graph->AddBlock(outer_header);
903 HPhi* phi_i = new (&allocator) HPhi(&allocator, 0, 0, Primitive::kPrimInt);
904 phi_i->AddInput(constant_0);
905 HNullCheck* null_check = new (&allocator) HNullCheck(parameter, 0);
906 HArrayLength* array_length = new (&allocator) HArrayLength(null_check);
907 HAdd* add = new (&allocator) HAdd(Primitive::kPrimInt, array_length, constant_minus_1);
908 HInstruction* cmp = new (&allocator) HGreaterThanOrEqual(phi_i, add);
909 HIf* if_inst = new (&allocator) HIf(cmp);
910 outer_header->AddPhi(phi_i);
911 outer_header->AddInstruction(null_check);
912 outer_header->AddInstruction(array_length);
913 outer_header->AddInstruction(add);
914 outer_header->AddInstruction(cmp);
915 outer_header->AddInstruction(if_inst);
916
917 HBasicBlock* inner_header = new (&allocator) HBasicBlock(graph);
918 graph->AddBlock(inner_header);
919 HPhi* phi_j = new (&allocator) HPhi(&allocator, 0, 0, Primitive::kPrimInt);
920 phi_j->AddInput(constant_0);
921 null_check = new (&allocator) HNullCheck(parameter, 0);
922 array_length = new (&allocator) HArrayLength(null_check);
923 HSub* sub = new (&allocator) HSub(Primitive::kPrimInt, array_length, phi_i);
924 add = new (&allocator) HAdd(Primitive::kPrimInt, sub, constant_minus_1);
925 cmp = new (&allocator) HGreaterThanOrEqual(phi_j, add);
926 if_inst = new (&allocator) HIf(cmp);
927 inner_header->AddPhi(phi_j);
928 inner_header->AddInstruction(null_check);
929 inner_header->AddInstruction(array_length);
930 inner_header->AddInstruction(sub);
931 inner_header->AddInstruction(add);
932 inner_header->AddInstruction(cmp);
933 inner_header->AddInstruction(if_inst);
934
935 HBasicBlock* inner_body_compare = new (&allocator) HBasicBlock(graph);
936 graph->AddBlock(inner_body_compare);
937 null_check = new (&allocator) HNullCheck(parameter, 0);
938 array_length = new (&allocator) HArrayLength(null_check);
939 HBoundsCheck* bounds_check1 = new (&allocator) HBoundsCheck(phi_j, array_length, 0);
940 HArrayGet* array_get_j = new (&allocator)
941 HArrayGet(null_check, bounds_check1, Primitive::kPrimInt);
942 inner_body_compare->AddInstruction(null_check);
943 inner_body_compare->AddInstruction(array_length);
944 inner_body_compare->AddInstruction(bounds_check1);
945 inner_body_compare->AddInstruction(array_get_j);
946 HInstruction* j_plus_1 = new (&allocator) HAdd(Primitive::kPrimInt, phi_j, constant_1);
947 null_check = new (&allocator) HNullCheck(parameter, 0);
948 array_length = new (&allocator) HArrayLength(null_check);
949 HBoundsCheck* bounds_check2 = new (&allocator) HBoundsCheck(j_plus_1, array_length, 0);
950 HArrayGet* array_get_j_plus_1 = new (&allocator)
951 HArrayGet(null_check, bounds_check2, Primitive::kPrimInt);
952 cmp = new (&allocator) HGreaterThanOrEqual(array_get_j, array_get_j_plus_1);
953 if_inst = new (&allocator) HIf(cmp);
954 inner_body_compare->AddInstruction(j_plus_1);
955 inner_body_compare->AddInstruction(null_check);
956 inner_body_compare->AddInstruction(array_length);
957 inner_body_compare->AddInstruction(bounds_check2);
958 inner_body_compare->AddInstruction(array_get_j_plus_1);
959 inner_body_compare->AddInstruction(cmp);
960 inner_body_compare->AddInstruction(if_inst);
961
962 HBasicBlock* inner_body_swap = new (&allocator) HBasicBlock(graph);
963 graph->AddBlock(inner_body_swap);
964 j_plus_1 = new (&allocator) HAdd(Primitive::kPrimInt, phi_j, constant_1);
965 // temp = array[j+1]
966 null_check = new (&allocator) HNullCheck(parameter, 0);
967 array_length = new (&allocator) HArrayLength(null_check);
968 HInstruction* bounds_check3 = new (&allocator) HBoundsCheck(j_plus_1, array_length, 0);
969 array_get_j_plus_1 = new (&allocator)
970 HArrayGet(null_check, bounds_check3, Primitive::kPrimInt);
971 inner_body_swap->AddInstruction(j_plus_1);
972 inner_body_swap->AddInstruction(null_check);
973 inner_body_swap->AddInstruction(array_length);
974 inner_body_swap->AddInstruction(bounds_check3);
975 inner_body_swap->AddInstruction(array_get_j_plus_1);
976 // array[j+1] = array[j]
977 null_check = new (&allocator) HNullCheck(parameter, 0);
978 array_length = new (&allocator) HArrayLength(null_check);
979 HInstruction* bounds_check4 = new (&allocator) HBoundsCheck(phi_j, array_length, 0);
980 array_get_j = new (&allocator)
981 HArrayGet(null_check, bounds_check4, Primitive::kPrimInt);
982 inner_body_swap->AddInstruction(null_check);
983 inner_body_swap->AddInstruction(array_length);
984 inner_body_swap->AddInstruction(bounds_check4);
985 inner_body_swap->AddInstruction(array_get_j);
986 null_check = new (&allocator) HNullCheck(parameter, 0);
987 array_length = new (&allocator) HArrayLength(null_check);
988 HInstruction* bounds_check5 = new (&allocator) HBoundsCheck(j_plus_1, array_length, 0);
989 HArraySet* array_set_j_plus_1 = new (&allocator)
990 HArraySet(null_check, bounds_check5, array_get_j, Primitive::kPrimInt, 0);
991 inner_body_swap->AddInstruction(null_check);
992 inner_body_swap->AddInstruction(array_length);
993 inner_body_swap->AddInstruction(bounds_check5);
994 inner_body_swap->AddInstruction(array_set_j_plus_1);
995 // array[j] = temp
996 null_check = new (&allocator) HNullCheck(parameter, 0);
997 array_length = new (&allocator) HArrayLength(null_check);
998 HInstruction* bounds_check6 = new (&allocator) HBoundsCheck(phi_j, array_length, 0);
999 HArraySet* array_set_j = new (&allocator)
1000 HArraySet(null_check, bounds_check6, array_get_j_plus_1, Primitive::kPrimInt, 0);
1001 inner_body_swap->AddInstruction(null_check);
1002 inner_body_swap->AddInstruction(array_length);
1003 inner_body_swap->AddInstruction(bounds_check6);
1004 inner_body_swap->AddInstruction(array_set_j);
1005 inner_body_swap->AddInstruction(new (&allocator) HGoto());
1006
1007 HBasicBlock* inner_body_add = new (&allocator) HBasicBlock(graph);
1008 graph->AddBlock(inner_body_add);
1009 add = new (&allocator) HAdd(Primitive::kPrimInt, phi_j, constant_1);
1010 inner_body_add->AddInstruction(add);
1011 inner_body_add->AddInstruction(new (&allocator) HGoto());
1012 phi_j->AddInput(add);
1013
1014 HBasicBlock* outer_body_add = new (&allocator) HBasicBlock(graph);
1015 graph->AddBlock(outer_body_add);
1016 add = new (&allocator) HAdd(Primitive::kPrimInt, phi_i, constant_1);
1017 outer_body_add->AddInstruction(add);
1018 outer_body_add->AddInstruction(new (&allocator) HGoto());
1019 phi_i->AddInput(add);
1020
1021 block->AddSuccessor(outer_header);
1022 outer_header->AddSuccessor(exit);
1023 outer_header->AddSuccessor(inner_header);
1024 inner_header->AddSuccessor(outer_body_add);
1025 inner_header->AddSuccessor(inner_body_compare);
1026 inner_body_compare->AddSuccessor(inner_body_add);
1027 inner_body_compare->AddSuccessor(inner_body_swap);
1028 inner_body_swap->AddSuccessor(inner_body_add);
1029 inner_body_add->AddSuccessor(inner_header);
1030 outer_body_add->AddSuccessor(outer_header);
1031
1032 graph->BuildDominatorTree();
Nicolas Geoffraye6f17152015-01-26 15:13:47 +00001033 RunGvn(graph);
Mingyao Yangf384f882014-10-22 16:08:18 -07001034 // gvn should remove the same bounds check.
1035 ASSERT_FALSE(IsRemoved(bounds_check1));
1036 ASSERT_FALSE(IsRemoved(bounds_check2));
1037 ASSERT_TRUE(IsRemoved(bounds_check3));
1038 ASSERT_TRUE(IsRemoved(bounds_check4));
1039 ASSERT_TRUE(IsRemoved(bounds_check5));
1040 ASSERT_TRUE(IsRemoved(bounds_check6));
1041
1042 BoundsCheckElimination bounds_check_elimination(graph);
1043 bounds_check_elimination.Run();
1044 ASSERT_TRUE(IsRemoved(bounds_check1));
1045 ASSERT_TRUE(IsRemoved(bounds_check2));
1046 ASSERT_TRUE(IsRemoved(bounds_check3));
1047 ASSERT_TRUE(IsRemoved(bounds_check4));
1048 ASSERT_TRUE(IsRemoved(bounds_check5));
1049 ASSERT_TRUE(IsRemoved(bounds_check6));
1050}
1051
1052} // namespace art