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 class Circle { Circle(double radius)18 Circle(double radius) { 19 this.radius = radius; 20 } getRadius()21 public double getRadius() { 22 return radius; 23 } getArea()24 public double getArea() { 25 return radius * radius * Math.PI; 26 } 27 private double radius; 28 } 29 30 class TestClass { 31 static { 32 sTestClassObj = new TestClass(-1, -2); 33 } TestClass()34 TestClass() { 35 } TestClass(int i, int j)36 TestClass(int i, int j) { 37 this.i = i; 38 this.j = j; 39 } 40 int i; 41 int j; 42 volatile int k; 43 TestClass next; 44 String str; 45 byte b; 46 static int si; 47 static TestClass sTestClassObj; 48 } 49 50 class SubTestClass extends TestClass { 51 int k; 52 } 53 54 class TestClass2 { 55 int i; 56 int j; 57 int k; 58 int l; 59 int m; 60 } 61 62 class TestClass3 { 63 float floatField = 8.0f; 64 boolean test1 = true; 65 } 66 67 // Chosen to have different values with (x + 1) * 10 and (x - 1) * 10. This 68 // means we can easily make sure that different code is in fact executed on 69 // escape and non-escape paths. 70 // Negative so that high-bits will be set for all the 64-bit values allowing us 71 // to easily check for truncation. 72 class TestClass4 { 73 float floatField = -3.0f; 74 double doubleField = -3.0d; 75 short shortField = -3; 76 int intField = -3; 77 byte byteField = -3; 78 long longField = -3l; 79 } 80 81 class Finalizable { 82 static boolean sVisited = false; 83 static final int VALUE1 = 0xbeef; 84 static final int VALUE2 = 0xcafe; 85 int i; 86 finalize()87 protected void finalize() { 88 if (i != VALUE1) { 89 System.out.println("Where is the beef?"); 90 } 91 sVisited = true; 92 } 93 } 94 95 interface Filter { isValid(int i)96 public boolean isValid(int i); 97 } 98 99 public class Main { $noinline$Escape4(TestClass4 o)100 static void $noinline$Escape4(TestClass4 o) { 101 o.floatField += 1.0f; 102 o.doubleField += 1.0d; 103 o.byteField += 1; 104 o.shortField += 1; 105 o.intField += 1; 106 o.longField += 1; 107 } 108 109 static Object ESCAPE = null; $noinline$Escape(TestClass o)110 static void $noinline$Escape(TestClass o) { 111 if (o == null) { 112 return; 113 } 114 ESCAPE = o; 115 o.next.i++; 116 } 117 118 /// CHECK-START: double Main.calcCircleArea(double) load_store_elimination (before) 119 /// CHECK: NewInstance 120 /// CHECK: InstanceFieldSet 121 /// CHECK: InstanceFieldGet 122 123 /// CHECK-START: double Main.calcCircleArea(double) load_store_elimination (after) 124 /// CHECK-NOT: NewInstance 125 /// CHECK-NOT: InstanceFieldSet 126 /// CHECK-NOT: InstanceFieldGet 127 calcCircleArea(double radius)128 static double calcCircleArea(double radius) { 129 return new Circle(radius).getArea(); 130 } 131 132 /// CHECK-START: int Main.test1(TestClass, TestClass) load_store_elimination (before) 133 /// CHECK: InstanceFieldSet 134 /// CHECK: InstanceFieldSet 135 /// CHECK: InstanceFieldGet 136 /// CHECK: InstanceFieldGet 137 138 /// CHECK-START: int Main.test1(TestClass, TestClass) load_store_elimination (after) 139 /// CHECK: InstanceFieldSet 140 /// CHECK: InstanceFieldSet 141 /// CHECK-NOT: NullCheck 142 /// CHECK-NOT: InstanceFieldGet 143 144 // Different fields shouldn't alias. test1(TestClass obj1, TestClass obj2)145 static int test1(TestClass obj1, TestClass obj2) { 146 obj1.i = 1; 147 obj2.j = 2; 148 return obj1.i + obj2.j; 149 } 150 151 /// CHECK-START: int Main.test2(TestClass) load_store_elimination (before) 152 /// CHECK: InstanceFieldSet 153 /// CHECK: InstanceFieldSet 154 /// CHECK: InstanceFieldGet 155 156 /// CHECK-START: int Main.test2(TestClass) load_store_elimination (after) 157 /// CHECK: InstanceFieldSet 158 /// CHECK-NOT: NullCheck 159 /// CHECK-NOT: InstanceFieldSet 160 /// CHECK-NOT: InstanceFieldGet 161 162 // Redundant store of the same value. test2(TestClass obj)163 static int test2(TestClass obj) { 164 obj.j = 1; 165 obj.j = 1; 166 return obj.j; 167 } 168 169 /// CHECK-START: int Main.test3(TestClass) load_store_elimination (before) 170 /// CHECK: StaticFieldGet 171 /// CHECK: NewInstance 172 /// CHECK: InstanceFieldSet 173 /// CHECK: InstanceFieldSet 174 /// CHECK: InstanceFieldSet 175 /// CHECK: InstanceFieldSet 176 /// CHECK: InstanceFieldSet 177 /// CHECK: InstanceFieldGet 178 /// CHECK: InstanceFieldGet 179 /// CHECK: InstanceFieldGet 180 /// CHECK: InstanceFieldGet 181 182 /// CHECK-START: int Main.test3(TestClass) load_store_elimination (after) 183 /// CHECK: StaticFieldGet 184 /// CHECK: NewInstance 185 /// CHECK: InstanceFieldSet 186 /// CHECK: InstanceFieldSet 187 /// CHECK: InstanceFieldSet 188 /// CHECK: InstanceFieldSet 189 /// CHECK: InstanceFieldSet 190 191 /// CHECK-START: int Main.test3(TestClass) load_store_elimination (after) 192 /// CHECK-NOT: InstanceFieldGet 193 194 // A new allocation (even non-singleton) shouldn't alias with pre-existing values. test3(TestClass obj)195 static int test3(TestClass obj) { 196 TestClass obj1 = TestClass.sTestClassObj; 197 TestClass obj2 = new TestClass(); // Cannot alias with obj or obj1 which pre-exist. 198 obj.next = obj2; // Make obj2 a non-singleton. 199 // All stores below need to stay since obj/obj1/obj2 are not singletons. 200 obj.i = 1; 201 obj1.j = 2; 202 // Following stores won't kill values of obj.i and obj1.j. 203 obj2.i = 3; 204 obj2.j = 4; 205 return obj.i + obj1.j + obj2.i + obj2.j; 206 } 207 208 /// CHECK-START: int Main.test4(TestClass, boolean) load_store_elimination (before) 209 /// CHECK-DAG: InstanceFieldSet 210 /// CHECK-DAG: InstanceFieldSet 211 /// CHECK-DAG: InstanceFieldGet 212 /// CHECK-DAG: Return 213 214 /// CHECK-START: int Main.test4(TestClass, boolean) load_store_elimination (after) 215 /// CHECK-DAG: InstanceFieldSet 216 /// CHECK-DAG: InstanceFieldSet 217 /// CHECK-DAG: Return 218 219 /// CHECK-START: int Main.test4(TestClass, boolean) load_store_elimination (after) 220 /// CHECK: NullCheck 221 /// CHECK: NullCheck 222 /// CHECK-NOT: NullCheck 223 224 /// CHECK-START: int Main.test4(TestClass, boolean) load_store_elimination (after) 225 /// CHECK-NOT: InstanceFieldGet 226 /// CHECK-NOT: Phi 227 228 // Set and merge the same value in two branches. test4(TestClass obj, boolean b)229 static int test4(TestClass obj, boolean b) { 230 if (b) { 231 obj.i = 1; 232 } else { 233 obj.i = 1; 234 } 235 return obj.i; 236 } 237 238 /// CHECK-START: int Main.test5(TestClass, boolean) load_store_elimination (before) 239 /// CHECK-DAG: <<Int1:i\d+>> IntConstant 1 240 /// CHECK-DAG: <<Int2:i\d+>> IntConstant 2 241 /// CHECK-DAG: <<Obj:l\d+>> ParameterValue 242 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Int1>>] 243 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Int2>>] 244 /// CHECK-DAG: <<GetField:i\d+>> InstanceFieldGet [{{l\d+}}] 245 /// CHECK-DAG: Return [<<GetField>>] 246 247 /// CHECK-START: int Main.test5(TestClass, boolean) load_store_elimination (after) 248 /// CHECK-DAG: <<Int1:i\d+>> IntConstant 1 249 /// CHECK-DAG: <<Int2:i\d+>> IntConstant 2 250 /// CHECK-DAG: <<Obj:l\d+>> ParameterValue 251 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Int1>>] 252 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Int2>>] 253 /// CHECK-DAG: <<Phi:i\d+>> Phi [<<Arg1:i\d+>>,<<Arg2:i\d+>>] 254 /// CHECK-DAG: Return [<<Phi>>] 255 /// CHECK-EVAL: set(["<<Arg1>>","<<Arg2>>"]) == set(["<<Int1>>","<<Int2>>"]) 256 257 /// CHECK-START: int Main.test5(TestClass, boolean) load_store_elimination (after) 258 /// CHECK-NOT: InstanceFieldGet 259 260 // Set and merge different values in two branches. test5(TestClass obj, boolean b)261 static int test5(TestClass obj, boolean b) { 262 if (b) { 263 obj.i = 1; 264 } else { 265 obj.i = 2; 266 } 267 return obj.i; 268 } 269 270 /// CHECK-START: int Main.test6(TestClass, TestClass, boolean) load_store_elimination (before) 271 /// CHECK-DAG: InstanceFieldSet 272 /// CHECK-DAG: InstanceFieldSet 273 /// CHECK-DAG: InstanceFieldSet 274 /// CHECK-DAG: InstanceFieldGet 275 /// CHECK-DAG: InstanceFieldGet 276 277 /// CHECK-START: int Main.test6(TestClass, TestClass, boolean) load_store_elimination (after) 278 /// CHECK-DAG: InstanceFieldSet 279 /// CHECK-DAG: InstanceFieldSet 280 /// CHECK-DAG: InstanceFieldSet 281 /// CHECK-DAG: InstanceFieldGet 282 283 /// CHECK-START: int Main.test6(TestClass, TestClass, boolean) load_store_elimination (after) 284 /// CHECK: InstanceFieldGet 285 /// CHECK-NOT: InstanceFieldGet 286 287 // Setting the same value doesn't clear the value for aliased locations. test6(TestClass obj1, TestClass obj2, boolean b)288 static int test6(TestClass obj1, TestClass obj2, boolean b) { 289 obj1.i = 1; 290 obj1.j = 2; 291 if (b) { 292 obj2.j = 2; 293 } 294 return obj1.j + obj2.j; 295 } 296 297 /// CHECK-START: int Main.test7(TestClass) load_store_elimination (before) 298 /// CHECK: InstanceFieldSet 299 /// CHECK: InstanceFieldGet 300 301 /// CHECK-START: int Main.test7(TestClass) load_store_elimination (after) 302 /// CHECK: InstanceFieldSet 303 /// CHECK: InstanceFieldGet 304 305 // Invocation should kill values in non-singleton heap locations. test7(TestClass obj)306 static int test7(TestClass obj) { 307 obj.i = 1; 308 System.out.print(""); 309 return obj.i; 310 } 311 312 /// CHECK-START: int Main.test8() load_store_elimination (before) 313 /// CHECK: NewInstance 314 /// CHECK: InstanceFieldSet 315 /// CHECK: InvokeVirtual 316 /// CHECK: InstanceFieldGet 317 318 /// CHECK-START: int Main.test8() load_store_elimination (after) 319 /// CHECK-NOT: NewInstance 320 /// CHECK-NOT: InstanceFieldSet 321 /// CHECK: InvokeVirtual 322 /// CHECK-NOT: NullCheck 323 /// CHECK-NOT: InstanceFieldGet 324 325 // Invocation should not kill values in singleton heap locations. test8()326 static int test8() { 327 TestClass obj = new TestClass(); 328 obj.i = 1; 329 System.out.print(""); 330 return obj.i; 331 } 332 333 /// CHECK-START: int Main.test9(TestClass) load_store_elimination (before) 334 /// CHECK: NewInstance 335 /// CHECK: InstanceFieldSet 336 /// CHECK: InstanceFieldSet 337 /// CHECK: InstanceFieldGet 338 339 /// CHECK-START: int Main.test9(TestClass) load_store_elimination (after) 340 /// CHECK: NewInstance 341 /// CHECK: InstanceFieldSet 342 /// CHECK: InstanceFieldSet 343 /// CHECK: InstanceFieldGet 344 345 // Invocation should kill values in non-singleton heap locations. test9(TestClass obj)346 static int test9(TestClass obj) { 347 TestClass obj2 = new TestClass(); 348 obj2.i = 1; 349 obj.next = obj2; 350 System.out.print(""); 351 return obj2.i; 352 } 353 354 /// CHECK-START: int Main.test10(TestClass) load_store_elimination (before) 355 /// CHECK-DAG: StaticFieldGet 356 /// CHECK-DAG: InstanceFieldGet 357 /// CHECK-DAG: StaticFieldSet 358 /// CHECK-DAG: InstanceFieldGet 359 360 /// CHECK-START: int Main.test10(TestClass) load_store_elimination (after) 361 /// CHECK-DAG: StaticFieldGet 362 /// CHECK-DAG: InstanceFieldGet 363 /// CHECK-DAG: StaticFieldSet 364 365 /// CHECK-START: int Main.test10(TestClass) load_store_elimination (after) 366 /// CHECK: NullCheck 367 /// CHECK-NOT: NullCheck 368 369 /// CHECK-START: int Main.test10(TestClass) load_store_elimination (after) 370 /// CHECK: InstanceFieldGet 371 /// CHECK-NOT: InstanceFieldGet 372 373 // Static fields shouldn't alias with instance fields. test10(TestClass obj)374 static int test10(TestClass obj) { 375 TestClass.si += obj.i; 376 return obj.i; 377 } 378 379 /// CHECK-START: int Main.test11(TestClass) load_store_elimination (before) 380 /// CHECK: InstanceFieldSet 381 /// CHECK: InstanceFieldGet 382 383 /// CHECK-START: int Main.test11(TestClass) load_store_elimination (after) 384 /// CHECK: InstanceFieldSet 385 /// CHECK-NOT: NullCheck 386 /// CHECK-NOT: InstanceFieldGet 387 388 // Loop without heap writes. test11(TestClass obj)389 static int test11(TestClass obj) { 390 obj.i = 1; 391 int sum = 0; 392 for (int i = 0; i < 10; i++) { 393 sum += obj.i; 394 } 395 return sum; 396 } 397 398 /// CHECK-START: int Main.test12(TestClass, TestClass) load_store_elimination (before) 399 /// CHECK: InstanceFieldSet 400 /// CHECK: InstanceFieldGet 401 /// CHECK: InstanceFieldSet 402 403 /// CHECK-START: int Main.test12(TestClass, TestClass) load_store_elimination (after) 404 /// CHECK: InstanceFieldSet 405 /// CHECK: InstanceFieldGet 406 /// CHECK: InstanceFieldSet 407 408 // Loop with heap writes. test12(TestClass obj1, TestClass obj2)409 static int test12(TestClass obj1, TestClass obj2) { 410 obj1.i = 1; 411 int sum = 0; 412 for (int i = 0; i < 10; i++) { 413 sum += obj1.i; 414 obj2.i = sum; 415 } 416 return sum; 417 } 418 419 /// CHECK-START: int Main.test13(TestClass, TestClass2) load_store_elimination (before) 420 /// CHECK: InstanceFieldSet 421 /// CHECK: InstanceFieldSet 422 /// CHECK: InstanceFieldGet 423 /// CHECK: InstanceFieldGet 424 425 /// CHECK-START: int Main.test13(TestClass, TestClass2) load_store_elimination (after) 426 /// CHECK: InstanceFieldSet 427 /// CHECK: InstanceFieldSet 428 /// CHECK-NOT: NullCheck 429 /// CHECK-NOT: InstanceFieldGet 430 431 // Different classes shouldn't alias. test13(TestClass obj1, TestClass2 obj2)432 static int test13(TestClass obj1, TestClass2 obj2) { 433 obj1.i = 1; 434 obj2.i = 2; 435 return obj1.i + obj2.i; 436 } 437 438 /// CHECK-START: int Main.test14(TestClass, SubTestClass) load_store_elimination (before) 439 /// CHECK: InstanceFieldSet 440 /// CHECK: InstanceFieldSet 441 /// CHECK: InstanceFieldGet 442 443 /// CHECK-START: int Main.test14(TestClass, SubTestClass) load_store_elimination (after) 444 /// CHECK: InstanceFieldSet 445 /// CHECK: InstanceFieldSet 446 /// CHECK: InstanceFieldGet 447 448 // Subclass may alias with super class. test14(TestClass obj1, SubTestClass obj2)449 static int test14(TestClass obj1, SubTestClass obj2) { 450 obj1.i = 1; 451 obj2.i = 2; 452 return obj1.i; 453 } 454 455 /// CHECK-START: int Main.test15() load_store_elimination (before) 456 /// CHECK: StaticFieldSet 457 /// CHECK: StaticFieldSet 458 /// CHECK: StaticFieldGet 459 460 /// CHECK-START: int Main.test15() load_store_elimination (after) 461 /// CHECK: <<Const2:i\d+>> IntConstant 2 462 /// CHECK: StaticFieldSet 463 /// CHECK: Return [<<Const2>>] 464 465 /// CHECK-START: int Main.test15() load_store_elimination (after) 466 /// CHECK-NOT: StaticFieldGet 467 468 // Static field access from subclass's name. test15()469 static int test15() { 470 TestClass.si = 1; 471 SubTestClass.si = 2; 472 return TestClass.si; 473 } 474 475 /// CHECK-START: int Main.test16() load_store_elimination (before) 476 /// CHECK: NewInstance 477 /// CHECK: InstanceFieldSet 478 /// CHECK: InstanceFieldSet 479 /// CHECK: InstanceFieldGet 480 /// CHECK: InstanceFieldGet 481 482 /// CHECK-START: int Main.test16() load_store_elimination (after) 483 /// CHECK-NOT: NewInstance 484 /// CHECK-NOT: InstanceFieldSet 485 /// CHECK-NOT: InstanceFieldGet 486 487 // Test inlined constructor. test16()488 static int test16() { 489 TestClass obj = new TestClass(1, 2); 490 return obj.i + obj.j; 491 } 492 493 /// CHECK-START: int Main.test17() load_store_elimination (before) 494 /// CHECK: NewInstance 495 /// CHECK: InstanceFieldSet 496 /// CHECK: InstanceFieldGet 497 498 /// CHECK-START: int Main.test17() load_store_elimination (after) 499 /// CHECK: <<Const0:i\d+>> IntConstant 0 500 /// CHECK-NOT: NewInstance 501 /// CHECK-NOT: InstanceFieldSet 502 /// CHECK-NOT: InstanceFieldGet 503 /// CHECK: Return [<<Const0>>] 504 505 // Test getting default value. test17()506 static int test17() { 507 TestClass obj = new TestClass(); 508 obj.j = 1; 509 return obj.i; 510 } 511 512 /// CHECK-START: int Main.test18(TestClass) load_store_elimination (before) 513 /// CHECK: InstanceFieldSet 514 /// CHECK: InstanceFieldGet 515 516 /// CHECK-START: int Main.test18(TestClass) load_store_elimination (after) 517 /// CHECK: InstanceFieldSet 518 /// CHECK: InstanceFieldGet 519 520 // Volatile field load/store shouldn't be eliminated. test18(TestClass obj)521 static int test18(TestClass obj) { 522 obj.k = 1; 523 return obj.k; 524 } 525 526 /// CHECK-START: float Main.test19(float[], float[]) load_store_elimination (before) 527 /// CHECK: {{f\d+}} ArrayGet 528 /// CHECK: {{f\d+}} ArrayGet 529 530 /// CHECK-START: float Main.test19(float[], float[]) load_store_elimination (after) 531 /// CHECK: {{f\d+}} ArrayGet 532 /// CHECK-NOT: {{f\d+}} ArrayGet 533 534 // I/F, J/D aliasing should not happen any more and LSE should eliminate the load. test19(float[] fa1, float[] fa2)535 static float test19(float[] fa1, float[] fa2) { 536 fa1[0] = fa2[0]; 537 return fa1[0]; 538 } 539 540 /// CHECK-START: TestClass Main.test20() load_store_elimination (before) 541 /// CHECK: NewInstance 542 /// CHECK: InstanceFieldSet 543 544 /// CHECK-START: TestClass Main.test20() load_store_elimination (after) 545 /// CHECK: NewInstance 546 /// CHECK-NOT: InstanceFieldSet 547 548 // Storing default heap value is redundant if the heap location has the 549 // default heap value. test20()550 static TestClass test20() { 551 TestClass obj = new TestClass(); 552 obj.i = 0; 553 return obj; 554 } 555 556 /// CHECK-START: void Main.test21(TestClass) load_store_elimination (before) 557 /// CHECK: NewInstance 558 /// CHECK: InstanceFieldSet 559 /// CHECK: InstanceFieldSet 560 /// CHECK: InstanceFieldSet 561 /// CHECK: InstanceFieldGet 562 /// CHECK: InstanceFieldGet 563 564 /// CHECK-START: void Main.test21(TestClass) load_store_elimination (after) 565 /// CHECK-DAG: InstanceFieldSet 566 /// CHECK-DAG: Phi 567 568 /// CHECK-START: void Main.test21(TestClass) load_store_elimination (after) 569 /// CHECK-NOT: NewInstance 570 /// CHECK-NOT: InstanceFieldGet 571 572 // Loop side effects can kill heap values, stores need to be kept in that case. test21(TestClass obj0)573 static void test21(TestClass obj0) { 574 TestClass obj = new TestClass(); 575 obj0.str = "abc"; 576 obj.str = "abc"; 577 // Note: This loop is transformed by the loop optimization pass, therefore we 578 // are not checking the exact number of InstanceFieldSet and Phi instructions. 579 for (int i = 0; i < 2; i++) { 580 // Generate some loop side effect that writes into obj. 581 obj.str = "def"; 582 } 583 $noinline$printSubstrings00(obj0.str, obj.str); 584 } 585 $noinline$printSubstrings00(String str1, String str2)586 static void $noinline$printSubstrings00(String str1, String str2) { 587 System.out.print(str1.substring(0, 0) + str2.substring(0, 0)); 588 } 589 590 /// CHECK-START: int Main.test22() load_store_elimination (before) 591 /// CHECK: NewInstance 592 /// CHECK: InstanceFieldSet 593 /// CHECK: NewInstance 594 /// CHECK: InstanceFieldSet 595 /// CHECK: InstanceFieldGet 596 /// CHECK: NewInstance 597 /// CHECK: InstanceFieldSet 598 /// CHECK: InstanceFieldGet 599 /// CHECK: InstanceFieldGet 600 601 /// CHECK-START: int Main.test22() load_store_elimination (after) 602 /// CHECK-NOT: NewInstance 603 /// CHECK-NOT: InstanceFieldSet 604 /// CHECK-NOT: InstanceFieldGet 605 606 // For a singleton, loop side effects can kill its field values only if: 607 // (1) it dominiates the loop header, and 608 // (2) its fields are stored into inside a loop. test22()609 static int test22() { 610 int sum = 0; 611 TestClass obj1 = new TestClass(); 612 obj1.i = 2; // This store can be eliminated since obj1 is never stored into inside a loop. 613 for (int i = 0; i < 2; i++) { 614 TestClass obj2 = new TestClass(); 615 obj2.i = 3; // This store can be eliminated since the singleton is inside the loop. 616 sum += obj2.i; 617 } 618 TestClass obj3 = new TestClass(); 619 obj3.i = 5; // This store can be eliminated since the singleton is created after the loop. 620 sum += obj1.i + obj3.i; 621 return sum; 622 } 623 624 /// CHECK-START: int Main.test23(boolean) load_store_elimination (before) 625 /// CHECK-DAG: <<Int1:i\d+>> IntConstant 1 626 /// CHECK-DAG: <<Int2:i\d+>> IntConstant 2 627 /// CHECK-DAG: <<Int3:i\d+>> IntConstant 3 628 /// CHECK-DAG: <<Obj:l\d+>> NewInstance 629 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Int3>>] 630 /// CHECK-DAG: <<Add1:i\d+>> Add [<<Get1:i\d+>>,<<Int1>>] 631 /// CHECK-DAG: <<Get1>> InstanceFieldGet [<<Obj>>] 632 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Add1>>] 633 /// CHECK-DAG: <<Add2:i\d+>> Add [<<Get2:i\d+>>,<<Int2>>] 634 /// CHECK-DAG: <<Get2>> InstanceFieldGet [<<Obj>>] 635 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Add2>>] 636 /// CHECK-DAG: Return [<<Get3:i\d+>>] 637 /// CHECK-DAG: <<Get3>> InstanceFieldGet [<<Obj>>] 638 639 /// CHECK-START: int Main.test23(boolean) load_store_elimination (after) 640 /// CHECK-DAG: <<Int1:i\d+>> IntConstant 1 641 /// CHECK-DAG: <<Int2:i\d+>> IntConstant 2 642 /// CHECK-DAG: <<Int3:i\d+>> IntConstant 3 643 /// CHECK-DAG: <<Add1:i\d+>> Add [<<Int3>>,<<Int1>>] 644 /// CHECK-DAG: <<Add2:i\d+>> Add [<<Int3>>,<<Int2>>] 645 /// CHECK-DAG: <<Phi:i\d+>> Phi [<<Arg1:i\d+>>,<<Arg2:i\d+>>] 646 /// CHECK-DAG: Return [<<Phi>>] 647 /// CHECK-EVAL: set(["<<Arg1>>","<<Arg2>>"]) == set(["<<Add1>>","<<Add2>>"]) 648 649 /// CHECK-START: int Main.test23(boolean) load_store_elimination (after) 650 /// CHECK-NOT: NewInstance 651 /// CHECK-NOT: InstanceFieldSet 652 /// CHECK-NOT: InstanceFieldGet 653 654 // Test heap value merging from multiple branches. test23(boolean b)655 static int test23(boolean b) { 656 TestClass obj = new TestClass(); 657 obj.i = 3; // This store can be eliminated since the value flows into each branch. 658 if (b) { 659 obj.i += 1; // This store can be eliminated after replacing the load below with a Phi. 660 } else { 661 obj.i += 2; // This store can be eliminated after replacing the load below with a Phi. 662 } 663 return obj.i; // This load is eliminated by creating a Phi. 664 } 665 666 /// CHECK-START: float Main.test24() load_store_elimination (before) 667 /// CHECK-DAG: <<True:i\d+>> IntConstant 1 668 /// CHECK-DAG: <<Float8:f\d+>> FloatConstant 8 669 /// CHECK-DAG: <<Float42:f\d+>> FloatConstant 42 670 /// CHECK-DAG: <<Obj:l\d+>> NewInstance 671 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<True>>] 672 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Float8>>] 673 /// CHECK-DAG: <<GetTest:z\d+>> InstanceFieldGet [<<Obj>>] 674 /// CHECK-DAG: <<GetField:f\d+>> InstanceFieldGet [<<Obj>>] 675 /// CHECK-DAG: <<Select:f\d+>> Select [<<Float42>>,<<GetField>>,<<GetTest>>] 676 /// CHECK-DAG: Return [<<Select>>] 677 678 /// CHECK-START: float Main.test24() load_store_elimination (after) 679 /// CHECK-DAG: <<True:i\d+>> IntConstant 1 680 /// CHECK-DAG: <<Float8:f\d+>> FloatConstant 8 681 /// CHECK-DAG: <<Float42:f\d+>> FloatConstant 42 682 /// CHECK-DAG: <<Select:f\d+>> Select [<<Float42>>,<<Float8>>,<<True>>] 683 /// CHECK-DAG: Return [<<Select>>] 684 685 /// CHECK-START: float Main.test24() load_store_elimination (after) 686 /// CHECK-NOT: NewInstance 687 /// CHECK-NOT: InstanceFieldGet test24()688 static float test24() { 689 float a = 42.0f; 690 TestClass3 obj = new TestClass3(); 691 if (obj.test1) { 692 a = obj.floatField; 693 } 694 return a; 695 } 696 697 /// CHECK-START: int Main.test25(boolean, boolean, boolean) load_store_elimination (before) 698 /// CHECK-DAG: <<Int1:i\d+>> IntConstant 1 699 /// CHECK-DAG: <<Int2:i\d+>> IntConstant 2 700 /// CHECK-DAG: <<Int3:i\d+>> IntConstant 3 701 /// CHECK-DAG: <<Int5:i\d+>> IntConstant 5 702 /// CHECK-DAG: <<Int6:i\d+>> IntConstant 6 703 /// CHECK-DAG: <<Obj:l\d+>> NewInstance 704 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Int1>>] 705 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Int2>>] 706 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Int3>>] 707 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Int5>>] 708 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Int6>>] 709 /// CHECK-DAG: <<GetField:i\d+>> InstanceFieldGet [<<Obj>>] 710 /// CHECK-DAG: Return [<<GetField>>] 711 712 /// CHECK-START: int Main.test25(boolean, boolean, boolean) load_store_elimination (after) 713 /// CHECK-DAG: <<Int1:i\d+>> IntConstant 1 714 /// CHECK-DAG: <<Int2:i\d+>> IntConstant 2 715 /// CHECK-DAG: <<Int3:i\d+>> IntConstant 3 716 /// CHECK-DAG: <<Int5:i\d+>> IntConstant 5 717 /// CHECK-DAG: <<Int6:i\d+>> IntConstant 6 718 /// CHECK-DAG: <<Phi:i\d+>> Phi [<<Arg1:i\d+>>,<<Arg2:i\d+>>,<<Arg3:i\d+>>,<<Arg4:i\d+>>,<<Arg5:i\d+>>] 719 /// CHECK-DAG: Return [<<Phi>>] 720 /// CHECK-EVAL: set(["<<Arg1>>","<<Arg2>>","<<Arg3>>","<<Arg4>>","<<Arg5>>"]) == set(["<<Int1>>","<<Int2>>","<<Int3>>","<<Int5>>","<<Int6>>"]) 721 722 /// CHECK-START: int Main.test25(boolean, boolean, boolean) load_store_elimination (after) 723 /// CHECK-NOT: NewInstance 724 /// CHECK-NOT: InstanceFieldSet 725 /// CHECK-NOT: InstanceFieldGet 726 727 // Test heap value merging from nested branches. test25(boolean b, boolean c, boolean d)728 static int test25(boolean b, boolean c, boolean d) { 729 TestClass obj = new TestClass(); 730 if (b) { 731 if (c) { 732 obj.i = 1; 733 } else { 734 if (d) { 735 obj.i = 2; 736 } else { 737 obj.i = 3; 738 } 739 } 740 } else { 741 if (c) { 742 obj.i = 5; 743 } else { 744 obj.i = 6; 745 } 746 } 747 return obj.i; 748 } 749 750 /// CHECK-START: float Main.test26(int) load_store_elimination (before) 751 /// CHECK-DAG: <<Float0:f\d+>> FloatConstant 0 752 /// CHECK-DAG: <<Float1:f\d+>> FloatConstant 1 753 /// CHECK-DAG: <<Float2:f\d+>> FloatConstant 2 754 /// CHECK-DAG: <<Float3:f\d+>> FloatConstant 3 755 /// CHECK-DAG: <<Float8:f\d+>> FloatConstant 8 756 /// CHECK-DAG: <<Obj:l\d+>> NewInstance 757 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Float8>>] 758 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Float0>>] 759 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Float1>>] 760 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Float2>>] 761 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Float3>>] 762 /// CHECK-DAG: <<GetField:f\d+>> InstanceFieldGet [<<Obj>>] 763 /// CHECK-DAG: Return [<<GetField>>] 764 765 /// CHECK-START: float Main.test26(int) load_store_elimination (after) 766 /// CHECK-DAG: <<Float0:f\d+>> FloatConstant 0 767 /// CHECK-DAG: <<Float1:f\d+>> FloatConstant 1 768 /// CHECK-DAG: <<Float2:f\d+>> FloatConstant 2 769 /// CHECK-DAG: <<Float3:f\d+>> FloatConstant 3 770 /// CHECK-DAG: <<Float8:f\d+>> FloatConstant 8 771 /// CHECK-DAG: <<Phi:f\d+>> Phi [<<Arg1:f\d+>>,<<Arg2:f\d+>>,<<Arg3:f\d+>>,<<Arg4:f\d+>>] 772 /// CHECK-DAG: Return [<<Phi>>] 773 /// CHECK-EVAL: set(["<<Arg1>>","<<Arg2>>","<<Arg3>>","<<Arg4>>"]) == set(["<<Float0>>","<<Float1>>","<<Float2>>","<<Float3>>"]) 774 775 /// CHECK-START: float Main.test26(int) load_store_elimination (after) 776 /// CHECK-NOT: NewInstance 777 /// CHECK-NOT: InstanceFieldSet 778 /// CHECK-NOT: InstanceFieldGet 779 780 // Test heap value merging from switch statement. test26(int b)781 static float test26(int b) { 782 TestClass3 obj = new TestClass3(); 783 switch (b) { 784 case 1: 785 obj.floatField = 3.0f; 786 break; 787 case 2: 788 obj.floatField = 2.0f; 789 break; 790 case 3: 791 obj.floatField = 1.0f; 792 break; 793 default: 794 obj.floatField = 0.0f; 795 break; 796 } 797 return obj.floatField; 798 } 799 800 /// CHECK-START: int Main.test27(boolean, boolean) load_store_elimination (before) 801 /// CHECK-DAG: <<Int1:i\d+>> IntConstant 1 802 /// CHECK-DAG: <<Obj:l\d+>> NewInstance 803 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Int1>>] 804 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Int1>>] 805 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Int1>>] 806 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Int1>>] 807 /// CHECK-DAG: <<GetField:i\d+>> InstanceFieldGet [<<Obj>>] 808 /// CHECK-DAG: Return [<<GetField>>] 809 810 /// CHECK-START: int Main.test27(boolean, boolean) load_store_elimination (after) 811 /// CHECK-DAG: <<Int1:i\d+>> IntConstant 1 812 /// CHECK-DAG: Return [<<Int1>>] 813 814 /// CHECK-START: int Main.test27(boolean, boolean) load_store_elimination (after) 815 /// CHECK-NOT: NewInstance 816 /// CHECK-NOT: InstanceFieldSet 817 /// CHECK-NOT: InstanceFieldGet 818 /// CHECK-NOT: Phi 819 820 // Test merging same value from nested branches. test27(boolean b, boolean c)821 static int test27(boolean b, boolean c) { 822 TestClass obj = new TestClass(); 823 if (b) { 824 if (c) { 825 obj.i = 1; 826 } else { 827 obj.i = 1; 828 } 829 } else { 830 if (c) { 831 obj.i = 1; 832 } else { 833 obj.i = 1; 834 } 835 } 836 return obj.i; 837 } 838 839 /// CHECK-START: int Main.test28(boolean, boolean) load_store_elimination (before) 840 /// CHECK-DAG: <<Int0:i\d+>> IntConstant 0 841 /// CHECK-DAG: <<Int5:i\d+>> IntConstant 5 842 /// CHECK-DAG: <<Int6:i\d+>> IntConstant 6 843 /// CHECK-DAG: <<Array:l\d+>> NewArray 844 /// CHECK-DAG: ArraySet [<<Array>>,<<Int0>>,<<Int5>>] 845 /// CHECK-DAG: ArraySet [<<Array>>,<<Int0>>,<<Int6>>] 846 /// CHECK-DAG: <<GetIndex:i\d+>> ArrayGet [<<Array>>,<<Int0>>] 847 /// CHECK-DAG: Return [<<GetIndex>>] 848 849 /// CHECK-START: int Main.test28(boolean, boolean) load_store_elimination (after) 850 /// CHECK-DAG: <<Int0:i\d+>> IntConstant 0 851 /// CHECK-DAG: <<Int5:i\d+>> IntConstant 5 852 /// CHECK-DAG: <<Int6:i\d+>> IntConstant 6 853 /// CHECK-DAG: <<Phi:i\d+>> Phi [<<Arg1:i\d+>>,<<Arg2:i\d+>>,<<Arg3:i\d+>>] 854 /// CHECK-DAG: Return [<<Phi>>] 855 /// CHECK-EVAL: set(["<<Arg1>>","<<Arg2>>","<<Arg3>>"]) == set(["<<Int0>>","<<Int5>>","<<Int6>>"]) 856 857 /// CHECK-START: int Main.test28(boolean, boolean) load_store_elimination (after) 858 /// CHECK-NOT: NewArray 859 /// CHECK-NOT: ArraySet 860 /// CHECK-NOT: ArrayGet 861 862 // Test merging array stores in branches. test28(boolean b, boolean c)863 static int test28(boolean b, boolean c) { 864 int[] array = new int[1]; 865 if (b) { 866 if (c) { 867 array[0] = 5; 868 } else { 869 array[0] = 6; 870 } 871 } else { /* Default value: 0. */ } 872 return array[0]; 873 } 874 875 /// CHECK-START: float Main.test29(boolean) load_store_elimination (before) 876 /// CHECK-DAG: <<Float2:f\d+>> FloatConstant 2 877 /// CHECK-DAG: <<Float5:f\d+>> FloatConstant 5 878 /// CHECK-DAG: <<Float8:f\d+>> FloatConstant 8 879 /// CHECK-DAG: <<Obj:l\d+>> NewInstance 880 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Float8>>] 881 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Float2>>] 882 /// CHECK-DAG: InstanceFieldSet [<<Obj>>,<<Float5>>] 883 /// CHECK-DAG: <<GetField:f\d+>> InstanceFieldGet [<<Obj>>] 884 /// CHECK-DAG: Return [<<GetField>>] 885 886 /// CHECK-START: float Main.test29(boolean) load_store_elimination (after) 887 /// CHECK-DAG: <<Float2:f\d+>> FloatConstant 2 888 /// CHECK-DAG: <<Float5:f\d+>> FloatConstant 5 889 /// CHECK-DAG: <<Float8:f\d+>> FloatConstant 8 890 /// CHECK-DAG: <<Phi:f\d+>> Phi [<<Arg1:f\d+>>,<<Arg2:f\d+>>] 891 /// CHECK-DAG: Return [<<Phi>>] 892 /// CHECK-EVAL: set(["<<Arg1>>","<<Arg2>>"]) == set(["<<Float5>>","<<Float2>>"]) 893 894 /// CHECK-START: float Main.test29(boolean) load_store_elimination (after) 895 /// CHECK-NOT: NewInstance 896 /// CHECK-NOT: InstanceFieldSet 897 /// CHECK-NOT: InstanceFieldGet 898 899 // Test implicit type conversion in branches. test29(boolean b)900 static float test29(boolean b) { 901 TestClass3 obj = new TestClass3(); 902 if (b) { 903 obj.floatField = 5; // Int 904 } else { 905 obj.floatField = 2L; // Long 906 } 907 return obj.floatField; 908 } 909 910 /// CHECK-START: int Main.test30(TestClass, boolean) load_store_elimination (before) 911 /// CHECK-DAG: <<Int1:i\d+>> IntConstant 1 912 /// CHECK-DAG: <<Int2:i\d+>> IntConstant 2 913 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Int1>>] 914 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Int2>>] 915 /// CHECK-DAG: <<GetField:i\d+>> InstanceFieldGet [{{l\d+}}] 916 /// CHECK-DAG: Return [<<GetField>>] 917 918 /// CHECK-START: int Main.test30(TestClass, boolean) load_store_elimination (after) 919 /// CHECK-DAG: <<Int1:i\d+>> IntConstant 1 920 /// CHECK-DAG: <<Int2:i\d+>> IntConstant 2 921 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Int1>>] 922 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Int2>>] 923 /// CHECK-DAG: <<GetField:i\d+>> InstanceFieldGet [{{l\d+}}] 924 /// CHECK-DAG: Return [<<GetField>>] 925 926 /// CHECK-START: int Main.test30(TestClass, boolean) load_store_elimination (after) 927 /// CHECK-NOT: Phi 928 929 // Don't merge different values in two branches for different variables. test30(TestClass obj, boolean b)930 static int test30(TestClass obj, boolean b) { 931 if (b) { 932 obj.i = 1; 933 } else { 934 obj.j = 2; 935 } 936 return obj.i; 937 } 938 939 /// CHECK-START: int Main.test31(boolean, boolean) load_store_elimination (before) 940 /// CHECK-DAG: <<Int2:i\d+>> IntConstant 2 941 /// CHECK-DAG: <<Int5:i\d+>> IntConstant 5 942 /// CHECK-DAG: <<Int6:i\d+>> IntConstant 6 943 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Int5>>] field_name:{{.*TestClass.i}} 944 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Int6>>] field_name:{{.*TestClass.i}} 945 /// CHECK-DAG: <<Get1:i\d+>> InstanceFieldGet [{{l\d+}}] field_name:{{.*TestClass.i}} 946 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Get1>>] field_name:{{.*TestClass.j}} 947 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Int2>>] field_name:{{.*TestClass.i}} 948 /// CHECK-DAG: <<Get2:i\d+>> InstanceFieldGet [{{l\d+}}] 949 /// CHECK-DAG: Return [<<Get2>>] 950 951 /// CHECK-START: int Main.test31(boolean, boolean) load_store_elimination (after) 952 /// CHECK-DAG: <<Int2:i\d+>> IntConstant 2 953 /// CHECK-DAG: <<Int5:i\d+>> IntConstant 5 954 /// CHECK-DAG: <<Int6:i\d+>> IntConstant 6 955 /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Int5>>,<<Int6>>] 956 /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<Phi1>>,<<Int2>>] 957 /// CHECK-DAG: Return [<<Phi2>>] 958 959 /// CHECK-START: int Main.test31(boolean, boolean) load_store_elimination (after) 960 /// CHECK-NOT: NewInstance 961 /// CHECK-NOT: InstanceFieldSet 962 /// CHECK-NOT: InstanceFieldGet 963 964 // Test nested branches that can't be flattened. test31(boolean b, boolean c)965 static int test31(boolean b, boolean c) { 966 TestClass obj = new TestClass(); 967 if (b) { 968 if (c) { 969 obj.i = 5; 970 } else { 971 obj.i = 6; 972 } 973 obj.j = obj.i; 974 } else { 975 obj.i = 2; 976 } 977 return obj.i; 978 } 979 980 /// CHECK-START: int Main.test32(int) load_store_elimination (before) 981 /// CHECK-DAG: <<Int1:i\d+>> IntConstant 1 982 /// CHECK-DAG: <<Int10:i\d+>> IntConstant 10 983 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Int1>>] field_name:{{.*TestClass2.i}} 984 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Int1>>] field_name:{{.*TestClass2.j}} 985 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Int1>>] field_name:{{.*TestClass2.k}} 986 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Int1>>] field_name:{{.*TestClass2.l}} 987 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Int1>>] field_name:{{.*TestClass2.m}} 988 /// CHECK-DAG: Return [<<Int10>>] 989 990 /// CHECK-START: int Main.test32(int) load_store_elimination (after) 991 /// CHECK-DAG: <<Int10:i\d+>> IntConstant 10 992 /// CHECK-DAG: Return [<<Int10>>] 993 994 /// CHECK-START: int Main.test32(int) load_store_elimination (after) 995 /// CHECK-NOT: NewInstance 996 /// CHECK-NOT: InstanceFieldGet 997 /// CHECK-NOT: InstanceFieldSet 998 /// CHECK-NOT: Phi 999 1000 // Test no unused Phi instructions are created. test32(int i)1001 static int test32(int i) { 1002 TestClass2 obj = new TestClass2(); 1003 // By default, i/j/k/l/m are initialized to 0. 1004 switch (i) { 1005 case 1: obj.i = 1; break; 1006 case 2: obj.j = 1; break; 1007 case 3: obj.k = 1; break; 1008 case 4: obj.l = 1; break; 1009 case 5: obj.m = 1; break; 1010 } 1011 // So here, each variable has value Phi [0,1,1,1,1,1]. 1012 // But since no heap values are used, we should not be creating these Phis. 1013 return 10; 1014 } 1015 1016 /// CHECK-START: int Main.test33(TestClass, boolean) load_store_elimination (before) 1017 /// CHECK-DAG: InstanceFieldSet 1018 /// CHECK-DAG: InstanceFieldSet 1019 /// CHECK-DAG: <<Phi:i\d+>> Phi 1020 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Phi>>] 1021 1022 /// CHECK-START: int Main.test33(TestClass, boolean) load_store_elimination (after) 1023 /// CHECK-DAG: InstanceFieldSet 1024 /// CHECK-DAG: Phi 1025 1026 /// CHECK-START: int Main.test33(TestClass, boolean) load_store_elimination (after) 1027 /// CHECK: InstanceFieldSet 1028 /// CHECK-NOT: InstanceFieldSet 1029 1030 // Test eliminating non-observable stores. test33(TestClass obj, boolean x)1031 static int test33(TestClass obj, boolean x) { 1032 int phi; 1033 if (x) { 1034 obj.i = 1; 1035 phi = 1; 1036 } else { 1037 obj.i = 2; 1038 phi = 2; 1039 } 1040 obj.i = phi; 1041 return phi; 1042 } 1043 1044 /// CHECK-START: int Main.test34(TestClass, boolean, boolean) load_store_elimination (before) 1045 /// CHECK-DAG: InstanceFieldSet 1046 /// CHECK-DAG: InstanceFieldSet 1047 /// CHECK-DAG: <<Phi:i\d+>> Phi 1048 /// CHECK-DAG: InstanceFieldSet [{{l\d+}},<<Phi>>] 1049 1050 /// CHECK-START: int Main.test34(TestClass, boolean, boolean) load_store_elimination (after) 1051 /// CHECK-DAG: InstanceFieldSet 1052 /// CHECK-DAG: InstanceFieldSet 1053 /// CHECK-DAG: Phi 1054 1055 /// CHECK-START: int Main.test34(TestClass, boolean, boolean) load_store_elimination (after) 1056 /// CHECK: InstanceFieldSet 1057 /// CHECK: InstanceFieldSet 1058 /// CHECK-NOT: InstanceFieldSet 1059 1060 // Test eliminating a store that writes a Phi equivalent to merged 1061 // heap values of observable stores. test34(TestClass obj, boolean x, boolean y)1062 static int test34(TestClass obj, boolean x, boolean y) { 1063 int phi; 1064 if (x) { 1065 obj.i = 1; 1066 phi = 1; 1067 if (y) { 1068 return 3; 1069 } 1070 } else { 1071 obj.i = 2; 1072 phi = 2; 1073 if (y) { 1074 return 4; 1075 } 1076 } 1077 obj.i = phi; 1078 return phi; 1079 } 1080 1081 /// CHECK-START: int Main.test35(TestClass, boolean, boolean) load_store_elimination (before) 1082 /// CHECK-DAG: InstanceFieldSet 1083 /// CHECK-DAG: InstanceFieldSet 1084 /// CHECK-DAG: InstanceFieldSet 1085 /// CHECK-DAG: InstanceFieldSet 1086 /// CHECK-DAG: InstanceFieldGet 1087 1088 /// CHECK-START: int Main.test35(TestClass, boolean, boolean) load_store_elimination (after) 1089 /// CHECK-DAG: InstanceFieldSet 1090 /// CHECK-DAG: InstanceFieldSet 1091 /// CHECK-DAG: InstanceFieldSet 1092 /// CHECK-DAG: InstanceFieldSet 1093 /// CHECK-DAG: Phi 1094 /// CHECK-DAG: Phi 1095 /// CHECK-DAG: Phi 1096 1097 /// CHECK-START: int Main.test35(TestClass, boolean, boolean) load_store_elimination (after) 1098 /// CHECK-NOT: InstanceFieldGet 1099 1100 // Test Phi creation for load elimination. test35(TestClass obj, boolean x, boolean y)1101 static int test35(TestClass obj, boolean x, boolean y) { 1102 if (x) { 1103 obj.i = 1; 1104 } else { 1105 obj.i = 2; 1106 } 1107 if (y) { 1108 if (x) { 1109 obj.i = 3; 1110 } 1111 obj.j = 5; 1112 } 1113 return obj.i; 1114 } 1115 1116 /// CHECK-START: int Main.test36(TestClass, boolean) load_store_elimination (before) 1117 /// CHECK-DAG: InstanceFieldSet 1118 /// CHECK-DAG: InstanceFieldSet 1119 /// CHECK-DAG: Phi 1120 /// CHECK-DAG: InstanceFieldGet 1121 1122 /// CHECK-START: int Main.test36(TestClass, boolean) load_store_elimination (after) 1123 /// CHECK-DAG: InstanceFieldSet 1124 /// CHECK-DAG: InstanceFieldSet 1125 /// CHECK-DAG: Phi 1126 1127 /// CHECK-START: int Main.test36(TestClass, boolean) load_store_elimination (after) 1128 /// CHECK-NOT: InstanceFieldGet 1129 1130 /// CHECK-START: int Main.test36(TestClass, boolean) load_store_elimination (after) 1131 /// CHECK: Phi 1132 /// CHECK-NOT: Phi 1133 1134 // Test Phi matching for load elimination. test36(TestClass obj, boolean x)1135 static int test36(TestClass obj, boolean x) { 1136 int phi; 1137 if (x) { 1138 obj.i = 1; 1139 phi = 1; 1140 } else { 1141 obj.i = 2; 1142 phi = 2; 1143 } 1144 // The load is replaced by the existing Phi instead of constructing a new one. 1145 return obj.i + phi; 1146 } 1147 1148 /// CHECK-START: int Main.test37(TestClass, boolean) load_store_elimination (before) 1149 /// CHECK-DAG: InstanceFieldSet 1150 /// CHECK-DAG: InstanceFieldGet 1151 /// CHECK-DAG: InstanceFieldSet 1152 1153 /// CHECK-START: int Main.test37(TestClass, boolean) load_store_elimination (after) 1154 /// CHECK-DAG: InstanceFieldSet 1155 /// CHECK-DAG: InstanceFieldGet 1156 /// CHECK-DAG: InstanceFieldSet 1157 1158 // Test preserving observable stores. test37(TestClass obj, boolean x)1159 static int test37(TestClass obj, boolean x) { 1160 if (x) { 1161 obj.i = 1; 1162 } 1163 int tmp = obj.i; // The store above must be kept. 1164 obj.i = 2; 1165 return tmp; 1166 } 1167 1168 /// CHECK-START: int Main.test38(TestClass, boolean) load_store_elimination (before) 1169 /// CHECK-DAG: InstanceFieldSet 1170 /// CHECK-DAG: InstanceFieldSet 1171 /// CHECK-DAG: InstanceFieldSet 1172 /// CHECK-DAG: InstanceFieldSet 1173 1174 /// CHECK-START: int Main.test38(TestClass, boolean) load_store_elimination (after) 1175 /// CHECK: InstanceFieldSet 1176 /// CHECK-NOT: InstanceFieldSet 1177 1178 // Test eliminating store of the same value after eliminating non-observable stores. test38(TestClass obj, boolean x)1179 static int test38(TestClass obj, boolean x) { 1180 obj.i = 1; 1181 if (x) { 1182 return 1; // The store above must be kept. 1183 } 1184 obj.i = 2; // Not observable, shall be eliminated. 1185 obj.i = 3; // Not observable, shall be eliminated. 1186 obj.i = 1; // After eliminating the non-observable stores above, this stores the 1187 // same value that is already stored in `obj.i` and shall be eliminated. 1188 return 2; 1189 } 1190 1191 /// CHECK-START: int Main.test39(TestClass, boolean) load_store_elimination (before) 1192 /// CHECK-DAG: NewInstance 1193 /// CHECK-DAG: InstanceFieldSet 1194 /// CHECK-DAG: NewInstance 1195 /// CHECK-DAG: InstanceFieldSet 1196 /// CHECK-DAG: InstanceFieldGet 1197 /// CHECK-DAG: InstanceFieldGet 1198 1199 /// CHECK-START: int Main.test39(TestClass, boolean) load_store_elimination (after) 1200 /// CHECK-DAG: NewInstance 1201 /// CHECK-DAG: InstanceFieldSet 1202 /// CHECK-DAG: NewInstance 1203 /// CHECK-DAG: InstanceFieldSet 1204 /// CHECK-DAG: Phi 1205 /// CHECK-DAG: InstanceFieldGet 1206 1207 /// CHECK-START: int Main.test39(TestClass, boolean) load_store_elimination (after) 1208 /// CHECK: InstanceFieldGet 1209 /// CHECK-NOT: InstanceFieldGet 1210 1211 // Test creating a reference Phi for load elimination. test39(TestClass obj, boolean x)1212 static int test39(TestClass obj, boolean x) { 1213 obj.next = new TestClass(1, 2); 1214 if (x) { 1215 obj.next = new SubTestClass(); 1216 } 1217 return obj.next.i; 1218 } 1219 1220 /// CHECK-START: int Main.$noinline$testConversion1(TestClass, int) load_store_elimination (before) 1221 /// CHECK-DAG: InstanceFieldSet 1222 /// CHECK-DAG: InstanceFieldSet 1223 /// CHECK-DAG: InstanceFieldGet 1224 /// CHECK-DAG: InstanceFieldSet 1225 /// CHECK-DAG: InstanceFieldGet 1226 1227 /// CHECK-START: int Main.$noinline$testConversion1(TestClass, int) load_store_elimination (after) 1228 /// CHECK-DAG: InstanceFieldSet 1229 /// CHECK-DAG: InstanceFieldSet 1230 /// CHECK-DAG: TypeConversion 1231 /// CHECK-DAG: InstanceFieldSet 1232 /// CHECK-DAG: Phi 1233 1234 /// CHECK-START: int Main.$noinline$testConversion1(TestClass, int) load_store_elimination (after) 1235 /// CHECK: Phi 1236 /// CHECK-NOT: Phi 1237 1238 // Test tracking values containing type conversion. 1239 // Regression test for b/161521389 . $noinline$testConversion1(TestClass obj, int x)1240 static int $noinline$testConversion1(TestClass obj, int x) { 1241 obj.i = x; 1242 if ((x & 1) != 0) { 1243 obj.b = (byte) x; 1244 obj.i = obj.b; 1245 } 1246 return obj.i; 1247 } 1248 1249 /// CHECK-START: int Main.$noinline$testConversion2(TestClass, int) load_store_elimination (before) 1250 /// CHECK-DAG: InstanceFieldSet 1251 /// CHECK-DAG: InstanceFieldSet 1252 /// CHECK-DAG: InstanceFieldGet 1253 /// CHECK-DAG: InstanceFieldSet 1254 /// CHECK-DAG: TypeConversion 1255 /// CHECK-DAG: Phi 1256 /// CHECK-DAG: InstanceFieldGet 1257 1258 /// CHECK-START: int Main.$noinline$testConversion2(TestClass, int) load_store_elimination (after) 1259 /// CHECK-DAG: InstanceFieldSet 1260 /// CHECK-DAG: InstanceFieldSet 1261 /// CHECK-DAG: TypeConversion 1262 /// CHECK-DAG: InstanceFieldSet 1263 /// CHECK-DAG: Phi 1264 /// CHECK-DAG: Phi 1265 1266 /// CHECK-START: int Main.$noinline$testConversion2(TestClass, int) load_store_elimination (after) 1267 /// CHECK: Phi 1268 /// CHECK: Phi 1269 /// CHECK-NOT: Phi 1270 1271 /// CHECK-START: int Main.$noinline$testConversion2(TestClass, int) load_store_elimination (after) 1272 /// CHECK: TypeConversion 1273 /// CHECK-NOT: TypeConversion 1274 1275 /// CHECK-START: int Main.$noinline$testConversion2(TestClass, int) load_store_elimination (after) 1276 /// CHECK-NOT: InstanceFieldGet 1277 1278 // Test moving type conversion when needed. $noinline$testConversion2(TestClass obj, int x)1279 static int $noinline$testConversion2(TestClass obj, int x) { 1280 int tmp = 0; 1281 obj.i = x; 1282 if ((x & 1) != 0) { 1283 // The instruction simplifier can remove this TypeConversion if there are 1284 // no environment uses. Currently, there is an environment use in NullCheck, 1285 // so this TypeConversion remains and GVN removes the second TypeConversion 1286 // below. Since we really want to test that the TypeConversion from below 1287 // can be moved and used for the load of `obj.b`, we have a similar test 1288 // written in smali in 530-checker-lse3, StoreLoad.test3(int), except that 1289 // it's using static fields (which would not help with the environment use). 1290 obj.b = (byte) x; 1291 obj.i = obj.b; 1292 tmp = (byte) x; 1293 } 1294 return obj.i + tmp; 1295 } 1296 1297 /// CHECK-START: int Main.$noinline$testConversion3(TestClass, int) load_store_elimination (before) 1298 /// CHECK-DAG: InstanceFieldSet 1299 /// CHECK-DAG: Phi 1300 /// CHECK-DAG: InstanceFieldSet 1301 /// CHECK-DAG: InstanceFieldGet 1302 /// CHECK-DAG: InstanceFieldSet 1303 /// CHECK-DAG: InstanceFieldGet 1304 1305 /// CHECK-START: int Main.$noinline$testConversion3(TestClass, int) load_store_elimination (after) 1306 /// CHECK-DAG: InstanceFieldSet 1307 /// CHECK-DAG: Phi 1308 /// CHECK-DAG: Phi 1309 /// CHECK-DAG: InstanceFieldSet 1310 /// CHECK-DAG: TypeConversion 1311 /// CHECK-DAG: InstanceFieldSet 1312 1313 /// CHECK-START: int Main.$noinline$testConversion3(TestClass, int) load_store_elimination (after) 1314 /// CHECK: Phi 1315 /// CHECK: Phi 1316 /// CHECK-NOT: Phi 1317 1318 /// CHECK-START: int Main.$noinline$testConversion3(TestClass, int) load_store_elimination (after) 1319 /// CHECK: TypeConversion 1320 /// CHECK-NOT: TypeConversion 1321 1322 /// CHECK-START: int Main.$noinline$testConversion3(TestClass, int) load_store_elimination (after) 1323 /// CHECK-NOT: InstanceFieldGet 1324 1325 // Test tracking values containing type conversion with loop. $noinline$testConversion3(TestClass obj, int x)1326 static int $noinline$testConversion3(TestClass obj, int x) { 1327 obj.i = x; 1328 for (int i = 0; i < x; ++i) { 1329 obj.b = (byte) i; 1330 obj.i = obj.b; 1331 } 1332 return obj.i; 1333 } 1334 1335 /// CHECK-START: int Main.$noinline$testConversion4(TestClass, int) load_store_elimination (before) 1336 /// CHECK-DAG: InstanceFieldSet 1337 /// CHECK-DAG: Phi 1338 /// CHECK-DAG: Phi 1339 /// CHECK-DAG: InstanceFieldSet 1340 /// CHECK-DAG: InstanceFieldGet 1341 /// CHECK-DAG: InstanceFieldSet 1342 /// CHECK-DAG: TypeConversion 1343 /// CHECK-DAG: InstanceFieldGet 1344 1345 /// CHECK-START: int Main.$noinline$testConversion4(TestClass, int) load_store_elimination (after) 1346 /// CHECK-DAG: InstanceFieldSet 1347 /// CHECK-DAG: Phi 1348 /// CHECK-DAG: Phi 1349 /// CHECK-DAG: InstanceFieldSet 1350 /// CHECK-DAG: TypeConversion 1351 /// CHECK-DAG: InstanceFieldSet 1352 1353 /// CHECK-START: int Main.$noinline$testConversion4(TestClass, int) load_store_elimination (after) 1354 /// CHECK: Phi 1355 /// CHECK: Phi 1356 /// CHECK-NOT: Phi 1357 1358 /// CHECK-START: int Main.$noinline$testConversion4(TestClass, int) load_store_elimination (after) 1359 /// CHECK: TypeConversion 1360 /// CHECK-NOT: TypeConversion 1361 1362 /// CHECK-START: int Main.$noinline$testConversion4(TestClass, int) load_store_elimination (after) 1363 /// CHECK-NOT: InstanceFieldGet 1364 1365 // Test moving type conversion when needed with loop. $noinline$testConversion4(TestClass obj, int x)1366 static int $noinline$testConversion4(TestClass obj, int x) { 1367 int tmp = x; 1368 obj.i = x; 1369 for (int i = 0; i < x; ++i) { 1370 obj.b = (byte) i; 1371 obj.i = obj.b; 1372 tmp = (byte) i; 1373 } 1374 return obj.i + tmp; 1375 } 1376 1377 /// CHECK-START: void Main.testFinalizable() load_store_elimination (before) 1378 /// CHECK: NewInstance 1379 /// CHECK: InstanceFieldSet 1380 /// CHECK: InstanceFieldSet 1381 1382 /// CHECK-START: void Main.testFinalizable() load_store_elimination (after) 1383 /// CHECK: NewInstance 1384 /// CHECK: InstanceFieldSet 1385 /// CHECK-NOT: InstanceFieldSet 1386 1387 // Allocations of finalizable objects cannot be eliminated. testFinalizable()1388 static void testFinalizable() { 1389 Finalizable finalizable = new Finalizable(); 1390 finalizable.i = Finalizable.VALUE2; 1391 finalizable.i = Finalizable.VALUE1; 1392 } 1393 getWeakReference()1394 static java.lang.ref.WeakReference<Object> getWeakReference() { 1395 return new java.lang.ref.WeakReference<>(new Object()); 1396 } 1397 testFinalizableByForcingGc()1398 static void testFinalizableByForcingGc() { 1399 testFinalizable(); 1400 java.lang.ref.WeakReference<Object> reference = getWeakReference(); 1401 1402 Runtime runtime = Runtime.getRuntime(); 1403 for (int i = 0; i < 20; ++i) { 1404 runtime.gc(); 1405 System.runFinalization(); 1406 try { 1407 Thread.sleep(1); 1408 } catch (InterruptedException e) { 1409 throw new AssertionError(e); 1410 } 1411 1412 // Check to see if the weak reference has been garbage collected. 1413 if (reference.get() == null) { 1414 // A little bit more sleep time to make sure. 1415 try { 1416 Thread.sleep(100); 1417 } catch (InterruptedException e) { 1418 throw new AssertionError(e); 1419 } 1420 if (!Finalizable.sVisited) { 1421 System.out.println("finalize() not called."); 1422 } 1423 return; 1424 } 1425 } 1426 System.out.println("testFinalizableByForcingGc() failed to force gc."); 1427 } 1428 1429 /// CHECK-START: int Main.$noinline$testHSelect(boolean) load_store_elimination (before) 1430 /// CHECK: InstanceFieldSet 1431 /// CHECK: Select 1432 1433 /// CHECK-START: int Main.$noinline$testHSelect(boolean) load_store_elimination (after) 1434 /// CHECK: InstanceFieldSet 1435 /// CHECK: Select 1436 1437 // Test that HSelect creates alias. $noinline$testHSelect(boolean b)1438 static int $noinline$testHSelect(boolean b) { 1439 TestClass obj = new TestClass(); 1440 TestClass obj2 = null; 1441 obj.i = 0xdead; 1442 if (b) { 1443 obj2 = obj; 1444 } 1445 return obj2.i; 1446 } 1447 sumWithFilter(int[] array, Filter f)1448 static int sumWithFilter(int[] array, Filter f) { 1449 int sum = 0; 1450 for (int i = 0; i < array.length; i++) { 1451 if (f.isValid(array[i])) { 1452 sum += array[i]; 1453 } 1454 } 1455 return sum; 1456 } 1457 1458 /// CHECK-START: int Main.sumWithinRange(int[], int, int) load_store_elimination (before) 1459 /// CHECK-DAG: NewInstance 1460 /// CHECK-DAG: InstanceFieldSet 1461 /// CHECK-DAG: InstanceFieldSet 1462 /// CHECK-DAG: InstanceFieldGet 1463 /// CHECK-DAG: InstanceFieldGet 1464 1465 /// CHECK-START: int Main.sumWithinRange(int[], int, int) load_store_elimination (after) 1466 /// CHECK-NOT: NewInstance 1467 /// CHECK-NOT: InstanceFieldSet 1468 /// CHECK-NOT: InstanceFieldGet 1469 1470 // A lambda-style allocation can be eliminated after inlining. sumWithinRange(int[] array, final int low, final int high)1471 static int sumWithinRange(int[] array, final int low, final int high) { 1472 Filter filter = new Filter() { 1473 public boolean isValid(int i) { 1474 return (i >= low) && (i <= high); 1475 } 1476 }; 1477 return sumWithFilter(array, filter); 1478 } 1479 1480 private static int mI = 0; 1481 private static float mF = 0f; 1482 1483 /// CHECK-START: float Main.testAllocationEliminationWithLoops() load_store_elimination (before) 1484 /// CHECK: NewInstance 1485 /// CHECK: NewInstance 1486 /// CHECK: NewInstance 1487 1488 /// CHECK-START: float Main.testAllocationEliminationWithLoops() load_store_elimination (after) 1489 /// CHECK-NOT: NewInstance 1490 testAllocationEliminationWithLoops()1491 private static float testAllocationEliminationWithLoops() { 1492 for (int i0 = 0; i0 < 5; i0++) { 1493 for (int i1 = 0; i1 < 5; i1++) { 1494 for (int i2 = 0; i2 < 5; i2++) { 1495 int lI0 = ((int) new Integer(((int) new Integer(mI)))); 1496 if (((boolean) new Boolean(false))) { 1497 for (int i3 = 576 - 1; i3 >= 0; i3--) { 1498 mF -= 976981405.0f; 1499 } 1500 } 1501 } 1502 } 1503 } 1504 return 1.0f; 1505 } 1506 1507 /// CHECK-START: TestClass2 Main.testStoreStore() load_store_elimination (before) 1508 /// CHECK: NewInstance 1509 /// CHECK: InstanceFieldSet 1510 /// CHECK: InstanceFieldSet 1511 /// CHECK: InstanceFieldSet 1512 /// CHECK: InstanceFieldSet 1513 1514 /// CHECK-START: TestClass2 Main.testStoreStore() load_store_elimination (after) 1515 /// CHECK: NewInstance 1516 /// CHECK: InstanceFieldSet 1517 /// CHECK: InstanceFieldSet 1518 /// CHECK-NOT: InstanceFieldSet 1519 testStoreStore()1520 private static TestClass2 testStoreStore() { 1521 TestClass2 obj = new TestClass2(); 1522 obj.i = 41; 1523 obj.j = 42; 1524 obj.i = 41; 1525 obj.j = 43; 1526 return obj; 1527 } 1528 1529 /// CHECK-START: void Main.testStoreStore2(TestClass2) load_store_elimination (before) 1530 /// CHECK: InstanceFieldSet 1531 /// CHECK: InstanceFieldSet 1532 /// CHECK: InstanceFieldSet 1533 /// CHECK: InstanceFieldSet 1534 1535 /// CHECK-START: void Main.testStoreStore2(TestClass2) load_store_elimination (after) 1536 /// CHECK: InstanceFieldSet 1537 /// CHECK: InstanceFieldSet 1538 /// CHECK-NOT: InstanceFieldSet 1539 testStoreStore2(TestClass2 obj)1540 private static void testStoreStore2(TestClass2 obj) { 1541 obj.i = 41; 1542 obj.j = 42; 1543 obj.i = 43; 1544 obj.j = 44; 1545 } 1546 1547 /// CHECK-START: void Main.testStoreStore3(TestClass2, boolean) load_store_elimination (before) 1548 /// CHECK: InstanceFieldSet 1549 /// CHECK: InstanceFieldSet 1550 /// CHECK: InstanceFieldSet 1551 /// CHECK: InstanceFieldSet 1552 1553 /// CHECK-START: void Main.testStoreStore3(TestClass2, boolean) load_store_elimination (after) 1554 /// CHECK: InstanceFieldSet 1555 /// CHECK: InstanceFieldSet 1556 /// CHECK: InstanceFieldSet 1557 /// CHECK-NOT: InstanceFieldSet 1558 1559 /// CHECK-START: void Main.testStoreStore3(TestClass2, boolean) load_store_elimination (after) 1560 /// CHECK-NOT: Phi 1561 testStoreStore3(TestClass2 obj, boolean flag)1562 private static void testStoreStore3(TestClass2 obj, boolean flag) { 1563 obj.i = 41; 1564 obj.j = 42; // redundant since it's overwritten in both branches below. 1565 if (flag) { 1566 obj.j = 43; 1567 } else { 1568 obj.j = 44; 1569 } 1570 } 1571 1572 /// CHECK-START: void Main.testStoreStore4() load_store_elimination (before) 1573 /// CHECK: StaticFieldSet 1574 /// CHECK: StaticFieldSet 1575 1576 /// CHECK-START: void Main.testStoreStore4() load_store_elimination (after) 1577 /// CHECK: StaticFieldSet 1578 /// CHECK-NOT: StaticFieldSet 1579 testStoreStore4()1580 private static void testStoreStore4() { 1581 TestClass.si = 61; 1582 TestClass.si = 62; 1583 } 1584 1585 /// CHECK-START: int Main.testStoreStore5(TestClass2, TestClass2) load_store_elimination (before) 1586 /// CHECK: InstanceFieldSet 1587 /// CHECK: InstanceFieldGet 1588 /// CHECK: InstanceFieldSet 1589 1590 /// CHECK-START: int Main.testStoreStore5(TestClass2, TestClass2) load_store_elimination (after) 1591 /// CHECK: InstanceFieldSet 1592 /// CHECK: InstanceFieldGet 1593 /// CHECK: InstanceFieldSet 1594 testStoreStore5(TestClass2 obj1, TestClass2 obj2)1595 private static int testStoreStore5(TestClass2 obj1, TestClass2 obj2) { 1596 obj1.i = 71; // This store is needed since obj2.i may load from it. 1597 int i = obj2.i; 1598 obj1.i = 72; 1599 return i; 1600 } 1601 1602 /// CHECK-START: int Main.testStoreStore6(TestClass2, TestClass2) load_store_elimination (before) 1603 /// CHECK: InstanceFieldSet 1604 /// CHECK: InstanceFieldGet 1605 /// CHECK: InstanceFieldSet 1606 1607 /// CHECK-START: int Main.testStoreStore6(TestClass2, TestClass2) load_store_elimination (after) 1608 /// CHECK-NOT: InstanceFieldSet 1609 /// CHECK: InstanceFieldGet 1610 /// CHECK: InstanceFieldSet 1611 testStoreStore6(TestClass2 obj1, TestClass2 obj2)1612 private static int testStoreStore6(TestClass2 obj1, TestClass2 obj2) { 1613 obj1.i = 81; // This store is not needed since obj2.j cannot load from it. 1614 int j = obj2.j; 1615 obj1.i = 82; 1616 return j; 1617 } 1618 1619 /// CHECK-START: int Main.testNoSideEffects(int[]) load_store_elimination (before) 1620 /// CHECK: ArraySet 1621 /// CHECK: ArraySet 1622 /// CHECK: ArraySet 1623 /// CHECK: ArrayGet 1624 1625 /// CHECK-START: int Main.testNoSideEffects(int[]) load_store_elimination (after) 1626 /// CHECK: ArraySet 1627 /// CHECK: ArraySet 1628 /// CHECK-NOT: ArraySet 1629 /// CHECK-NOT: ArrayGet 1630 testNoSideEffects(int[] array)1631 private static int testNoSideEffects(int[] array) { 1632 array[0] = 101; 1633 array[1] = 102; 1634 int bitCount = Integer.bitCount(0x3456); 1635 array[1] = 103; 1636 return array[0] + bitCount; 1637 } 1638 1639 /// CHECK-START: void Main.testThrow(TestClass2, java.lang.Exception) load_store_elimination (before) 1640 /// CHECK: InstanceFieldSet 1641 /// CHECK: Throw 1642 1643 /// CHECK-START: void Main.testThrow(TestClass2, java.lang.Exception) load_store_elimination (after) 1644 /// CHECK: InstanceFieldSet 1645 /// CHECK: Throw 1646 1647 // Make sure throw keeps the store. testThrow(TestClass2 obj, Exception e)1648 private static void testThrow(TestClass2 obj, Exception e) throws Exception { 1649 obj.i = 55; 1650 throw e; 1651 } 1652 1653 /// CHECK-START: int Main.testStoreStoreWithDeoptimize(int[]) load_store_elimination (before) 1654 /// CHECK: NewInstance 1655 /// CHECK: InstanceFieldSet 1656 /// CHECK: InstanceFieldSet 1657 /// CHECK: InstanceFieldSet 1658 /// CHECK: InstanceFieldSet 1659 /// CHECK: Deoptimize 1660 /// CHECK: ArraySet 1661 /// CHECK: ArraySet 1662 /// CHECK: ArraySet 1663 /// CHECK: ArraySet 1664 /// CHECK: ArrayGet 1665 /// CHECK: ArrayGet 1666 /// CHECK: ArrayGet 1667 /// CHECK: ArrayGet 1668 1669 /// CHECK-START: int Main.testStoreStoreWithDeoptimize(int[]) load_store_elimination (after) 1670 /// CHECK: NewInstance 1671 /// CHECK: InstanceFieldSet 1672 /// CHECK: InstanceFieldSet 1673 /// CHECK-NOT: InstanceFieldSet 1674 /// CHECK: Deoptimize 1675 /// CHECK: ArraySet 1676 /// CHECK: ArraySet 1677 /// CHECK: ArraySet 1678 /// CHECK: ArraySet 1679 /// CHECK-NOT: ArrayGet 1680 testStoreStoreWithDeoptimize(int[] arr)1681 private static int testStoreStoreWithDeoptimize(int[] arr) { 1682 TestClass2 obj = new TestClass2(); 1683 obj.i = 41; 1684 obj.j = 42; 1685 obj.i = 41; 1686 obj.j = 43; 1687 arr[0] = 1; // One HDeoptimize here. 1688 arr[1] = 1; 1689 arr[2] = 1; 1690 arr[3] = 1; 1691 return arr[0] + arr[1] + arr[2] + arr[3]; 1692 } 1693 1694 /// CHECK-START: double Main.getCircleArea(double, boolean) load_store_elimination (before) 1695 /// CHECK: NewInstance 1696 1697 /// CHECK-START: double Main.getCircleArea(double, boolean) load_store_elimination (after) 1698 /// CHECK-NOT: NewInstance 1699 getCircleArea(double radius, boolean b)1700 private static double getCircleArea(double radius, boolean b) { 1701 double area = 0d; 1702 if (b) { 1703 area = new Circle(radius).getArea(); 1704 } 1705 return area; 1706 } 1707 1708 /// CHECK-START: double Main.testDeoptimize(int[], double[], double) load_store_elimination (before) 1709 /// CHECK: Deoptimize 1710 /// CHECK: NewInstance 1711 /// CHECK: Deoptimize 1712 /// CHECK: NewInstance 1713 1714 /// CHECK-START: double Main.testDeoptimize(int[], double[], double) load_store_elimination (after) 1715 /// CHECK: Deoptimize 1716 /// CHECK: NewInstance 1717 /// CHECK: Deoptimize 1718 /// CHECK-NOT: NewInstance 1719 testDeoptimize(int[] iarr, double[] darr, double radius)1720 private static double testDeoptimize(int[] iarr, double[] darr, double radius) { 1721 iarr[0] = 1; // One HDeoptimize here. Not triggered. 1722 iarr[1] = 1; 1723 Circle circle1 = new Circle(radius); 1724 iarr[2] = 1; 1725 darr[0] = circle1.getRadius(); // One HDeoptimize here, which holds circle1 live. Triggered. 1726 darr[1] = circle1.getRadius(); 1727 darr[2] = circle1.getRadius(); 1728 darr[3] = circle1.getRadius(); 1729 return new Circle(Math.PI).getArea(); 1730 } 1731 1732 /// CHECK-START: int Main.testAllocationEliminationOfArray1() load_store_elimination (before) 1733 /// CHECK: NewArray 1734 /// CHECK: ArraySet 1735 /// CHECK: ArraySet 1736 /// CHECK: ArrayGet 1737 /// CHECK: ArrayGet 1738 /// CHECK: ArrayGet 1739 /// CHECK: ArrayGet 1740 1741 /// CHECK-START: int Main.testAllocationEliminationOfArray1() load_store_elimination (after) 1742 /// CHECK-NOT: NewArray 1743 /// CHECK-NOT: ArraySet 1744 /// CHECK-NOT: ArrayGet testAllocationEliminationOfArray1()1745 private static int testAllocationEliminationOfArray1() { 1746 int[] array = new int[4]; 1747 array[2] = 4; 1748 array[3] = 7; 1749 return array[0] + array[1] + array[2] + array[3]; 1750 } 1751 1752 /// CHECK-START: int Main.testAllocationEliminationOfArray2() load_store_elimination (before) 1753 /// CHECK: NewArray 1754 /// CHECK: ArraySet 1755 /// CHECK: ArraySet 1756 /// CHECK: ArrayGet 1757 1758 /// CHECK-START: int Main.testAllocationEliminationOfArray2() load_store_elimination (after) 1759 /// CHECK: NewArray 1760 /// CHECK: ArraySet 1761 /// CHECK: ArraySet 1762 /// CHECK: ArrayGet testAllocationEliminationOfArray2()1763 private static int testAllocationEliminationOfArray2() { 1764 // Cannot eliminate array allocation since array is accessed with non-constant 1765 // index (only 3 elements to prevent vectorization of the reduction). 1766 int[] array = new int[3]; 1767 array[1] = 4; 1768 array[2] = 7; 1769 int sum = 0; 1770 for (int e : array) { 1771 sum += e; 1772 } 1773 return sum; 1774 } 1775 1776 /// CHECK-START: int Main.testAllocationEliminationOfArray3(int) load_store_elimination (before) 1777 /// CHECK: NewArray 1778 /// CHECK: ArraySet 1779 /// CHECK: ArrayGet 1780 1781 /// CHECK-START: int Main.testAllocationEliminationOfArray3(int) load_store_elimination (after) 1782 /// CHECK-NOT: NewArray 1783 /// CHECK-NOT: ArraySet 1784 /// CHECK-NOT: ArrayGet testAllocationEliminationOfArray3(int i)1785 private static int testAllocationEliminationOfArray3(int i) { 1786 int[] array = new int[4]; 1787 array[i] = 4; 1788 return array[i]; 1789 } 1790 1791 /// CHECK-START: int Main.testAllocationEliminationOfArray4(int) load_store_elimination (before) 1792 /// CHECK: NewArray 1793 /// CHECK: ArraySet 1794 /// CHECK: ArraySet 1795 /// CHECK: ArrayGet 1796 /// CHECK: ArrayGet 1797 1798 /// CHECK-START: int Main.testAllocationEliminationOfArray4(int) load_store_elimination (after) 1799 /// CHECK: NewArray 1800 /// CHECK: ArraySet 1801 /// CHECK: ArraySet 1802 /// CHECK: ArrayGet 1803 /// CHECK-NOT: ArrayGet testAllocationEliminationOfArray4(int i)1804 private static int testAllocationEliminationOfArray4(int i) { 1805 // Cannot eliminate array allocation due to index aliasing between 1 and i. 1806 int[] array = new int[4]; 1807 array[1] = 2; 1808 array[i] = 4; 1809 return array[1] + array[i]; 1810 } 1811 1812 /// CHECK-START: int Main.testAllocationEliminationOfArray5(int) load_store_elimination (before) 1813 /// CHECK: NewArray 1814 /// CHECK: ArraySet 1815 /// CHECK: ArrayGet 1816 1817 /// CHECK-START: int Main.testAllocationEliminationOfArray5(int) load_store_elimination (after) 1818 /// CHECK: NewArray 1819 /// CHECK-NOT: ArraySet 1820 /// CHECK-NOT: ArrayGet testAllocationEliminationOfArray5(int i)1821 private static int testAllocationEliminationOfArray5(int i) { 1822 // Cannot eliminate array allocation due to unknown i that may 1823 // cause NegativeArraySizeException. 1824 int[] array = new int[i]; 1825 array[1] = 12; 1826 return array[1]; 1827 } 1828 1829 /// CHECK-START: int Main.testExitMerge(boolean) load_store_elimination (before) 1830 /// CHECK-DAG: NewInstance 1831 /// CHECK-DAG: InstanceFieldSet 1832 /// CHECK-DAG: InstanceFieldGet 1833 /// CHECK-DAG: Return 1834 /// CHECK-DAG: InstanceFieldSet 1835 /// CHECK-DAG: Throw 1836 1837 /// CHECK-START: int Main.testExitMerge(boolean) load_store_elimination (after) 1838 /// CHECK-DAG: Return 1839 /// CHECK-DAG: Throw 1840 1841 /// CHECK-START: int Main.testExitMerge(boolean) load_store_elimination (after) 1842 /// CHECK-NOT: InstanceFieldSet 1843 /// CHECK-NOT: InstanceFieldGet 1844 1845 /// CHECK-START: int Main.testExitMerge(boolean) load_store_elimination (after) 1846 /// CHECK: NewInstance 1847 /// CHECK-NOT: NewInstance testExitMerge(boolean cond)1848 private static int testExitMerge(boolean cond) { 1849 TestClass obj = new TestClass(); 1850 if (cond) { 1851 obj.i = 1; 1852 return obj.i + 1; 1853 } else { 1854 obj.i = 2; 1855 throw new Error(); // Note: We have a NewInstance here. 1856 } 1857 } 1858 1859 /// CHECK-START: int Main.testExitMerge2(boolean) load_store_elimination (before) 1860 /// CHECK-DAG: NewInstance 1861 /// CHECK-DAG: InstanceFieldSet 1862 /// CHECK-DAG: InstanceFieldGet 1863 /// CHECK-DAG: InstanceFieldSet 1864 /// CHECK-DAG: InstanceFieldGet 1865 1866 /// CHECK-START: int Main.testExitMerge2(boolean) load_store_elimination (after) 1867 /// CHECK-NOT: NewInstance 1868 /// CHECK-NOT: InstanceFieldSet 1869 /// CHECK-NOT: InstanceFieldGet testExitMerge2(boolean cond)1870 private static int testExitMerge2(boolean cond) { 1871 TestClass obj = new TestClass(); 1872 int res; 1873 if (cond) { 1874 obj.i = 1; 1875 res = obj.i + 1; 1876 } else { 1877 obj.i = 2; 1878 res = obj.j + 2; 1879 } 1880 return res; 1881 } 1882 1883 /// CHECK-START: void Main.testStoreSameValue() load_store_elimination (before) 1884 /// CHECK: NewArray 1885 /// CHECK: ArrayGet 1886 /// CHECK: ArraySet 1887 1888 /// CHECK-START: void Main.testStoreSameValue() load_store_elimination (after) 1889 /// CHECK: NewArray 1890 /// CHECK-NOT: ArrayGet 1891 /// CHECK-NOT: ArraySet testStoreSameValue()1892 private static void testStoreSameValue() { 1893 Object[] array = new Object[2]; 1894 sArray = array; 1895 Object obj = array[0]; 1896 array[1] = obj; // Store the same value as the default value. 1897 } 1898 1899 /// CHECK-START: int Main.$noinline$testByteArrayDefaultValue() load_store_elimination (before) 1900 /// CHECK-DAG: NewArray 1901 /// CHECK-DAG: <<Value:b\d+>> ArrayGet 1902 /// CHECK-DAG: Return [<<Value>>] 1903 1904 /// CHECK-START: int Main.$noinline$testByteArrayDefaultValue() load_store_elimination (after) 1905 /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 1906 /// CHECK-DAG: Return [<<Const0>>] 1907 1908 /// CHECK-START: int Main.$noinline$testByteArrayDefaultValue() load_store_elimination (after) 1909 /// CHECK-NOT: NewArray 1910 /// CHECK-NOT: ArrayGet 1911 /// CHECK-NOT: TypeConversion $noinline$testByteArrayDefaultValue()1912 private static int $noinline$testByteArrayDefaultValue() { 1913 byte[] array = new byte[2]; 1914 array[1] = 1; // FIXME: Without any stores, LSA tells LSE not to run. 1915 return array[0]; 1916 } 1917 1918 static Object[] sArray; 1919 1920 /// CHECK-START: int Main.testLocalArrayMerge1(boolean) load_store_elimination (before) 1921 /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 1922 /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 1923 /// CHECK-DAG: <<A:l\d+>> NewArray 1924 /// CHECK-DAG: ArraySet [<<A>>,<<Const0>>,<<Const0>>] 1925 /// CHECK-DAG: ArraySet [<<A>>,<<Const0>>,<<Const1>>] 1926 /// CHECK-DAG: ArraySet [<<A>>,<<Const0>>,<<Const1>>] 1927 /// CHECK-DAG: <<Get:i\d+>> ArrayGet [<<A>>,<<Const0>>] 1928 /// CHECK-DAG: Return [<<Get>>] 1929 // 1930 /// CHECK-START: int Main.testLocalArrayMerge1(boolean) load_store_elimination (after) 1931 /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 1932 /// CHECK-DAG: Return [<<Const1>>] 1933 // 1934 /// CHECK-START: int Main.testLocalArrayMerge1(boolean) load_store_elimination (after) 1935 /// CHECK-NOT: NewArray 1936 /// CHECK-NOT: ArraySet 1937 /// CHECK-NOT: ArrayGet testLocalArrayMerge1(boolean x)1938 private static int testLocalArrayMerge1(boolean x) { 1939 // The explicit store can be removed right away 1940 // since it is equivalent to the default. 1941 int[] a = { 0 }; 1942 // The diamond pattern stores/load can be replaced 1943 // by the direct value. 1944 if (x) { 1945 a[0] = 1; 1946 } else { 1947 a[0] = 1; 1948 } 1949 return a[0]; 1950 } 1951 1952 /// CHECK-START: int Main.testLocalArrayMerge2(boolean) load_store_elimination (before) 1953 /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 1954 /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 1955 /// CHECK-DAG: <<Const2:i\d+>> IntConstant 2 1956 /// CHECK-DAG: <<Const3:i\d+>> IntConstant 3 1957 /// CHECK-DAG: <<A:l\d+>> NewArray 1958 /// CHECK-DAG: ArraySet [<<A>>,<<Const0>>,<<Const1>>] 1959 /// CHECK-DAG: ArraySet [<<A>>,<<Const0>>,<<Const2>>] 1960 /// CHECK-DAG: ArraySet [<<A>>,<<Const0>>,<<Const3>>] 1961 /// CHECK-DAG: <<Get:i\d+>> ArrayGet [<<A>>,<<Const0>>] 1962 /// CHECK-DAG: Return [<<Get>>] 1963 1964 /// CHECK-START: int Main.testLocalArrayMerge2(boolean) load_store_elimination (after) 1965 /// CHECK-DAG: <<Const2:i\d+>> IntConstant 2 1966 /// CHECK-DAG: <<Const3:i\d+>> IntConstant 3 1967 /// CHECK-DAG: <<Phi:i\d+>> Phi [<<Arg1:i\d+>>,<<Arg2:i\d+>>] 1968 /// CHECK-DAG: Return [<<Phi>>] 1969 /// CHECK-EVAL: set(["<<Arg1>>","<<Arg2>>"]) == set(["<<Const2>>","<<Const3>>"]) 1970 1971 /// CHECK-START: int Main.testLocalArrayMerge2(boolean) load_store_elimination (after) 1972 /// CHECK-NOT: NewArray 1973 /// CHECK-NOT: ArraySet 1974 /// CHECK-NOT: ArrayGet testLocalArrayMerge2(boolean x)1975 private static int testLocalArrayMerge2(boolean x) { 1976 // The explicit store can be removed eventually even 1977 // though it is not equivalent to the default. 1978 int[] a = { 1 }; 1979 // The load after the diamond pattern is eliminated and replaced with a Phi, 1980 // stores are then also eliminated. 1981 if (x) { 1982 a[0] = 2; 1983 } else { 1984 a[0] = 3; 1985 } 1986 return a[0]; 1987 } 1988 1989 /// CHECK-START: int Main.testLocalArrayMerge3(boolean) load_store_elimination (before) 1990 /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 1991 /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 1992 /// CHECK-DAG: <<Const2:i\d+>> IntConstant 2 1993 /// CHECK-DAG: <<A:l\d+>> NewArray 1994 /// CHECK-DAG: ArraySet [<<A>>,<<Const0>>,<<Const1>>] 1995 /// CHECK-DAG: ArraySet [<<A>>,<<Const0>>,<<Const2>>] 1996 /// CHECK-DAG: <<Get:i\d+>> ArrayGet [<<A>>,<<Const0>>] 1997 /// CHECK-DAG: Return [<<Get>>] 1998 1999 /// CHECK-START: int Main.testLocalArrayMerge3(boolean) load_store_elimination (after) 2000 /// CHECK-NOT: NewArray 2001 /// CHECK-NOT: ArraySet 2002 /// CHECK-NOT: ArrayGet testLocalArrayMerge3(boolean x)2003 private static int testLocalArrayMerge3(boolean x) { 2004 int[] a = { 1 }; 2005 if (x) { 2006 a[0] = 2; 2007 } 2008 return a[0]; 2009 } 2010 2011 /// CHECK-START: int Main.testLocalArrayMerge4(boolean) load_store_elimination (before) 2012 /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 2013 /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 2014 /// CHECK-DAG: <<A:l\d+>> NewArray 2015 /// CHECK-DAG: ArraySet [<<A>>,<<Const0>>,<<Const0>>] 2016 /// CHECK-DAG: ArraySet [<<A>>,<<Const0>>,<<Const1>>] 2017 /// CHECK-DAG: ArraySet [<<A>>,<<Const0>>,<<Const1>>] 2018 /// CHECK-DAG: <<Get1:b\d+>> ArrayGet [<<A>>,<<Const0>>] 2019 /// CHECK-DAG: <<Get2:a\d+>> ArrayGet [<<A>>,<<Const0>>] 2020 /// CHECK-DAG: <<Add:i\d+>> Add [<<Get1>>,<<Get2>>] 2021 /// CHECK-DAG: Return [<<Add>>] 2022 // 2023 /// CHECK-START: int Main.testLocalArrayMerge4(boolean) load_store_elimination (after) 2024 /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 2025 /// CHECK-DAG: <<Cnv1:b\d+>> TypeConversion [<<Const1>>] 2026 /// CHECK-DAG: <<Cnv2:a\d+>> TypeConversion [<<Const1>>] 2027 /// CHECK-DAG: <<Add:i\d+>> Add [<<Cnv1>>,<<Cnv2>>] 2028 /// CHECK-DAG: Return [<<Add>>] 2029 // 2030 /// CHECK-START: int Main.testLocalArrayMerge4(boolean) load_store_elimination (after) 2031 /// CHECK-NOT: NewArray 2032 /// CHECK-NOT: ArraySet 2033 /// CHECK-NOT: ArrayGet testLocalArrayMerge4(boolean x)2034 private static int testLocalArrayMerge4(boolean x) { 2035 byte[] a = { 0 }; 2036 if (x) { 2037 a[0] = 1; 2038 } else { 2039 a[0] = 1; 2040 } 2041 // Differently typed (signed vs unsigned), 2042 // but same reference. 2043 return a[0] + (a[0] & 0xff); 2044 } 2045 2046 /// CHECK-START: int Main.testLocalArrayMerge5(int[], boolean) load_store_elimination (before) 2047 /// CHECK: ArraySet 2048 /// CHECK: ArraySet 2049 /// CHECK: ArraySet 2050 2051 /// CHECK-START: int Main.testLocalArrayMerge5(int[], boolean) load_store_elimination (after) 2052 /// CHECK-NOT: ArraySet 2053 2054 // Test eliminating store of the same value after eliminating non-observable stores. testLocalArrayMerge5(int[] a, boolean x)2055 private static int testLocalArrayMerge5(int[] a, boolean x) { 2056 int old = a[0]; 2057 if (x) { 2058 a[0] = 1; 2059 } else { 2060 a[0] = 1; 2061 } 2062 // This store makes the stores above dead and they will be eliminated. 2063 // That makes this store unnecessary as we're storing the same value already 2064 // present in this location, so it shall also be eliminated. 2065 a[0] = old; 2066 return old; 2067 } 2068 2069 /// CHECK-START: int Main.testLocalArrayMerge6(int[], boolean, boolean) load_store_elimination (before) 2070 /// CHECK-DAG: ArraySet 2071 /// CHECK-DAG: ArraySet 2072 /// CHECK-DAG: ArraySet 2073 /// CHECK-DAG: ArrayGet 2074 /// CHECK-DAG: ArrayGet 2075 2076 /// CHECK-START: int Main.testLocalArrayMerge6(int[], boolean, boolean) load_store_elimination (after) 2077 /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 2078 /// CHECK-DAG: <<Const2:i\d+>> IntConstant 2 2079 /// CHECK-DAG: <<Const3:i\d+>> IntConstant 3 2080 /// CHECK-DAG: ArraySet 2081 /// CHECK-DAG: ArraySet 2082 /// CHECK-DAG: <<Phi:i\d+>> Phi [<<Arg1:i\d+>>,<<Arg2:i\d+>>] 2083 /// CHECK-DAG: Return [<<Phi>>] 2084 /// CHECK-DAG: <<Sub:i\d+>> Sub [<<Const3>>,<<Phi>>] 2085 /// CHECK-DAG: Return [<<Sub>>] 2086 /// CHECK-EVAL: set(["<<Arg1>>","<<Arg2>>"]) == set(["<<Const1>>","<<Const2>>"]) 2087 2088 /// CHECK-START: int Main.testLocalArrayMerge6(int[], boolean, boolean) load_store_elimination (after) 2089 /// CHECK: Phi 2090 /// CHECK-NOT: Phi 2091 2092 /// CHECK-START: int Main.testLocalArrayMerge6(int[], boolean, boolean) load_store_elimination (after) 2093 /// CHECK-NOT: ArrayGet 2094 2095 // Test that we create a single Phi for eliminating two loads in different blocks. testLocalArrayMerge6(int[] a, boolean x, boolean y)2096 private static int testLocalArrayMerge6(int[] a, boolean x, boolean y) { 2097 a[0] = 0; 2098 if (x) { 2099 a[0] = 1; 2100 } else { 2101 a[0] = 2; 2102 } 2103 // Phi for load elimination is created here. 2104 if (y) { 2105 return a[0]; 2106 } else { 2107 return 3 - a[0]; 2108 } 2109 } 2110 2111 /// CHECK-START: int Main.testLocalArrayMerge7(int[], boolean, boolean) load_store_elimination (before) 2112 /// CHECK-DAG: ArraySet 2113 /// CHECK-DAG: ArraySet 2114 /// CHECK-DAG: ArraySet 2115 /// CHECK-DAG: ArrayGet 2116 /// CHECK-DAG: ArraySet 2117 /// CHECK-DAG: ArrayGet 2118 2119 /// CHECK-START: int Main.testLocalArrayMerge7(int[], boolean, boolean) load_store_elimination (after) 2120 /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 2121 /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 2122 /// CHECK-DAG: <<Const2:i\d+>> IntConstant 2 2123 /// CHECK-DAG: ArraySet 2124 /// CHECK-DAG: ArraySet 2125 /// CHECK-DAG: ArraySet 2126 /// CHECK-DAG: ArraySet 2127 /// CHECK-DAG: Return [<<Phi2:i\d+>>] 2128 /// CHECK-DAG: <<Phi2>> Phi [<<Arg3:i\d+>>,<<Arg4:i\d+>>] 2129 /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Arg1:i\d+>>,<<Arg2:i\d+>>] 2130 /// CHECK-EVAL: set(["<<Arg1>>","<<Arg2>>"]) == set(["<<Const1>>","<<Const2>>"]) 2131 /// CHECK-EVAL: set(["<<Arg3>>","<<Arg4>>"]) == set(["<<Const0>>","<<Phi1>>"]) 2132 2133 /// CHECK-START: int Main.testLocalArrayMerge7(int[], boolean, boolean) load_store_elimination (after) 2134 /// CHECK-NOT: ArrayGet 2135 2136 // Test Phi creation for load elimination. testLocalArrayMerge7(int[] a, boolean x, boolean y)2137 private static int testLocalArrayMerge7(int[] a, boolean x, boolean y) { 2138 a[1] = 0; 2139 if (x) { 2140 if (y) { 2141 a[0] = 1; 2142 } else { 2143 a[0] = 2; 2144 } 2145 a[1] = a[0]; 2146 } 2147 return a[1]; 2148 } 2149 2150 /// CHECK-START: int Main.testLocalArrayMerge8(boolean) load_store_elimination (before) 2151 /// CHECK-DAG: NewArray 2152 /// CHECK-DAG: ArraySet 2153 /// CHECK-DAG: ArraySet 2154 /// CHECK-DAG: ArraySet 2155 /// CHECK-DAG: ArraySet 2156 /// CHECK-DAG: ArrayGet 2157 /// CHECK-DAG: ArrayGet 2158 2159 /// CHECK-START: int Main.testLocalArrayMerge8(boolean) load_store_elimination (after) 2160 /// CHECK-NOT: NewArray 2161 /// CHECK-NOT: ArraySet 2162 /// CHECK-NOT: ArrayGet 2163 2164 // Test Merging default value and an identical value. testLocalArrayMerge8(boolean x)2165 private static int testLocalArrayMerge8(boolean x) { 2166 int[] a = new int[2]; 2167 if (x) { 2168 a[0] = 1; // Make sure the store below is not eliminated immediately as 2169 // storing the same value already present in the heap location. 2170 a[0] = 0; // Store the same value as default value to test merging with 2171 // the default value from else-block. 2172 } else { 2173 // Do the same as then-block for a different heap location to avoid 2174 // relying on block ordering. (Test both `default+0` and `0+default`.) 2175 a[1] = 1; 2176 a[1] = 0; 2177 } 2178 return a[0] + a[1]; 2179 } 2180 2181 /// CHECK-START: void Main.$noinline$testThrowingArraySet(java.lang.Object[], java.lang.Object) load_store_elimination (before) 2182 /// CHECK-DAG: ArrayGet 2183 /// CHECK-DAG: ArraySet 2184 /// CHECK-DAG: ArraySet 2185 /// CHECK-DAG: ArraySet 2186 /// CHECK-DAG: ArraySet 2187 2188 /// CHECK-START: void Main.$noinline$testThrowingArraySet(java.lang.Object[], java.lang.Object) load_store_elimination (after) 2189 /// CHECK-DAG: ArrayGet 2190 /// CHECK-DAG: ArraySet 2191 /// CHECK-DAG: ArraySet 2192 /// CHECK-DAG: ArraySet 2193 /// CHECK-DAG: ArraySet $noinline$testThrowingArraySet(Object[] a, Object o)2194 private static void $noinline$testThrowingArraySet(Object[] a, Object o) { 2195 Object olda0 = a[0]; 2196 a[0] = null; 2197 a[1] = olda0; 2198 a[0] = o; 2199 a[1] = null; 2200 } 2201 2202 /// CHECK-START: int Main.testLoop1(TestClass, int) load_store_elimination (before) 2203 /// CHECK-DAG: InstanceFieldSet 2204 /// CHECK-DAG: InstanceFieldSet 2205 /// CHECK-DAG: InstanceFieldGet 2206 /// CHECK-DAG: Phi 2207 2208 /// CHECK-START: int Main.testLoop1(TestClass, int) load_store_elimination (after) 2209 /// CHECK-DAG: InstanceFieldSet 2210 /// CHECK-DAG: InstanceFieldSet 2211 /// CHECK-DAG: Phi 2212 /// CHECK-DAG: Phi 2213 2214 /// CHECK-START: int Main.testLoop1(TestClass, int) load_store_elimination (after) 2215 /// CHECK-NOT: InstanceFieldGet 2216 2217 // Test Phi creation for load elimination with loop. testLoop1(TestClass obj, int n)2218 private static int testLoop1(TestClass obj, int n) { 2219 obj.i = 0; 2220 for (int i = 0; i < n; ++i) { 2221 obj.i = i; 2222 } 2223 return obj.i; 2224 } 2225 2226 /// CHECK-START: int Main.testLoop2(TestClass, int) load_store_elimination (before) 2227 /// CHECK-DAG: InstanceFieldSet 2228 /// CHECK-DAG: InstanceFieldSet 2229 /// CHECK-DAG: InstanceFieldGet 2230 /// CHECK-DAG: Phi 2231 2232 /// CHECK-START: int Main.testLoop2(TestClass, int) load_store_elimination (after) 2233 /// CHECK-DAG: InstanceFieldSet 2234 /// CHECK-DAG: InstanceFieldSet 2235 2236 /// CHECK-START: int Main.testLoop2(TestClass, int) load_store_elimination (after) 2237 /// CHECK-NOT: InstanceFieldGet 2238 2239 /// CHECK-START: int Main.testLoop2(TestClass, int) load_store_elimination (after) 2240 /// CHECK: Phi 2241 /// CHECK-NOT: Phi 2242 2243 // Test that we do not create any Phis for load elimination when 2244 // the heap value was not modified in the loop. testLoop2(TestClass obj, int n)2245 private static int testLoop2(TestClass obj, int n) { 2246 obj.i = 1; 2247 for (int i = 0; i < n; ++i) { 2248 obj.j = i; 2249 } 2250 return obj.i; 2251 } 2252 2253 /// CHECK-START: int Main.testLoop3(TestClass, int) load_store_elimination (before) 2254 /// CHECK-DAG: InstanceFieldSet 2255 /// CHECK-DAG: InstanceFieldSet 2256 /// CHECK-DAG: InstanceFieldGet 2257 2258 /// CHECK-START: int Main.testLoop3(TestClass, int) load_store_elimination (after) 2259 /// CHECK: InstanceFieldSet 2260 /// CHECK-NOT: InstanceFieldSet 2261 2262 /// CHECK-START: int Main.testLoop3(TestClass, int) load_store_elimination (after) 2263 /// CHECK-NOT: InstanceFieldGet 2264 2265 // Test elimination of a store in the loop that stores the same value that was already 2266 // stored before the loop and eliminating the load of that value after the loop. testLoop3(TestClass obj, int n)2267 private static int testLoop3(TestClass obj, int n) { 2268 obj.i = 1; 2269 for (int i = 0; i < n; ++i) { 2270 obj.i = 1; 2271 } 2272 return obj.i; 2273 } 2274 2275 /// CHECK-START: int Main.testLoop4(TestClass, int) load_store_elimination (before) 2276 /// CHECK-DAG: InstanceFieldSet 2277 /// CHECK-DAG: InstanceFieldSet 2278 2279 /// CHECK-START: int Main.testLoop4(TestClass, int) load_store_elimination (after) 2280 /// CHECK: InstanceFieldSet 2281 /// CHECK-NOT: InstanceFieldSet 2282 2283 /// CHECK-START: int Main.testLoop4(TestClass, int) load_store_elimination (after) 2284 /// CHECK-NOT: InstanceFieldGet 2285 2286 // Test store elimination in the loop that stores the same value that was already 2287 // stored before the loop, without any loads of that value. testLoop4(TestClass obj, int n)2288 private static int testLoop4(TestClass obj, int n) { 2289 obj.i = 1; 2290 for (int i = 0; i < n; ++i) { 2291 obj.i = 1; 2292 } 2293 return n; 2294 } 2295 2296 /// CHECK-START: int Main.testLoop5(TestClass, int) load_store_elimination (before) 2297 /// CHECK-DAG: InstanceFieldSet 2298 /// CHECK-DAG: InstanceFieldSet 2299 /// CHECK-DAG: InstanceFieldGet 2300 /// CHECK-DAG: InstanceFieldGet 2301 /// CHECK-DAG: InstanceFieldSet 2302 /// CHECK-DAG: InstanceFieldSet 2303 /// CHECK-DAG: InstanceFieldGet 2304 2305 /// CHECK-START: int Main.testLoop5(TestClass, int) load_store_elimination (after) 2306 /// CHECK: InstanceFieldSet 2307 /// CHECK: InstanceFieldSet 2308 /// CHECK-NOT: InstanceFieldSet 2309 2310 /// CHECK-START: int Main.testLoop5(TestClass, int) load_store_elimination (after) 2311 /// CHECK-NOT: InstanceFieldGet 2312 2313 // Test eliminating loads and stores that just shuffle the same value between 2314 // different heap locations. testLoop5(TestClass obj, int n)2315 private static int testLoop5(TestClass obj, int n) { 2316 // Initialize both `obj.i` and `obj.j` to the same value and then swap these values 2317 // in the loop. We should be able to determine that the values are always the same. 2318 obj.i = n; 2319 obj.j = n; 2320 for (int i = 0; i < n; ++i) { 2321 if ((i & 1) != 0) { 2322 int tmp = obj.i; 2323 obj.i = obj.j; 2324 obj.j = tmp; 2325 } 2326 } 2327 return obj.i; 2328 } 2329 2330 /// CHECK-START: int Main.testLoop6(TestClass, int) load_store_elimination (before) 2331 /// CHECK-DAG: InstanceFieldSet 2332 /// CHECK-DAG: InstanceFieldSet 2333 /// CHECK-DAG: InstanceFieldGet 2334 /// CHECK-DAG: InstanceFieldGet 2335 /// CHECK-DAG: InstanceFieldSet 2336 /// CHECK-DAG: InstanceFieldSet 2337 /// CHECK-DAG: InstanceFieldSet 2338 /// CHECK-DAG: InstanceFieldGet 2339 2340 /// CHECK-START: int Main.testLoop6(TestClass, int) load_store_elimination (after) 2341 /// CHECK: InstanceFieldSet 2342 /// CHECK: InstanceFieldSet 2343 /// CHECK-NOT: InstanceFieldSet 2344 2345 /// CHECK-START: int Main.testLoop6(TestClass, int) load_store_elimination (after) 2346 /// CHECK-NOT: InstanceFieldGet 2347 2348 // Test eliminating loads and stores that just shuffle the same value between 2349 // different heap locations, or store the same value. testLoop6(TestClass obj, int n)2350 private static int testLoop6(TestClass obj, int n) { 2351 // Initialize both `obj.i` and `obj.j` to the same value and then swap these values 2352 // in the loop or set `obj.i` to the same value. We should be able to determine 2353 // that the values are always the same. 2354 obj.i = n; 2355 obj.j = n; 2356 for (int i = 0; i < n; ++i) { 2357 if ((i & 1) != 0) { 2358 int tmp = obj.i; 2359 obj.i = obj.j; 2360 obj.j = tmp; 2361 } else { 2362 obj.i = n; 2363 } 2364 } 2365 return obj.i; 2366 } 2367 2368 /// CHECK-START: int Main.testLoop7(int) load_store_elimination (before) 2369 /// CHECK-DAG: NewInstance 2370 /// CHECK-DAG: InstanceFieldGet 2371 /// CHECK-DAG: InstanceFieldGet 2372 /// CHECK-DAG: InstanceFieldSet 2373 /// CHECK-DAG: InstanceFieldSet 2374 /// CHECK-DAG: InstanceFieldSet 2375 /// CHECK-DAG: InstanceFieldGet 2376 2377 /// CHECK-START: int Main.testLoop7(int) load_store_elimination (after) 2378 /// CHECK-NOT: NewInstance 2379 /// CHECK-NOT: InstanceFieldSet 2380 /// CHECK-NOT: InstanceFieldGet 2381 2382 // Test eliminating loads and stores that just shuffle the default value between 2383 // different heap locations, or store the same value. testLoop7(int n)2384 private static int testLoop7(int n) { 2385 // Leave both `obj.i` and `obj.j` initialized to the default value and then 2386 // swap these values in the loop or set some to the identical value 0. 2387 // We should be able to determine that the values are always the same. 2388 TestClass obj = new TestClass(); 2389 for (int i = 0; i < n; ++i) { 2390 if ((i & 1) != 0) { 2391 int tmp = obj.i; 2392 obj.i = obj.j; 2393 obj.j = tmp; 2394 } else { 2395 obj.i = 0; 2396 } 2397 } 2398 return obj.i; 2399 } 2400 2401 /// CHECK-START: int Main.testLoop8(int) load_store_elimination (before) 2402 /// CHECK-DAG: NewInstance 2403 /// CHECK-DAG: InstanceFieldGet 2404 /// CHECK-DAG: InstanceFieldGet 2405 /// CHECK-DAG: InstanceFieldSet 2406 /// CHECK-DAG: InstanceFieldSet 2407 /// CHECK-DAG: InstanceFieldSet 2408 /// CHECK-DAG: InstanceFieldSet 2409 /// CHECK-DAG: InstanceFieldGet 2410 2411 /// CHECK-START: int Main.testLoop8(int) load_store_elimination (after) 2412 /// CHECK-NOT: NewInstance 2413 /// CHECK-NOT: InstanceFieldSet 2414 /// CHECK-NOT: InstanceFieldGet 2415 2416 /// CHECK-START: int Main.testLoop8(int) load_store_elimination (after) 2417 /// CHECK: Phi 2418 /// CHECK: Phi 2419 /// CHECK-NOT: Phi 2420 2421 // Test eliminating loads and stores that just shuffle the same value between 2422 // different heap locations, or store the same value. The value is loaded 2423 // after conditionally setting a different value after the loop to test that 2424 // this does not cause creation of excessive Phis. testLoop8(int n)2425 private static int testLoop8(int n) { 2426 // Leave both `obj.i` and `obj.j` initialized to the default value and then 2427 // swap these values in the loop or set some to the identical value 0. 2428 // We should be able to determine that the values are always the same. 2429 TestClass obj = new TestClass(); 2430 for (int i = 0; i < n; ++i) { 2431 if ((i & 1) != 0) { 2432 int tmp = obj.i; 2433 obj.i = obj.j; 2434 obj.j = tmp; 2435 } else { 2436 obj.i = 0; 2437 } 2438 } 2439 // Up to this point, `obj.i` is always 0 but the Phi placeholder below 2440 // must not be included in that determination despite using lazy search 2441 // for Phi placeholders triggered by the `obj.i` load below. 2442 if ((n & 1) == 0) { 2443 obj.i = 1; 2444 } 2445 return obj.i; 2446 } 2447 2448 /// CHECK-START: int Main.testLoop9(TestClass, int) load_store_elimination (before) 2449 /// CHECK-DAG: NewInstance 2450 /// CHECK-DAG: InstanceFieldSet 2451 /// CHECK-DAG: InstanceFieldSet 2452 /// CHECK-DAG: Phi 2453 /// CHECK-DAG: InstanceFieldGet 2454 /// CHECK-DAG: InstanceFieldGet 2455 /// CHECK-DAG: InstanceFieldSet 2456 /// CHECK-DAG: InstanceFieldSet 2457 /// CHECK-DAG: InvokeStaticOrDirect 2458 /// CHECK-DAG: InstanceFieldGet 2459 2460 /// CHECK-START: int Main.testLoop9(TestClass, int) load_store_elimination (after) 2461 /// CHECK-DAG: InstanceFieldSet 2462 /// CHECK-DAG: Phi 2463 /// CHECK-DAG: Phi 2464 /// CHECK-DAG: InstanceFieldGet 2465 /// CHECK-DAG: InstanceFieldSet 2466 /// CHECK-DAG: Phi 2467 2468 /// CHECK-START: int Main.testLoop9(TestClass, int) load_store_elimination (after) 2469 /// CHECK: InstanceFieldSet 2470 /// CHECK: InstanceFieldSet 2471 /// CHECK-NOT: InstanceFieldSet 2472 2473 /// CHECK-START: int Main.testLoop9(TestClass, int) load_store_elimination (after) 2474 /// CHECK-NOT: NewInstance 2475 2476 /// CHECK-START: int Main.testLoop9(TestClass, int) load_store_elimination (after) 2477 /// CHECK: InstanceFieldGet 2478 /// CHECK-NOT: InstanceFieldGet 2479 2480 /// CHECK-START: int Main.testLoop9(TestClass, int) load_store_elimination (after) 2481 /// CHECK: Phi 2482 /// CHECK: Phi 2483 /// CHECK: Phi 2484 /// CHECK-NOT: Phi 2485 2486 // Test that unknown value flowing through a loop back-edge prevents 2487 // elimination of a load but that load can be used as an input to a Phi 2488 // created to eliminate another load. testLoop9(TestClass obj, int n)2489 private static int testLoop9(TestClass obj, int n) { 2490 TestClass obj0 = new TestClass(); 2491 // Initialize both `obj.i` and `obj0.i` to the same value and then swap these values 2492 // in the loop or clobber `obj.i`. We should determine that the `obj.i` load in the 2493 // loop must be kept but the `obj0.i` load can be replaced by a Phi chain. 2494 obj0.i = n; 2495 obj.i = n; 2496 for (int i = 0; i < n; ++i) { 2497 if ((i & 1) != 0) { 2498 int tmp = obj0.i; 2499 obj0.i = obj.i; // Load cannot be eliminated. 2500 obj.i = tmp; 2501 } else { 2502 $noinline$clobberObservables(); // Makes obj.i unknown. 2503 } 2504 } 2505 return obj0.i; 2506 } 2507 2508 /// CHECK-START: int Main.testLoop10(TestClass, int) load_store_elimination (before) 2509 /// CHECK-DAG: InstanceFieldSet 2510 /// CHECK-DAG: InstanceFieldGet 2511 /// CHECK-DAG: InstanceFieldSet 2512 /// CHECK-DAG: InstanceFieldGet 2513 2514 /// CHECK-START: int Main.testLoop10(TestClass, int) load_store_elimination (after) 2515 /// CHECK-DAG: InstanceFieldSet 2516 /// CHECK-DAG: InstanceFieldGet 2517 /// CHECK-DAG: InstanceFieldSet 2518 2519 /// CHECK-START: int Main.testLoop10(TestClass, int) load_store_elimination (after) 2520 /// CHECK: InstanceFieldGet 2521 /// CHECK-NOT: InstanceFieldGet 2522 2523 // Test load elimination after finding a non-eliminated load depending 2524 // on loop Phi placeholder. testLoop10(TestClass obj, int n)2525 private static int testLoop10(TestClass obj, int n) { 2526 obj.i = 1; 2527 for (int i = 0; i < n; ++i) { 2528 $noinline$clobberObservables(); 2529 } 2530 int i1 = obj.i; 2531 obj.j = 2; // Use write side effects to stop GVN from eliminating the load below. 2532 int i2 = obj.i; 2533 return i1 + i2; 2534 } 2535 2536 /// CHECK-START: int Main.testLoop11(TestClass, int) load_store_elimination (before) 2537 /// CHECK-DAG: InstanceFieldSet 2538 /// CHECK-DAG: Phi 2539 /// CHECK-DAG: InstanceFieldSet 2540 /// CHECK-DAG: InstanceFieldSet 2541 /// CHECK-DAG: InstanceFieldGet 2542 2543 /// CHECK-START: int Main.testLoop11(TestClass, int) load_store_elimination (after) 2544 /// CHECK-DAG: InstanceFieldSet 2545 /// CHECK-DAG: Phi 2546 /// CHECK-DAG: Phi 2547 /// CHECK-DAG: InstanceFieldSet 2548 /// CHECK-DAG: InstanceFieldSet 2549 /// CHECK-DAG: Phi 2550 2551 /// CHECK-START: int Main.testLoop11(TestClass, int) load_store_elimination (after) 2552 /// CHECK: Phi 2553 /// CHECK: Phi 2554 /// CHECK: Phi 2555 /// CHECK-NOT: Phi 2556 2557 /// CHECK-START: int Main.testLoop11(TestClass, int) load_store_elimination (after) 2558 /// CHECK-NOT: InstanceFieldGet 2559 2560 // Test load elimination creating two Phis that depend on each other. testLoop11(TestClass obj, int n)2561 private static int testLoop11(TestClass obj, int n) { 2562 obj.i = 1; 2563 for (int i = 0; i < n; ++i) { 2564 if ((i & 1) != 0) { 2565 obj.i = 2; 2566 } else { 2567 obj.i = 3; 2568 } 2569 // There shall be a Phi created here for `obj.i` before the "++i". 2570 // This Phi and the loop Phi that shall be created for `obj.i` depend on each other. 2571 } 2572 return obj.i; 2573 } 2574 2575 /// CHECK-START: int Main.testLoop12(TestClass, int) load_store_elimination (before) 2576 /// CHECK-DAG: InstanceFieldSet 2577 /// CHECK-DAG: Phi 2578 /// CHECK-DAG: InstanceFieldSet 2579 /// CHECK-DAG: InstanceFieldSet 2580 /// CHECK-DAG: InstanceFieldGet 2581 2582 /// CHECK-START: int Main.testLoop12(TestClass, int) load_store_elimination (after) 2583 /// CHECK-DAG: InstanceFieldSet 2584 /// CHECK-DAG: Phi 2585 /// CHECK-DAG: Phi 2586 /// CHECK-DAG: InstanceFieldSet 2587 /// CHECK-DAG: InstanceFieldSet 2588 2589 /// CHECK-START: int Main.testLoop12(TestClass, int) load_store_elimination (after) 2590 /// CHECK: Phi 2591 /// CHECK: Phi 2592 /// CHECK-NOT: Phi 2593 2594 /// CHECK-START: int Main.testLoop12(TestClass, int) load_store_elimination (after) 2595 /// CHECK-NOT: InstanceFieldGet 2596 2597 // Test load elimination creating a single Phi with more than 2 inputs. testLoop12(TestClass obj, int n)2598 private static int testLoop12(TestClass obj, int n) { 2599 obj.i = 1; 2600 for (int i = 0; i < n; ) { 2601 // Do the loop variable increment first, so that there are back-edges 2602 // directly from the "then" and "else" blocks below. 2603 ++i; 2604 if ((i & 1) != 0) { 2605 obj.i = 2; 2606 } else { 2607 obj.i = 3; 2608 } 2609 } 2610 return obj.i; 2611 } 2612 2613 /// CHECK-START: int Main.testLoop13(TestClass, int) load_store_elimination (before) 2614 /// CHECK-DAG: NewArray 2615 /// CHECK-DAG: Phi 2616 /// CHECK-DAG: ArrayGet 2617 /// CHECK-DAG: ArraySet 2618 /// CHECK-DAG: ArrayGet 2619 /// CHECK-DAG: ArraySet 2620 /// CHECK-DAG: InstanceFieldGet 2621 /// CHECK-DAG: ArraySet 2622 /// CHECK-DAG: ArrayGet 2623 2624 /// CHECK-START: int Main.testLoop13(TestClass, int) load_store_elimination (after) 2625 /// CHECK-DAG: Phi 2626 /// CHECK-DAG: Phi 2627 /// CHECK-DAG: Phi 2628 /// CHECK-DAG: Phi 2629 /// CHECK-DAG: InstanceFieldGet 2630 2631 /// CHECK-START: int Main.testLoop13(TestClass, int) load_store_elimination (after) 2632 /// CHECK-NOT: NewArray 2633 /// CHECK-NOT: ArrayGet 2634 /// CHECK-NOT: ArraySet 2635 2636 /// CHECK-START: int Main.testLoop13(TestClass, int) load_store_elimination (after) 2637 /// CHECK: Phi 2638 /// CHECK: Phi 2639 /// CHECK: Phi 2640 /// CHECK: Phi 2641 /// CHECK-NOT: Phi 2642 2643 // Test eliminating array allocation, loads and stores and creating loop Phis. testLoop13(TestClass obj, int n)2644 private static int testLoop13(TestClass obj, int n) { 2645 int[] a = new int[3]; 2646 for (int i = 0; i < n; ++i) { 2647 a[0] = a[1]; 2648 a[1] = a[2]; 2649 a[2] = obj.i; 2650 } 2651 return a[0]; 2652 } 2653 2654 /// CHECK-START: int Main.testLoop14(TestClass2, int) load_store_elimination (before) 2655 /// CHECK-DAG: NewArray 2656 /// CHECK-DAG: InstanceFieldSet field_name:TestClass2.i 2657 /// CHECK-DAG: Phi 2658 /// CHECK-DAG: ArrayGet 2659 /// CHECK-DAG: ArraySet 2660 /// CHECK-DAG: ArrayGet 2661 /// CHECK-DAG: ArraySet 2662 /// CHECK-DAG: InstanceFieldGet field_name:TestClass2.i 2663 /// CHECK-DAG: InstanceFieldSet field_name:TestClass2.j 2664 /// CHECK-DAG: InstanceFieldGet field_name:TestClass2.i 2665 /// CHECK-DAG: ArraySet 2666 /// CHECK-DAG: InstanceFieldSet field_name:TestClass2.k 2667 /// CHECK-DAG: InstanceFieldSet field_name:TestClass2.j 2668 /// CHECK-DAG: InstanceFieldGet field_name:TestClass2.i 2669 /// CHECK-DAG: InstanceFieldSet field_name:TestClass2.k 2670 /// CHECK-DAG: ArrayGet 2671 2672 /// CHECK-START: int Main.testLoop14(TestClass2, int) load_store_elimination (after) 2673 /// CHECK-DAG: InstanceFieldSet field_name:TestClass2.i 2674 /// CHECK-DAG: Phi 2675 /// CHECK-DAG: Phi 2676 /// CHECK-DAG: Phi 2677 /// CHECK-DAG: Phi 2678 /// CHECK-DAG: InstanceFieldGet field_name:TestClass2.i 2679 /// CHECK-DAG: InstanceFieldSet field_name:TestClass2.j 2680 /// CHECK-DAG: InstanceFieldSet field_name:TestClass2.k 2681 /// CHECK-DAG: InstanceFieldSet field_name:TestClass2.j 2682 /// CHECK-DAG: InstanceFieldSet field_name:TestClass2.k 2683 2684 /// CHECK-START: int Main.testLoop14(TestClass2, int) load_store_elimination (after) 2685 /// CHECK-NOT: NewArray 2686 2687 /// CHECK-START: int Main.testLoop14(TestClass2, int) load_store_elimination (after) 2688 /// CHECK: InstanceFieldGet field_name:TestClass2.i 2689 /// CHECK-NOT: InstanceFieldGet field_name:TestClass2.i 2690 2691 /// CHECK-START: int Main.testLoop14(TestClass2, int) load_store_elimination (after) 2692 /// CHECK: Phi 2693 /// CHECK: Phi 2694 /// CHECK: Phi 2695 /// CHECK: Phi 2696 /// CHECK-NOT: Phi 2697 2698 // Test load elimination in a loop after determing that the first field load 2699 // (depending on loop Phi placeholder) cannot be eliminated. testLoop14(TestClass2 obj, int n)2700 private static int testLoop14(TestClass2 obj, int n) { 2701 int[] a = new int[3]; 2702 obj.i = 1; 2703 for (int i = 0; i < n; ++i) { 2704 a[0] = a[1]; 2705 a[1] = a[2]; 2706 int i1 = obj.i; 2707 obj.j = 2; // Use write side effects to stop GVN from eliminating the load below. 2708 int i2 = obj.i; 2709 a[2] = i1; 2710 if ((i & 2) != 0) { 2711 obj.k = i2; 2712 } else { 2713 obj.j = 3; // Use write side effects to stop GVN from eliminating the load below. 2714 obj.k = obj.i; 2715 $noinline$clobberObservables(); // Make obj.i unknown. 2716 } 2717 } 2718 return a[0]; 2719 } 2720 2721 /// CHECK-START: int Main.testLoop15(int) load_store_elimination (before) 2722 /// CHECK-DAG: NewArray 2723 /// CHECK-IF: hasIsaFeature("sve") 2724 // 2725 /// CHECK-DAG: VecPredWhile 2726 /// CHECK-DAG: VecStore 2727 // 2728 /// CHECK-ELSE: 2729 // 2730 /// CHECK-DAG: ArraySet 2731 // 2732 /// CHECK-FI: 2733 // 2734 /// CHECK-DAG: ArrayGet 2735 2736 /// CHECK-START: int Main.testLoop15(int) load_store_elimination (after) 2737 /// CHECK-DAG: NewArray 2738 /// CHECK-IF: hasIsaFeature("sve") 2739 // 2740 /// CHECK-DAG: VecPredWhile 2741 /// CHECK-DAG: VecStore 2742 // 2743 /// CHECK-ELSE: 2744 // 2745 /// CHECK-DAG: ArraySet 2746 // 2747 /// CHECK-FI: 2748 // 2749 /// CHECK-DAG: ArrayGet 2750 // Test that aliasing array store in the loop is not eliminated 2751 // when a loop Phi placeholder is marked for keeping. testLoop15(int n)2752 private static int testLoop15(int n) { 2753 int[] a = new int[n + 1]; 2754 for (int i = 0; i < n; ++i) { 2755 a[i] = 1; // Cannot be eliminated due to aliasing. 2756 } 2757 return a[0]; 2758 } 2759 2760 /// CHECK-START: int Main.testLoop16(TestClass, int) load_store_elimination (before) 2761 /// CHECK-DAG: InstanceFieldSet 2762 /// CHECK-DAG: Phi 2763 /// CHECK-DAG: InstanceFieldSet 2764 /// CHECK-DAG: InstanceFieldGet 2765 2766 /// CHECK-START: int Main.testLoop16(TestClass, int) load_store_elimination (after) 2767 /// CHECK-DAG: InstanceFieldSet 2768 /// CHECK-DAG: Phi 2769 /// CHECK-DAG: InstanceFieldSet 2770 2771 /// CHECK-START: int Main.testLoop16(TestClass, int) load_store_elimination (after) 2772 /// CHECK-NOT: InstanceFieldGet 2773 2774 /// CHECK-START: int Main.testLoop16(TestClass, int) load_store_elimination (after) 2775 /// CHECK: Phi 2776 /// CHECK-NOT: Phi 2777 2778 // Test that we match an existing loop Phi for eliminating a load. testLoop16(TestClass obj, int n)2779 static int testLoop16(TestClass obj, int n) { 2780 obj.i = 0; 2781 for (int i = 0; i < n; ) { 2782 ++i; 2783 obj.i = i; 2784 } 2785 // The load is replaced by the existing Phi instead of constructing a new one. 2786 return obj.i; 2787 } 2788 2789 /// CHECK-START: int Main.testLoop17(TestClass, int) load_store_elimination (before) 2790 /// CHECK-DAG: InstanceFieldSet 2791 /// CHECK-DAG: Phi 2792 /// CHECK-DAG: InstanceFieldSet 2793 /// CHECK-DAG: InstanceFieldSet 2794 /// CHECK-DAG: Phi 2795 /// CHECK-DAG: InstanceFieldGet 2796 2797 /// CHECK-START: int Main.testLoop17(TestClass, int) load_store_elimination (after) 2798 /// CHECK-DAG: InstanceFieldSet 2799 /// CHECK-DAG: Phi 2800 /// CHECK-DAG: InstanceFieldSet 2801 /// CHECK-DAG: InstanceFieldSet 2802 /// CHECK-DAG: Phi 2803 2804 /// CHECK-START: int Main.testLoop17(TestClass, int) load_store_elimination (after) 2805 /// CHECK-NOT: InstanceFieldGet 2806 2807 /// CHECK-START: int Main.testLoop17(TestClass, int) load_store_elimination (after) 2808 /// CHECK: Phi 2809 /// CHECK: Phi 2810 /// CHECK-NOT: Phi 2811 2812 // Test that we match an existing non-loop Phi for eliminating a load, 2813 // one input of the Phi being invariant across a preceding loop. testLoop17(TestClass obj, int n)2814 static int testLoop17(TestClass obj, int n) { 2815 obj.i = 1; 2816 int phi = 1; 2817 for (int i = 0; i < n; ++i) { 2818 obj.j = 2; // Unrelated. 2819 } 2820 if ((n & 1) != 0) { 2821 obj.i = 2; 2822 phi = 2; 2823 } 2824 // The load is replaced by the existing Phi instead of constructing a new one. 2825 return obj.i + phi; 2826 } 2827 2828 /// CHECK-START: int Main.testLoop18(TestClass, int) load_store_elimination (before) 2829 /// CHECK-DAG: NewArray 2830 /// CHECK-DAG: Phi 2831 /// CHECK-DAG: ArrayGet 2832 /// CHECK-DAG: InstanceFieldSet 2833 2834 /// CHECK-START: int Main.testLoop18(TestClass, int) load_store_elimination (after) 2835 /// CHECK-DAG: NewArray 2836 /// CHECK-DAG: Phi 2837 /// CHECK-DAG: InstanceFieldSet 2838 2839 /// CHECK-START: int Main.testLoop18(TestClass, int) load_store_elimination (after) 2840 /// CHECK-NOT: ArrayGet 2841 2842 // Test eliminating a load of the default value in a loop 2843 // with the array index being defined inside the loop. testLoop18(TestClass obj, int n)2844 static int testLoop18(TestClass obj, int n) { 2845 // The NewArray is kept as it may throw for negative n. 2846 // TODO: Eliminate constructor fence even though the NewArray is kept. 2847 int[] a0 = new int[n]; 2848 for (int i = 0; i < n; ++i) { 2849 obj.i = a0[i]; 2850 } 2851 return n; 2852 } 2853 2854 /// CHECK-START: int Main.testLoop19(TestClass, int) load_store_elimination (before) 2855 /// CHECK-DAG: NewArray 2856 /// CHECK-DAG: Phi 2857 /// CHECK-DAG: ArrayGet 2858 /// CHECK-DAG: InstanceFieldSet 2859 /// CHECK-DAG: ArraySet 2860 2861 /// CHECK-START: int Main.testLoop19(TestClass, int) load_store_elimination (after) 2862 /// CHECK-DAG: NewArray 2863 /// CHECK-DAG: Phi 2864 /// CHECK-DAG: InstanceFieldSet 2865 2866 /// CHECK-START: int Main.testLoop19(TestClass, int) load_store_elimination (after) 2867 /// CHECK-NOT: ArrayGet 2868 /// CHECK-NOT: ArraySet 2869 2870 // Test eliminating a load of the default value and store of an identical value 2871 // in a loop with the array index being defined inside the loop. testLoop19(TestClass obj, int n)2872 static int testLoop19(TestClass obj, int n) { 2873 // The NewArray is kept as it may throw for negative n. 2874 // TODO: Eliminate constructor fence even though the NewArray is kept. 2875 int[] a0 = new int[n]; 2876 for (int i = 0; i < n; ++i) { 2877 obj.i = a0[i]; 2878 a0[i] = 0; // Store the same value as default. 2879 } 2880 return n; 2881 } 2882 2883 /// CHECK-START: int Main.testLoop20(TestClass, int) load_store_elimination (before) 2884 /// CHECK-DAG: NewArray 2885 /// CHECK-DAG: Phi 2886 /// CHECK-DAG: ArrayGet 2887 /// CHECK-DAG: InstanceFieldSet 2888 /// CHECK-DAG: ArraySet 2889 2890 /// CHECK-START: int Main.testLoop20(TestClass, int) load_store_elimination (after) 2891 /// CHECK-DAG: NewArray 2892 /// CHECK-DAG: Phi 2893 /// CHECK-DAG: InstanceFieldSet 2894 2895 /// CHECK-START: int Main.testLoop20(TestClass, int) load_store_elimination (after) 2896 /// CHECK-NOT: ArrayGet 2897 /// CHECK-NOT: ArraySet 2898 2899 // Test eliminating a load of the default value and a conditional store of an 2900 // identical value in a loop with the array index being defined inside the loop. testLoop20(TestClass obj, int n)2901 static int testLoop20(TestClass obj, int n) { 2902 // The NewArray is kept as it may throw for negative n. 2903 // TODO: Eliminate constructor fence even though the NewArray is kept. 2904 int[] a0 = new int[n]; 2905 for (int i = 0; i < n; ++i) { 2906 obj.i = a0[i]; 2907 if ((i & 1) != 0) { 2908 a0[i] = 0; // Store the same value as default. 2909 } 2910 } 2911 return n; 2912 } 2913 2914 /// CHECK-START: int Main.testLoop21(TestClass, int) load_store_elimination (before) 2915 /// CHECK-DAG: InstanceFieldSet 2916 /// CHECK-DAG: InstanceFieldGet 2917 /// CHECK-DAG: InstanceFieldSet 2918 /// CHECK-DAG: InstanceFieldGet 2919 /// CHECK-DAG: InstanceFieldSet 2920 /// CHECK-DAG: InstanceFieldGet 2921 /// CHECK-DAG: InstanceFieldSet 2922 2923 /// CHECK-START: int Main.testLoop21(TestClass, int) load_store_elimination (before) 2924 /// CHECK-NOT: Phi 2925 2926 /// CHECK-START: int Main.testLoop21(TestClass, int) load_store_elimination (after) 2927 /// CHECK-NOT: InstanceFieldGet 2928 2929 /// CHECK-START: int Main.testLoop21(TestClass, int) load_store_elimination (after) 2930 /// CHECK: InstanceFieldSet 2931 /// CHECK: InstanceFieldSet 2932 /// CHECK: InstanceFieldSet 2933 /// CHECK-NOT: InstanceFieldSet 2934 2935 /// CHECK-START: int Main.testLoop21(TestClass, int) load_store_elimination (after) 2936 /// CHECK: Phi 2937 /// CHECK-NOT: Phi 2938 2939 // Test load elimination when an instance field is used as the loop variable. testLoop21(TestClass obj, int n)2940 static int testLoop21(TestClass obj, int n) { 2941 for (obj.i = 0; obj.i < n; ++obj.i) { 2942 obj.j = 0; // Use write side effects to stop GVN from eliminating the load below. 2943 obj.j = obj.i; 2944 } 2945 return n; 2946 } 2947 2948 /// CHECK-START: int Main.testLoop22(TestClass, int) load_store_elimination (before) 2949 /// CHECK-DAG: InstanceFieldSet 2950 /// CHECK-DAG: InstanceFieldGet 2951 /// CHECK-DAG: InstanceFieldSet 2952 /// CHECK-DAG: InstanceFieldGet 2953 /// CHECK-DAG: InstanceFieldSet 2954 /// CHECK-DAG: InstanceFieldGet 2955 /// CHECK-DAG: InstanceFieldSet 2956 /// CHECK-DAG: InstanceFieldSet 2957 2958 /// CHECK-START: int Main.testLoop22(TestClass, int) load_store_elimination (before) 2959 /// CHECK-NOT: Phi 2960 2961 /// CHECK-START: int Main.testLoop22(TestClass, int) load_store_elimination (after) 2962 /// CHECK-NOT: InstanceFieldGet 2963 2964 /// CHECK-START: int Main.testLoop22(TestClass, int) load_store_elimination (after) 2965 /// CHECK: InstanceFieldSet 2966 /// CHECK: InstanceFieldSet 2967 /// CHECK-NOT: InstanceFieldSet 2968 2969 /// CHECK-START: int Main.testLoop22(TestClass, int) load_store_elimination (after) 2970 /// CHECK: Phi 2971 /// CHECK-NOT: Phi 2972 2973 // Test load and store elimination when an instance field is used as the loop 2974 // variable and then overwritten after the loop. testLoop22(TestClass obj, int n)2975 static int testLoop22(TestClass obj, int n) { 2976 for (obj.i = 0; obj.i < n; ++obj.i) { 2977 obj.j = 0; // Use write side effects to stop GVN from eliminating the load below. 2978 obj.j = obj.i; 2979 } 2980 obj.i = 0; 2981 return n; 2982 } 2983 2984 /// CHECK-START: int Main.testLoop23(TestClass, int) load_store_elimination (before) 2985 /// CHECK-DAG: InstanceFieldSet 2986 /// CHECK-DAG: Phi 2987 /// CHECK-DAG: Phi 2988 /// CHECK-DAG: InstanceFieldSet 2989 /// CHECK-DAG: InstanceFieldSet 2990 /// CHECK-DAG: Phi 2991 /// CHECK-DAG: InstanceFieldSet 2992 2993 /// CHECK-START: int Main.testLoop23(TestClass, int) load_store_elimination (after) 2994 /// CHECK-DAG: Phi 2995 /// CHECK-DAG: Phi 2996 /// CHECK-DAG: Phi 2997 /// CHECK-DAG: InstanceFieldSet 2998 2999 /// CHECK-START: int Main.testLoop23(TestClass, int) load_store_elimination (after) 3000 /// CHECK: InstanceFieldSet 3001 /// CHECK-NOT: InstanceFieldSet 3002 3003 // Test elimination of non-observable stores. testLoop23(TestClass obj, int n)3004 static int testLoop23(TestClass obj, int n) { 3005 obj.i = -1; 3006 int phi = -1; 3007 for (int i = 0; i < n; ++i) { 3008 obj.i = i; 3009 phi = i; 3010 } 3011 if ((n & 1) != 0) { 3012 obj.i = 2; 3013 phi = 2; 3014 } 3015 obj.i = phi; // This store shall be kept, the stores above shall be eliminated. 3016 return phi; 3017 } 3018 3019 /// CHECK-START: int Main.testLoop24(TestClass, int) load_store_elimination (before) 3020 /// CHECK-DAG: InstanceFieldSet 3021 /// CHECK-DAG: Phi 3022 /// CHECK-DAG: Phi 3023 /// CHECK-DAG: InstanceFieldSet 3024 /// CHECK-DAG: InstanceFieldSet 3025 /// CHECK-DAG: Phi 3026 /// CHECK-DAG: InstanceFieldSet 3027 3028 /// CHECK-START: int Main.testLoop24(TestClass, int) load_store_elimination (after) 3029 /// CHECK-DAG: InstanceFieldSet 3030 /// CHECK-DAG: Phi 3031 /// CHECK-DAG: Phi 3032 /// CHECK-DAG: InstanceFieldSet 3033 /// CHECK-DAG: InstanceFieldSet 3034 /// CHECK-DAG: Phi 3035 3036 /// CHECK-START: int Main.testLoop24(TestClass, int) load_store_elimination (after) 3037 /// CHECK: InstanceFieldSet 3038 /// CHECK: InstanceFieldSet 3039 /// CHECK: InstanceFieldSet 3040 /// CHECK-NOT: InstanceFieldSet 3041 3042 // Test matching Phis for store elimination. testLoop24(TestClass obj, int n)3043 static int testLoop24(TestClass obj, int n) { 3044 obj.i = -1; 3045 int phi = -1; 3046 for (int i = 0; i < n; ++i) { 3047 obj.i = i; 3048 phi = i; 3049 } 3050 if ((n & 1) != 0) { 3051 obj.i = 2; 3052 phi = 2; 3053 } 3054 if (n == 3) { 3055 return -2; // Make the above stores observable. 3056 } 3057 // As the stores above are observable and kept, we match the merged 3058 // heap value with existing Phis and determine that we're storing 3059 // the same value that's already there, so we eliminate this store. 3060 obj.i = phi; 3061 return phi; 3062 } 3063 3064 /// CHECK-START: int Main.testLoop25(TestClass, int) load_store_elimination (before) 3065 /// CHECK-DAG: InstanceFieldSet 3066 /// CHECK-DAG: Phi 3067 /// CHECK-DAG: Phi 3068 /// CHECK-DAG: InstanceFieldSet 3069 /// CHECK-DAG: Phi 3070 /// CHECK-DAG: InstanceFieldGet 3071 /// CHECK-DAG: InstanceFieldSet 3072 3073 /// CHECK-START: int Main.testLoop25(TestClass, int) load_store_elimination (after) 3074 /// CHECK-DAG: InstanceFieldSet 3075 /// CHECK-DAG: Phi 3076 /// CHECK-DAG: Phi 3077 /// CHECK-DAG: Phi 3078 /// CHECK-DAG: InstanceFieldSet 3079 /// CHECK-DAG: Phi 3080 /// CHECK-DAG: Phi 3081 /// CHECK-DAG: InstanceFieldSet 3082 3083 /// CHECK-START: int Main.testLoop25(TestClass, int) load_store_elimination (after) 3084 /// CHECK-NOT: InstanceFieldGet 3085 3086 // Test that we do not match multiple dependent Phis for load and store elimination. testLoop25(TestClass obj, int n)3087 static int testLoop25(TestClass obj, int n) { 3088 obj.i = 1; 3089 int phi = 1; 3090 for (int i = 0; i < n; ++i) { 3091 if ((i & 1) != 0) { 3092 obj.i = 2; 3093 phi = 2; 3094 } 3095 // There is a Phi here for the variable `phi` before the "++i". 3096 // This Phi and the loop Phi for `phi` depend on each other. 3097 } 3098 if (n == 3) { 3099 return -1; // Make above stores observable. 3100 } 3101 // We're not matching multiple Phi placeholders to existing Phis. Therefore the load 3102 // below requires 2 extra Phis to be created and the store below shall not be eliminated 3103 // even though it stores the same value that's already present in the heap location. 3104 int tmp = obj.i; 3105 obj.i = phi; 3106 return tmp + phi; 3107 } 3108 3109 /// CHECK-START: int Main.testLoop26(TestClass, int) load_store_elimination (before) 3110 /// CHECK-DAG: NewInstance 3111 /// CHECK-DAG: InstanceFieldSet 3112 /// CHECK-DAG: Phi 3113 /// CHECK-DAG: NewInstance 3114 /// CHECK-DAG: InstanceFieldSet 3115 /// CHECK-DAG: InstanceFieldGet 3116 /// CHECK-DAG: InstanceFieldGet 3117 3118 /// CHECK-START: int Main.testLoop26(TestClass, int) load_store_elimination (after) 3119 /// CHECK-DAG: NewInstance 3120 /// CHECK-DAG: InstanceFieldSet 3121 /// CHECK-DAG: Phi 3122 /// CHECK-DAG: Phi 3123 /// CHECK-DAG: NewInstance 3124 /// CHECK-DAG: InstanceFieldSet 3125 /// CHECK-DAG: InstanceFieldGet 3126 3127 /// CHECK-START: int Main.testLoop26(TestClass, int) load_store_elimination (after) 3128 /// CHECK: InstanceFieldGet 3129 /// CHECK-NOT: InstanceFieldGet 3130 3131 // Test load elimination creating a reference Phi. testLoop26(TestClass obj, int n)3132 static int testLoop26(TestClass obj, int n) { 3133 obj.next = new TestClass(1, 2); 3134 for (int i = 0; i < n; ++i) { 3135 obj.next = new SubTestClass(); 3136 } 3137 return obj.next.i; 3138 } 3139 3140 /// CHECK-START: int Main.testLoop27(TestClass, int) load_store_elimination (before) 3141 /// CHECK-DAG: NewInstance 3142 /// CHECK-DAG: InstanceFieldSet 3143 /// CHECK-DAG: Phi 3144 /// CHECK-DAG: NewInstance 3145 /// CHECK-DAG: InstanceFieldSet 3146 /// CHECK-DAG: InstanceFieldGet 3147 /// CHECK-DAG: InstanceFieldGet 3148 3149 /// CHECK-START: int Main.testLoop27(TestClass, int) load_store_elimination (after) 3150 /// CHECK-DAG: NewInstance 3151 /// CHECK-DAG: InstanceFieldSet 3152 /// CHECK-DAG: Phi 3153 /// CHECK-DAG: Phi 3154 /// CHECK-DAG: NewInstance 3155 /// CHECK-DAG: InstanceFieldSet 3156 /// CHECK-DAG: Phi 3157 /// CHECK-DAG: InstanceFieldGet 3158 3159 /// CHECK-START: int Main.testLoop27(TestClass, int) load_store_elimination (after) 3160 /// CHECK: InstanceFieldGet 3161 /// CHECK-NOT: InstanceFieldGet 3162 3163 // Test load elimination creating two reference Phis that depend on each other. testLoop27(TestClass obj, int n)3164 static int testLoop27(TestClass obj, int n) { 3165 obj.next = new TestClass(1, 2); 3166 for (int i = 0; i < n; ++i) { 3167 if ((i & 1) != 0) { 3168 obj.next = new SubTestClass(); 3169 } 3170 // There shall be a Phi created here for `obj.next` before the "++i". 3171 // This Phi and the loop Phi that shall be created for `obj.next` depend on each other. 3172 } 3173 return obj.next.i; 3174 } 3175 3176 /// CHECK-START: int Main.testLoop28(TestClass, int) load_store_elimination (before) 3177 /// CHECK-DAG: InstanceFieldSet 3178 /// CHECK-DAG: NewArray 3179 /// CHECK-DAG: Phi 3180 /// CHECK-DAG: ArrayGet 3181 /// CHECK-DAG: ArraySet 3182 /// CHECK-DAG: ArrayGet 3183 /// CHECK-DAG: ArraySet 3184 /// CHECK-DAG: InstanceFieldGet 3185 /// CHECK-DAG: ArraySet 3186 /// CHECK-DAG: ArrayGet 3187 3188 /// CHECK-START: int Main.testLoop28(TestClass, int) load_store_elimination (after) 3189 /// CHECK-DAG: InstanceFieldSet 3190 /// CHECK-DAG: Phi 3191 /// CHECK-DAG: Phi 3192 /// CHECK-DAG: Phi 3193 /// CHECK-DAG: Phi 3194 /// CHECK-DAG: InstanceFieldGet 3195 3196 /// CHECK-START: int Main.testLoop28(TestClass, int) load_store_elimination (after) 3197 /// CHECK-NOT: NewArray 3198 /// CHECK-NOT: ArrayGet 3199 /// CHECK-NOT: ArraySet 3200 3201 /// CHECK-START: int Main.testLoop28(TestClass, int) load_store_elimination (after) 3202 /// CHECK: Phi 3203 /// CHECK: Phi 3204 /// CHECK: Phi 3205 /// CHECK: Phi 3206 /// CHECK-NOT: Phi 3207 3208 // Test eliminating array allocation, loads and stores and creating loop Phis 3209 // after determining that a field load depending on loop Phi placeholder cannot 3210 // be eliminated. testLoop28(TestClass obj, int n)3211 private static int testLoop28(TestClass obj, int n) { 3212 obj.i = 1; 3213 int[] a = new int[3]; 3214 for (int i = 0; i < n; ++i) { 3215 a[0] = a[1]; 3216 a[1] = a[2]; 3217 a[2] = obj.i; 3218 $noinline$clobberObservables(); 3219 } 3220 return a[0]; 3221 } 3222 3223 /// CHECK-START: int Main.testLoop29(int) load_store_elimination (before) 3224 /// CHECK-DAG: NewArray 3225 /// CHECK-DAG: Phi 3226 /// CHECK-DAG: Phi 3227 /// CHECK-DAG: ArrayGet 3228 /// CHECK-DAG: ArraySet 3229 3230 /// CHECK-START: int Main.testLoop29(int) load_store_elimination (after) 3231 /// CHECK-DAG: NewArray 3232 /// CHECK-DAG: Phi 3233 /// CHECK-DAG: Phi 3234 /// CHECK-DAG: ArrayGet 3235 /// CHECK-DAG: ArraySet 3236 3237 // Test that ArraySet with non-default value prevents matching ArrayGet for 3238 // the same array to default value even when the ArraySet is using an index 3239 // offset by one, making LSA declare that the two heap locations do not alias. testLoop29(int n)3240 private static int testLoop29(int n) { 3241 int[] a = new int[4]; 3242 int sum = 0; 3243 for (int i = 0; i < n; ) { 3244 int value = a[i] + 1; 3245 sum += value; 3246 ++i; 3247 a[i] = value; 3248 } 3249 return sum; 3250 } 3251 3252 /// CHECK-START: int Main.testLoop30(int) load_store_elimination (before) 3253 /// CHECK-DAG: NewArray 3254 /// CHECK-DAG: Phi 3255 /// CHECK-DAG: Phi 3256 /// CHECK-DAG: ArrayGet 3257 /// CHECK-DAG: ArraySet 3258 3259 /// CHECK-START: int Main.testLoop30(int) load_store_elimination (after) 3260 /// CHECK-NOT: ArrayGet 3261 /// CHECK-NOT: ArraySet 3262 3263 // Test that ArraySet with default value does not prevent matching ArrayGet 3264 // for the same array to the default value. testLoop30(int n)3265 private static int testLoop30(int n) { 3266 int[] a = new int[4]; // NewArray is kept due to environment use by Deoptimize. 3267 int sum = 0; 3268 for (int i = 0; i < n; ) { 3269 int value = a[i] + 1; 3270 sum += value; 3271 ++i; 3272 a[i] = 0; 3273 } 3274 return sum; 3275 } 3276 3277 /// CHECK-START: int Main.testLoop31(int) load_store_elimination (before) 3278 /// CHECK-DAG: NewArray 3279 /// CHECK-DAG: Phi 3280 /// CHECK-DAG: Phi 3281 /// CHECK-DAG: ArrayGet 3282 /// CHECK-DAG: ArraySet 3283 3284 /// CHECK-START: int Main.testLoop31(int) load_store_elimination (after) 3285 /// CHECK-NOT: ArrayGet 3286 /// CHECK-NOT: ArraySet 3287 3288 // Test that ArraySet with default value read from the array does not 3289 // prevent matching ArrayGet for the same array to the default value. testLoop31(int n)3290 private static int testLoop31(int n) { 3291 int[] a = new int[4]; // NewArray is kept due to environment use by Deoptimize. 3292 int sum = 0; 3293 for (int i = 0; i < n; ) { 3294 int value = a[i]; 3295 sum += value; 3296 ++i; 3297 a[i] = value; 3298 } 3299 return sum; 3300 } 3301 3302 /// CHECK-START: int Main.testLoop32(TestClass, int) load_store_elimination (before) 3303 /// CHECK-DAG: InstanceFieldSet 3304 /// CHECK-DAG: Phi 3305 /// CHECK-DAG: Phi 3306 /// CHECK-DAG: InstanceFieldSet 3307 /// CHECK-DAG: InstanceFieldSet 3308 /// CHECK-DAG: Phi 3309 /// CHECK-DAG: InstanceFieldSet 3310 3311 /// CHECK-START: int Main.testLoop32(TestClass, int) load_store_elimination (after) 3312 /// CHECK-DAG: InstanceFieldSet 3313 /// CHECK-DAG: Phi 3314 /// CHECK-DAG: Phi 3315 /// CHECK-DAG: InstanceFieldSet 3316 /// CHECK-DAG: InstanceFieldSet 3317 /// CHECK-DAG: Phi 3318 3319 /// CHECK-START: int Main.testLoop32(TestClass, int) load_store_elimination (after) 3320 /// CHECK: InstanceFieldSet 3321 /// CHECK: InstanceFieldSet 3322 /// CHECK: InstanceFieldSet 3323 /// CHECK-NOT: InstanceFieldSet 3324 3325 // Test matching Phis for store elimination. testLoop32(TestClass obj, int n)3326 static int testLoop32(TestClass obj, int n) { 3327 obj.i = -1; 3328 int phi = -1; 3329 for (int i = 0; i < n; ) { 3330 ++i; 3331 if ((i & 1) != 0) { 3332 obj.i = i; 3333 phi = i; 3334 } 3335 } 3336 if ((n & 1) != 0) { 3337 obj.i = 2; 3338 phi = 2; 3339 } 3340 if (n == 3) { 3341 return -2; // Make the above stores observable. 3342 } 3343 // As the stores above are observable and kept, we match the merged 3344 // heap value with existing Phis and determine that we're storing 3345 // the same value that's already there, so we eliminate this store. 3346 obj.i = phi; 3347 return phi; 3348 } 3349 3350 // CHECK-START: int Main.testLoop33(TestClass, int) load_store_elimination (before) 3351 // CHECK-DAG: InstanceFieldSet 3352 // CHECK-DAG: NewArray 3353 // CHECK-DAG: Phi 3354 // CHECK-DAG: ArrayGet 3355 // CHECK-DAG: InstanceFieldSet 3356 // CHECK-DAG: Phi 3357 // CHECK-DAG: ArrayGet 3358 // CHECK-DAG: InstanceFieldGet 3359 // CHECK-DAG: InstanceFieldSet 3360 // CHECK-DAG: InstanceFieldGet 3361 3362 // CHECK-START: int Main.testLoop33(TestClass, int) load_store_elimination (after) 3363 // CHECK-DAG: InstanceFieldSet 3364 // CHECK-DAG: Phi 3365 // CHECK-DAG: InstanceFieldSet 3366 // CHECK-DAG: Phi 3367 // CHECK-DAG: InstanceFieldGet 3368 // CHECK-DAG: InstanceFieldSet 3369 // CHECK-DAG: InstanceFieldGet 3370 3371 // CHECK-START: int Main.testLoop33(TestClass, int) load_store_elimination (after) 3372 // CHECK-NOT: ArrayGet 3373 3374 // Test that when processing Phi placeholder with unknown input, we allow materialized 3375 // default value in pre-header for array location with index defined in the loop. testLoop33(TestClass obj, int n)3376 static int testLoop33(TestClass obj, int n) { 3377 obj.i = 0; 3378 int[] a0 = new int[n]; 3379 for (int i = 0; i < n; ++i) { 3380 obj.i = a0[i]; 3381 $noinline$clobberObservables(); // Make `obj.i` unknown. 3382 } 3383 for (int i = 0; i < n; ++i) { 3384 int zero = a0[i]; 3385 int unknown = obj.i; 3386 obj.j += zero + unknown; 3387 } 3388 return obj.j; 3389 } 3390 3391 /// CHECK-START: int Main.testLoop34(int) load_store_elimination (before) 3392 /// CHECK-DAG: NewArray 3393 /// CHECK-DAG: Phi 3394 /// CHECK-DAG: Phi 3395 /// CHECK-DAG: ArrayGet 3396 /// CHECK-DAG: ArraySet 3397 3398 /// CHECK-START: int Main.testLoop34(int) load_store_elimination (after) 3399 /// CHECK-DAG: NewArray 3400 /// CHECK-DAG: Phi 3401 /// CHECK-DAG: Phi 3402 /// CHECK-DAG: ArrayGet 3403 /// CHECK-DAG: ArraySet 3404 3405 // Test that ArraySet with non-default value prevents matching ArrayGet for 3406 // the same array to default value even when the ArraySet is using an index 3407 // offset by one, making LSA declare that the two heap locations do not alias. 3408 // Also test that the ArraySet is not eliminated. testLoop34(int n)3409 private static int testLoop34(int n) { 3410 int[] a = new int[n + 1]; 3411 int sum = 0; 3412 for (int i = 0; i < n; ) { 3413 int value = a[i] + 1; 3414 sum += value; 3415 ++i; 3416 a[i] = value; 3417 } 3418 return sum; 3419 } 3420 3421 /// CHECK-START: int Main.testLoop35(int) load_store_elimination (before) 3422 /// CHECK-DAG: NewArray 3423 /// CHECK-DAG: Phi 3424 /// CHECK-DAG: Phi 3425 /// CHECK-DAG: ArrayGet 3426 /// CHECK-DAG: ArraySet 3427 /// CHECK-DAG: ArraySet 3428 3429 /// CHECK-START: int Main.testLoop35(int) load_store_elimination (after) 3430 /// CHECK-DAG: NewArray 3431 /// CHECK-DAG: Phi 3432 /// CHECK-DAG: Phi 3433 /// CHECK-DAG: ArrayGet 3434 /// CHECK-DAG: ArraySet 3435 3436 /// CHECK-START: int Main.testLoop35(int) load_store_elimination (after) 3437 /// CHECK: ArraySet 3438 /// CHECK-NOT: ArraySet 3439 3440 // Test that ArraySet with non-default value prevents matching ArrayGet for 3441 // the same array to default value even when the ArraySet is using an index 3442 // offset by one, making LSA declare that the two heap locations do not alias. 3443 // Also test that the ArraySet is not eliminated and that a store after the 3444 // loop is eliminated. testLoop35(int n)3445 private static int testLoop35(int n) { 3446 int[] a = new int[n + 1]; 3447 int sum = 0; 3448 for (int i = 0; i < n; ) { 3449 int value = a[i] + 1; 3450 sum += value; 3451 ++i; 3452 a[i] = value; 3453 } 3454 a[0] = 1; 3455 return sum; 3456 } 3457 3458 /// CHECK-START: int Main.testLoop36(int) load_store_elimination (before) 3459 /// CHECK-DAG: ArraySet 3460 /// CHECK-DAG: Deoptimize 3461 /// CHECK-DAG: ArrayGet 3462 /// CHECK-DAG: ArrayGet 3463 /// CHECK-DAG: ArrayGet 3464 /// CHECK-DAG: ArrayGet 3465 3466 /// CHECK-START: int Main.testLoop36(int) load_store_elimination (before) 3467 /// CHECK-NOT: BoundsCheck 3468 3469 /// CHECK-START: int Main.testLoop36(int) load_store_elimination (after) 3470 /// CHECK-DAG: ArraySet 3471 /// CHECK-DAG: Deoptimize 3472 /// CHECK-DAG: ArrayGet 3473 /// CHECK-DAG: ArrayGet 3474 /// CHECK-DAG: ArrayGet 3475 /// CHECK-DAG: ArrayGet 3476 3477 // Regression test for b/187487955. 3478 // We previously failed a DCHECK() during the search for kept stores when 3479 // we encountered two array locations for the same array and considered 3480 // non-aliasing by LSA when only one of the array locations had index 3481 // defined inside the loop. Note that this situation requires that BCE 3482 // eliminates BoundsCheck instructions, otherwise LSA considers those 3483 // locations aliasing. testLoop36(int n)3484 private static int testLoop36(int n) { 3485 int[] a = new int[n]; 3486 int zero = 0; 3487 int i = 0; 3488 for (; i < n; ++i) { 3489 a[i] = i; 3490 // Extra instructions to avoid loop unrolling. 3491 zero = (((zero ^ 1) + 2) ^ 1) - 2; 3492 zero = (((zero ^ 4) + 8) ^ 4) - 8; 3493 } 3494 // Use 4 loads with consecutive fixed offsets from the loop Phi for `i`. 3495 // BCE shall replace BoundsChecks with Deoptimize, so that indexes here are 3496 // the Phi plus/minus a constant, something that LSA considers non-aliasing 3497 // with the Phi (LSA does not take different loop iterations into account) 3498 // but LSE must consider aliasing across dfferent loop iterations. 3499 return a[i - 1] + a[i - 2] + a[i - 3] + a[i - 4] + zero; 3500 } 3501 3502 /// CHECK-START: int Main.testLoop37(int) load_store_elimination (before) 3503 /// CHECK-DAG: ArraySet 3504 /// CHECK-DAG: Deoptimize 3505 /// CHECK-DAG: ArrayGet 3506 /// CHECK-DAG: ArrayGet 3507 /// CHECK-DAG: ArrayGet 3508 /// CHECK-DAG: ArrayGet 3509 3510 /// CHECK-START: int Main.testLoop37(int) load_store_elimination (before) 3511 /// CHECK-NOT: BoundsCheck 3512 3513 /// CHECK-START: int Main.testLoop37(int) load_store_elimination (after) 3514 /// CHECK-DAG: ArraySet 3515 /// CHECK-DAG: Deoptimize 3516 /// CHECK-DAG: ArrayGet 3517 /// CHECK-DAG: ArrayGet 3518 /// CHECK-DAG: ArrayGet 3519 /// CHECK-DAG: ArrayGet 3520 3521 // Similar to testLoop36 but the writes are done via a different reference to the same array. 3522 // We previously used a reference comparison for back-edge aliasing analysis but this test 3523 // has different references and therefore needs `HeapLocationCollector::CanReferencesAlias()`. testLoop37(int n)3524 private static int testLoop37(int n) { 3525 int[] a = new int[n]; 3526 int[] b = $noinline$returnArg(a); 3527 int zero = 0; 3528 int i = 0; 3529 for (; i < n; ++i) { 3530 b[i] = i; 3531 // Extra instructions to avoid loop unrolling. 3532 zero = (((zero ^ 1) + 2) ^ 1) - 2; 3533 zero = (((zero ^ 4) + 8) ^ 4) - 8; 3534 } 3535 // Use 4 loads with consecutive fixed offsets from the loop Phi for `i`. 3536 // BCE shall replace BoundsChecks with Deoptimize, so that indexes here are 3537 // the Phi plus/minus a constant, something that LSA considers non-aliasing 3538 // with the Phi (LSA does not take different loop iterations into account) 3539 // but LSE must consider aliasing across dfferent loop iterations. 3540 return a[i - 1] + a[i - 2] + a[i - 3] + a[i - 4] + zero; 3541 } 3542 $noinline$returnArg(int[] a)3543 private static int[] $noinline$returnArg(int[] a) { 3544 return a; 3545 } 3546 3547 /// CHECK-START: int Main.testLoop38(int, int[]) load_store_elimination (before) 3548 /// CHECK-DAG: ArraySet 3549 /// CHECK-DAG: Deoptimize 3550 /// CHECK-DAG: ArrayGet 3551 /// CHECK-DAG: ArrayGet 3552 /// CHECK-DAG: ArrayGet 3553 /// CHECK-DAG: ArrayGet 3554 3555 /// CHECK-START: int Main.testLoop38(int, int[]) load_store_elimination (before) 3556 /// CHECK-NOT: BoundsCheck 3557 3558 /// CHECK-START: int Main.testLoop38(int, int[]) load_store_elimination (after) 3559 /// CHECK-DAG: ArraySet 3560 /// CHECK-DAG: Deoptimize 3561 3562 /// CHECK-START: int Main.testLoop38(int, int[]) load_store_elimination (after) 3563 /// CHECK-NOT: ArrayGet 3564 3565 // Similar to testLoop37 but writing to a different array that exists before allocating `a`, 3566 // so that `HeapLocationCollector::CanReferencesAlias()` returns false and all the ArrayGet 3567 // instructions are actually eliminated. testLoop38(int n, int[] b)3568 private static int testLoop38(int n, int[] b) { 3569 int[] a = new int[n]; 3570 int zero = 0; 3571 int i = 0; 3572 for (; i < n; ++i) { 3573 b[i] = i; 3574 // Extra instructions to avoid loop unrolling. 3575 zero = (((zero ^ 1) + 2) ^ 1) - 2; 3576 zero = (((zero ^ 4) + 8) ^ 4) - 8; 3577 } 3578 // Use 4 loads with consecutive fixed offsets from the loop Phi for `i`. 3579 // BCE shall replace BoundsChecks with Deoptimize, so that indexes here are 3580 // the Phi plus/minus a constant, something that LSA considers non-aliasing 3581 // with the Phi (LSA does not take different loop iterations into account) 3582 // but LSE must consider aliasing across dfferent loop iterations. 3583 return a[i - 1] + a[i - 2] + a[i - 3] + a[i - 4] + zero; 3584 } 3585 3586 /// CHECK-START: int Main.testNestedLoop1(TestClass, int) load_store_elimination (before) 3587 /// CHECK-DAG: InstanceFieldSet 3588 /// CHECK-DAG: InstanceFieldGet 3589 3590 /// CHECK-START: int Main.testNestedLoop1(TestClass, int) load_store_elimination (after) 3591 /// CHECK-DAG: InstanceFieldSet 3592 /// CHECK-DAG: InstanceFieldGet 3593 3594 // Test heap value clobbering in nested loop. testNestedLoop1(TestClass obj, int n)3595 private static int testNestedLoop1(TestClass obj, int n) { 3596 obj.i = 1; 3597 for (int i = 0; i < n; ++i) { 3598 for (int j = i + 1; j < n; ++j) { 3599 $noinline$clobberObservables(); 3600 } 3601 } 3602 return obj.i; 3603 } 3604 3605 /// CHECK-START: int Main.testNestedLoop2(TestClass, int) load_store_elimination (before) 3606 /// CHECK-DAG: InstanceFieldSet 3607 /// CHECK-DAG: InstanceFieldSet 3608 /// CHECK-DAG: Phi 3609 /// CHECK-DAG: InstanceFieldGet 3610 /// CHECK-DAG: Phi 3611 /// CHECK-DAG: InstanceFieldSet 3612 /// CHECK-DAG: InstanceFieldGet 3613 3614 /// CHECK-START: int Main.testNestedLoop2(TestClass, int) load_store_elimination (after) 3615 /// CHECK-DAG: InstanceFieldSet 3616 /// CHECK-DAG: InstanceFieldSet 3617 /// CHECK-DAG: Phi 3618 /// CHECK-DAG: Phi 3619 /// CHECK-DAG: InstanceFieldGet 3620 /// CHECK-DAG: Phi 3621 /// CHECK-DAG: InstanceFieldSet 3622 3623 /// CHECK-START: int Main.testNestedLoop2(TestClass, int) load_store_elimination (after) 3624 /// CHECK: InstanceFieldGet 3625 /// CHECK-NOT: InstanceFieldGet 3626 3627 /// CHECK-START: int Main.testNestedLoop2(TestClass, int) load_store_elimination (after) 3628 /// CHECK: Phi 3629 /// CHECK: Phi 3630 /// CHECK: Phi 3631 /// CHECK-NOT: Phi 3632 3633 // Test heap value clobbering in the nested loop and load elimination for a heap 3634 // location then set to known value before the end of the outer loop. testNestedLoop2(TestClass obj, int n)3635 private static int testNestedLoop2(TestClass obj, int n) { 3636 obj.i = 1; 3637 obj.j = 2; 3638 for (int i = 0; i < n; ++i) { 3639 int tmp = obj.j; 3640 for (int j = i + 1; j < n; ++j) { 3641 $noinline$clobberObservables(); 3642 } 3643 obj.i = tmp; 3644 } 3645 return obj.i; 3646 } 3647 3648 /// CHECK-START: int Main.testNestedLoop3(TestClass, int) load_store_elimination (before) 3649 /// CHECK-DAG: InstanceFieldSet 3650 /// CHECK-DAG: Phi 3651 /// CHECK-DAG: InstanceFieldSet 3652 /// CHECK-DAG: Phi 3653 /// CHECK-DAG: InstanceFieldGet 3654 /// CHECK-DAG: InstanceFieldSet 3655 /// CHECK-DAG: InstanceFieldGet 3656 3657 /// CHECK-START: int Main.testNestedLoop3(TestClass, int) load_store_elimination (after) 3658 /// CHECK-DAG: InstanceFieldSet 3659 /// CHECK-DAG: Phi 3660 /// CHECK-DAG: Phi 3661 /// CHECK-DAG: InstanceFieldSet 3662 /// CHECK-DAG: Phi 3663 /// CHECK-DAG: InstanceFieldGet 3664 /// CHECK-DAG: InstanceFieldSet 3665 3666 /// CHECK-START: int Main.testNestedLoop3(TestClass, int) load_store_elimination (after) 3667 /// CHECK: InstanceFieldGet 3668 /// CHECK-NOT: InstanceFieldGet 3669 3670 /// CHECK-START: int Main.testNestedLoop3(TestClass, int) load_store_elimination (after) 3671 /// CHECK: Phi 3672 /// CHECK: Phi 3673 /// CHECK: Phi 3674 /// CHECK-NOT: Phi 3675 3676 // Test heap value clobbering in the nested loop and load elimination for a heap 3677 // location then set to known value before the end of the outer loop. testNestedLoop3(TestClass obj, int n)3678 private static int testNestedLoop3(TestClass obj, int n) { 3679 obj.i = 1; 3680 for (int i = 0; i < n; ++i) { 3681 obj.j = 2; 3682 for (int j = i + 1; j < n; ++j) { 3683 $noinline$clobberObservables(); 3684 } 3685 obj.i = obj.j; 3686 } 3687 return obj.i; 3688 } 3689 3690 /// CHECK-START: int Main.testNestedLoop4(TestClass, int) load_store_elimination (before) 3691 /// CHECK-DAG: InstanceFieldSet 3692 /// CHECK-DAG: Phi 3693 /// CHECK-DAG: Phi 3694 /// CHECK-DAG: InstanceFieldSet 3695 /// CHECK-DAG: InstanceFieldGet 3696 3697 /// CHECK-START: int Main.testNestedLoop4(TestClass, int) load_store_elimination (after) 3698 /// CHECK-DAG: InstanceFieldSet 3699 /// CHECK-DAG: Phi 3700 /// CHECK-DAG: Phi 3701 /// CHECK-DAG: Phi 3702 /// CHECK-DAG: Phi 3703 /// CHECK-DAG: InstanceFieldSet 3704 3705 /// CHECK-START: int Main.testNestedLoop4(TestClass, int) load_store_elimination (after) 3706 /// CHECK-NOT: InstanceFieldGet 3707 3708 /// CHECK-START: int Main.testNestedLoop4(TestClass, int) load_store_elimination (after) 3709 /// CHECK: Phi 3710 /// CHECK: Phi 3711 /// CHECK: Phi 3712 /// CHECK: Phi 3713 /// CHECK-NOT: Phi 3714 3715 // Test creating loop Phis for both inner and outer loop to eliminate a load. testNestedLoop4(TestClass obj, int n)3716 private static int testNestedLoop4(TestClass obj, int n) { 3717 obj.i = 1; 3718 for (int i = 0; i < n; ++i) { 3719 for (int j = i + 1; j < n; ++j) { 3720 obj.i = 2; 3721 } 3722 } 3723 return obj.i; 3724 } 3725 3726 /// CHECK-START: int Main.testNestedLoop5(TestClass, int) load_store_elimination (before) 3727 /// CHECK-DAG: InstanceFieldSet 3728 /// CHECK-DAG: Phi 3729 /// CHECK-DAG: InstanceFieldSet 3730 /// CHECK-DAG: Phi 3731 /// CHECK-DAG: InstanceFieldSet 3732 /// CHECK-DAG: InstanceFieldGet 3733 3734 /// CHECK-START: int Main.testNestedLoop5(TestClass, int) load_store_elimination (after) 3735 /// CHECK-DAG: InstanceFieldSet 3736 /// CHECK-DAG: Phi 3737 /// CHECK-DAG: Phi 3738 /// CHECK-DAG: InstanceFieldSet 3739 /// CHECK-DAG: Phi 3740 /// CHECK-DAG: InstanceFieldSet 3741 3742 /// CHECK-START: int Main.testNestedLoop5(TestClass, int) load_store_elimination (after) 3743 /// CHECK-NOT: InstanceFieldGet 3744 3745 /// CHECK-START: int Main.testNestedLoop5(TestClass, int) load_store_elimination (after) 3746 /// CHECK: Phi 3747 /// CHECK: Phi 3748 /// CHECK: Phi 3749 /// CHECK-NOT: Phi 3750 3751 // Test creating a loop Phi for outer loop to eliminate a load. testNestedLoop5(TestClass obj, int n)3752 private static int testNestedLoop5(TestClass obj, int n) { 3753 obj.i = 1; 3754 for (int i = 0; i < n; ++i) { 3755 obj.i = 2; 3756 for (int j = i + 1; j < n; ++j) { 3757 obj.j = 3; // Unrelated. 3758 } 3759 } 3760 return obj.i; 3761 } 3762 3763 /// CHECK-START: int Main.testNestedLoop6(TestClass, int) load_store_elimination (before) 3764 /// CHECK-DAG: InstanceFieldSet 3765 /// CHECK-DAG: InstanceFieldSet 3766 /// CHECK-DAG: Phi 3767 /// CHECK-DAG: Phi 3768 /// CHECK-DAG: InstanceFieldGet 3769 /// CHECK-DAG: InstanceFieldSet 3770 /// CHECK-DAG: InstanceFieldGet 3771 3772 /// CHECK-START: int Main.testNestedLoop6(TestClass, int) load_store_elimination (after) 3773 /// CHECK-DAG: InstanceFieldSet 3774 /// CHECK-DAG: InstanceFieldSet 3775 /// CHECK-DAG: Phi 3776 /// CHECK-DAG: Phi 3777 /// CHECK-DAG: Phi 3778 /// CHECK-DAG: Phi 3779 /// CHECK-DAG: InstanceFieldGet 3780 /// CHECK-DAG: InstanceFieldSet 3781 3782 /// CHECK-START: int Main.testNestedLoop6(TestClass, int) load_store_elimination (after) 3783 /// CHECK: InstanceFieldGet 3784 /// CHECK-NOT: InstanceFieldGet 3785 3786 /// CHECK-START: int Main.testNestedLoop6(TestClass, int) load_store_elimination (after) 3787 /// CHECK: Phi 3788 /// CHECK: Phi 3789 /// CHECK: Phi 3790 /// CHECK: Phi 3791 /// CHECK-NOT: Phi 3792 3793 // Test heap value clobbering in the nested loop and load elimination for a heap 3794 // location then set to known value before the end of that inner loop. testNestedLoop6(TestClass obj, int n)3795 private static int testNestedLoop6(TestClass obj, int n) { 3796 obj.i = 1; 3797 obj.j = 2; 3798 for (int i = 0; i < n; ++i) { 3799 for (int j = i + 1; j < n; ++j) { 3800 int tmp = obj.j; 3801 $noinline$clobberObservables(); 3802 obj.i = tmp; 3803 } 3804 } 3805 return obj.i; 3806 } 3807 3808 /// CHECK-START: int Main.testNestedLoop7(TestClass, int) load_store_elimination (before) 3809 /// CHECK-DAG: NewArray 3810 /// CHECK-DAG: Phi 3811 /// CHECK-DAG: Phi 3812 /// CHECK-DAG: ArrayGet 3813 /// CHECK-DAG: InstanceFieldSet 3814 3815 /// CHECK-START: int Main.testNestedLoop7(TestClass, int) load_store_elimination (after) 3816 /// CHECK-DAG: NewArray 3817 /// CHECK-DAG: Phi 3818 /// CHECK-DAG: Phi 3819 /// CHECK-DAG: InstanceFieldSet 3820 3821 /// CHECK-START: int Main.testNestedLoop7(TestClass, int) load_store_elimination (after) 3822 /// CHECK-NOT: ArrayGet 3823 3824 // Test load elimination in inner loop reading default value that is loop invariant 3825 // with an index defined inside the inner loop. testNestedLoop7(TestClass obj, int n)3826 private static int testNestedLoop7(TestClass obj, int n) { 3827 // The NewArray is kept as it may throw for negative n. 3828 // TODO: Eliminate constructor fence even though the NewArray is kept. 3829 int[] a0 = new int[n]; 3830 for (int i = 0; i < n; ++i) { 3831 for (int j = i + 1; j < n; ++j) { 3832 obj.i = a0[j]; 3833 } 3834 } 3835 return n; 3836 } 3837 3838 /// CHECK-START: int Main.testNestedLoop8(TestClass, int) load_store_elimination (before) 3839 /// CHECK-DAG: NewInstance 3840 /// CHECK-DAG: InstanceFieldSet 3841 /// CHECK-DAG: Phi 3842 /// CHECK-DAG: Phi 3843 /// CHECK-DAG: NewInstance 3844 /// CHECK-DAG: InstanceFieldSet 3845 /// CHECK-DAG: InstanceFieldGet 3846 /// CHECK-DAG: InstanceFieldGet 3847 3848 /// CHECK-START: int Main.testNestedLoop8(TestClass, int) load_store_elimination (after) 3849 /// CHECK-DAG: NewInstance 3850 /// CHECK-DAG: InstanceFieldSet 3851 /// CHECK-DAG: Phi 3852 /// CHECK-DAG: Phi 3853 /// CHECK-DAG: Phi 3854 /// CHECK-DAG: Phi 3855 /// CHECK-DAG: NewInstance 3856 /// CHECK-DAG: InstanceFieldSet 3857 /// CHECK-DAG: InstanceFieldGet 3858 3859 /// CHECK-START: int Main.testNestedLoop8(TestClass, int) load_store_elimination (after) 3860 /// CHECK: InstanceFieldGet 3861 /// CHECK-NOT: InstanceFieldGet 3862 3863 // Test reference type propagation for Phis created for outer and inner loop. testNestedLoop8(TestClass obj, int n)3864 private static int testNestedLoop8(TestClass obj, int n) { 3865 obj.next = new SubTestClass(); 3866 for (int i = 0; i < n; ++i) { 3867 for (int j = i + 1; j < n; ++j) { 3868 obj.next = new TestClass(); 3869 } 3870 } 3871 // The Phis created in both loop headers for replacing `obj.next` depend on each other. 3872 return obj.next.i; 3873 } 3874 3875 3876 /// CHECK-START: long Main.testOverlapLoop(int) load_store_elimination (before) 3877 /// CHECK-DAG: NewArray 3878 /// CHECK-DAG: ArraySet 3879 /// CHECK-DAG: If 3880 /// CHECK-DAG: ArrayGet 3881 /// CHECK-DAG: ArrayGet 3882 /// CHECK-DAG: ArraySet 3883 /// CHECK-DAG: ArrayGet 3884 /// CHECK-DAG: Goto 3885 3886 /// CHECK-START: long Main.testOverlapLoop(int) load_store_elimination (after) 3887 /// CHECK-DAG: NewArray 3888 /// CHECK-DAG: ArraySet 3889 /// CHECK-DAG: If 3890 /// CHECK-DAG: ArrayGet 3891 /// CHECK-DAG: ArrayGet 3892 /// CHECK-DAG: ArraySet 3893 /// CHECK-DAG: Goto 3894 /// CHECK-NOT: ArrayGet 3895 3896 // Test that we don't incorrectly remove writes needed by later loop iterations 3897 // NB This is fibonacci numbers testOverlapLoop(int cnt)3898 private static long testOverlapLoop(int cnt) { 3899 long[] w = new long[cnt]; 3900 w[1] = 1; 3901 long t = 1; 3902 for (int i = 2; i < cnt; ++i) { 3903 w[i] = w[i - 1] + w[i - 2]; 3904 t = w[i]; 3905 } 3906 return t; 3907 } 3908 $noinline$getBoolean(boolean val)3909 private static boolean $noinline$getBoolean(boolean val) { 3910 return val; 3911 } 3912 3913 /// CHECK-START: int Main.$noinline$testPartialEscape1(TestClass, boolean) load_store_elimination (before) 3914 /// CHECK-DAG: ParameterValue 3915 /// CHECK-DAG: NewInstance 3916 /// CHECK-DAG: InvokeStaticOrDirect 3917 /// CHECK-DAG: InstanceFieldSet 3918 /// CHECK-DAG: InvokeStaticOrDirect 3919 /// CHECK-DAG: InstanceFieldGet 3920 /// CHECK-DAG: InstanceFieldGet 3921 /// CHECK-DAG: InstanceFieldSet 3922 /// CHECK-DAG: InstanceFieldGet 3923 /// CHECK-DAG: InstanceFieldGet 3924 /// CHECK-DAG: Phi 3925 // 3926 /// CHECK-NOT: NewInstance 3927 /// CHECK-NOT: InvokeStaticOrDirect 3928 /// CHECK-NOT: InstanceFieldSet 3929 /// CHECK-NOT: InstanceFieldGet 3930 // 3931 /// CHECK-START: int Main.$noinline$testPartialEscape1(TestClass, boolean) load_store_elimination (after) 3932 /// CHECK-DAG: ParameterValue 3933 /// CHECK-DAG: NewInstance 3934 /// CHECK-DAG: Phi 3935 // 3936 /// CHECK-START: int Main.$noinline$testPartialEscape1(TestClass, boolean) load_store_elimination (after) 3937 /// CHECK: InvokeStaticOrDirect 3938 /// CHECK: InvokeStaticOrDirect 3939 // 3940 /// CHECK-NOT: InvokeStaticOrDirect 3941 3942 /// CHECK-START: int Main.$noinline$testPartialEscape1(TestClass, boolean) load_store_elimination (after) 3943 /// CHECK: InstanceFieldSet 3944 // 3945 /// CHECK-NOT: InstanceFieldSet 3946 // 3947 /// CHECK-START: int Main.$noinline$testPartialEscape1(TestClass, boolean) load_store_elimination (after) 3948 /// CHECK: InstanceFieldGet 3949 /// CHECK: InstanceFieldGet 3950 /// CHECK: InstanceFieldGet 3951 // 3952 /// CHECK-NOT: InstanceFieldGet $noinline$testPartialEscape1(TestClass obj, boolean escape)3953 private static int $noinline$testPartialEscape1(TestClass obj, boolean escape) { 3954 TestClass i = new SubTestClass(); 3955 int res; 3956 if ($noinline$getBoolean(escape)) { 3957 i.next = obj; 3958 $noinline$Escape(i); 3959 res = i.next.i; 3960 } else { 3961 i.next = obj; 3962 res = i.next.i; 3963 } 3964 return res; 3965 } 3966 $noinline$clobberObservables()3967 private static void $noinline$clobberObservables() {} 3968 assertLongEquals(long result, long expected)3969 static void assertLongEquals(long result, long expected) { 3970 if (expected != result) { 3971 throw new Error("Expected: " + expected + ", found: " + result); 3972 } 3973 } 3974 assertIntEquals(int result, int expected)3975 static void assertIntEquals(int result, int expected) { 3976 if (expected != result) { 3977 throw new Error("Expected: " + expected + ", found: " + result); 3978 } 3979 } 3980 assertFloatEquals(float result, float expected)3981 static void assertFloatEquals(float result, float expected) { 3982 if (expected != result) { 3983 throw new Error("Expected: " + expected + ", found: " + result); 3984 } 3985 } 3986 assertDoubleEquals(double result, double expected)3987 static void assertDoubleEquals(double result, double expected) { 3988 if (expected != result) { 3989 throw new Error("Expected: " + expected + ", found: " + result); 3990 } 3991 } 3992 main(String[] args)3993 public static void main(String[] args) { 3994 assertDoubleEquals(Math.PI * Math.PI * Math.PI, calcCircleArea(Math.PI)); 3995 assertIntEquals(test1(new TestClass(), new TestClass()), 3); 3996 assertIntEquals(test2(new TestClass()), 1); 3997 TestClass obj1 = new TestClass(); 3998 TestClass obj2 = new TestClass(); 3999 obj1.next = obj2; 4000 assertIntEquals(test3(obj1), 10); 4001 assertIntEquals(test4(new TestClass(), true), 1); 4002 assertIntEquals(test4(new TestClass(), false), 1); 4003 assertIntEquals(test5(new TestClass(), true), 1); 4004 assertIntEquals(test5(new TestClass(), false), 2); 4005 assertIntEquals(test6(new TestClass(), new TestClass(), true), 4); 4006 assertIntEquals(test6(new TestClass(), new TestClass(), false), 2); 4007 assertIntEquals(test7(new TestClass()), 1); 4008 assertIntEquals(test8(), 1); 4009 obj1 = new TestClass(); 4010 obj2 = new TestClass(); 4011 obj1.next = obj2; 4012 assertIntEquals(test9(new TestClass()), 1); 4013 assertIntEquals(test10(new TestClass(3, 4)), 3); 4014 assertIntEquals(TestClass.si, 3); 4015 assertIntEquals(test11(new TestClass()), 10); 4016 assertIntEquals(test12(new TestClass(), new TestClass()), 10); 4017 assertIntEquals(test13(new TestClass(), new TestClass2()), 3); 4018 SubTestClass obj3 = new SubTestClass(); 4019 assertIntEquals(test14(obj3, obj3), 2); 4020 assertIntEquals(test15(), 2); 4021 assertIntEquals(test16(), 3); 4022 assertIntEquals(test17(), 0); 4023 assertIntEquals(test18(new TestClass()), 1); 4024 float[] fa1 = { 0.8f }; 4025 float[] fa2 = { 1.8f }; 4026 assertFloatEquals(test19(fa1, fa2), 1.8f); 4027 assertFloatEquals(test20().i, 0); 4028 test21(new TestClass()); 4029 assertIntEquals(test22(), 13); 4030 assertIntEquals(test23(true), 4); 4031 assertIntEquals(test23(false), 5); 4032 assertFloatEquals(test24(), 8.0f); 4033 assertIntEquals(test25(false, true, true), 5); 4034 assertIntEquals(test25(true, false, true), 2); 4035 assertFloatEquals(test26(5), 0.0f); 4036 assertFloatEquals(test26(3), 1.0f); 4037 assertIntEquals(test27(false, true), 1); 4038 assertIntEquals(test27(true, false), 1); 4039 assertIntEquals(test28(false, true), 0); 4040 assertIntEquals(test28(true, true), 5); 4041 assertFloatEquals(test29(true), 5.0f); 4042 assertFloatEquals(test29(false), 2.0f); 4043 assertIntEquals(test30(new TestClass(), true), 1); 4044 assertIntEquals(test30(new TestClass(), false), 0); 4045 assertIntEquals(test31(true, true), 5); 4046 assertIntEquals(test31(true, false), 6); 4047 assertIntEquals(test32(1), 10); 4048 assertIntEquals(test32(2), 10); 4049 assertIntEquals(test33(new TestClass(), true), 1); 4050 assertIntEquals(test33(new TestClass(), false), 2); 4051 assertIntEquals(test34(new TestClass(), true, true), 3); 4052 assertIntEquals(test34(new TestClass(), false, true), 4); 4053 assertIntEquals(test34(new TestClass(), true, false), 1); 4054 assertIntEquals(test34(new TestClass(), false, false), 2); 4055 assertIntEquals(test35(new TestClass(), true, true), 3); 4056 assertIntEquals(test35(new TestClass(), false, true), 2); 4057 assertIntEquals(test35(new TestClass(), true, false), 1); 4058 assertIntEquals(test35(new TestClass(), false, false), 2); 4059 assertIntEquals(test36(new TestClass(), true), 2); 4060 assertIntEquals(test36(new TestClass(), false), 4); 4061 assertIntEquals(test37(new TestClass(), true), 1); 4062 assertIntEquals(test37(new TestClass(), false), 0); 4063 assertIntEquals(test38(new TestClass(), true), 1); 4064 assertIntEquals(test38(new TestClass(), false), 2); 4065 assertIntEquals(test39(new TestClass(), true), 0); 4066 assertIntEquals(test39(new TestClass(), false), 1); 4067 4068 testFinalizableByForcingGc(); 4069 assertIntEquals($noinline$testHSelect(true), 0xdead); 4070 int[] array = {2, 5, 9, -1, -3, 10, 8, 4}; 4071 assertIntEquals(sumWithinRange(array, 1, 5), 11); 4072 assertFloatEquals(testAllocationEliminationWithLoops(), 1.0f); 4073 assertFloatEquals(mF, 0f); 4074 assertDoubleEquals(Math.PI * Math.PI * Math.PI, getCircleArea(Math.PI, true)); 4075 assertDoubleEquals(0d, getCircleArea(Math.PI, false)); 4076 4077 assertIntEquals($noinline$testConversion1(new TestClass(), 300), 300); 4078 assertIntEquals($noinline$testConversion1(new TestClass(), 301), 45); 4079 assertIntEquals($noinline$testConversion2(new TestClass(), 300), 300); 4080 assertIntEquals($noinline$testConversion2(new TestClass(), 301), 90); 4081 assertIntEquals($noinline$testConversion3(new TestClass(), 0), 0); 4082 assertIntEquals($noinline$testConversion3(new TestClass(), 1), 0); 4083 assertIntEquals($noinline$testConversion3(new TestClass(), 128), 127); 4084 assertIntEquals($noinline$testConversion3(new TestClass(), 129), -128); 4085 assertIntEquals($noinline$testConversion4(new TestClass(), 0), 0); 4086 assertIntEquals($noinline$testConversion4(new TestClass(), 1), 0); 4087 assertIntEquals($noinline$testConversion4(new TestClass(), 128), 254); 4088 assertIntEquals($noinline$testConversion4(new TestClass(), 129), -256); 4089 4090 int[] iarray = {0, 0, 0}; 4091 double[] darray = {0d, 0d, 0d}; 4092 try { 4093 assertDoubleEquals(Math.PI * Math.PI * Math.PI, testDeoptimize(iarray, darray, Math.PI)); 4094 } catch (Exception e) { 4095 System.out.println(e.getClass().getName()); 4096 } 4097 assertIntEquals(iarray[0], 1); 4098 assertIntEquals(iarray[1], 1); 4099 assertIntEquals(iarray[2], 1); 4100 assertDoubleEquals(darray[0], Math.PI); 4101 assertDoubleEquals(darray[1], Math.PI); 4102 assertDoubleEquals(darray[2], Math.PI); 4103 4104 assertIntEquals(testAllocationEliminationOfArray1(), 11); 4105 assertIntEquals(testAllocationEliminationOfArray2(), 11); 4106 assertIntEquals(testAllocationEliminationOfArray3(2), 4); 4107 assertIntEquals(testAllocationEliminationOfArray4(2), 6); 4108 assertIntEquals(testAllocationEliminationOfArray5(2), 12); 4109 try { 4110 testAllocationEliminationOfArray5(-2); 4111 } catch (NegativeArraySizeException e) { 4112 System.out.println("Got NegativeArraySizeException."); 4113 } 4114 4115 assertIntEquals(testStoreStore().i, 41); 4116 assertIntEquals(testStoreStore().j, 43); 4117 4118 assertIntEquals(testExitMerge(true), 2); 4119 assertIntEquals(testExitMerge2(true), 2); 4120 assertIntEquals(testExitMerge2(false), 2); 4121 4122 TestClass2 testclass2 = new TestClass2(); 4123 testStoreStore2(testclass2); 4124 assertIntEquals(testclass2.i, 43); 4125 assertIntEquals(testclass2.j, 44); 4126 4127 testStoreStore3(testclass2, true); 4128 assertIntEquals(testclass2.i, 41); 4129 assertIntEquals(testclass2.j, 43); 4130 testStoreStore3(testclass2, false); 4131 assertIntEquals(testclass2.i, 41); 4132 assertIntEquals(testclass2.j, 44); 4133 4134 testStoreStore4(); 4135 assertIntEquals(TestClass.si, 62); 4136 4137 int ret = testStoreStore5(testclass2, testclass2); 4138 assertIntEquals(testclass2.i, 72); 4139 assertIntEquals(ret, 71); 4140 4141 testclass2.j = 88; 4142 ret = testStoreStore6(testclass2, testclass2); 4143 assertIntEquals(testclass2.i, 82); 4144 assertIntEquals(ret, 88); 4145 4146 ret = testNoSideEffects(iarray); 4147 assertIntEquals(iarray[0], 101); 4148 assertIntEquals(iarray[1], 103); 4149 assertIntEquals(ret, 108); 4150 4151 try { 4152 testThrow(testclass2, new Exception()); 4153 } catch (Exception e) {} 4154 assertIntEquals(testclass2.i, 55); 4155 4156 assertIntEquals(testStoreStoreWithDeoptimize(new int[4]), 4); 4157 4158 assertIntEquals($noinline$testByteArrayDefaultValue(), 0); 4159 4160 assertIntEquals(testLocalArrayMerge1(true), 1); 4161 assertIntEquals(testLocalArrayMerge1(false), 1); 4162 assertIntEquals(testLocalArrayMerge2(true), 2); 4163 assertIntEquals(testLocalArrayMerge2(false), 3); 4164 assertIntEquals(testLocalArrayMerge3(true), 2); 4165 assertIntEquals(testLocalArrayMerge3(false), 1); 4166 assertIntEquals(testLocalArrayMerge4(true), 2); 4167 assertIntEquals(testLocalArrayMerge4(false), 2); 4168 assertIntEquals(testLocalArrayMerge5(new int[]{ 7 }, true), 7); 4169 assertIntEquals(testLocalArrayMerge5(new int[]{ 9 }, false), 9); 4170 assertIntEquals(testLocalArrayMerge6(new int[1], true, true), 1); 4171 assertIntEquals(testLocalArrayMerge6(new int[1], true, false), 2); 4172 assertIntEquals(testLocalArrayMerge6(new int[1], false, true), 2); 4173 assertIntEquals(testLocalArrayMerge6(new int[1], false, false), 1); 4174 assertIntEquals(testLocalArrayMerge7(new int[2], true, true), 1); 4175 assertIntEquals(testLocalArrayMerge7(new int[2], true, false), 2); 4176 assertIntEquals(testLocalArrayMerge7(new int[2], false, true), 0); 4177 assertIntEquals(testLocalArrayMerge7(new int[2], false, false), 0); 4178 assertIntEquals(testLocalArrayMerge8(true), 0); 4179 assertIntEquals(testLocalArrayMerge8(false), 0); 4180 4181 TestClass[] tca = new TestClass[] { new TestClass(), null }; 4182 try { 4183 $noinline$testThrowingArraySet(tca, new TestClass2()); 4184 } catch (ArrayStoreException expected) { 4185 if (tca[0] != null) { 4186 throw new Error("tca[0] is not null"); 4187 } 4188 if (tca[1] == null) { 4189 throw new Error("tca[1] is null"); 4190 } 4191 } 4192 4193 assertIntEquals(testLoop1(new TestClass(), 0), 0); 4194 assertIntEquals(testLoop1(new TestClass(), 1), 0); 4195 assertIntEquals(testLoop1(new TestClass(), 2), 1); 4196 assertIntEquals(testLoop1(new TestClass(), 3), 2); 4197 assertIntEquals(testLoop2(new TestClass(), 0), 1); 4198 assertIntEquals(testLoop2(new TestClass(), 1), 1); 4199 assertIntEquals(testLoop2(new TestClass(), 2), 1); 4200 assertIntEquals(testLoop2(new TestClass(), 3), 1); 4201 assertIntEquals(testLoop3(new TestClass(), 0), 1); 4202 assertIntEquals(testLoop3(new TestClass(), 1), 1); 4203 assertIntEquals(testLoop3(new TestClass(), 2), 1); 4204 assertIntEquals(testLoop3(new TestClass(), 3), 1); 4205 assertIntEquals(testLoop4(new TestClass(), 0), 0); 4206 assertIntEquals(testLoop4(new TestClass(), 1), 1); 4207 assertIntEquals(testLoop4(new TestClass(), 2), 2); 4208 assertIntEquals(testLoop4(new TestClass(), 3), 3); 4209 assertIntEquals(testLoop5(new TestClass(), 0), 0); 4210 assertIntEquals(testLoop5(new TestClass(), 1), 1); 4211 assertIntEquals(testLoop5(new TestClass(), 2), 2); 4212 assertIntEquals(testLoop5(new TestClass(), 3), 3); 4213 assertIntEquals(testLoop6(new TestClass(), 0), 0); 4214 assertIntEquals(testLoop6(new TestClass(), 1), 1); 4215 assertIntEquals(testLoop6(new TestClass(), 2), 2); 4216 assertIntEquals(testLoop6(new TestClass(), 3), 3); 4217 assertIntEquals(testLoop7(0), 0); 4218 assertIntEquals(testLoop7(1), 0); 4219 assertIntEquals(testLoop7(2), 0); 4220 assertIntEquals(testLoop7(3), 0); 4221 assertIntEquals(testLoop8(0), 1); 4222 assertIntEquals(testLoop8(1), 0); 4223 assertIntEquals(testLoop8(2), 1); 4224 assertIntEquals(testLoop8(3), 0); 4225 assertIntEquals(testLoop9(new TestClass(), 0), 0); 4226 assertIntEquals(testLoop9(new TestClass(), 1), 1); 4227 assertIntEquals(testLoop9(new TestClass(), 2), 2); 4228 assertIntEquals(testLoop9(new TestClass(), 3), 3); 4229 assertIntEquals(testLoop10(new TestClass(), 0), 2); 4230 assertIntEquals(testLoop10(new TestClass(), 1), 2); 4231 assertIntEquals(testLoop10(new TestClass(), 2), 2); 4232 assertIntEquals(testLoop10(new TestClass(), 3), 2); 4233 assertIntEquals(testLoop11(new TestClass(), 0), 1); 4234 assertIntEquals(testLoop11(new TestClass(), 1), 3); 4235 assertIntEquals(testLoop11(new TestClass(), 2), 2); 4236 assertIntEquals(testLoop11(new TestClass(), 3), 3); 4237 assertIntEquals(testLoop12(new TestClass(), 0), 1); 4238 assertIntEquals(testLoop12(new TestClass(), 1), 2); 4239 assertIntEquals(testLoop12(new TestClass(), 2), 3); 4240 assertIntEquals(testLoop12(new TestClass(), 3), 2); 4241 assertIntEquals(testLoop13(new TestClass(1, 2), 0), 0); 4242 assertIntEquals(testLoop13(new TestClass(1, 2), 1), 0); 4243 assertIntEquals(testLoop13(new TestClass(1, 2), 2), 0); 4244 assertIntEquals(testLoop13(new TestClass(1, 2), 3), 1); 4245 assertIntEquals(testLoop14(new TestClass2(), 0), 0); 4246 assertIntEquals(testLoop14(new TestClass2(), 1), 0); 4247 assertIntEquals(testLoop14(new TestClass2(), 2), 0); 4248 assertIntEquals(testLoop14(new TestClass2(), 3), 1); 4249 assertIntEquals(testLoop15(0), 0); 4250 assertIntEquals(testLoop15(1), 1); 4251 assertIntEquals(testLoop15(2), 1); 4252 assertIntEquals(testLoop15(3), 1); 4253 assertIntEquals(testLoop16(new TestClass(), 0), 0); 4254 assertIntEquals(testLoop16(new TestClass(), 1), 1); 4255 assertIntEquals(testLoop16(new TestClass(), 2), 2); 4256 assertIntEquals(testLoop16(new TestClass(), 3), 3); 4257 assertIntEquals(testLoop17(new TestClass(), 0), 2); 4258 assertIntEquals(testLoop17(new TestClass(), 1), 4); 4259 assertIntEquals(testLoop17(new TestClass(), 2), 2); 4260 assertIntEquals(testLoop17(new TestClass(), 3), 4); 4261 assertIntEquals(testLoop18(new TestClass(), 0), 0); 4262 assertIntEquals(testLoop18(new TestClass(), 1), 1); 4263 assertIntEquals(testLoop18(new TestClass(), 2), 2); 4264 assertIntEquals(testLoop18(new TestClass(), 3), 3); 4265 assertIntEquals(testLoop19(new TestClass(), 0), 0); 4266 assertIntEquals(testLoop19(new TestClass(), 1), 1); 4267 assertIntEquals(testLoop19(new TestClass(), 2), 2); 4268 assertIntEquals(testLoop19(new TestClass(), 3), 3); 4269 assertIntEquals(testLoop20(new TestClass(), 0), 0); 4270 assertIntEquals(testLoop20(new TestClass(), 1), 1); 4271 assertIntEquals(testLoop20(new TestClass(), 2), 2); 4272 assertIntEquals(testLoop20(new TestClass(), 3), 3); 4273 assertIntEquals(testLoop21(new TestClass(), 0), 0); 4274 assertIntEquals(testLoop21(new TestClass(), 1), 1); 4275 assertIntEquals(testLoop21(new TestClass(), 2), 2); 4276 assertIntEquals(testLoop21(new TestClass(), 3), 3); 4277 assertIntEquals(testLoop22(new TestClass(), 0), 0); 4278 assertIntEquals(testLoop22(new TestClass(), 1), 1); 4279 assertIntEquals(testLoop22(new TestClass(), 2), 2); 4280 assertIntEquals(testLoop22(new TestClass(), 3), 3); 4281 assertIntEquals(testLoop23(new TestClass(), 0), -1); 4282 assertIntEquals(testLoop23(new TestClass(), 1), 2); 4283 assertIntEquals(testLoop23(new TestClass(), 2), 1); 4284 assertIntEquals(testLoop23(new TestClass(), 3), 2); 4285 assertIntEquals(testLoop24(new TestClass(), 0), -1); 4286 assertIntEquals(testLoop24(new TestClass(), 1), 2); 4287 assertIntEquals(testLoop24(new TestClass(), 2), 1); 4288 assertIntEquals(testLoop24(new TestClass(), 3), -2); 4289 assertIntEquals(testLoop25(new TestClass(), 0), 2); 4290 assertIntEquals(testLoop25(new TestClass(), 1), 2); 4291 assertIntEquals(testLoop25(new TestClass(), 2), 4); 4292 assertIntEquals(testLoop25(new TestClass(), 3), -1); 4293 assertIntEquals(testLoop26(new TestClass(), 0), 1); 4294 assertIntEquals(testLoop26(new TestClass(), 1), 0); 4295 assertIntEquals(testLoop26(new TestClass(), 2), 0); 4296 assertIntEquals(testLoop26(new TestClass(), 3), 0); 4297 assertIntEquals(testLoop27(new TestClass(), 0), 1); 4298 assertIntEquals(testLoop27(new TestClass(), 1), 1); 4299 assertIntEquals(testLoop27(new TestClass(), 2), 0); 4300 assertIntEquals(testLoop27(new TestClass(), 3), 0); 4301 assertIntEquals(testLoop28(new TestClass(1, 2), 0), 0); 4302 assertIntEquals(testLoop28(new TestClass(1, 2), 1), 0); 4303 assertIntEquals(testLoop28(new TestClass(1, 2), 2), 0); 4304 assertIntEquals(testLoop28(new TestClass(1, 2), 3), 1); 4305 assertIntEquals(testLoop29(0), 0); 4306 assertIntEquals(testLoop29(1), 1); 4307 assertIntEquals(testLoop29(2), 3); 4308 assertIntEquals(testLoop29(3), 6); 4309 assertIntEquals(testLoop30(0), 0); 4310 assertIntEquals(testLoop30(1), 1); 4311 assertIntEquals(testLoop30(2), 2); 4312 assertIntEquals(testLoop30(3), 3); 4313 assertIntEquals(testLoop31(0), 0); 4314 assertIntEquals(testLoop31(1), 0); 4315 assertIntEquals(testLoop31(2), 0); 4316 assertIntEquals(testLoop31(3), 0); 4317 assertIntEquals(testLoop32(new TestClass(), 0), -1); 4318 assertIntEquals(testLoop32(new TestClass(), 1), 2); 4319 assertIntEquals(testLoop32(new TestClass(), 2), 1); 4320 assertIntEquals(testLoop32(new TestClass(), 3), -2); 4321 assertIntEquals(testLoop33(new TestClass(), 0), 0); 4322 assertIntEquals(testLoop33(new TestClass(), 1), 0); 4323 assertIntEquals(testLoop33(new TestClass(), 2), 0); 4324 assertIntEquals(testLoop33(new TestClass(), 3), 0); 4325 assertIntEquals(testLoop34(0), 0); 4326 assertIntEquals(testLoop34(1), 1); 4327 assertIntEquals(testLoop34(2), 3); 4328 assertIntEquals(testLoop34(3), 6); 4329 assertIntEquals(testLoop35(0), 0); 4330 assertIntEquals(testLoop35(1), 1); 4331 assertIntEquals(testLoop35(2), 3); 4332 assertIntEquals(testLoop35(3), 6); 4333 assertIntEquals(testLoop36(4), 6); 4334 assertIntEquals(testLoop37(4), 6); 4335 assertIntEquals(testLoop38(4, new int[4]), 0); 4336 4337 assertIntEquals(testNestedLoop1(new TestClass(), 0), 1); 4338 assertIntEquals(testNestedLoop1(new TestClass(), 1), 1); 4339 assertIntEquals(testNestedLoop1(new TestClass(), 2), 1); 4340 assertIntEquals(testNestedLoop1(new TestClass(), 3), 1); 4341 assertIntEquals(testNestedLoop2(new TestClass(), 0), 1); 4342 assertIntEquals(testNestedLoop2(new TestClass(), 1), 2); 4343 assertIntEquals(testNestedLoop2(new TestClass(), 2), 2); 4344 assertIntEquals(testNestedLoop2(new TestClass(), 3), 2); 4345 assertIntEquals(testNestedLoop3(new TestClass(), 0), 1); 4346 assertIntEquals(testNestedLoop3(new TestClass(), 1), 2); 4347 assertIntEquals(testNestedLoop3(new TestClass(), 2), 2); 4348 assertIntEquals(testNestedLoop3(new TestClass(), 3), 2); 4349 assertIntEquals(testNestedLoop4(new TestClass(), 0), 1); 4350 assertIntEquals(testNestedLoop4(new TestClass(), 1), 1); 4351 assertIntEquals(testNestedLoop4(new TestClass(), 2), 2); 4352 assertIntEquals(testNestedLoop4(new TestClass(), 3), 2); 4353 assertIntEquals(testNestedLoop5(new TestClass(), 0), 1); 4354 assertIntEquals(testNestedLoop5(new TestClass(), 1), 2); 4355 assertIntEquals(testNestedLoop5(new TestClass(), 2), 2); 4356 assertIntEquals(testNestedLoop5(new TestClass(), 3), 2); 4357 assertIntEquals(testNestedLoop6(new TestClass(), 0), 1); 4358 assertIntEquals(testNestedLoop6(new TestClass(), 1), 1); 4359 assertIntEquals(testNestedLoop6(new TestClass(), 2), 2); 4360 assertIntEquals(testNestedLoop6(new TestClass(), 3), 2); 4361 assertIntEquals(testNestedLoop7(new TestClass(), 0), 0); 4362 assertIntEquals(testNestedLoop7(new TestClass(), 1), 1); 4363 assertIntEquals(testNestedLoop7(new TestClass(), 2), 2); 4364 assertIntEquals(testNestedLoop7(new TestClass(), 3), 3); 4365 assertIntEquals(testNestedLoop8(new TestClass(), 0), 0); 4366 assertIntEquals(testNestedLoop8(new TestClass(), 1), 0); 4367 assertIntEquals(testNestedLoop8(new TestClass(), 2), 0); 4368 assertIntEquals(testNestedLoop8(new TestClass(), 3), 0); 4369 assertLongEquals(testOverlapLoop(10), 34l); 4370 assertLongEquals(testOverlapLoop(50), 7778742049l); 4371 assertIntEquals($noinline$testPartialEscape1(new TestClass(), true), 1); 4372 assertIntEquals($noinline$testPartialEscape1(new TestClass(), false), 0); 4373 } 4374 } 4375