blob: 64be1a2be4db7546408d3fd4fb39bdfa7d846eb1 [file] [log] [blame]
Nicolas Geoffraybef5eba2016-02-25 12:40:27 +00001/*
2 * Copyright (C) 2015 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//
18// Test on loop optimizations.
19//
20public class Main {
21
22 static int sResult;
23
24 //
25 // Various sequence variables used in bound checks.
26 //
27
28 /// CHECK-START: void Main.bubble(int[]) BCE (before)
29 /// CHECK-DAG: BoundsCheck
30 /// CHECK-DAG: BoundsCheck
31 //
32 /// CHECK-START: void Main.bubble(int[]) BCE (after)
33 /// CHECK-NOT: BoundsCheck
34 // TODO: also CHECK-NOT: Deoptimize, see b/27151190
35 private static void bubble(int[] a) {
36 for (int i = a.length; --i >= 0;) {
37 for (int j = 0; j < i; j++) {
38 if (a[j] > a[j+1]) {
39 int tmp = a[j];
40 a[j] = a[j+1];
41 a[j+1] = tmp;
42 }
43 }
44 }
45 }
46
47 /// CHECK-START: int Main.periodicIdiom(int) BCE (before)
48 /// CHECK-DAG: BoundsCheck
49 //
50 /// CHECK-START: int Main.periodicIdiom(int) BCE (after)
51 /// CHECK-NOT: BoundsCheck
52 /// CHECK-NOT: Deoptimize
53 private static int periodicIdiom(int tc) {
54 int[] x = { 1, 3 };
55 // Loop with periodic sequence (0, 1).
56 int k = 0;
57 int result = 0;
58 for (int i = 0; i < tc; i++) {
59 result += x[k];
60 k = 1 - k;
61 }
62 return result;
63 }
64
65 /// CHECK-START: int Main.periodicSequence2(int) BCE (before)
66 /// CHECK-DAG: BoundsCheck
67 //
68 /// CHECK-START: int Main.periodicSequence2(int) BCE (after)
69 /// CHECK-NOT: BoundsCheck
70 /// CHECK-NOT: Deoptimize
71 private static int periodicSequence2(int tc) {
72 int[] x = { 1, 3 };
73 // Loop with periodic sequence (0, 1).
74 int k = 0;
75 int l = 1;
76 int result = 0;
77 for (int i = 0; i < tc; i++) {
78 result += x[k];
79 int t = l;
80 l = k;
81 k = t;
82 }
83 return result;
84 }
85
86 /// CHECK-START: int Main.periodicSequence4(int) BCE (before)
87 /// CHECK-DAG: BoundsCheck
88 /// CHECK-DAG: BoundsCheck
89 /// CHECK-DAG: BoundsCheck
90 /// CHECK-DAG: BoundsCheck
91 //
92 /// CHECK-START: int Main.periodicSequence4(int) BCE (after)
93 /// CHECK-NOT: BoundsCheck
94 /// CHECK-NOT: Deoptimize
95 private static int periodicSequence4(int tc) {
96 int[] x = { 1, 3, 5, 7 };
97 // Loop with periodic sequence (0, 1, 2, 3).
98 int k = 0;
99 int l = 1;
100 int m = 2;
101 int n = 3;
102 int result = 0;
103 for (int i = 0; i < tc; i++) {
104 result += x[k] + x[l] + x[m] + x[n]; // all used at once
105 int t = n;
106 n = k;
107 k = l;
108 l = m;
109 m = t;
110 }
111 return result;
112 }
113
114 /// CHECK-START: int Main.justRightUp1() BCE (before)
115 /// CHECK-DAG: BoundsCheck
116 //
117 /// CHECK-START: int Main.justRightUp1() BCE (after)
118 /// CHECK-NOT: BoundsCheck
119 /// CHECK-NOT: Deoptimize
120 private static int justRightUp1() {
121 int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
122 int result = 0;
123 for (int i = Integer.MAX_VALUE - 10, k = 0; i < Integer.MAX_VALUE; i++) {
124 result += x[k++];
125 }
126 return result;
127 }
128
129 /// CHECK-START: int Main.justRightUp2() BCE (before)
130 /// CHECK-DAG: BoundsCheck
131 //
132 /// CHECK-START: int Main.justRightUp2() BCE (after)
133 /// CHECK-NOT: BoundsCheck
134 /// CHECK-NOT: Deoptimize
135 private static int justRightUp2() {
136 int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
137 int result = 0;
138 for (int i = Integer.MAX_VALUE - 10; i < Integer.MAX_VALUE; i++) {
139 result += x[i - Integer.MAX_VALUE + 10];
140 }
141 return result;
142 }
143
144 /// CHECK-START: int Main.justRightUp3() BCE (before)
145 /// CHECK-DAG: BoundsCheck
146 //
147 /// CHECK-START: int Main.justRightUp3() BCE (after)
148 /// CHECK-NOT: BoundsCheck
149 /// CHECK-NOT: Deoptimize
150 private static int justRightUp3() {
151 int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
152 int result = 0;
153 for (int i = Integer.MAX_VALUE - 10, k = 0; i <= Integer.MAX_VALUE - 1; i++) {
154 result += x[k++];
155 }
156 return result;
157 }
158
159 /// CHECK-START: int Main.justOOBUp() BCE (before)
160 /// CHECK-DAG: BoundsCheck
161 //
162 /// CHECK-START: int Main.justOOBUp() BCE (after)
163 /// CHECK-DAG: BoundsCheck
164 //
165 /// CHECK-START: int Main.justOOBUp() BCE (after)
166 /// CHECK-NOT: Deoptimize
167 private static int justOOBUp() {
168 int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
169 int result = 0;
170 // Infinite loop!
171 for (int i = Integer.MAX_VALUE - 9, k = 0; i <= Integer.MAX_VALUE; i++) {
172 result += x[k++];
173 }
174 return result;
175 }
176
177 /// CHECK-START: int Main.justRightDown1() BCE (before)
178 /// CHECK-DAG: BoundsCheck
179 //
180 /// CHECK-START: int Main.justRightDown1() BCE (after)
181 /// CHECK-NOT: BoundsCheck
182 /// CHECK-NOT: Deoptimize
183 private static int justRightDown1() {
184 int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
185 int result = 0;
186 for (int i = Integer.MIN_VALUE + 10, k = 0; i > Integer.MIN_VALUE; i--) {
187 result += x[k++];
188 }
189 return result;
190 }
191
192 /// CHECK-START: int Main.justRightDown2() BCE (before)
193 /// CHECK-DAG: BoundsCheck
194 //
195 /// CHECK-START: int Main.justRightDown2() BCE (after)
196 /// CHECK-NOT: BoundsCheck
197 /// CHECK-NOT: Deoptimize
198 private static int justRightDown2() {
199 int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
200 int result = 0;
201 for (int i = Integer.MIN_VALUE + 10; i > Integer.MIN_VALUE; i--) {
202 result += x[Integer.MAX_VALUE + i];
203 }
204 return result;
205 }
206
207 /// CHECK-START: int Main.justRightDown3() BCE (before)
208 /// CHECK-DAG: BoundsCheck
209 //
210 /// CHECK-START: int Main.justRightDown3() BCE (after)
211 /// CHECK-NOT: BoundsCheck
212 /// CHECK-NOT: Deoptimize
213 private static int justRightDown3() {
214 int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
215 int result = 0;
216 for (int i = Integer.MIN_VALUE + 10, k = 0; i >= Integer.MIN_VALUE + 1; i--) {
217 result += x[k++];
218 }
219 return result;
220 }
221
222 /// CHECK-START: int Main.justOOBDown() BCE (before)
223 /// CHECK-DAG: BoundsCheck
224 //
225 /// CHECK-START: int Main.justOOBDown() BCE (after)
226 /// CHECK-DAG: BoundsCheck
227 //
228 /// CHECK-START: int Main.justOOBDown() BCE (after)
229 /// CHECK-NOT: Deoptimize
230 private static int justOOBDown() {
231 int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
232 int result = 0;
233 // Infinite loop!
234 for (int i = Integer.MIN_VALUE + 9, k = 0; i >= Integer.MIN_VALUE; i--) {
235 result += x[k++];
236 }
237 return result;
238 }
239
240 /// CHECK-START: void Main.lowerOOB(int[]) BCE (before)
241 /// CHECK-DAG: BoundsCheck
242 //
243 /// CHECK-START: void Main.lowerOOB(int[]) BCE (after)
244 /// CHECK-DAG: BoundsCheck
245 //
246 /// CHECK-START: void Main.lowerOOB(int[]) BCE (after)
247 /// CHECK-NOT: Deoptimize
248 private static void lowerOOB(int[] x) {
249 // OOB!
250 for (int i = -1; i < x.length; i++) {
251 sResult += x[i];
252 }
253 }
254
255 /// CHECK-START: void Main.upperOOB(int[]) BCE (before)
256 /// CHECK-DAG: BoundsCheck
257 //
258 /// CHECK-START: void Main.upperOOB(int[]) BCE (after)
259 /// CHECK-DAG: BoundsCheck
260 //
261 /// CHECK-START: void Main.upperOOB(int[]) BCE (after)
262 /// CHECK-NOT: Deoptimize
263 private static void upperOOB(int[] x) {
264 // OOB!
265 for (int i = 0; i <= x.length; i++) {
266 sResult += x[i];
267 }
268 }
269
270 /// CHECK-START: void Main.doWhileUpOOB() BCE (before)
271 /// CHECK-DAG: BoundsCheck
272 //
273 /// CHECK-START: void Main.doWhileUpOOB() BCE (after)
274 /// CHECK-DAG: BoundsCheck
275 //
276 /// CHECK-START: void Main.doWhileUpOOB() BCE (after)
277 /// CHECK-NOT: Deoptimize
278 private static void doWhileUpOOB() {
279 int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
280 int i = 0;
281 // OOB!
282 do {
283 sResult += x[i++];
284 } while (i <= x.length);
285 }
286
287 /// CHECK-START: void Main.doWhileDownOOB() BCE (before)
288 /// CHECK-DAG: BoundsCheck
289 //
290 /// CHECK-START: void Main.doWhileDownOOB() BCE (after)
291 /// CHECK-DAG: BoundsCheck
292 //
293 /// CHECK-START: void Main.doWhileDownOOB() BCE (after)
294 /// CHECK-NOT: Deoptimize
295 private static void doWhileDownOOB() {
296 int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
297 int i = x.length - 1;
298 // OOB!
299 do {
300 sResult += x[i--];
301 } while (-1 <= i);
302 }
303
304 /// CHECK-START: void Main.hiddenOOB1(int) BCE (before)
305 /// CHECK-DAG: BoundsCheck
306 //
307 /// CHECK-START: void Main.hiddenOOB1(int) BCE (after)
308 /// CHECK-DAG: Deoptimize
309 //
310 /// CHECK-START: void Main.hiddenOOB1(int) BCE (after)
311 /// CHECK-NOT: BoundsCheck
312 private static void hiddenOOB1(int lo) {
313 int[] a = { 1 } ;
314 for (int i = lo; i <= 10; i++) {
315 // Dangerous loop where careless static range analysis would yield strict upper bound
316 // on index j of 5. When, for instance, lo and thus i = -2147483648, the upper bound
317 // becomes really positive due to arithmetic wrap-around, causing OOB.
318 // Dynamic BCE is feasible though, since it checks the range.
319 for (int j = 4; j < i - 5; j++) {
320 sResult += a[j - 4];
321 }
322 }
323 }
324
325 /// CHECK-START: void Main.hiddenOOB2(int) BCE (before)
326 /// CHECK-DAG: BoundsCheck
327 //
328 /// CHECK-START: void Main.hiddenOOB2(int) BCE (after)
329 /// CHECK-DAG: Deoptimize
330 //
331 /// CHECK-START: void Main.hiddenOOB2(int) BCE (after)
332 /// CHECK-NOT: BoundsCheck
333 private static void hiddenOOB2(int hi) {
334 int[] a = { 1 } ;
335 for (int i = 0; i < hi; i++) {
336 // Dangerous loop where careless static range analysis would yield strict lower bound
337 // on index j of 5. When, for instance, hi and thus i = 2147483647, the upper bound
338 // becomes really negative due to arithmetic wrap-around, causing OOB.
339 // Dynamic BCE is feasible though, since it checks the range.
340 for (int j = 6; j > i + 5; j--) {
341 sResult += a[j - 6];
342 }
343 }
344 }
345
346 /// CHECK-START: void Main.hiddenInfiniteOOB() BCE (before)
347 /// CHECK-DAG: BoundsCheck
348 //
349 /// CHECK-START: void Main.hiddenInfiniteOOB() BCE (after)
350 /// CHECK-DAG: BoundsCheck
351 //
352 /// CHECK-START: void Main.hiddenInfiniteOOB() BCE (after)
353 /// CHECK-NOT: Deoptimize
354 private static void hiddenInfiniteOOB() {
355 int[] a = { 11 } ;
356 for (int i = -1; i <= 0; i++) {
357 // Dangerous loop where careless static range analysis would yield a safe upper bound
358 // of -3. In reality, due to arithmetic wrap-around (when i = -1, j <= 2147483647;
359 // whereas when i = 0, j <= -3), this is an infinite loop that goes OOB.
360 for (int j = -3; j <= 2147483646 * i - 3; j++) {
361 sResult += a[j + 3];
362 }
363 }
364 }
365
366 /// CHECK-START: void Main.hiddenFiniteOOB() BCE (before)
367 /// CHECK-DAG: BoundsCheck
368 //
369 /// CHECK-START: void Main.hiddenFiniteOOB() BCE (after)
370 /// CHECK-DAG: Deoptimize
371 //
372 /// CHECK-START: void Main.hiddenFiniteOOB() BCE (after)
373 /// CHECK-NOT: BoundsCheck
374 private static void hiddenFiniteOOB() {
375 int[] a = { 111 } ;
376 for (int i = -1; i <= 0; i++) {
377 // Dangerous loop similar as above where the loop is now finite, but the
378 // loop still goes out of bounds for i = -1 due to the large upper bound.
379 // Dynamic BCE is feasible though, since it checks the range.
380 for (int j = -4; j < 2147483646 * i - 3; j++) {
381 sResult += a[j + 4];
382 }
383 }
384 }
385
386 /// CHECK-START: int[] Main.add() BCE (before)
387 /// CHECK-DAG: BoundsCheck
388 //
389 /// CHECK-START: int[] Main.add() BCE (after)
390 /// CHECK-NOT: BoundsCheck
391 /// CHECK-NOT: Deoptimize
392 private static int[] add() {
393 int[] a = new int[10];
394 for (int i = 0; i <= 3; i++) {
395 for (int j = 0; j <= 6; j++) {
396 a[i + j] += 1;
397 }
398 }
399 return a;
400 }
401
402 /// CHECK-START: int[] Main.multiply1() BCE (before)
403 /// CHECK-DAG: BoundsCheck
404 //
405 /// CHECK-START: int[] Main.multiply1() BCE (after)
406 /// CHECK-NOT: BoundsCheck
407 /// CHECK-NOT: Deoptimize
408 private static int[] multiply1() {
409 int[] a = new int[10];
410 try {
411 for (int i = 0; i <= 3; i++) {
412 for (int j = 0; j <= 3; j++) {
413 // Range [0,9]: safe.
414 a[i * j] += 1;
415 }
416 }
417 } catch (Exception e) {
418 a[0] += 1000;
419 }
420 return a;
421 }
422
423 /// CHECK-START: int[] Main.multiply2() BCE (before)
424 /// CHECK-DAG: BoundsCheck
425 //
426 /// CHECK-START: int[] Main.multiply2() BCE (after)
427 /// CHECK-DAG: BoundsCheck
428 //
429 /// CHECK-START: int[] Main.multiply2() BCE (after)
430 /// CHECK-NOT: Deoptimize
431 static int[] multiply2() {
432 int[] a = new int[10];
433 try {
434 for (int i = -3; i <= 3; i++) {
435 for (int j = -3; j <= 3; j++) {
436 // Range [-9,9]: unsafe.
437 a[i * j] += 1;
438 }
439 }
440 } catch (Exception e) {
441 a[0] += 1000;
442 }
443 return a;
444 }
445
446 /// CHECK-START: int Main.linearDynamicBCE1(int[], int, int) BCE (before)
447 /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>>
448 /// CHECK-DAG: NullCheck loop:<<Loop>>
449 /// CHECK-DAG: ArrayLength loop:<<Loop>>
450 /// CHECK-DAG: BoundsCheck loop:<<Loop>>
451 //
452 /// CHECK-START: int Main.linearDynamicBCE1(int[], int, int) BCE (after)
453 /// CHECK-DAG: ArrayGet loop:{{B\d+}}
454 /// CHECK-DAG: Deoptimize loop:none
455 //
456 /// CHECK-START: int Main.linearDynamicBCE1(int[], int, int) BCE (after)
457 /// CHECK-NOT: NullCheck loop:{{B\d+}}
458 /// CHECK-NOT: ArrayLength loop:{{B\d+}}
459 /// CHECK-NOT: BoundsCheck loop:{{B\d+}}
460 private static int linearDynamicBCE1(int[] x, int lo, int hi) {
461 int result = 0;
462 for (int i = lo; i < hi; i++) {
463 sResult += x[i];
464 }
465 return result;
466 }
467
468 /// CHECK-START: int Main.linearDynamicBCE2(int[], int, int, int) BCE (before)
469 /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>>
470 /// CHECK-DAG: NullCheck loop:<<Loop>>
471 /// CHECK-DAG: ArrayLength loop:<<Loop>>
472 /// CHECK-DAG: BoundsCheck loop:<<Loop>>
473 //
474 /// CHECK-START: int Main.linearDynamicBCE2(int[], int, int, int) BCE (after)
475 /// CHECK-DAG: ArrayGet loop:{{B\d+}}
476 /// CHECK-DAG: Deoptimize loop:none
477 //
478 /// CHECK-START: int Main.linearDynamicBCE2(int[], int, int, int) BCE (after)
479 /// CHECK-NOT: NullCheck loop:{{B\d+}}
480 /// CHECK-NOT: ArrayLength loop:{{B\d+}}
481 /// CHECK-NOT: BoundsCheck loop:{{B\d+}}
482 private static int linearDynamicBCE2(int[] x, int lo, int hi, int offset) {
483 int result = 0;
484 for (int i = lo; i < hi; i++) {
485 sResult += x[offset + i];
486 }
487 return result;
488 }
489
490 /// CHECK-START: int Main.wrapAroundDynamicBCE(int[]) BCE (before)
491 /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>>
492 /// CHECK-DAG: NullCheck loop:<<Loop>>
493 /// CHECK-DAG: ArrayLength loop:<<Loop>>
494 /// CHECK-DAG: BoundsCheck loop:<<Loop>>
495 //
496 /// CHECK-START: int Main.wrapAroundDynamicBCE(int[]) BCE (after)
497 /// CHECK-DAG: ArrayGet loop:{{B\d+}}
498 /// CHECK-DAG: Deoptimize loop:none
499 //
500 /// CHECK-START: int Main.wrapAroundDynamicBCE(int[]) BCE (after)
501 /// CHECK-NOT: NullCheck loop:{{B\d+}}
502 /// CHECK-NOT: ArrayLength loop:{{B\d+}}
503 /// CHECK-NOT: BoundsCheck loop:{{B\d+}}
504 private static int wrapAroundDynamicBCE(int[] x) {
505 int w = 9;
506 int result = 0;
507 for (int i = 0; i < 10; i++) {
508 result += x[w];
509 w = i;
510 }
511 return result;
512 }
513
514 /// CHECK-START: int Main.periodicDynamicBCE(int[]) BCE (before)
515 /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>>
516 /// CHECK-DAG: NullCheck loop:<<Loop>>
517 /// CHECK-DAG: ArrayLength loop:<<Loop>>
518 /// CHECK-DAG: BoundsCheck loop:<<Loop>>
519 //
520 /// CHECK-START: int Main.periodicDynamicBCE(int[]) BCE (after)
521 /// CHECK-DAG: ArrayGet loop:{{B\d+}}
522 /// CHECK-DAG: Deoptimize loop:none
523 //
524 /// CHECK-START: int Main.periodicDynamicBCE(int[]) BCE (after)
525 /// CHECK-NOT: NullCheck loop:{{B\d+}}
526 /// CHECK-NOT: ArrayLength loop:{{B\d+}}
527 /// CHECK-NOT: BoundsCheck loop:{{B\d+}}
528 private static int periodicDynamicBCE(int[] x) {
529 int k = 0;
530 int result = 0;
531 for (int i = 0; i < 10; i++) {
532 result += x[k];
533 k = 1 - k;
534 }
535 return result;
536 }
537
538 /// CHECK-START: int Main.dynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (before)
539 /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>>
540 /// CHECK-DAG: NullCheck loop:<<Loop>>
541 /// CHECK-DAG: ArrayLength loop:<<Loop>>
542 /// CHECK-DAG: BoundsCheck loop:<<Loop>>
543 //
544 /// CHECK-START: int Main.dynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (after)
545 /// CHECK-DAG: ArrayGet loop:{{B\d+}}
546 /// CHECK-DAG: Deoptimize loop:none
547 //
548 /// CHECK-START: int Main.dynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (after)
549 /// CHECK-NOT: NullCheck loop:{{B\d+}}
550 /// CHECK-NOT: ArrayLength loop:{{B\d+}}
551 /// CHECK-NOT: BoundsCheck loop:{{B\d+}}
552 static int dynamicBCEPossiblyInfiniteLoop(int[] x, int lo, int hi) {
553 // This loop could be infinite for hi = max int. Since i is also used
554 // as subscript, however, dynamic bce can proceed.
555 int result = 0;
556 for (int i = lo; i <= hi; i++) {
557 result += x[i];
558 }
559 return result;
560 }
561
562 /// CHECK-START: int Main.noDynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (before)
563 /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>>
564 /// CHECK-DAG: BoundsCheck loop:<<Loop>>
565 //
566 /// CHECK-START: int Main.noDynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (after)
567 /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>>
568 /// CHECK-DAG: BoundsCheck loop:<<Loop>>
569 //
570 /// CHECK-START: int Main.noDynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (after)
571 /// CHECK-NOT: Deoptimize
572 static int noDynamicBCEPossiblyInfiniteLoop(int[] x, int lo, int hi) {
573 // As above, but now the index is not used as subscript,
574 // and dynamic bce is not applied.
575 int result = 0;
576 for (int k = 0, i = lo; i <= hi; i++) {
577 result += x[k++];
578 }
579 return result;
580 }
581
582 /// CHECK-START: int Main.noDynamicBCEMixedInductionTypes(int[], long, long) BCE (before)
583 /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>>
584 /// CHECK-DAG: BoundsCheck loop:<<Loop>>
585 //
586 /// CHECK-START: int Main.noDynamicBCEMixedInductionTypes(int[], long, long) BCE (after)
587 /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>>
588 /// CHECK-DAG: BoundsCheck loop:<<Loop>>
589 //
590 /// CHECK-START: int Main.noDynamicBCEMixedInductionTypes(int[], long, long) BCE (after)
591 /// CHECK-NOT: Deoptimize
592 static int noDynamicBCEMixedInductionTypes(int[] x, long lo, long hi) {
593 int result = 0;
594 // Mix of int and long induction.
595 int k = 0;
596 for (long i = lo; i < hi; i++) {
597 result += x[k++];
598 }
599 return result;
600 }
601
602 /// CHECK-START: int Main.dynamicBCEConstantRange(int[]) BCE (before)
603 /// CHECK-DAG: BoundsCheck loop:<<InnerLoop:B\d+>>
604 /// CHECK-DAG: ArrayGet loop:<<InnerLoop>>
605 /// CHECK-DAG: If loop:<<InnerLoop>>
606 /// CHECK-DAG: If loop:<<OuterLoop:B\d+>>
607 /// CHECK-EVAL: "<<InnerLoop>>" != "<<OuterLoop>>"
608 //
609 /// CHECK-START: int Main.dynamicBCEConstantRange(int[]) BCE (after)
610 /// CHECK-DAG: ArrayGet loop:<<InnerLoop:B\d+>>
611 /// CHECK-DAG: Deoptimize loop:<<OuterLoop:B\d+>>
612 /// CHECK-EVAL: "<<InnerLoop>>" != "<<OuterLoop>>"
613 //
614 /// CHECK-START: int Main.dynamicBCEConstantRange(int[]) BCE (after)
615 /// CHECK-NOT: BoundsCheck
616 //
617 // No additional top tests were introduced.
618 /// CHECK-START: int Main.dynamicBCEConstantRange(int[]) BCE (after)
619 /// CHECK-DAG: If
620 /// CHECK-DAG: If
621 /// CHECK-NOT: If
622 static int dynamicBCEConstantRange(int[] x) {
623 int result = 0;
624 for (int i = 2; i <= 6; i++) {
625 // Range analysis sees that innermost loop is finite and always taken.
626 for (int j = i - 2; j <= i + 2; j++) {
627 result += x[j];
628 }
629 }
630 return result;
631 }
632
633 /// CHECK-START: int Main.dynamicBCEAndConstantIndices(int[], int[][], int, int) BCE (before)
634 /// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop:B\d+>>
635 /// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop>>
636 /// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop>>
637 //
638 /// CHECK-START: int Main.dynamicBCEAndConstantIndices(int[], int[][], int, int) BCE (after)
639 // Order matters:
640 /// CHECK: Deoptimize loop:<<Loop:B\d+>>
641 // CHECK-NOT: Goto loop:<<Loop>>
642 /// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop>>
643 /// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop>>
644 /// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop>>
645 /// CHECK: Goto loop:<<Loop>>
646 //
647 /// CHECK-START: int Main.dynamicBCEAndConstantIndices(int[], int[][], int, int) BCE (after)
648 /// CHECK-DAG: Deoptimize loop:none
649 static int dynamicBCEAndConstantIndices(int[] x, int[][] a, int lo, int hi) {
650 // Deliberately test array length on a before the loop so that only bounds checks
651 // on constant subscripts remain, making them a viable candidate for hoisting.
652 if (a.length == 0) {
653 return -1;
654 }
655 // Loop that allows BCE on x[i].
656 int result = 0;
657 for (int i = lo; i < hi; i++) {
658 result += x[i];
659 if ((i % 10) != 0) {
660 // None of the subscripts inside a conditional are removed by dynamic bce,
661 // making them a candidate for deoptimization based on constant indices.
662 // Compiler should ensure the array loads are not subsequently hoisted
663 // "above" the deoptimization "barrier" on the bounds.
664 a[0][i] = 1;
665 a[1][i] = 2;
666 a[99][i] = 3;
667 }
668 }
669 return result;
670 }
671
672 /// CHECK-START: int Main.dynamicBCEAndConstantIndicesAllPrimTypes(int[], boolean[], byte[], char[], short[], int[], long[], float[], double[], int, int) BCE (before)
673 /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>>
674 /// CHECK-DAG: ArrayGet loop:<<Loop>>
675 /// CHECK-DAG: ArrayGet loop:<<Loop>>
676 /// CHECK-DAG: ArrayGet loop:<<Loop>>
677 /// CHECK-DAG: ArrayGet loop:<<Loop>>
678 /// CHECK-DAG: ArrayGet loop:<<Loop>>
679 /// CHECK-DAG: ArrayGet loop:<<Loop>>
680 /// CHECK-DAG: ArrayGet loop:<<Loop>>
681 /// CHECK-DAG: ArrayGet loop:<<Loop>>
682 // For brevity, just test occurrence of at least one of each in the loop:
683 /// CHECK-DAG: NullCheck loop:<<Loop>>
684 /// CHECK-DAG: ArrayLength loop:<<Loop>>
685 /// CHECK-DAG: BoundsCheck loop:<<Loop>>
686 //
687 /// CHECK-START: int Main.dynamicBCEAndConstantIndicesAllPrimTypes(int[], boolean[], byte[], char[], short[], int[], long[], float[], double[], int, int) BCE (after)
688 /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>>
689 /// CHECK-NOT: ArrayGet loop:<<Loop>>
690 //
691 /// CHECK-START: int Main.dynamicBCEAndConstantIndicesAllPrimTypes(int[], boolean[], byte[], char[], short[], int[], long[], float[], double[], int, int) BCE (after)
692 /// CHECK-NOT: NullCheck loop:{{B\d+}}
693 /// CHECK-NOT: ArrayLength loop:{{B\d+}}
694 /// CHECK-NOT: BoundsCheck loop:{{B\d+}}
695 //
696 /// CHECK-START: int Main.dynamicBCEAndConstantIndicesAllPrimTypes(int[], boolean[], byte[], char[], short[], int[], long[], float[], double[], int, int) BCE (after)
697 /// CHECK-DAG: Deoptimize loop:none
698 static int dynamicBCEAndConstantIndicesAllPrimTypes(int[] q,
699 boolean[] r,
700 byte[] s,
701 char[] t,
702 short[] u,
703 int[] v,
704 long[] w,
705 float[] x,
706 double[] y, int lo, int hi) {
707 int result = 0;
708 for (int i = lo; i < hi; i++) {
709 // All constant index array references can be hoisted out of the loop during BCE on q[i].
710 result += q[i] + (r[0] ? 1 : 0) + (int) s[0] + (int) t[0] + (int) u[0] + (int) v[0] +
711 (int) w[0] + (int) x[0] + (int) y[0];
712 }
713 return result;
714 }
715
716 /// CHECK-START: int Main.dynamicBCEAndConstantIndexRefType(int[], java.lang.Integer[], int, int) BCE (before)
717 /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>>
718 /// CHECK-DAG: NullCheck loop:<<Loop>>
719 /// CHECK-DAG: ArrayLength loop:<<Loop>>
720 /// CHECK-DAG: BoundsCheck loop:<<Loop>>
721 /// CHECK-DAG: ArrayGet loop:<<Loop>>
722 /// CHECK-DAG: NullCheck loop:<<Loop>>
723 /// CHECK-DAG: ArrayLength loop:<<Loop>>
724 /// CHECK-DAG: BoundsCheck loop:<<Loop>>
725 //
726 /// CHECK-START: int Main.dynamicBCEAndConstantIndexRefType(int[], java.lang.Integer[], int, int) BCE (after)
727 /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>>
728 /// CHECK-DAG: Deoptimize loop:none
729 //
730 /// CHECK-START: int Main.dynamicBCEAndConstantIndexRefType(int[], java.lang.Integer[], int, int) BCE (after)
731 /// CHECK-NOT: ArrayLength loop:{{B\d+}}
732 /// CHECK-NOT: BoundsCheck loop:{{B\d+}}
733 static int dynamicBCEAndConstantIndexRefType(int[] q, Integer[] z, int lo, int hi) {
734 int result = 0;
735 for (int i = lo; i < hi; i++) {
736 // Similar to above, but now implicit call to intValue() may prevent hoisting
737 // z[0] itself during BCE on q[i]. Therefore, we just check BCE on q[i].
738 result += q[i] + z[0];
739 }
740 return result;
741 }
742
743 //
744 // Verifier.
745 //
746
747 public static void main(String[] args) {
748 // Set to run expensive tests for correctness too.
749 boolean HEAVY = false;
750
751 int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
752
753 // Sorting.
754 int[] sort = { 5, 4, 1, 9, 10, 2, 7, 6, 3, 8 };
755 bubble(sort);
756 for (int i = 0; i < 10; i++) {
757 expectEquals(sort[i], x[i]);
758 }
759
760 // Periodic adds (1, 3), one at the time.
761 expectEquals(0, periodicIdiom(-1));
762 for (int tc = 0; tc < 32; tc++) {
763 int expected = (tc >> 1) << 2;
764 if ((tc & 1) != 0)
765 expected += 1;
766 expectEquals(expected, periodicIdiom(tc));
767 }
768
769 // Periodic adds (1, 3), one at the time.
770 expectEquals(0, periodicSequence2(-1));
771 for (int tc = 0; tc < 32; tc++) {
772 int expected = (tc >> 1) << 2;
773 if ((tc & 1) != 0)
774 expected += 1;
775 expectEquals(expected, periodicSequence2(tc));
776 }
777
778 // Periodic adds (1, 3, 5, 7), all at once.
779 expectEquals(0, periodicSequence4(-1));
780 for (int tc = 0; tc < 32; tc++) {
781 expectEquals(tc * 16, periodicSequence4(tc));
782 }
783
784 // Large bounds.
785 expectEquals(55, justRightUp1());
786 expectEquals(55, justRightUp2());
787 expectEquals(55, justRightUp3());
788 expectEquals(55, justRightDown1());
789 expectEquals(55, justRightDown2());
790 expectEquals(55, justRightDown3());
791 sResult = 0;
792 try {
793 justOOBUp();
794 } catch (ArrayIndexOutOfBoundsException e) {
795 sResult = 1;
796 }
797 expectEquals(1, sResult);
798 sResult = 0;
799 try {
800 justOOBDown();
801 } catch (ArrayIndexOutOfBoundsException e) {
802 sResult = 1;
803 }
804 expectEquals(1, sResult);
805
806 // Lower bound goes OOB.
807 sResult = 0;
808 try {
809 lowerOOB(x);
810 } catch (ArrayIndexOutOfBoundsException e) {
811 sResult += 1000;
812 }
813 expectEquals(1000, sResult);
814
815 // Upper bound goes OOB.
816 sResult = 0;
817 try {
818 upperOOB(x);
819 } catch (ArrayIndexOutOfBoundsException e) {
820 sResult += 1000;
821 }
822 expectEquals(1055, sResult);
823
824 // Do while up goes OOB.
825 sResult = 0;
826 try {
827 doWhileUpOOB();
828 } catch (ArrayIndexOutOfBoundsException e) {
829 sResult += 1000;
830 }
831 expectEquals(1055, sResult);
832
833 // Do while down goes OOB.
834 sResult = 0;
835 try {
836 doWhileDownOOB();
837 } catch (ArrayIndexOutOfBoundsException e) {
838 sResult += 1000;
839 }
840 expectEquals(1055, sResult);
841
842 // Hidden OOB.
843 sResult = 0;
844 try {
845 hiddenOOB1(10); // no OOB
846 } catch (ArrayIndexOutOfBoundsException e) {
847 sResult += 1000;
848 }
849 expectEquals(1, sResult);
850 sResult = 0;
851 try {
852 hiddenOOB1(-2147483648); // OOB
853 } catch (ArrayIndexOutOfBoundsException e) {
854 sResult += 1000;
855 }
856 expectEquals(1001, sResult);
857 sResult = 0;
858 try {
859 hiddenOOB2(1); // no OOB
860 } catch (ArrayIndexOutOfBoundsException e) {
861 sResult += 1000;
862 }
863 expectEquals(1, sResult);
864 if (HEAVY) {
865 sResult = 0;
866 try {
867 hiddenOOB2(2147483647); // OOB
868 } catch (ArrayIndexOutOfBoundsException e) {
869 sResult += 1000;
870 }
871 expectEquals(1002, sResult);
872 }
873 sResult = 0;
874 try {
875 hiddenInfiniteOOB();
876 } catch (ArrayIndexOutOfBoundsException e) {
877 sResult += 1000;
878 }
879 expectEquals(1011, sResult);
880 sResult = 0;
881 try {
882 hiddenFiniteOOB();
883 } catch (ArrayIndexOutOfBoundsException e) {
884 sResult += 1000;
885 }
886 expectEquals(1111, sResult);
887
888 // Addition.
889 {
890 int[] e1 ={ 1, 2, 3, 4, 4, 4, 4, 3, 2, 1 };
891 int[] a1 = add();
892 for (int i = 0; i < 10; i++) {
893 expectEquals(a1[i], e1[i]);
894 }
895 }
896
897 // Multiplication.
898 {
899 int[] e1 = { 7, 1, 2, 2, 1, 0, 2, 0, 0, 1 };
900 int[] a1 = multiply1();
901 for (int i = 0; i < 10; i++) {
902 expectEquals(a1[i], e1[i]);
903 }
904 int[] e2 = { 1001, 0, 0, 1, 0, 0, 1, 0, 0, 1 };
905 int[] a2 = multiply2();
906 for (int i = 0; i < 10; i++) {
907 expectEquals(a2[i], e2[i]);
908 }
909 }
910
911 // Dynamic BCE.
912 sResult = 0;
913 try {
914 linearDynamicBCE1(x, -1, x.length);
915 } catch (ArrayIndexOutOfBoundsException e) {
916 sResult += 1000;
917 }
918 expectEquals(1000, sResult);
919 sResult = 0;
920 linearDynamicBCE1(x, 0, x.length);
921 expectEquals(55, sResult);
922 sResult = 0;
923 try {
924 linearDynamicBCE1(x, 0, x.length + 1);
925 } catch (ArrayIndexOutOfBoundsException e) {
926 sResult += 1000;
927 }
928 expectEquals(1055, sResult);
929
930 // Dynamic BCE with offset.
931 sResult = 0;
932 try {
933 linearDynamicBCE2(x, 0, x.length, -1);
934 } catch (ArrayIndexOutOfBoundsException e) {
935 sResult += 1000;
936 }
937 expectEquals(1000, sResult);
938 sResult = 0;
939 linearDynamicBCE2(x, 0, x.length, 0);
940 expectEquals(55, sResult);
941 sResult = 0;
942 try {
943 linearDynamicBCE2(x, 0, x.length, 1);
944 } catch (ArrayIndexOutOfBoundsException e) {
945 sResult += 1000;
946 }
947 expectEquals(1054, sResult);
948
949 // Dynamic BCE candidates.
950 expectEquals(55, wrapAroundDynamicBCE(x));
951 expectEquals(15, periodicDynamicBCE(x));
952 expectEquals(55, dynamicBCEPossiblyInfiniteLoop(x, 0, 9));
953 expectEquals(55, noDynamicBCEPossiblyInfiniteLoop(x, 0, 9));
954 expectEquals(55, noDynamicBCEMixedInductionTypes(x, 0, 10));
955 expectEquals(125, dynamicBCEConstantRange(x));
956
957 // Dynamic BCE combined with constant indices.
958 int[][] a;
959 a = new int[0][0];
960 expectEquals(-1, dynamicBCEAndConstantIndices(x, a, 0, 10));
961 a = new int[100][10];
962 expectEquals(55, dynamicBCEAndConstantIndices(x, a, 0, 10));
963 for (int i = 0; i < 10; i++) {
964 expectEquals((i % 10) != 0 ? 1 : 0, a[0][i]);
965 expectEquals((i % 10) != 0 ? 2 : 0, a[1][i]);
966 expectEquals((i % 10) != 0 ? 3 : 0, a[99][i]);
967 }
968 a = new int[2][10];
969 sResult = 0;
970 try {
971 expectEquals(55, dynamicBCEAndConstantIndices(x, a, 0, 10));
972 } catch (ArrayIndexOutOfBoundsException e) {
973 sResult = 1;
974 }
975 expectEquals(1, sResult);
976 expectEquals(a[0][1], 1);
977 expectEquals(a[1][1], 2);
978
979 // Dynamic BCE combined with constant indices of all types.
980 boolean[] x1 = { true };
981 byte[] x2 = { 2 };
982 char[] x3 = { 3 };
983 short[] x4 = { 4 };
984 int[] x5 = { 5 };
985 long[] x6 = { 6 };
986 float[] x7 = { 7 };
987 double[] x8 = { 8 };
988 expectEquals(415,
989 dynamicBCEAndConstantIndicesAllPrimTypes(x, x1, x2, x3, x4, x5, x6, x7, x8, 0, 10));
990 Integer[] x9 = { 9 };
991 expectEquals(145, dynamicBCEAndConstantIndexRefType(x, x9, 0, 10));
992 }
993
994 private static void expectEquals(int expected, int result) {
995 if (expected != result) {
996 throw new Error("Expected: " + expected + ", found: " + result);
997 }
998 }
999}