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