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