1 /* 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 // 20 public 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: void Main.inductionOOB(int[]) BCE (before) 387 /// CHECK-DAG: BoundsCheck 388 // 389 /// CHECK-START: void Main.inductionOOB(int[]) BCE (after) 390 /// CHECK-DAG: BoundsCheck 391 // 392 /// CHECK-START: void Main.inductionOOB(int[]) BCE (after) 393 /// CHECK-NOT: Deoptimize 394 private static void inductionOOB(int[] a) { 395 // Careless range analysis would remove the bounds check. 396 // However, the narrower induction b wraps around arithmetically 397 // before it reaches the end of arrays longer than 127. 398 byte b = 0; 399 for (int i = 0; i < a.length; i++) { 400 a[b++] = i; 401 } 402 } 403 404 /// CHECK-START: void Main.controlOOB(int[]) BCE (before) 405 /// CHECK-DAG: BoundsCheck 406 // 407 /// CHECK-START: void Main.controlOOB(int[]) BCE (after) 408 /// CHECK-DAG: BoundsCheck 409 // 410 /// CHECK-START: void Main.controlOOB(int[]) BCE (after) 411 /// CHECK-NOT: Deoptimize 412 private static void controlOOB(int[] a) { 413 // As above, but now the loop control also wraps around. 414 for (byte i = 0; i < a.length; i++) { 415 a[i] = -i; 416 } 417 } 418 419 /// CHECK-START: void Main.conversionOOB(int[]) BCE (before) 420 /// CHECK-DAG: BoundsCheck 421 // 422 /// CHECK-START: void Main.conversionOOB(int[]) BCE (after) 423 /// CHECK-DAG: BoundsCheck 424 // 425 /// CHECK-START: void Main.conversionOOB(int[]) BCE (after) 426 /// CHECK-NOT: Deoptimize 427 private static void conversionOOB(int[] a) { 428 // As above, but with wrap around caused by an explicit conversion. 429 for (int i = 0; i < a.length; ) { 430 a[i] = i; 431 i = (byte) (i + 1); 432 } 433 } 434 435 /// CHECK-START: int[] Main.add() BCE (before) 436 /// CHECK-DAG: BoundsCheck 437 // 438 /// CHECK-START: int[] Main.add() BCE (after) 439 /// CHECK-NOT: BoundsCheck 440 /// CHECK-NOT: Deoptimize 441 private static int[] add() { 442 int[] a = new int[10]; 443 for (int i = 0; i <= 3; i++) { 444 for (int j = 0; j <= 6; j++) { 445 a[i + j] += 1; 446 } 447 } 448 return a; 449 } 450 451 /// CHECK-START: int[] Main.multiply1() BCE (before) 452 /// CHECK-DAG: BoundsCheck 453 // 454 /// CHECK-START: int[] Main.multiply1() BCE (after) 455 /// CHECK-NOT: BoundsCheck 456 /// CHECK-NOT: Deoptimize 457 private static int[] multiply1() { 458 int[] a = new int[10]; 459 try { 460 for (int i = 0; i <= 3; i++) { 461 for (int j = 0; j <= 3; j++) { 462 // Range [0,9]: safe. 463 a[i * j] += 1; 464 } 465 } 466 } catch (Exception e) { 467 a[0] += 1000; 468 } 469 return a; 470 } 471 472 /// CHECK-START: int[] Main.multiply2() BCE (before) 473 /// CHECK-DAG: BoundsCheck 474 // 475 /// CHECK-START: int[] Main.multiply2() BCE (after) 476 /// CHECK-DAG: BoundsCheck 477 // 478 /// CHECK-START: int[] Main.multiply2() BCE (after) 479 /// CHECK-NOT: Deoptimize 480 static int[] multiply2() { 481 int[] a = new int[10]; 482 try { 483 for (int i = -3; i <= 3; i++) { 484 for (int j = -3; j <= 3; j++) { 485 // Range [-9,9]: unsafe. 486 a[i * j] += 1; 487 } 488 } 489 } catch (Exception e) { 490 a[0] += 1000; 491 } 492 return a; 493 } 494 495 /// CHECK-START: int Main.linearDynamicBCE1(int[], int, int) BCE (before) 496 /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> 497 /// CHECK-DAG: NullCheck loop:<<Loop>> 498 /// CHECK-DAG: ArrayLength loop:<<Loop>> 499 /// CHECK-DAG: BoundsCheck loop:<<Loop>> 500 // 501 /// CHECK-START: int Main.linearDynamicBCE1(int[], int, int) BCE (after) 502 /// CHECK-DAG: ArrayGet loop:{{B\d+}} 503 /// CHECK-DAG: Deoptimize loop:none 504 // 505 /// CHECK-START: int Main.linearDynamicBCE1(int[], int, int) BCE (after) 506 /// CHECK-NOT: NullCheck loop:{{B\d+}} 507 /// CHECK-NOT: ArrayLength loop:{{B\d+}} 508 /// CHECK-NOT: BoundsCheck loop:{{B\d+}} 509 private static int linearDynamicBCE1(int[] x, int lo, int hi) { 510 int result = 0; 511 for (int i = lo; i < hi; i++) { 512 sResult += x[i]; 513 } 514 return result; 515 } 516 517 /// CHECK-START: int Main.linearDynamicBCE2(int[], int, int, int) BCE (before) 518 /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> 519 /// CHECK-DAG: NullCheck loop:<<Loop>> 520 /// CHECK-DAG: ArrayLength loop:<<Loop>> 521 /// CHECK-DAG: BoundsCheck loop:<<Loop>> 522 // 523 /// CHECK-START: int Main.linearDynamicBCE2(int[], int, int, int) BCE (after) 524 /// CHECK-DAG: ArrayGet loop:{{B\d+}} 525 /// CHECK-DAG: Deoptimize loop:none 526 // 527 /// CHECK-START: int Main.linearDynamicBCE2(int[], int, int, int) BCE (after) 528 /// CHECK-NOT: NullCheck loop:{{B\d+}} 529 /// CHECK-NOT: ArrayLength loop:{{B\d+}} 530 /// CHECK-NOT: BoundsCheck loop:{{B\d+}} 531 private static int linearDynamicBCE2(int[] x, int lo, int hi, int offset) { 532 int result = 0; 533 for (int i = lo; i < hi; i++) { 534 sResult += x[offset + i]; 535 } 536 return result; 537 } 538 539 /// CHECK-START: int Main.wrapAroundDynamicBCE(int[]) BCE (before) 540 /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> 541 /// CHECK-DAG: NullCheck loop:<<Loop>> 542 /// CHECK-DAG: ArrayLength loop:<<Loop>> 543 /// CHECK-DAG: BoundsCheck loop:<<Loop>> 544 // 545 /// CHECK-START: int Main.wrapAroundDynamicBCE(int[]) BCE (after) 546 /// CHECK-DAG: ArrayGet loop:{{B\d+}} 547 /// CHECK-DAG: Deoptimize loop:none 548 // 549 /// CHECK-START: int Main.wrapAroundDynamicBCE(int[]) BCE (after) 550 /// CHECK-NOT: NullCheck loop:{{B\d+}} 551 /// CHECK-NOT: ArrayLength loop:{{B\d+}} 552 /// CHECK-NOT: BoundsCheck loop:{{B\d+}} 553 private static int wrapAroundDynamicBCE(int[] x) { 554 int w = 9; 555 int result = 0; 556 for (int i = 0; i < 10; i++) { 557 result += x[w]; 558 w = i; 559 } 560 return result; 561 } 562 563 /// CHECK-START: int Main.periodicDynamicBCE(int[]) BCE (before) 564 /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> 565 /// CHECK-DAG: NullCheck loop:<<Loop>> 566 /// CHECK-DAG: ArrayLength loop:<<Loop>> 567 /// CHECK-DAG: BoundsCheck loop:<<Loop>> 568 // 569 /// CHECK-START: int Main.periodicDynamicBCE(int[]) BCE (after) 570 /// CHECK-DAG: ArrayGet loop:{{B\d+}} 571 /// CHECK-DAG: Deoptimize loop:none 572 // 573 /// CHECK-START: int Main.periodicDynamicBCE(int[]) BCE (after) 574 /// CHECK-NOT: NullCheck loop:{{B\d+}} 575 /// CHECK-NOT: ArrayLength loop:{{B\d+}} 576 /// CHECK-NOT: BoundsCheck loop:{{B\d+}} 577 private static int periodicDynamicBCE(int[] x) { 578 int k = 0; 579 int result = 0; 580 for (int i = 0; i < 10; i++) { 581 result += x[k]; 582 k = 1 - k; 583 } 584 return result; 585 } 586 587 /// CHECK-START: int Main.dynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (before) 588 /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> 589 /// CHECK-DAG: NullCheck loop:<<Loop>> 590 /// CHECK-DAG: ArrayLength loop:<<Loop>> 591 /// CHECK-DAG: BoundsCheck loop:<<Loop>> 592 // 593 /// CHECK-START: int Main.dynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (after) 594 /// CHECK-DAG: ArrayGet loop:{{B\d+}} 595 /// CHECK-DAG: Deoptimize loop:none 596 // 597 /// CHECK-START: int Main.dynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (after) 598 /// CHECK-NOT: NullCheck loop:{{B\d+}} 599 /// CHECK-NOT: ArrayLength loop:{{B\d+}} 600 /// CHECK-NOT: BoundsCheck loop:{{B\d+}} 601 static int dynamicBCEPossiblyInfiniteLoop(int[] x, int lo, int hi) { 602 // This loop could be infinite for hi = max int. Since i is also used 603 // as subscript, however, dynamic bce can proceed. 604 int result = 0; 605 for (int i = lo; i <= hi; i++) { 606 result += x[i]; 607 } 608 return result; 609 } 610 611 /// CHECK-START: int Main.noDynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (before) 612 /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> 613 /// CHECK-DAG: BoundsCheck loop:<<Loop>> 614 // 615 /// CHECK-START: int Main.noDynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (after) 616 /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> 617 /// CHECK-DAG: BoundsCheck loop:<<Loop>> 618 // 619 /// CHECK-START: int Main.noDynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (after) 620 /// CHECK-NOT: Deoptimize 621 static int noDynamicBCEPossiblyInfiniteLoop(int[] x, int lo, int hi) { 622 // As above, but now the index is not used as subscript, 623 // and dynamic bce is not applied. 624 int result = 0; 625 for (int k = 0, i = lo; i <= hi; i++) { 626 result += x[k++]; 627 } 628 return result; 629 } 630 631 /// CHECK-START: int Main.noDynamicBCEMixedInductionTypes(int[], long, long) BCE (before) 632 /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> 633 /// CHECK-DAG: BoundsCheck loop:<<Loop>> 634 // 635 /// CHECK-START: int Main.noDynamicBCEMixedInductionTypes(int[], long, long) BCE (after) 636 /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> 637 /// CHECK-DAG: BoundsCheck loop:<<Loop>> 638 // 639 /// CHECK-START: int Main.noDynamicBCEMixedInductionTypes(int[], long, long) BCE (after) 640 /// CHECK-NOT: Deoptimize 641 static int noDynamicBCEMixedInductionTypes(int[] x, long lo, long hi) { 642 int result = 0; 643 // Mix of int and long induction. 644 int k = 0; 645 for (long i = lo; i < hi; i++) { 646 result += x[k++]; 647 } 648 return result; 649 } 650 651 /// CHECK-START: int Main.dynamicBCEConstantRange(int[]) BCE (before) 652 /// CHECK-DAG: BoundsCheck loop:<<InnerLoop:B\d+>> 653 /// CHECK-DAG: ArrayGet loop:<<InnerLoop>> 654 /// CHECK-DAG: If loop:<<InnerLoop>> 655 /// CHECK-DAG: If loop:<<OuterLoop:B\d+>> 656 /// CHECK-EVAL: "<<InnerLoop>>" != "<<OuterLoop>>" 657 // 658 /// CHECK-START: int Main.dynamicBCEConstantRange(int[]) BCE (after) 659 /// CHECK-DAG: ArrayGet loop:<<InnerLoop:B\d+>> 660 /// CHECK-DAG: Deoptimize loop:<<OuterLoop:B\d+>> 661 /// CHECK-EVAL: "<<InnerLoop>>" != "<<OuterLoop>>" 662 // 663 /// CHECK-START: int Main.dynamicBCEConstantRange(int[]) BCE (after) 664 /// CHECK-NOT: BoundsCheck 665 // 666 // No additional top tests were introduced. 667 /// CHECK-START: int Main.dynamicBCEConstantRange(int[]) BCE (after) 668 /// CHECK-DAG: If 669 /// CHECK-DAG: If 670 /// CHECK-NOT: If 671 static int dynamicBCEConstantRange(int[] x) { 672 int result = 0; 673 for (int i = 2; i <= 6; i++) { 674 // Range analysis sees that innermost loop is finite and always taken. 675 for (int j = i - 2; j <= i + 2; j++) { 676 result += x[j]; 677 } 678 } 679 return result; 680 } 681 682 /// CHECK-START: int Main.dynamicBCEAndConstantIndices(int[], int[][], int, int) BCE (before) 683 /// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop:B\d+>> 684 /// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop>> 685 /// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop>> 686 // 687 /// CHECK-START: int Main.dynamicBCEAndConstantIndices(int[], int[][], int, int) BCE (after) 688 // Order matters: 689 /// CHECK: Deoptimize loop:<<Loop:B\d+>> 690 // CHECK-NOT: Goto loop:<<Loop>> 691 /// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop>> 692 /// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop>> 693 /// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop>> 694 /// CHECK: Goto loop:<<Loop>> 695 // 696 /// CHECK-START: int Main.dynamicBCEAndConstantIndices(int[], int[][], int, int) BCE (after) 697 /// CHECK-DAG: Deoptimize loop:none 698 static int dynamicBCEAndConstantIndices(int[] x, int[][] a, int lo, int hi) { 699 // Deliberately test array length on a before the loop so that only bounds checks 700 // on constant subscripts remain, making them a viable candidate for hoisting. 701 if (a.length == 0) { 702 return -1; 703 } 704 // Loop that allows BCE on x[i]. 705 int result = 0; 706 for (int i = lo; i < hi; i++) { 707 result += x[i]; 708 if ((i % 10) != 0) { 709 // None of the subscripts inside a conditional are removed by dynamic bce, 710 // making them a candidate for deoptimization based on constant indices. 711 // Compiler should ensure the array loads are not subsequently hoisted 712 // "above" the deoptimization "barrier" on the bounds. 713 a[0][i] = 1; 714 a[1][i] = 2; 715 a[99][i] = 3; 716 } 717 } 718 return result; 719 } 720 721 /// CHECK-START: int Main.dynamicBCEAndConstantIndicesAllPrimTypes(int[], boolean[], byte[], char[], short[], int[], long[], float[], double[], int, int) BCE (before) 722 /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> 723 /// CHECK-DAG: ArrayGet loop:<<Loop>> 724 /// CHECK-DAG: ArrayGet loop:<<Loop>> 725 /// CHECK-DAG: ArrayGet loop:<<Loop>> 726 /// CHECK-DAG: ArrayGet loop:<<Loop>> 727 /// CHECK-DAG: ArrayGet loop:<<Loop>> 728 /// CHECK-DAG: ArrayGet loop:<<Loop>> 729 /// CHECK-DAG: ArrayGet loop:<<Loop>> 730 /// CHECK-DAG: ArrayGet loop:<<Loop>> 731 // For brevity, just test occurrence of at least one of each in the loop: 732 /// CHECK-DAG: NullCheck loop:<<Loop>> 733 /// CHECK-DAG: ArrayLength loop:<<Loop>> 734 /// CHECK-DAG: BoundsCheck loop:<<Loop>> 735 // 736 /// CHECK-START: int Main.dynamicBCEAndConstantIndicesAllPrimTypes(int[], boolean[], byte[], char[], short[], int[], long[], float[], double[], int, int) BCE (after) 737 /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> 738 /// CHECK-NOT: ArrayGet loop:<<Loop>> 739 // 740 /// CHECK-START: int Main.dynamicBCEAndConstantIndicesAllPrimTypes(int[], boolean[], byte[], char[], short[], int[], long[], float[], double[], int, int) BCE (after) 741 /// CHECK-NOT: NullCheck loop:{{B\d+}} 742 /// CHECK-NOT: ArrayLength loop:{{B\d+}} 743 /// CHECK-NOT: BoundsCheck loop:{{B\d+}} 744 // 745 /// CHECK-START: int Main.dynamicBCEAndConstantIndicesAllPrimTypes(int[], boolean[], byte[], char[], short[], int[], long[], float[], double[], int, int) BCE (after) 746 /// CHECK-DAG: Deoptimize loop:none 747 static int dynamicBCEAndConstantIndicesAllPrimTypes(int[] q, 748 boolean[] r, 749 byte[] s, 750 char[] t, 751 short[] u, 752 int[] v, 753 long[] w, 754 float[] x, 755 double[] y, int lo, int hi) { 756 int result = 0; 757 for (int i = lo; i < hi; i++) { 758 // All constant index array references can be hoisted out of the loop during BCE on q[i]. 759 result += q[i] + (r[0] ? 1 : 0) + (int) s[0] + (int) t[0] + (int) u[0] + (int) v[0] + 760 (int) w[0] + (int) x[0] + (int) y[0]; 761 } 762 return result; 763 } 764 765 /// CHECK-START: int Main.dynamicBCEAndConstantIndexRefType(int[], java.lang.Integer[], int, int) BCE (before) 766 /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> 767 /// CHECK-DAG: NullCheck loop:<<Loop>> 768 /// CHECK-DAG: ArrayLength loop:<<Loop>> 769 /// CHECK-DAG: BoundsCheck loop:<<Loop>> 770 /// CHECK-DAG: ArrayGet loop:<<Loop>> 771 /// CHECK-DAG: NullCheck loop:<<Loop>> 772 /// CHECK-DAG: ArrayLength loop:<<Loop>> 773 /// CHECK-DAG: BoundsCheck loop:<<Loop>> 774 // 775 /// CHECK-START: int Main.dynamicBCEAndConstantIndexRefType(int[], java.lang.Integer[], int, int) BCE (after) 776 /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> 777 /// CHECK-DAG: Deoptimize loop:none 778 // 779 /// CHECK-START: int Main.dynamicBCEAndConstantIndexRefType(int[], java.lang.Integer[], int, int) BCE (after) 780 /// CHECK-NOT: ArrayLength loop:{{B\d+}} 781 /// CHECK-NOT: BoundsCheck loop:{{B\d+}} 782 static int dynamicBCEAndConstantIndexRefType(int[] q, Integer[] z, int lo, int hi) { 783 int result = 0; 784 for (int i = lo; i < hi; i++) { 785 // Similar to above, but now implicit call to intValue() may prevent hoisting 786 // z[0] itself during BCE on q[i]. Therefore, we just check BCE on q[i]. 787 result += q[i] + z[0]; 788 } 789 return result; 790 } 791 792 // 793 // Verifier. 794 // 795 796 public static void main(String[] args) { 797 // Set to run expensive tests for correctness too. 798 boolean HEAVY = false; 799 800 int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 801 802 int[] a200 = new int[200]; 803 804 // Sorting. 805 int[] sort = { 5, 4, 1, 9, 10, 2, 7, 6, 3, 8 }; 806 bubble(sort); 807 for (int i = 0; i < 10; i++) { 808 expectEquals(sort[i], x[i]); 809 } 810 811 // Periodic adds (1, 3), one at the time. 812 expectEquals(0, periodicIdiom(-1)); 813 for (int tc = 0; tc < 32; tc++) { 814 int expected = (tc >> 1) << 2; 815 if ((tc & 1) != 0) 816 expected += 1; 817 expectEquals(expected, periodicIdiom(tc)); 818 } 819 820 // Periodic adds (1, 3), one at the time. 821 expectEquals(0, periodicSequence2(-1)); 822 for (int tc = 0; tc < 32; tc++) { 823 int expected = (tc >> 1) << 2; 824 if ((tc & 1) != 0) 825 expected += 1; 826 expectEquals(expected, periodicSequence2(tc)); 827 } 828 829 // Periodic adds (1, 3, 5, 7), all at once. 830 expectEquals(0, periodicSequence4(-1)); 831 for (int tc = 0; tc < 32; tc++) { 832 expectEquals(tc * 16, periodicSequence4(tc)); 833 } 834 835 // Large bounds. 836 expectEquals(55, justRightUp1()); 837 expectEquals(55, justRightUp2()); 838 expectEquals(55, justRightUp3()); 839 expectEquals(55, justRightDown1()); 840 expectEquals(55, justRightDown2()); 841 expectEquals(55, justRightDown3()); 842 sResult = 0; 843 try { 844 justOOBUp(); 845 } catch (ArrayIndexOutOfBoundsException e) { 846 sResult = 1; 847 } 848 expectEquals(1, sResult); 849 sResult = 0; 850 try { 851 justOOBDown(); 852 } catch (ArrayIndexOutOfBoundsException e) { 853 sResult = 1; 854 } 855 expectEquals(1, sResult); 856 857 // Lower bound goes OOB. 858 sResult = 0; 859 try { 860 lowerOOB(x); 861 } catch (ArrayIndexOutOfBoundsException e) { 862 sResult += 1000; 863 } 864 expectEquals(1000, sResult); 865 866 // Upper bound goes OOB. 867 sResult = 0; 868 try { 869 upperOOB(x); 870 } catch (ArrayIndexOutOfBoundsException e) { 871 sResult += 1000; 872 } 873 expectEquals(1055, sResult); 874 875 // Do while up goes OOB. 876 sResult = 0; 877 try { 878 doWhileUpOOB(); 879 } catch (ArrayIndexOutOfBoundsException e) { 880 sResult += 1000; 881 } 882 expectEquals(1055, sResult); 883 884 // Do while down goes OOB. 885 sResult = 0; 886 try { 887 doWhileDownOOB(); 888 } catch (ArrayIndexOutOfBoundsException e) { 889 sResult += 1000; 890 } 891 expectEquals(1055, sResult); 892 893 // Hidden OOB. 894 sResult = 0; 895 try { 896 hiddenOOB1(10); // no OOB 897 } catch (ArrayIndexOutOfBoundsException e) { 898 sResult += 1000; 899 } 900 expectEquals(1, sResult); 901 sResult = 0; 902 try { 903 hiddenOOB1(-2147483648); // OOB 904 } catch (ArrayIndexOutOfBoundsException e) { 905 sResult += 1000; 906 } 907 expectEquals(1001, sResult); 908 sResult = 0; 909 try { 910 hiddenOOB2(1); // no OOB 911 } catch (ArrayIndexOutOfBoundsException e) { 912 sResult += 1000; 913 } 914 expectEquals(1, sResult); 915 if (HEAVY) { 916 sResult = 0; 917 try { 918 hiddenOOB2(2147483647); // OOB 919 } catch (ArrayIndexOutOfBoundsException e) { 920 sResult += 1000; 921 } 922 expectEquals(1002, sResult); 923 } 924 sResult = 0; 925 try { 926 hiddenInfiniteOOB(); 927 } catch (ArrayIndexOutOfBoundsException e) { 928 sResult += 1000; 929 } 930 expectEquals(1011, sResult); 931 sResult = 0; 932 try { 933 hiddenFiniteOOB(); 934 } catch (ArrayIndexOutOfBoundsException e) { 935 sResult += 1000; 936 } 937 expectEquals(1111, sResult); 938 sResult = 0; 939 try { 940 inductionOOB(a200); 941 } catch (ArrayIndexOutOfBoundsException e) { 942 sResult += 1000; 943 } 944 expectEquals(1000, sResult); 945 for (int i = 0; i < 200; i++) { 946 expectEquals(i < 128 ? i : 0, a200[i]); 947 } 948 sResult = 0; 949 try { 950 controlOOB(a200); 951 } catch (ArrayIndexOutOfBoundsException e) { 952 sResult += 1000; 953 } 954 expectEquals(1000, sResult); 955 for (int i = 0; i < 200; i++) { 956 expectEquals(i < 128 ? -i : 0, a200[i]); 957 } 958 sResult = 0; 959 try { 960 conversionOOB(a200); 961 } catch (ArrayIndexOutOfBoundsException e) { 962 sResult += 1000; 963 } 964 expectEquals(1000, sResult); 965 for (int i = 0; i < 200; i++) { 966 expectEquals(i < 128 ? i : 0, a200[i]); 967 } 968 969 // Addition. 970 { 971 int[] e1 ={ 1, 2, 3, 4, 4, 4, 4, 3, 2, 1 }; 972 int[] a1 = add(); 973 for (int i = 0; i < 10; i++) { 974 expectEquals(a1[i], e1[i]); 975 } 976 } 977 978 // Multiplication. 979 { 980 int[] e1 = { 7, 1, 2, 2, 1, 0, 2, 0, 0, 1 }; 981 int[] a1 = multiply1(); 982 for (int i = 0; i < 10; i++) { 983 expectEquals(a1[i], e1[i]); 984 } 985 int[] e2 = { 1001, 0, 0, 1, 0, 0, 1, 0, 0, 1 }; 986 int[] a2 = multiply2(); 987 for (int i = 0; i < 10; i++) { 988 expectEquals(a2[i], e2[i]); 989 } 990 } 991 992 // Dynamic BCE. 993 sResult = 0; 994 try { 995 linearDynamicBCE1(x, -1, x.length); 996 } catch (ArrayIndexOutOfBoundsException e) { 997 sResult += 1000; 998 } 999 expectEquals(1000, sResult); 1000 sResult = 0; 1001 linearDynamicBCE1(x, 0, x.length); 1002 expectEquals(55, sResult); 1003 sResult = 0; 1004 try { 1005 linearDynamicBCE1(x, 0, x.length + 1); 1006 } catch (ArrayIndexOutOfBoundsException e) { 1007 sResult += 1000; 1008 } 1009 expectEquals(1055, sResult); 1010 1011 // Dynamic BCE with offset. 1012 sResult = 0; 1013 try { 1014 linearDynamicBCE2(x, 0, x.length, -1); 1015 } catch (ArrayIndexOutOfBoundsException e) { 1016 sResult += 1000; 1017 } 1018 expectEquals(1000, sResult); 1019 sResult = 0; 1020 linearDynamicBCE2(x, 0, x.length, 0); 1021 expectEquals(55, sResult); 1022 sResult = 0; 1023 try { 1024 linearDynamicBCE2(x, 0, x.length, 1); 1025 } catch (ArrayIndexOutOfBoundsException e) { 1026 sResult += 1000; 1027 } 1028 expectEquals(1054, sResult); 1029 1030 // Dynamic BCE candidates. 1031 expectEquals(55, wrapAroundDynamicBCE(x)); 1032 expectEquals(15, periodicDynamicBCE(x)); 1033 expectEquals(55, dynamicBCEPossiblyInfiniteLoop(x, 0, 9)); 1034 expectEquals(55, noDynamicBCEPossiblyInfiniteLoop(x, 0, 9)); 1035 expectEquals(55, noDynamicBCEMixedInductionTypes(x, 0, 10)); 1036 expectEquals(125, dynamicBCEConstantRange(x)); 1037 1038 // Dynamic BCE combined with constant indices. 1039 int[][] a; 1040 a = new int[0][0]; 1041 expectEquals(-1, dynamicBCEAndConstantIndices(x, a, 0, 10)); 1042 a = new int[100][10]; 1043 expectEquals(55, dynamicBCEAndConstantIndices(x, a, 0, 10)); 1044 for (int i = 0; i < 10; i++) { 1045 expectEquals((i % 10) != 0 ? 1 : 0, a[0][i]); 1046 expectEquals((i % 10) != 0 ? 2 : 0, a[1][i]); 1047 expectEquals((i % 10) != 0 ? 3 : 0, a[99][i]); 1048 } 1049 a = new int[2][10]; 1050 sResult = 0; 1051 try { 1052 expectEquals(55, dynamicBCEAndConstantIndices(x, a, 0, 10)); 1053 } catch (ArrayIndexOutOfBoundsException e) { 1054 sResult = 1; 1055 } 1056 expectEquals(1, sResult); 1057 expectEquals(a[0][1], 1); 1058 expectEquals(a[1][1], 2); 1059 1060 // Dynamic BCE combined with constant indices of all types. 1061 boolean[] x1 = { true }; 1062 byte[] x2 = { 2 }; 1063 char[] x3 = { 3 }; 1064 short[] x4 = { 4 }; 1065 int[] x5 = { 5 }; 1066 long[] x6 = { 6 }; 1067 float[] x7 = { 7 }; 1068 double[] x8 = { 8 }; 1069 expectEquals(415, 1070 dynamicBCEAndConstantIndicesAllPrimTypes(x, x1, x2, x3, x4, x5, x6, x7, x8, 0, 10)); 1071 Integer[] x9 = { 9 }; 1072 expectEquals(145, dynamicBCEAndConstantIndexRefType(x, x9, 0, 10)); 1073 1074 System.out.println("passed"); 1075 } 1076 1077 private static void expectEquals(int expected, int result) { 1078 if (expected != result) { 1079 throw new Error("Expected: " + expected + ", found: " + result); 1080 } 1081 } 1082 } 1083