blob: f650ff21df526594e38feda6662f225e3603b1e6 [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"
22#include "utils/arena_allocator.h"
23
24#include "gtest/gtest.h"
25
26namespace art {
27
28// if (i < 0) { array[i] = 1; // Can't eliminate. }
29// else if (i >= array.length) { array[i] = 1; // Can't eliminate. }
30// else { array[i] = 1; // Can eliminate. }
31TEST(BoundsCheckEliminationTest, NarrowingRangeArrayBoundsElimination) {
32 ArenaPool pool;
33 ArenaAllocator allocator(&pool);
34
35 HGraph* graph = new (&allocator) HGraph(&allocator);
36
37 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
38 graph->AddBlock(entry);
39 graph->SetEntryBlock(entry);
40 HInstruction* parameter1 = new (&allocator)
41 HParameterValue(0, Primitive::kPrimNot); // array
42 HInstruction* parameter2 = new (&allocator)
43 HParameterValue(0, Primitive::kPrimInt); // i
44 HInstruction* constant_1 = new (&allocator) HIntConstant(1);
45 HInstruction* constant_0 = new (&allocator) HIntConstant(0);
46 entry->AddInstruction(parameter1);
47 entry->AddInstruction(parameter2);
48 entry->AddInstruction(constant_1);
49 entry->AddInstruction(constant_0);
50
51 HBasicBlock* block1 = new (&allocator) HBasicBlock(graph);
52 graph->AddBlock(block1);
53 HInstruction* cmp = new (&allocator) HGreaterThanOrEqual(parameter2, constant_0);
54 HIf* if_inst = new (&allocator) HIf(cmp);
55 block1->AddInstruction(cmp);
56 block1->AddInstruction(if_inst);
57 entry->AddSuccessor(block1);
58
59 HBasicBlock* block2 = new (&allocator) HBasicBlock(graph);
60 graph->AddBlock(block2);
61 HNullCheck* null_check = new (&allocator) HNullCheck(parameter1, 0);
62 HArrayLength* array_length = new (&allocator) HArrayLength(null_check);
63 HBoundsCheck* bounds_check2 = new (&allocator)
64 HBoundsCheck(parameter2, array_length, 0);
65 HArraySet* array_set = new (&allocator) HArraySet(
66 null_check, bounds_check2, constant_1, Primitive::kPrimInt, 0);
67 block2->AddInstruction(null_check);
68 block2->AddInstruction(array_length);
69 block2->AddInstruction(bounds_check2);
70 block2->AddInstruction(array_set);
71
72 HBasicBlock* block3 = new (&allocator) HBasicBlock(graph);
73 graph->AddBlock(block3);
74 null_check = new (&allocator) HNullCheck(parameter1, 0);
75 array_length = new (&allocator) HArrayLength(null_check);
76 cmp = new (&allocator) HLessThan(parameter2, array_length);
77 if_inst = new (&allocator) HIf(cmp);
78 block3->AddInstruction(null_check);
79 block3->AddInstruction(array_length);
80 block3->AddInstruction(cmp);
81 block3->AddInstruction(if_inst);
82
83 HBasicBlock* block4 = new (&allocator) HBasicBlock(graph);
84 graph->AddBlock(block4);
85 null_check = new (&allocator) HNullCheck(parameter1, 0);
86 array_length = new (&allocator) HArrayLength(null_check);
87 HBoundsCheck* bounds_check4 = new (&allocator)
88 HBoundsCheck(parameter2, array_length, 0);
89 array_set = new (&allocator) HArraySet(
90 null_check, bounds_check4, constant_1, Primitive::kPrimInt, 0);
91 block4->AddInstruction(null_check);
92 block4->AddInstruction(array_length);
93 block4->AddInstruction(bounds_check4);
94 block4->AddInstruction(array_set);
95
96 HBasicBlock* block5 = new (&allocator) HBasicBlock(graph);
97 graph->AddBlock(block5);
98 null_check = new (&allocator) HNullCheck(parameter1, 0);
99 array_length = new (&allocator) HArrayLength(null_check);
100 HBoundsCheck* bounds_check5 = new (&allocator)
101 HBoundsCheck(parameter2, array_length, 0);
102 array_set = new (&allocator) HArraySet(
103 null_check, bounds_check5, constant_1, Primitive::kPrimInt, 0);
104 block5->AddInstruction(null_check);
105 block5->AddInstruction(array_length);
106 block5->AddInstruction(bounds_check5);
107 block5->AddInstruction(array_set);
108
109 HBasicBlock* exit = new (&allocator) HBasicBlock(graph);
110 graph->AddBlock(exit);
111 block2->AddSuccessor(exit);
112 block4->AddSuccessor(exit);
113 block5->AddSuccessor(exit);
114 exit->AddInstruction(new (&allocator) HExit());
115
116 block1->AddSuccessor(block3); // True successor
117 block1->AddSuccessor(block2); // False successor
118
119 block3->AddSuccessor(block5); // True successor
120 block3->AddSuccessor(block4); // False successor
121
122 graph->BuildDominatorTree();
123 GlobalValueNumberer(&allocator, graph).Run();
124 BoundsCheckElimination bounds_check_elimination(graph);
125 bounds_check_elimination.Run();
126 ASSERT_FALSE(IsRemoved(bounds_check2));
127 ASSERT_FALSE(IsRemoved(bounds_check4));
128 ASSERT_TRUE(IsRemoved(bounds_check5));
129}
130
131// if (i > 0) {
132// // Positive number plus MAX_INT will overflow and be negative.
133// int j = i + Integer.MAX_VALUE;
134// if (j < array.length) array[j] = 1; // Can't eliminate.
135// }
136TEST(BoundsCheckEliminationTest, OverflowArrayBoundsElimination) {
137 ArenaPool pool;
138 ArenaAllocator allocator(&pool);
139
140 HGraph* graph = new (&allocator) HGraph(&allocator);
141
142 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
143 graph->AddBlock(entry);
144 graph->SetEntryBlock(entry);
145 HInstruction* parameter1 = new (&allocator)
146 HParameterValue(0, Primitive::kPrimNot); // array
147 HInstruction* parameter2 = new (&allocator)
148 HParameterValue(0, Primitive::kPrimInt); // i
149 HInstruction* constant_1 = new (&allocator) HIntConstant(1);
150 HInstruction* constant_0 = new (&allocator) HIntConstant(0);
151 HInstruction* constant_max_int = new (&allocator) HIntConstant(INT_MAX);
152 entry->AddInstruction(parameter1);
153 entry->AddInstruction(parameter2);
154 entry->AddInstruction(constant_1);
155 entry->AddInstruction(constant_0);
156 entry->AddInstruction(constant_max_int);
157
158 HBasicBlock* block1 = new (&allocator) HBasicBlock(graph);
159 graph->AddBlock(block1);
160 HInstruction* cmp = new (&allocator) HLessThanOrEqual(parameter2, constant_0);
161 HIf* if_inst = new (&allocator) HIf(cmp);
162 block1->AddInstruction(cmp);
163 block1->AddInstruction(if_inst);
164 entry->AddSuccessor(block1);
165
166 HBasicBlock* block2 = new (&allocator) HBasicBlock(graph);
167 graph->AddBlock(block2);
168 HInstruction* add = new (&allocator) HAdd(Primitive::kPrimInt, parameter2, constant_max_int);
169 HNullCheck* null_check = new (&allocator) HNullCheck(parameter1, 0);
170 HArrayLength* array_length = new (&allocator) HArrayLength(null_check);
171 HInstruction* cmp2 = new (&allocator) HGreaterThanOrEqual(add, array_length);
172 if_inst = new (&allocator) HIf(cmp2);
173 block2->AddInstruction(add);
174 block2->AddInstruction(null_check);
175 block2->AddInstruction(array_length);
176 block2->AddInstruction(cmp2);
177 block2->AddInstruction(if_inst);
178
179 HBasicBlock* block3 = new (&allocator) HBasicBlock(graph);
180 graph->AddBlock(block3);
181 HBoundsCheck* bounds_check = new (&allocator)
182 HBoundsCheck(add, array_length, 0);
183 HArraySet* array_set = new (&allocator) HArraySet(
184 null_check, bounds_check, constant_1, Primitive::kPrimInt, 0);
185 block3->AddInstruction(bounds_check);
186 block3->AddInstruction(array_set);
187
188 HBasicBlock* exit = new (&allocator) HBasicBlock(graph);
189 graph->AddBlock(exit);
190 exit->AddInstruction(new (&allocator) HExit());
Andreas Gampe0418b5b2014-12-04 17:24:50 -0800191 block1->AddSuccessor(exit); // true successor
192 block1->AddSuccessor(block2); // false successor
193 block2->AddSuccessor(exit); // true successor
194 block2->AddSuccessor(block3); // false successor
Mingyao Yangf384f882014-10-22 16:08:18 -0700195 block3->AddSuccessor(exit);
196
197 graph->BuildDominatorTree();
198 GlobalValueNumberer(&allocator, graph).Run();
199 BoundsCheckElimination bounds_check_elimination(graph);
200 bounds_check_elimination.Run();
201 ASSERT_FALSE(IsRemoved(bounds_check));
202}
203
204// if (i < array.length) {
205// int j = i - Integer.MAX_VALUE;
206// j = j - Integer.MAX_VALUE; // j is (i+2) after substracting MAX_INT twice
207// if (j > 0) array[j] = 1; // Can't eliminate.
208// }
209TEST(BoundsCheckEliminationTest, UnderflowArrayBoundsElimination) {
210 ArenaPool pool;
211 ArenaAllocator allocator(&pool);
212
213 HGraph* graph = new (&allocator) HGraph(&allocator);
214
215 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
216 graph->AddBlock(entry);
217 graph->SetEntryBlock(entry);
218 HInstruction* parameter1 = new (&allocator)
219 HParameterValue(0, Primitive::kPrimNot); // array
220 HInstruction* parameter2 = new (&allocator)
221 HParameterValue(0, Primitive::kPrimInt); // i
222 HInstruction* constant_1 = new (&allocator) HIntConstant(1);
223 HInstruction* constant_0 = new (&allocator) HIntConstant(0);
224 HInstruction* constant_max_int = new (&allocator) HIntConstant(INT_MAX);
225 entry->AddInstruction(parameter1);
226 entry->AddInstruction(parameter2);
227 entry->AddInstruction(constant_1);
228 entry->AddInstruction(constant_0);
229 entry->AddInstruction(constant_max_int);
230
231 HBasicBlock* block1 = new (&allocator) HBasicBlock(graph);
232 graph->AddBlock(block1);
233 HNullCheck* null_check = new (&allocator) HNullCheck(parameter1, 0);
234 HArrayLength* array_length = new (&allocator) HArrayLength(null_check);
235 HInstruction* cmp = new (&allocator) HGreaterThanOrEqual(parameter2, array_length);
236 HIf* if_inst = new (&allocator) HIf(cmp);
237 block1->AddInstruction(null_check);
238 block1->AddInstruction(array_length);
239 block1->AddInstruction(cmp);
240 block1->AddInstruction(if_inst);
241 entry->AddSuccessor(block1);
242
243 HBasicBlock* block2 = new (&allocator) HBasicBlock(graph);
244 graph->AddBlock(block2);
245 HInstruction* sub1 = new (&allocator) HSub(Primitive::kPrimInt, parameter2, constant_max_int);
246 HInstruction* sub2 = new (&allocator) HSub(Primitive::kPrimInt, sub1, constant_max_int);
247 HInstruction* cmp2 = new (&allocator) HLessThanOrEqual(sub2, constant_0);
248 if_inst = new (&allocator) HIf(cmp2);
249 block2->AddInstruction(sub1);
250 block2->AddInstruction(sub2);
251 block2->AddInstruction(cmp2);
252 block2->AddInstruction(if_inst);
253
254 HBasicBlock* block3 = new (&allocator) HBasicBlock(graph);
255 graph->AddBlock(block3);
256 HBoundsCheck* bounds_check = new (&allocator)
257 HBoundsCheck(sub2, array_length, 0);
258 HArraySet* array_set = new (&allocator) HArraySet(
259 null_check, bounds_check, constant_1, Primitive::kPrimInt, 0);
260 block3->AddInstruction(bounds_check);
261 block3->AddInstruction(array_set);
262
263 HBasicBlock* exit = new (&allocator) HBasicBlock(graph);
264 graph->AddBlock(exit);
265 exit->AddInstruction(new (&allocator) HExit());
Andreas Gampe0418b5b2014-12-04 17:24:50 -0800266 block1->AddSuccessor(exit); // true successor
267 block1->AddSuccessor(block2); // false successor
268 block2->AddSuccessor(exit); // true successor
269 block2->AddSuccessor(block3); // false successor
Mingyao Yangf384f882014-10-22 16:08:18 -0700270 block3->AddSuccessor(exit);
271
272 graph->BuildDominatorTree();
273 GlobalValueNumberer(&allocator, graph).Run();
274 BoundsCheckElimination bounds_check_elimination(graph);
275 bounds_check_elimination.Run();
276 ASSERT_FALSE(IsRemoved(bounds_check));
277}
278
279// array[5] = 1; // Can't eliminate.
280// array[4] = 1; // Can eliminate.
281// array[6] = 1; // Can't eliminate.
282TEST(BoundsCheckEliminationTest, ConstantArrayBoundsElimination) {
283 ArenaPool pool;
284 ArenaAllocator allocator(&pool);
285
286 HGraph* graph = new (&allocator) HGraph(&allocator);
287
288 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
289 graph->AddBlock(entry);
290 graph->SetEntryBlock(entry);
291 HInstruction* parameter = new (&allocator) HParameterValue(0, Primitive::kPrimNot);
292 HInstruction* constant_5 = new (&allocator) HIntConstant(5);
293 HInstruction* constant_4 = new (&allocator) HIntConstant(4);
294 HInstruction* constant_6 = new (&allocator) HIntConstant(6);
295 HInstruction* constant_1 = new (&allocator) HIntConstant(1);
296 entry->AddInstruction(parameter);
297 entry->AddInstruction(constant_5);
298 entry->AddInstruction(constant_4);
299 entry->AddInstruction(constant_6);
300 entry->AddInstruction(constant_1);
301
302 HBasicBlock* block = new (&allocator) HBasicBlock(graph);
303 graph->AddBlock(block);
304 entry->AddSuccessor(block);
305
306 HNullCheck* null_check = new (&allocator) HNullCheck(parameter, 0);
307 HArrayLength* array_length = new (&allocator) HArrayLength(null_check);
308 HBoundsCheck* bounds_check5 = new (&allocator)
309 HBoundsCheck(constant_5, array_length, 0);
310 HInstruction* array_set = new (&allocator) HArraySet(
311 null_check, bounds_check5, constant_1, Primitive::kPrimInt, 0);
312 block->AddInstruction(null_check);
313 block->AddInstruction(array_length);
314 block->AddInstruction(bounds_check5);
315 block->AddInstruction(array_set);
316
317 null_check = new (&allocator) HNullCheck(parameter, 0);
318 array_length = new (&allocator) HArrayLength(null_check);
319 HBoundsCheck* bounds_check4 = new (&allocator)
320 HBoundsCheck(constant_4, array_length, 0);
321 array_set = new (&allocator) HArraySet(
322 null_check, bounds_check4, constant_1, Primitive::kPrimInt, 0);
323 block->AddInstruction(null_check);
324 block->AddInstruction(array_length);
325 block->AddInstruction(bounds_check4);
326 block->AddInstruction(array_set);
327
328 null_check = new (&allocator) HNullCheck(parameter, 0);
329 array_length = new (&allocator) HArrayLength(null_check);
330 HBoundsCheck* bounds_check6 = new (&allocator)
331 HBoundsCheck(constant_6, array_length, 0);
332 array_set = new (&allocator) HArraySet(
333 null_check, bounds_check6, constant_1, Primitive::kPrimInt, 0);
334 block->AddInstruction(null_check);
335 block->AddInstruction(array_length);
336 block->AddInstruction(bounds_check6);
337 block->AddInstruction(array_set);
338
339 block->AddInstruction(new (&allocator) HGoto());
340
341 HBasicBlock* exit = new (&allocator) HBasicBlock(graph);
342 graph->AddBlock(exit);
343 block->AddSuccessor(exit);
344 exit->AddInstruction(new (&allocator) HExit());
345
346 graph->BuildDominatorTree();
347 GlobalValueNumberer(&allocator, graph).Run();
348 BoundsCheckElimination bounds_check_elimination(graph);
349 bounds_check_elimination.Run();
350 ASSERT_FALSE(IsRemoved(bounds_check5));
351 ASSERT_TRUE(IsRemoved(bounds_check4));
352 ASSERT_FALSE(IsRemoved(bounds_check6));
353}
354
355// for (int i=initial; i<array.length; i+=increment) { array[i] = 10; }
356static HGraph* BuildSSAGraph1(ArenaAllocator* allocator,
357 HInstruction** bounds_check,
358 int initial,
359 int increment,
360 IfCondition cond = kCondGE) {
361 HGraph* graph = new (allocator) HGraph(allocator);
362
363 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
364 graph->AddBlock(entry);
365 graph->SetEntryBlock(entry);
366 HInstruction* parameter = new (allocator) HParameterValue(0, Primitive::kPrimNot);
367 HInstruction* constant_initial = new (allocator) HIntConstant(initial);
368 HInstruction* constant_increment = new (allocator) HIntConstant(increment);
369 HInstruction* constant_10 = new (allocator) HIntConstant(10);
370 entry->AddInstruction(parameter);
371 entry->AddInstruction(constant_initial);
372 entry->AddInstruction(constant_increment);
373 entry->AddInstruction(constant_10);
374
375 HBasicBlock* block = new (allocator) HBasicBlock(graph);
376 graph->AddBlock(block);
377 entry->AddSuccessor(block);
378 block->AddInstruction(new (allocator) HGoto());
379
380 HBasicBlock* loop_header = new (allocator) HBasicBlock(graph);
381 HBasicBlock* loop_body = new (allocator) HBasicBlock(graph);
382 HBasicBlock* exit = new (allocator) HBasicBlock(graph);
383
384 graph->AddBlock(loop_header);
385 graph->AddBlock(loop_body);
386 graph->AddBlock(exit);
387 block->AddSuccessor(loop_header);
388 loop_header->AddSuccessor(exit); // true successor
389 loop_header->AddSuccessor(loop_body); // false successor
390 loop_body->AddSuccessor(loop_header);
391
392 HPhi* phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt);
393 phi->AddInput(constant_initial);
394 HInstruction* null_check = new (allocator) HNullCheck(parameter, 0);
395 HInstruction* array_length = new (allocator) HArrayLength(null_check);
396 HInstruction* cmp = nullptr;
397 if (cond == kCondGE) {
398 cmp = new (allocator) HGreaterThanOrEqual(phi, array_length);
399 } else {
400 DCHECK(cond == kCondGT);
401 cmp = new (allocator) HGreaterThan(phi, array_length);
402 }
403 HInstruction* if_inst = new (allocator) HIf(cmp);
404 loop_header->AddPhi(phi);
405 loop_header->AddInstruction(null_check);
406 loop_header->AddInstruction(array_length);
407 loop_header->AddInstruction(cmp);
408 loop_header->AddInstruction(if_inst);
409
410 null_check = new (allocator) HNullCheck(parameter, 0);
411 array_length = new (allocator) HArrayLength(null_check);
412 *bounds_check = new (allocator) HBoundsCheck(phi, array_length, 0);
413 HInstruction* array_set = new (allocator) HArraySet(
414 null_check, *bounds_check, constant_10, Primitive::kPrimInt, 0);
415
416 HInstruction* add = new (allocator) HAdd(Primitive::kPrimInt, phi, constant_increment);
417 loop_body->AddInstruction(null_check);
418 loop_body->AddInstruction(array_length);
419 loop_body->AddInstruction(*bounds_check);
420 loop_body->AddInstruction(array_set);
421 loop_body->AddInstruction(add);
422 loop_body->AddInstruction(new (allocator) HGoto());
423 phi->AddInput(add);
424
425 exit->AddInstruction(new (allocator) HExit());
426
427 return graph;
428}
429
430TEST(BoundsCheckEliminationTest, LoopArrayBoundsElimination1) {
431 ArenaPool pool;
432 ArenaAllocator allocator(&pool);
433
434 // for (int i=0; i<array.length; i++) { array[i] = 10; // Can eliminate with gvn. }
435 HInstruction* bounds_check = nullptr;
436 HGraph* graph = BuildSSAGraph1(&allocator, &bounds_check, 0, 1);
437 graph->BuildDominatorTree();
438 BoundsCheckElimination bounds_check_elimination(graph);
439 bounds_check_elimination.Run();
440 ASSERT_FALSE(IsRemoved(bounds_check));
441
442 // This time add gvn. Need gvn to eliminate the second
443 // HArrayLength which uses the null check as its input.
444 graph = BuildSSAGraph1(&allocator, &bounds_check, 0, 1);
445 graph->BuildDominatorTree();
446 GlobalValueNumberer(&allocator, graph).Run();
447 BoundsCheckElimination bounds_check_elimination_after_gvn(graph);
448 bounds_check_elimination_after_gvn.Run();
449 ASSERT_TRUE(IsRemoved(bounds_check));
450
451 // for (int i=1; i<array.length; i++) { array[i] = 10; // Can eliminate. }
452 graph = BuildSSAGraph1(&allocator, &bounds_check, 1, 1);
453 graph->BuildDominatorTree();
454 GlobalValueNumberer(&allocator, graph).Run();
455 BoundsCheckElimination bounds_check_elimination_with_initial_1(graph);
456 bounds_check_elimination_with_initial_1.Run();
457 ASSERT_TRUE(IsRemoved(bounds_check));
458
459 // for (int i=-1; i<array.length; i++) { array[i] = 10; // Can't eliminate. }
460 graph = BuildSSAGraph1(&allocator, &bounds_check, -1, 1);
461 graph->BuildDominatorTree();
462 GlobalValueNumberer(&allocator, graph).Run();
463 BoundsCheckElimination bounds_check_elimination_with_initial_minus_1(graph);
464 bounds_check_elimination_with_initial_minus_1.Run();
465 ASSERT_FALSE(IsRemoved(bounds_check));
466
467 // for (int i=0; i<=array.length; i++) { array[i] = 10; // Can't eliminate. }
468 graph = BuildSSAGraph1(&allocator, &bounds_check, 0, 1, kCondGT);
469 graph->BuildDominatorTree();
470 GlobalValueNumberer(&allocator, graph).Run();
471 BoundsCheckElimination bounds_check_elimination_with_greater_than(graph);
472 bounds_check_elimination_with_greater_than.Run();
473 ASSERT_FALSE(IsRemoved(bounds_check));
474
475 // for (int i=0; i<array.length; i += 2) {
476 // array[i] = 10; // Can't eliminate due to overflow concern. }
477 graph = BuildSSAGraph1(&allocator, &bounds_check, 0, 2);
478 graph->BuildDominatorTree();
479 GlobalValueNumberer(&allocator, graph).Run();
480 BoundsCheckElimination bounds_check_elimination_with_increment_2(graph);
481 bounds_check_elimination_with_increment_2.Run();
482 ASSERT_FALSE(IsRemoved(bounds_check));
483
484 // for (int i=1; i<array.length; i += 2) { array[i] = 10; // Can eliminate. }
485 graph = BuildSSAGraph1(&allocator, &bounds_check, 1, 2);
486 graph->BuildDominatorTree();
487 GlobalValueNumberer(&allocator, graph).Run();
488 BoundsCheckElimination bounds_check_elimination_with_increment_2_from_1(graph);
489 bounds_check_elimination_with_increment_2_from_1.Run();
490 ASSERT_TRUE(IsRemoved(bounds_check));
491}
492
493// for (int i=array.length; i>0; i+=increment) { array[i-1] = 10; }
494static HGraph* BuildSSAGraph2(ArenaAllocator* allocator,
495 HInstruction** bounds_check,
496 int initial,
497 int increment = -1,
498 IfCondition cond = kCondLE) {
499 HGraph* graph = new (allocator) HGraph(allocator);
500
501 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
502 graph->AddBlock(entry);
503 graph->SetEntryBlock(entry);
504 HInstruction* parameter = new (allocator) HParameterValue(0, Primitive::kPrimNot);
505 HInstruction* constant_initial = new (allocator) HIntConstant(initial);
506 HInstruction* constant_increment = new (allocator) HIntConstant(increment);
507 HInstruction* constant_minus_1 = new (allocator) HIntConstant(-1);
508 HInstruction* constant_10 = new (allocator) HIntConstant(10);
509 entry->AddInstruction(parameter);
510 entry->AddInstruction(constant_initial);
511 entry->AddInstruction(constant_increment);
512 entry->AddInstruction(constant_minus_1);
513 entry->AddInstruction(constant_10);
514
515 HBasicBlock* block = new (allocator) HBasicBlock(graph);
516 graph->AddBlock(block);
517 entry->AddSuccessor(block);
518 HInstruction* null_check = new (allocator) HNullCheck(parameter, 0);
519 HInstruction* array_length = new (allocator) HArrayLength(null_check);
520 block->AddInstruction(null_check);
521 block->AddInstruction(array_length);
522 block->AddInstruction(new (allocator) HGoto());
523
524 HBasicBlock* loop_header = new (allocator) HBasicBlock(graph);
525 HBasicBlock* loop_body = new (allocator) HBasicBlock(graph);
526 HBasicBlock* exit = new (allocator) HBasicBlock(graph);
527
528 graph->AddBlock(loop_header);
529 graph->AddBlock(loop_body);
530 graph->AddBlock(exit);
531 block->AddSuccessor(loop_header);
532 loop_header->AddSuccessor(exit); // true successor
533 loop_header->AddSuccessor(loop_body); // false successor
534 loop_body->AddSuccessor(loop_header);
535
536 HPhi* phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt);
537 phi->AddInput(array_length);
538 HInstruction* cmp = nullptr;
539 if (cond == kCondLE) {
540 cmp = new (allocator) HLessThanOrEqual(phi, constant_initial);
541 } else {
542 DCHECK(cond == kCondLT);
543 cmp = new (allocator) HLessThan(phi, constant_initial);
544 }
545 HInstruction* if_inst = new (allocator) HIf(cmp);
546 loop_header->AddPhi(phi);
547 loop_header->AddInstruction(cmp);
548 loop_header->AddInstruction(if_inst);
549
550 HInstruction* add = new (allocator) HAdd(Primitive::kPrimInt, phi, constant_minus_1);
551 null_check = new (allocator) HNullCheck(parameter, 0);
552 array_length = new (allocator) HArrayLength(null_check);
553 *bounds_check = new (allocator) HBoundsCheck(add, array_length, 0);
554 HInstruction* array_set = new (allocator) HArraySet(
555 null_check, *bounds_check, constant_10, Primitive::kPrimInt, 0);
556 HInstruction* add_phi = new (allocator) HAdd(Primitive::kPrimInt, phi, constant_increment);
557 loop_body->AddInstruction(add);
558 loop_body->AddInstruction(null_check);
559 loop_body->AddInstruction(array_length);
560 loop_body->AddInstruction(*bounds_check);
561 loop_body->AddInstruction(array_set);
562 loop_body->AddInstruction(add_phi);
563 loop_body->AddInstruction(new (allocator) HGoto());
564 phi->AddInput(add);
565
566 exit->AddInstruction(new (allocator) HExit());
567
568 return graph;
569}
570
571TEST(BoundsCheckEliminationTest, LoopArrayBoundsElimination2) {
572 ArenaPool pool;
573 ArenaAllocator allocator(&pool);
574
575 // for (int i=array.length; i>0; i--) { array[i-1] = 10; // Can eliminate with gvn. }
576 HInstruction* bounds_check = nullptr;
577 HGraph* graph = BuildSSAGraph2(&allocator, &bounds_check, 0);
578 graph->BuildDominatorTree();
579 BoundsCheckElimination bounds_check_elimination(graph);
580 bounds_check_elimination.Run();
581 ASSERT_FALSE(IsRemoved(bounds_check));
582
583 // This time add gvn. Need gvn to eliminate the second
584 // HArrayLength which uses the null check as its input.
585 graph = BuildSSAGraph2(&allocator, &bounds_check, 0);
586 graph->BuildDominatorTree();
587 GlobalValueNumberer(&allocator, graph).Run();
588 BoundsCheckElimination bounds_check_elimination_after_gvn(graph);
589 bounds_check_elimination_after_gvn.Run();
590 ASSERT_TRUE(IsRemoved(bounds_check));
591
592 // for (int i=array.length; i>1; i--) { array[i-1] = 10; // Can eliminate. }
593 graph = BuildSSAGraph2(&allocator, &bounds_check, 1);
594 graph->BuildDominatorTree();
595 GlobalValueNumberer(&allocator, graph).Run();
596 BoundsCheckElimination bounds_check_elimination_with_initial_1(graph);
597 bounds_check_elimination_with_initial_1.Run();
598 ASSERT_TRUE(IsRemoved(bounds_check));
599
600 // for (int i=array.length; i>-1; i--) { array[i-1] = 10; // Can't eliminate. }
601 graph = BuildSSAGraph2(&allocator, &bounds_check, -1);
602 graph->BuildDominatorTree();
603 GlobalValueNumberer(&allocator, graph).Run();
604 BoundsCheckElimination bounds_check_elimination_with_initial_minus_1(graph);
605 bounds_check_elimination_with_initial_minus_1.Run();
606 ASSERT_FALSE(IsRemoved(bounds_check));
607
608 // for (int i=array.length; i>=0; i--) { array[i-1] = 10; // Can't eliminate. }
609 graph = BuildSSAGraph2(&allocator, &bounds_check, 0, -1, kCondLT);
610 graph->BuildDominatorTree();
611 GlobalValueNumberer(&allocator, graph).Run();
612 BoundsCheckElimination bounds_check_elimination_with_less_than(graph);
613 bounds_check_elimination_with_less_than.Run();
614 ASSERT_FALSE(IsRemoved(bounds_check));
615
616 // for (int i=array.length; i>0; i-=2) { array[i-1] = 10; // Can eliminate. }
617 graph = BuildSSAGraph2(&allocator, &bounds_check, 0, -2);
618 graph->BuildDominatorTree();
619 GlobalValueNumberer(&allocator, graph).Run();
620 BoundsCheckElimination bounds_check_elimination_increment_minus_2(graph);
621 bounds_check_elimination_increment_minus_2.Run();
622 ASSERT_TRUE(IsRemoved(bounds_check));
623}
624
625// int[] array = new array[10];
626// for (int i=0; i<10; i+=increment) { array[i] = 10; }
627static HGraph* BuildSSAGraph3(ArenaAllocator* allocator,
628 HInstruction** bounds_check,
629 int initial,
630 int increment,
631 IfCondition cond) {
632 HGraph* graph = new (allocator) HGraph(allocator);
633
634 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
635 graph->AddBlock(entry);
636 graph->SetEntryBlock(entry);
637 HInstruction* constant_10 = new (allocator) HIntConstant(10);
638 HInstruction* constant_initial = new (allocator) HIntConstant(initial);
639 HInstruction* constant_increment = new (allocator) HIntConstant(increment);
640 entry->AddInstruction(constant_10);
641 entry->AddInstruction(constant_initial);
642 entry->AddInstruction(constant_increment);
643
644 HBasicBlock* block = new (allocator) HBasicBlock(graph);
645 graph->AddBlock(block);
646 entry->AddSuccessor(block);
647 HInstruction* new_array = new (allocator)
648 HNewArray(constant_10, 0, Primitive::kPrimInt);
649 block->AddInstruction(new_array);
650 block->AddInstruction(new (allocator) HGoto());
651
652 HBasicBlock* loop_header = new (allocator) HBasicBlock(graph);
653 HBasicBlock* loop_body = new (allocator) HBasicBlock(graph);
654 HBasicBlock* exit = new (allocator) HBasicBlock(graph);
655
656 graph->AddBlock(loop_header);
657 graph->AddBlock(loop_body);
658 graph->AddBlock(exit);
659 block->AddSuccessor(loop_header);
660 loop_header->AddSuccessor(exit); // true successor
661 loop_header->AddSuccessor(loop_body); // false successor
662 loop_body->AddSuccessor(loop_header);
663
664 HPhi* phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt);
665 phi->AddInput(constant_initial);
666 HInstruction* cmp = nullptr;
667 if (cond == kCondGE) {
668 cmp = new (allocator) HGreaterThanOrEqual(phi, constant_10);
669 } else {
670 DCHECK(cond == kCondGT);
671 cmp = new (allocator) HGreaterThan(phi, constant_10);
672 }
673 HInstruction* if_inst = new (allocator) HIf(cmp);
674 loop_header->AddPhi(phi);
675 loop_header->AddInstruction(cmp);
676 loop_header->AddInstruction(if_inst);
677
678 HNullCheck* null_check = new (allocator) HNullCheck(new_array, 0);
679 HArrayLength* array_length = new (allocator) HArrayLength(null_check);
680 *bounds_check = new (allocator) HBoundsCheck(phi, array_length, 0);
681 HInstruction* array_set = new (allocator) HArraySet(
682 null_check, *bounds_check, constant_10, Primitive::kPrimInt, 0);
683 HInstruction* add = new (allocator) HAdd(Primitive::kPrimInt, phi, constant_increment);
684 loop_body->AddInstruction(null_check);
685 loop_body->AddInstruction(array_length);
686 loop_body->AddInstruction(*bounds_check);
687 loop_body->AddInstruction(array_set);
688 loop_body->AddInstruction(add);
689 loop_body->AddInstruction(new (allocator) HGoto());
690 phi->AddInput(add);
691
692 exit->AddInstruction(new (allocator) HExit());
693
694 return graph;
695}
696
697TEST(BoundsCheckEliminationTest, LoopArrayBoundsElimination3) {
698 ArenaPool pool;
699 ArenaAllocator allocator(&pool);
700
701 // int[] array = new array[10];
702 // for (int i=0; i<10; i++) { array[i] = 10; // Can eliminate. }
703 HInstruction* bounds_check = nullptr;
704 HGraph* graph = BuildSSAGraph3(&allocator, &bounds_check, 0, 1, kCondGE);
705 graph->BuildDominatorTree();
706 GlobalValueNumberer(&allocator, graph).Run();
707 BoundsCheckElimination bounds_check_elimination_after_gvn(graph);
708 bounds_check_elimination_after_gvn.Run();
709 ASSERT_TRUE(IsRemoved(bounds_check));
710
711 // int[] array = new array[10];
712 // for (int i=1; i<10; i++) { array[i] = 10; // Can eliminate. }
713 graph = BuildSSAGraph3(&allocator, &bounds_check, 1, 1, kCondGE);
714 graph->BuildDominatorTree();
715 GlobalValueNumberer(&allocator, graph).Run();
716 BoundsCheckElimination bounds_check_elimination_with_initial_1(graph);
717 bounds_check_elimination_with_initial_1.Run();
718 ASSERT_TRUE(IsRemoved(bounds_check));
719
720 // int[] array = new array[10];
721 // for (int i=0; i<=10; i++) { array[i] = 10; // Can't eliminate. }
722 graph = BuildSSAGraph3(&allocator, &bounds_check, 0, 1, kCondGT);
723 graph->BuildDominatorTree();
724 GlobalValueNumberer(&allocator, graph).Run();
725 BoundsCheckElimination bounds_check_elimination_with_greater_than(graph);
726 bounds_check_elimination_with_greater_than.Run();
727 ASSERT_FALSE(IsRemoved(bounds_check));
728
729 // int[] array = new array[10];
730 // for (int i=1; i<10; i+=8) { array[i] = 10; // Can eliminate. }
731 graph = BuildSSAGraph3(&allocator, &bounds_check, 1, 8, kCondGE);
732 graph->BuildDominatorTree();
733 GlobalValueNumberer(&allocator, graph).Run();
734 BoundsCheckElimination bounds_check_elimination_increment_8(graph);
735 bounds_check_elimination_increment_8.Run();
736 ASSERT_TRUE(IsRemoved(bounds_check));
737}
738
739// for (int i=initial; i<array.length; i++) { array[array.length-i-1] = 10; }
740static HGraph* BuildSSAGraph4(ArenaAllocator* allocator,
741 HInstruction** bounds_check,
742 int initial,
743 IfCondition cond = kCondGE) {
744 HGraph* graph = new (allocator) HGraph(allocator);
745
746 HBasicBlock* entry = new (allocator) HBasicBlock(graph);
747 graph->AddBlock(entry);
748 graph->SetEntryBlock(entry);
749 HInstruction* parameter = new (allocator) HParameterValue(0, Primitive::kPrimNot);
750 HInstruction* constant_initial = new (allocator) HIntConstant(initial);
751 HInstruction* constant_1 = new (allocator) HIntConstant(1);
752 HInstruction* constant_10 = new (allocator) HIntConstant(10);
753 HInstruction* constant_minus_1 = new (allocator) HIntConstant(-1);
754 entry->AddInstruction(parameter);
755 entry->AddInstruction(constant_initial);
756 entry->AddInstruction(constant_1);
757 entry->AddInstruction(constant_10);
758 entry->AddInstruction(constant_minus_1);
759
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);
778 phi->AddInput(constant_initial);
779 HInstruction* null_check = new (allocator) HNullCheck(parameter, 0);
780 HInstruction* array_length = new (allocator) HArrayLength(null_check);
781 HInstruction* cmp = nullptr;
782 if (cond == kCondGE) {
783 cmp = new (allocator) HGreaterThanOrEqual(phi, array_length);
784 } else if (cond == kCondGT) {
785 cmp = new (allocator) HGreaterThan(phi, array_length);
786 }
787 HInstruction* if_inst = new (allocator) HIf(cmp);
788 loop_header->AddPhi(phi);
789 loop_header->AddInstruction(null_check);
790 loop_header->AddInstruction(array_length);
791 loop_header->AddInstruction(cmp);
792 loop_header->AddInstruction(if_inst);
793
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();
834 GlobalValueNumberer(&allocator, graph).Run();
835 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();
842 GlobalValueNumberer(&allocator, graph).Run();
843 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();
850 GlobalValueNumberer(&allocator, graph).Run();
851 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
871 HGraph* graph = new (&allocator) HGraph(&allocator);
872
873 HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
874 graph->AddBlock(entry);
875 graph->SetEntryBlock(entry);
876 HInstruction* parameter = new (&allocator) HParameterValue(0, Primitive::kPrimNot);
877 HInstruction* constant_0 = new (&allocator) HIntConstant(0);
878 HInstruction* constant_minus_1 = new (&allocator) HIntConstant(-1);
879 HInstruction* constant_1 = new (&allocator) HIntConstant(1);
880 entry->AddInstruction(parameter);
881 entry->AddInstruction(constant_0);
882 entry->AddInstruction(constant_minus_1);
883 entry->AddInstruction(constant_1);
884
885 HBasicBlock* block = new (&allocator) HBasicBlock(graph);
886 graph->AddBlock(block);
887 entry->AddSuccessor(block);
888 block->AddInstruction(new (&allocator) HGoto());
889
890 HBasicBlock* exit = new (&allocator) HBasicBlock(graph);
891 graph->AddBlock(exit);
892 exit->AddInstruction(new (&allocator) HExit());
893
894 HBasicBlock* outer_header = new (&allocator) HBasicBlock(graph);
895 graph->AddBlock(outer_header);
896 HPhi* phi_i = new (&allocator) HPhi(&allocator, 0, 0, Primitive::kPrimInt);
897 phi_i->AddInput(constant_0);
898 HNullCheck* null_check = new (&allocator) HNullCheck(parameter, 0);
899 HArrayLength* array_length = new (&allocator) HArrayLength(null_check);
900 HAdd* add = new (&allocator) HAdd(Primitive::kPrimInt, array_length, constant_minus_1);
901 HInstruction* cmp = new (&allocator) HGreaterThanOrEqual(phi_i, add);
902 HIf* if_inst = new (&allocator) HIf(cmp);
903 outer_header->AddPhi(phi_i);
904 outer_header->AddInstruction(null_check);
905 outer_header->AddInstruction(array_length);
906 outer_header->AddInstruction(add);
907 outer_header->AddInstruction(cmp);
908 outer_header->AddInstruction(if_inst);
909
910 HBasicBlock* inner_header = new (&allocator) HBasicBlock(graph);
911 graph->AddBlock(inner_header);
912 HPhi* phi_j = new (&allocator) HPhi(&allocator, 0, 0, Primitive::kPrimInt);
913 phi_j->AddInput(constant_0);
914 null_check = new (&allocator) HNullCheck(parameter, 0);
915 array_length = new (&allocator) HArrayLength(null_check);
916 HSub* sub = new (&allocator) HSub(Primitive::kPrimInt, array_length, phi_i);
917 add = new (&allocator) HAdd(Primitive::kPrimInt, sub, constant_minus_1);
918 cmp = new (&allocator) HGreaterThanOrEqual(phi_j, add);
919 if_inst = new (&allocator) HIf(cmp);
920 inner_header->AddPhi(phi_j);
921 inner_header->AddInstruction(null_check);
922 inner_header->AddInstruction(array_length);
923 inner_header->AddInstruction(sub);
924 inner_header->AddInstruction(add);
925 inner_header->AddInstruction(cmp);
926 inner_header->AddInstruction(if_inst);
927
928 HBasicBlock* inner_body_compare = new (&allocator) HBasicBlock(graph);
929 graph->AddBlock(inner_body_compare);
930 null_check = new (&allocator) HNullCheck(parameter, 0);
931 array_length = new (&allocator) HArrayLength(null_check);
932 HBoundsCheck* bounds_check1 = new (&allocator) HBoundsCheck(phi_j, array_length, 0);
933 HArrayGet* array_get_j = new (&allocator)
934 HArrayGet(null_check, bounds_check1, Primitive::kPrimInt);
935 inner_body_compare->AddInstruction(null_check);
936 inner_body_compare->AddInstruction(array_length);
937 inner_body_compare->AddInstruction(bounds_check1);
938 inner_body_compare->AddInstruction(array_get_j);
939 HInstruction* j_plus_1 = new (&allocator) HAdd(Primitive::kPrimInt, phi_j, constant_1);
940 null_check = new (&allocator) HNullCheck(parameter, 0);
941 array_length = new (&allocator) HArrayLength(null_check);
942 HBoundsCheck* bounds_check2 = new (&allocator) HBoundsCheck(j_plus_1, array_length, 0);
943 HArrayGet* array_get_j_plus_1 = new (&allocator)
944 HArrayGet(null_check, bounds_check2, Primitive::kPrimInt);
945 cmp = new (&allocator) HGreaterThanOrEqual(array_get_j, array_get_j_plus_1);
946 if_inst = new (&allocator) HIf(cmp);
947 inner_body_compare->AddInstruction(j_plus_1);
948 inner_body_compare->AddInstruction(null_check);
949 inner_body_compare->AddInstruction(array_length);
950 inner_body_compare->AddInstruction(bounds_check2);
951 inner_body_compare->AddInstruction(array_get_j_plus_1);
952 inner_body_compare->AddInstruction(cmp);
953 inner_body_compare->AddInstruction(if_inst);
954
955 HBasicBlock* inner_body_swap = new (&allocator) HBasicBlock(graph);
956 graph->AddBlock(inner_body_swap);
957 j_plus_1 = new (&allocator) HAdd(Primitive::kPrimInt, phi_j, constant_1);
958 // temp = array[j+1]
959 null_check = new (&allocator) HNullCheck(parameter, 0);
960 array_length = new (&allocator) HArrayLength(null_check);
961 HInstruction* bounds_check3 = new (&allocator) HBoundsCheck(j_plus_1, array_length, 0);
962 array_get_j_plus_1 = new (&allocator)
963 HArrayGet(null_check, bounds_check3, Primitive::kPrimInt);
964 inner_body_swap->AddInstruction(j_plus_1);
965 inner_body_swap->AddInstruction(null_check);
966 inner_body_swap->AddInstruction(array_length);
967 inner_body_swap->AddInstruction(bounds_check3);
968 inner_body_swap->AddInstruction(array_get_j_plus_1);
969 // array[j+1] = array[j]
970 null_check = new (&allocator) HNullCheck(parameter, 0);
971 array_length = new (&allocator) HArrayLength(null_check);
972 HInstruction* bounds_check4 = new (&allocator) HBoundsCheck(phi_j, array_length, 0);
973 array_get_j = new (&allocator)
974 HArrayGet(null_check, bounds_check4, Primitive::kPrimInt);
975 inner_body_swap->AddInstruction(null_check);
976 inner_body_swap->AddInstruction(array_length);
977 inner_body_swap->AddInstruction(bounds_check4);
978 inner_body_swap->AddInstruction(array_get_j);
979 null_check = new (&allocator) HNullCheck(parameter, 0);
980 array_length = new (&allocator) HArrayLength(null_check);
981 HInstruction* bounds_check5 = new (&allocator) HBoundsCheck(j_plus_1, array_length, 0);
982 HArraySet* array_set_j_plus_1 = new (&allocator)
983 HArraySet(null_check, bounds_check5, array_get_j, Primitive::kPrimInt, 0);
984 inner_body_swap->AddInstruction(null_check);
985 inner_body_swap->AddInstruction(array_length);
986 inner_body_swap->AddInstruction(bounds_check5);
987 inner_body_swap->AddInstruction(array_set_j_plus_1);
988 // array[j] = temp
989 null_check = new (&allocator) HNullCheck(parameter, 0);
990 array_length = new (&allocator) HArrayLength(null_check);
991 HInstruction* bounds_check6 = new (&allocator) HBoundsCheck(phi_j, array_length, 0);
992 HArraySet* array_set_j = new (&allocator)
993 HArraySet(null_check, bounds_check6, array_get_j_plus_1, Primitive::kPrimInt, 0);
994 inner_body_swap->AddInstruction(null_check);
995 inner_body_swap->AddInstruction(array_length);
996 inner_body_swap->AddInstruction(bounds_check6);
997 inner_body_swap->AddInstruction(array_set_j);
998 inner_body_swap->AddInstruction(new (&allocator) HGoto());
999
1000 HBasicBlock* inner_body_add = new (&allocator) HBasicBlock(graph);
1001 graph->AddBlock(inner_body_add);
1002 add = new (&allocator) HAdd(Primitive::kPrimInt, phi_j, constant_1);
1003 inner_body_add->AddInstruction(add);
1004 inner_body_add->AddInstruction(new (&allocator) HGoto());
1005 phi_j->AddInput(add);
1006
1007 HBasicBlock* outer_body_add = new (&allocator) HBasicBlock(graph);
1008 graph->AddBlock(outer_body_add);
1009 add = new (&allocator) HAdd(Primitive::kPrimInt, phi_i, constant_1);
1010 outer_body_add->AddInstruction(add);
1011 outer_body_add->AddInstruction(new (&allocator) HGoto());
1012 phi_i->AddInput(add);
1013
1014 block->AddSuccessor(outer_header);
1015 outer_header->AddSuccessor(exit);
1016 outer_header->AddSuccessor(inner_header);
1017 inner_header->AddSuccessor(outer_body_add);
1018 inner_header->AddSuccessor(inner_body_compare);
1019 inner_body_compare->AddSuccessor(inner_body_add);
1020 inner_body_compare->AddSuccessor(inner_body_swap);
1021 inner_body_swap->AddSuccessor(inner_body_add);
1022 inner_body_add->AddSuccessor(inner_header);
1023 outer_body_add->AddSuccessor(outer_header);
1024
1025 graph->BuildDominatorTree();
1026 GlobalValueNumberer(&allocator, graph).Run();
1027 // gvn should remove the same bounds check.
1028 ASSERT_FALSE(IsRemoved(bounds_check1));
1029 ASSERT_FALSE(IsRemoved(bounds_check2));
1030 ASSERT_TRUE(IsRemoved(bounds_check3));
1031 ASSERT_TRUE(IsRemoved(bounds_check4));
1032 ASSERT_TRUE(IsRemoved(bounds_check5));
1033 ASSERT_TRUE(IsRemoved(bounds_check6));
1034
1035 BoundsCheckElimination bounds_check_elimination(graph);
1036 bounds_check_elimination.Run();
1037 ASSERT_TRUE(IsRemoved(bounds_check1));
1038 ASSERT_TRUE(IsRemoved(bounds_check2));
1039 ASSERT_TRUE(IsRemoved(bounds_check3));
1040 ASSERT_TRUE(IsRemoved(bounds_check4));
1041 ASSERT_TRUE(IsRemoved(bounds_check5));
1042 ASSERT_TRUE(IsRemoved(bounds_check6));
1043}
1044
1045} // namespace art