Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Android/art/art/test/530-checker-lse/src/   (Android Betriebssystem Version 17©)  Datei vom 26.5.2026 mit Größe 168 kB image not shown  

Quelle  Main.java

  Sprache: JAVA
 

/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


class Circle {
  Circle(double radius) {
    this.radius = radius;
  }
  public double getRadius() {
    return radius;
  }
  public double getArea() {
    return radius * radius * Math.PI;
  }
  private double radius;
}

class TestClass {
  static {
    sTestClassObj = new TestClass(-1, -2);
  }
  TestClass() {
  }
  TestClass(int i, int j) {
    this.i = i;
    this.j = j;
  }
  int i;
  int j;
  volatile int k;
  TestClass next;
  String str;
  byte b;
  static int si;
  static TestClass sTestClassObj;
}

class SubTestClass extends TestClass {
  int k;
}

class TestClass2 {
  int i;
  int j;
  int k;
  int l;
  int m;
}

class TestClass3 {
  float floatField = 8.0f;
  boolean test1 = true;
}

// Chosen to have different values with (x + 1) * 10 and (x - 1) * 10. This
// means we can easily make sure that different code is in fact executed on
// escape and non-escape paths.
// Negative so that high-bits will be set for all the 64-bit values allowing us
// to easily check for truncation.
class TestClass4 {
  float floatField = -3.0f;
  double doubleField = -3.0d;
  short shortField = -3;
  int intField = -3;
  byte byteField = -3;
  long longField = -3l;
}

class Finalizable {
  static boolean sVisited = false;
  static final int VALUE1 = 0xbeef;
  static final int VALUE2 = 0xcafe;
  int i;

  protected void finalize() {
    if (i != VALUE1) {
      System.out.println("Where is the beef?");
    }
    sVisited = true;
  }
}

interface Filter {
  public boolean isValid(int i);
}

public class Main {
  static void $noinline$Escape4(TestClass4 o) {
    o.floatField += 1.0f;
    o.doubleField += 1.0d;
    o.byteField += 1;
    o.shortField += 1;
    o.intField += 1;
    o.longField += 1;
  }

  static Object ESCAPE = null;
  static void $noinline$Escape(TestClass o) {
    if (o == null) {
      return;
    }
    ESCAPE = o;
    o.next.i++;
  }

  /// CHECK-START: double Main.calcCircleArea(double) load_store_elimination (before)
  /// CHECK: NewInstance
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldGet

  /// CHECK-START: double Main.calcCircleArea(double) load_store_elimination (after)
  /// CHECK-NOT: NewInstance
  /// CHECK-NOT: InstanceFieldSet
  /// CHECK-NOT: InstanceFieldGet

  static double calcCircleArea(double radius) {
    return new Circle(radius).getArea();
  }

  /// CHECK-START: int Main.test1(TestClass, TestClass) load_store_elimination (before)
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldGet
  /// CHECK: InstanceFieldGet

  /// CHECK-START: int Main.test1(TestClass, TestClass) load_store_elimination (after)
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldSet
  /// CHECK-NOT: NullCheck
  /// CHECK-NOT: InstanceFieldGet

  // Different fields shouldn't alias.
  static int test1(TestClass obj1, TestClass obj2) {
    obj1.i = 1;
    obj2.j = 2;
    return obj1.i + obj2.j;
  }

  /// CHECK-START: int Main.test2(TestClass) load_store_elimination (before)
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldGet

  /// CHECK-START: int Main.test2(TestClass) load_store_elimination (after)
  /// CHECK: InstanceFieldSet
  /// CHECK-NOT: NullCheck
  /// CHECK-NOT: InstanceFieldSet
  /// CHECK-NOT: InstanceFieldGet

  // Redundant store of the same value.
  static int test2(TestClass obj) {
    obj.j = 1;
    obj.j = 1;
    return obj.j;
  }

  /// CHECK-START: int Main.test3(TestClass) load_store_elimination (before)
  /// CHECK: StaticFieldGet
  /// CHECK: NewInstance
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldGet
  /// CHECK: InstanceFieldGet
  /// CHECK: InstanceFieldGet
  /// CHECK: InstanceFieldGet

  /// CHECK-START: int Main.test3(TestClass) load_store_elimination (after)
  /// CHECK: StaticFieldGet
  /// CHECK: NewInstance
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldSet

  /// CHECK-START: int Main.test3(TestClass) load_store_elimination (after)
  /// CHECK-NOT: InstanceFieldGet

  // A new allocation (even non-singleton) shouldn't alias with pre-existing values.
  static int test3(TestClass obj) {
    TestClass obj1 = TestClass.sTestClassObj;
    TestClass obj2 = new TestClass();  // Cannot alias with obj or obj1 which pre-exist.
    obj.next = obj2;  // Make obj2 a non-singleton.
    // All stores below need to stay since obj/obj1/obj2 are not singletons.
    obj.i = 1;
    obj1.j = 2;
    // Following stores won't kill values of obj.i and obj1.j.
    obj2.i = 3;
    obj2.j = 4;
    return obj.i + obj1.j + obj2.i + obj2.j;
  }

  /// CHECK-START: int Main.test4(TestClass, boolean) load_store_elimination (before)
  /// CHECK-DAG: InstanceFieldSet
  /// CHECK-DAG: InstanceFieldSet
  /// CHECK-DAG: InstanceFieldGet
  /// CHECK-DAG: Return

  /// CHECK-START: int Main.test4(TestClass, boolean) load_store_elimination (after)
  /// CHECK-DAG: InstanceFieldSet
  /// CHECK-DAG: InstanceFieldSet
  /// CHECK-DAG: Return

  /// CHECK-START: int Main.test4(TestClass, boolean) load_store_elimination (after)
  /// CHECK-NOT: InstanceFieldGet

  /// CHECK-START: int Main.test4(TestClass, boolean) load_store_elimination (after)
  /// CHECK-NOT: Phi

  // Set and merge the same value in two branches.
  static int test4(TestClass obj, boolean b) {
    if (b) {
      obj.i = 1;
    } else {
      obj.i = 1;
    }
    return obj.i;
  }

  /// CHECK-START: int Main.test5(TestClass, boolean) load_store_elimination (before)
  /// CHECK-DAG:  <<Int1:i\d+>>      IntConstant 1
  /// CHECK-DAG:  <<Int2:i\d+>>      IntConstant 2
  /// CHECK-DAG:  <<Obj:l\d+>>       ParameterValue
  /// CHECK-DAG:                     InstanceFieldSet [{{l\d+}},<<Int1>>]
  /// CHECK-DAG:                     InstanceFieldSet [{{l\d+}},<<Int2>>]
  /// CHECK-DAG:  <<GetField:i\d+>>  InstanceFieldGet [{{l\d+}}]
  /// CHECK-DAG:                     Return [<<GetField>>]

  /// CHECK-START: int Main.test5(TestClass, boolean) load_store_elimination (after)
  /// CHECK-DAG:  <<Int1:i\d+>>      IntConstant 1
  /// CHECK-DAG:  <<Int2:i\d+>>      IntConstant 2
  /// CHECK-DAG:  <<Obj:l\d+>>       ParameterValue
  /// CHECK-DAG:                     InstanceFieldSet [{{l\d+}},<<Int1>>]
  /// CHECK-DAG:                     InstanceFieldSet [{{l\d+}},<<Int2>>]
  /// CHECK-DAG:  <<Phi:i\d+>>       Phi [<<Arg1:i\d+>>,<<Arg2:i\d+>>]
  /// CHECK-DAG:                     Return [<<Phi>>]
  /// CHECK-EVAL: set(["<<Arg1>>","<<Arg2>>"]) == set(["<<Int1>>","<<Int2>>"])

  /// CHECK-START: int Main.test5(TestClass, boolean) load_store_elimination (after)
  /// CHECK-NOT: InstanceFieldGet

  // Set and merge different values in two branches.
  static int test5(TestClass obj, boolean b) {
    if (b) {
      obj.i = 1;
    } else {
      obj.i = 2;
    }
    return obj.i;
  }

  /// CHECK-START: int Main.test6(TestClass, TestClass, boolean) load_store_elimination (before)
  /// CHECK-DAG: InstanceFieldSet
  /// CHECK-DAG: InstanceFieldSet
  /// CHECK-DAG: InstanceFieldSet
  /// CHECK-DAG: InstanceFieldGet
  /// CHECK-DAG: InstanceFieldGet

  /// CHECK-START: int Main.test6(TestClass, TestClass, boolean) load_store_elimination (after)
  /// CHECK-DAG: InstanceFieldSet
  /// CHECK-DAG: InstanceFieldSet
  /// CHECK-DAG: InstanceFieldSet
  /// CHECK-DAG: InstanceFieldGet

  /// CHECK-START: int Main.test6(TestClass, TestClass, boolean) load_store_elimination (after)
  /// CHECK: InstanceFieldGet
  /// CHECK-NOT: InstanceFieldGet

  // Setting the same value doesn't clear the value for aliased locations.
  static int test6(TestClass obj1, TestClass obj2, boolean b) {
    obj1.i = 1;
    obj1.j = 2;
    if (b) {
      obj2.j = 2;
    }
    return obj1.j + obj2.j;
  }

  /// CHECK-START: int Main.test7(TestClass) load_store_elimination (before)
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldGet

  /// CHECK-START: int Main.test7(TestClass) load_store_elimination (after)
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldGet

  // Invocation should kill values in non-singleton heap locations.
  static int test7(TestClass obj) {
    obj.i = 1;
    System.out.print("");
    return obj.i;
  }

  /// CHECK-START: int Main.test8() load_store_elimination (before)
  /// CHECK: NewInstance
  /// CHECK: InstanceFieldSet
  /// CHECK: InvokeVirtual
  /// CHECK: InstanceFieldGet

  /// CHECK-START: int Main.test8() load_store_elimination (after)
  /// CHECK-NOT: NewInstance
  /// CHECK-NOT: InstanceFieldSet
  /// CHECK: InvokeVirtual
  /// CHECK-NOT: NullCheck
  /// CHECK-NOT: InstanceFieldGet

  // Invocation should not kill values in singleton heap locations.
  static int test8() {
    TestClass obj = new TestClass();
    obj.i = 1;
    System.out.print("");
    return obj.i;
  }

  /// CHECK-START: int Main.test9(TestClass) load_store_elimination (before)
  /// CHECK: NewInstance
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldGet

  /// CHECK-START: int Main.test9(TestClass) load_store_elimination (after)
  /// CHECK: NewInstance
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldGet

  // Invocation should kill values in non-singleton heap locations.
  static int test9(TestClass obj) {
    TestClass obj2 = new TestClass();
    obj2.i = 1;
    obj.next = obj2;
    System.out.print("");
    return obj2.i;
  }

  /// CHECK-START: int Main.test10(TestClass) load_store_elimination (before)
  /// CHECK-DAG: StaticFieldGet
  /// CHECK-DAG: InstanceFieldGet
  /// CHECK-DAG: StaticFieldSet
  /// CHECK-DAG: InstanceFieldGet

  /// CHECK-START: int Main.test10(TestClass) load_store_elimination (after)
  /// CHECK-DAG: StaticFieldGet
  /// CHECK-DAG: InstanceFieldGet
  /// CHECK-DAG: StaticFieldSet

  /// CHECK-START: int Main.test10(TestClass) load_store_elimination (after)
  /// CHECK:     NullCheck
  /// CHECK-NOT: NullCheck

  /// CHECK-START: int Main.test10(TestClass) load_store_elimination (after)
  /// CHECK:     InstanceFieldGet
  /// CHECK-NOT: InstanceFieldGet

  // Static fields shouldn't alias with instance fields.
  static int test10(TestClass obj) {
    TestClass.si += obj.i;
    return obj.i;
  }

  /// CHECK-START: int Main.test11(TestClass) load_store_elimination (before)
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldGet

  /// CHECK-START: int Main.test11(TestClass) load_store_elimination (after)
  /// CHECK: InstanceFieldSet
  /// CHECK-NOT: NullCheck
  /// CHECK-NOT: InstanceFieldGet

  // Loop without heap writes.
  static int test11(TestClass obj) {
    obj.i = 1;
    int sum = 0;
    for (int i = 0; i < 10; i++) {
      sum += obj.i;
    }
    return sum;
  }

  /// CHECK-START: int Main.test12(TestClass, TestClass) load_store_elimination (before)
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldGet
  /// CHECK: InstanceFieldSet

  /// CHECK-START: int Main.test12(TestClass, TestClass) load_store_elimination (after)
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldGet
  /// CHECK: InstanceFieldSet

  // Loop with heap writes.
  static int test12(TestClass obj1, TestClass obj2) {
    obj1.i = 1;
    int sum = 0;
    for (int i = 0; i < 10; i++) {
      sum += obj1.i;
      obj2.i = sum;
    }
    return sum;
  }

  /// CHECK-START: int Main.test13(TestClass, TestClass2) load_store_elimination (before)
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldGet
  /// CHECK: InstanceFieldGet

  /// CHECK-START: int Main.test13(TestClass, TestClass2) load_store_elimination (after)
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldSet
  /// CHECK-NOT: NullCheck
  /// CHECK-NOT: InstanceFieldGet

  // Different classes shouldn't alias.
  static int test13(TestClass obj1, TestClass2 obj2) {
    obj1.i = 1;
    obj2.i = 2;
    return obj1.i + obj2.i;
  }

  /// CHECK-START: int Main.test14(TestClass, SubTestClass) load_store_elimination (before)
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldGet

  /// CHECK-START: int Main.test14(TestClass, SubTestClass) load_store_elimination (after)
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldGet

  // Subclass may alias with super class.
  static int test14(TestClass obj1, SubTestClass obj2) {
    obj1.i = 1;
    obj2.i = 2;
    return obj1.i;
  }

  /// CHECK-START: int Main.test15() load_store_elimination (before)
  /// CHECK: StaticFieldSet
  /// CHECK: StaticFieldSet
  /// CHECK: StaticFieldGet

  /// CHECK-START: int Main.test15() load_store_elimination (after)
  /// CHECK: <<Const2:i\d+>> IntConstant 2
  /// CHECK: StaticFieldSet
  /// CHECK: Return [<<Const2>>]

  /// CHECK-START: int Main.test15() load_store_elimination (after)
  /// CHECK-NOT: StaticFieldGet

  // Static field access from subclass's name.
  static int test15() {
    TestClass.si = 1;
    SubTestClass.si = 2;
    return TestClass.si;
  }

  /// CHECK-START: int Main.test16() load_store_elimination (before)
  /// CHECK: NewInstance
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldGet
  /// CHECK: InstanceFieldGet

  /// CHECK-START: int Main.test16() load_store_elimination (after)
  /// CHECK-NOT: NewInstance
  /// CHECK-NOT: InstanceFieldSet
  /// CHECK-NOT: InstanceFieldGet

  // Test inlined constructor.
  static int test16() {
    TestClass obj = new TestClass(12);
    return obj.i + obj.j;
  }

  /// CHECK-START: int Main.test17() load_store_elimination (before)
  /// CHECK: NewInstance
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldGet

  /// CHECK-START: int Main.test17() load_store_elimination (after)
  /// CHECK: <<Const0:i\d+>> IntConstant 0
  /// CHECK-NOT: NewInstance
  /// CHECK-NOT: InstanceFieldSet
  /// CHECK-NOT: InstanceFieldGet
  /// CHECK: Return [<<Const0>>]

  // Test getting default value.
  static int test17() {
    TestClass obj = new TestClass();
    obj.j = 1;
    return obj.i;
  }

  /// CHECK-START: int Main.test18(TestClass) load_store_elimination (before)
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldGet

  /// CHECK-START: int Main.test18(TestClass) load_store_elimination (after)
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldGet

  // Volatile field load/store shouldn't be eliminated.
  static int test18(TestClass obj) {
    obj.k = 1;
    return obj.k;
  }

  /// CHECK-START: float Main.test19(float[], float[]) load_store_elimination (before)
  /// CHECK:     {{f\d+}} ArrayGet
  /// CHECK:     {{f\d+}} ArrayGet

  /// CHECK-START: float Main.test19(float[], float[]) load_store_elimination (after)
  /// CHECK:     {{f\d+}} ArrayGet
  /// CHECK-NOT: {{f\d+}} ArrayGet

  // I/F, J/D aliasing should not happen any more and LSE should eliminate the load.
  static float test19(float[] fa1, float[] fa2) {
    fa1[0] = fa2[0];
    return fa1[0];
  }

  /// CHECK-START: TestClass Main.test20() load_store_elimination (before)
  /// CHECK: NewInstance
  /// CHECK: InstanceFieldSet

  /// CHECK-START: TestClass Main.test20() load_store_elimination (after)
  /// CHECK: NewInstance
  /// CHECK-NOT: InstanceFieldSet

  // Storing default heap value is redundant if the heap location has the
  // default heap value.
  static TestClass test20() {
    TestClass obj = new TestClass();
    obj.i = 0;
    return obj;
  }

  /// CHECK-START: void Main.test21(TestClass) load_store_elimination (before)
  /// CHECK-DAG: NewInstance
  /// CHECK-DAG: InstanceFieldSet
  /// CHECK-DAG: InstanceFieldSet
  /// CHECK-DAG: InstanceFieldSet
  /// CHECK-DAG: InstanceFieldGet
  /// CHECK-DAG: InstanceFieldGet

  /// CHECK-START: void Main.test21(TestClass) load_store_elimination (after)
  /// CHECK-DAG: InstanceFieldSet

  /// CHECK-START: void Main.test21(TestClass) load_store_elimination (after)
  /// CHECK-NOT: NewInstance
  /// CHECK-NOT: InstanceFieldGet

  // Loop side effects can kill heap values, stores need to be kept in that case.
  static void test21(TestClass obj0) {
    TestClass obj = new TestClass();
    obj0.str = "abc";
    obj.str = "abc";
    // Note: This loop is transformed by the loop optimization pass, therefore we
    // are not checking the exact number of InstanceFieldSet and Phi instructions.
    for (int i = 0; i < 2; i++) {
      // Generate some loop side effect that writes into obj.
      obj.str = "def";
    }
    $noinline$printSubstrings00(obj0.str, obj.str);
  }

  static void $noinline$printSubstrings00(String str1, String str2) {
    System.out.print(str1.substring(00) + str2.substring(00));
  }

  /// CHECK-START: int Main.test22() load_store_elimination (before)
  /// CHECK: NewInstance
  /// CHECK: InstanceFieldSet
  /// CHECK: NewInstance
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldGet
  /// CHECK: NewInstance
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldGet
  /// CHECK: InstanceFieldGet

  /// CHECK-START: int Main.test22() load_store_elimination (after)
  /// CHECK-NOT: NewInstance
  /// CHECK-NOT: InstanceFieldSet
  /// CHECK-NOT: InstanceFieldGet

  // For a singleton, loop side effects can kill its field values only if:
  // (1) it dominiates the loop header, and
  // (2) its fields are stored into inside a loop.
  static int test22() {
    int sum = 0;
    TestClass obj1 = new TestClass();
    obj1.i = 2;    // This store can be eliminated since obj1 is never stored into inside a loop.
    for (int i = 0; i < 2; i++) {
      TestClass obj2 = new TestClass();
      obj2.i = 3;  // This store can be eliminated since the singleton is inside the loop.
      sum += obj2.i;
    }
    TestClass obj3 = new TestClass();
    obj3.i = 5;    // This store can be eliminated since the singleton is created after the loop.
    sum += obj1.i + obj3.i;
    return sum;
  }

  /// CHECK-START: int Main.test23(boolean) load_store_elimination (before)
  /// CHECK-DAG:  <<Int1:i\d+>>      IntConstant 1
  /// CHECK-DAG:  <<Int2:i\d+>>      IntConstant 2
  /// CHECK-DAG:  <<Int3:i\d+>>      IntConstant 3
  /// CHECK-DAG:  <<Obj:l\d+>>       NewInstance
  /// CHECK-DAG:                     InstanceFieldSet [<<Obj>>,<<Int3>>]
  /// CHECK-DAG:  <<Add1:i\d+>>      Add [<<Get1:i\d+>>,<<Int1>>]
  /// CHECK-DAG:  <<Get1>>           InstanceFieldGet [<<Obj>>]
  /// CHECK-DAG:                     InstanceFieldSet [<<Obj>>,<<Add1>>]
  /// CHECK-DAG:  <<Add2:i\d+>>      Add [<<Get2:i\d+>>,<<Int2>>]
  /// CHECK-DAG:  <<Get2>>           InstanceFieldGet [<<Obj>>]
  /// CHECK-DAG:                     InstanceFieldSet [<<Obj>>,<<Add2>>]
  /// CHECK-DAG:                     Return [<<Get3:i\d+>>]
  /// CHECK-DAG:  <<Get3>>           InstanceFieldGet [<<Obj>>]

  /// CHECK-START: int Main.test23(boolean) load_store_elimination (after)
  /// CHECK-DAG:  <<Int1:i\d+>>      IntConstant 1
  /// CHECK-DAG:  <<Int2:i\d+>>      IntConstant 2
  /// CHECK-DAG:  <<Int3:i\d+>>      IntConstant 3
  /// CHECK-DAG:  <<Add1:i\d+>>      Add [<<Int3>>,<<Int1>>]
  /// CHECK-DAG:  <<Add2:i\d+>>      Add [<<Int3>>,<<Int2>>]
  /// CHECK-DAG:  <<Phi:i\d+>>       Phi [<<Arg1:i\d+>>,<<Arg2:i\d+>>]
  /// CHECK-DAG:                     Return [<<Phi>>]
  /// CHECK-EVAL: set(["<<Arg1>>","<<Arg2>>"]) == set(["<<Add1>>","<<Add2>>"])

  /// CHECK-START: int Main.test23(boolean) load_store_elimination (after)
  /// CHECK-NOT: NewInstance
  /// CHECK-NOT: InstanceFieldSet
  /// CHECK-NOT: InstanceFieldGet

  // Test heap value merging from multiple branches.
  static int test23(boolean b) {
    TestClass obj = new TestClass();
    obj.i = 3;      // This store can be eliminated since the value flows into each branch.
    if (b) {
      obj.i += 1;   // This store can be eliminated after replacing the load below with a Phi.
    } else {
      obj.i += 2;   // This store can be eliminated after replacing the load below with a Phi.
    }
    return obj.i;   // This load is eliminated by creating a Phi.
  }

  /// CHECK-START: float Main.test24() load_store_elimination (before)
  /// CHECK-DAG:     <<True:i\d+>>     IntConstant 1
  /// CHECK-DAG:     <<Float8:f\d+>>   FloatConstant 8
  /// CHECK-DAG:     <<Float42:f\d+>>  FloatConstant 42
  /// CHECK-DAG:     <<Obj:l\d+>>      NewInstance
  /// CHECK-DAG:                       InstanceFieldSet [<<Obj>>,<<True>>]
  /// CHECK-DAG:                       InstanceFieldSet [<<Obj>>,<<Float8>>]
  /// CHECK-DAG:     <<GetTest:z\d+>>  InstanceFieldGet [<<Obj>>]
  /// CHECK-DAG:     <<GetField:f\d+>> InstanceFieldGet [<<Obj>>]
  /// CHECK-DAG:     <<Select:f\d+>>   Select [<<Float42>>,<<GetField>>,<<GetTest>>]
  /// CHECK-DAG:                       Return [<<Select>>]

  /// CHECK-START: float Main.test24() load_store_elimination (after)
  /// CHECK-DAG:     <<True:i\d+>>     IntConstant 1
  /// CHECK-DAG:     <<Float8:f\d+>>   FloatConstant 8
  /// CHECK-DAG:     <<Float42:f\d+>>  FloatConstant 42
  /// CHECK-DAG:     <<Select:f\d+>>   Select [<<Float42>>,<<Float8>>,<<True>>]
  /// CHECK-DAG:                       Return [<<Select>>]

  /// CHECK-START: float Main.test24() load_store_elimination (after)
  /// CHECK-NOT:                       NewInstance
  /// CHECK-NOT:                       InstanceFieldGet
  static float test24() {
    float a = 42.0f;
    TestClass3 obj = new TestClass3();
    if (obj.test1) {
      a = obj.floatField;
    }
    return a;
  }

  /// CHECK-START: int Main.test25(boolean, boolean, boolean) load_store_elimination (before)
  /// CHECK-DAG:     <<Int1:i\d+>>     IntConstant 1
  /// CHECK-DAG:     <<Int2:i\d+>>     IntConstant 2
  /// CHECK-DAG:     <<Int3:i\d+>>     IntConstant 3
  /// CHECK-DAG:     <<Int5:i\d+>>     IntConstant 5
  /// CHECK-DAG:     <<Int6:i\d+>>     IntConstant 6
  /// CHECK-DAG:     <<Obj:l\d+>>      NewInstance
  /// CHECK-DAG:                       InstanceFieldSet [<<Obj>>,<<Int1>>]
  /// CHECK-DAG:                       InstanceFieldSet [<<Obj>>,<<Int2>>]
  /// CHECK-DAG:                       InstanceFieldSet [<<Obj>>,<<Int3>>]
  /// CHECK-DAG:                       InstanceFieldSet [<<Obj>>,<<Int5>>]
  /// CHECK-DAG:                       InstanceFieldSet [<<Obj>>,<<Int6>>]
  /// CHECK-DAG:     <<GetField:i\d+>> InstanceFieldGet [<<Obj>>]
  /// CHECK-DAG:                       Return [<<GetField>>]

  /// CHECK-START: int Main.test25(boolean, boolean, boolean) load_store_elimination (after)
  /// CHECK-DAG:     <<Int1:i\d+>>     IntConstant 1
  /// CHECK-DAG:     <<Int2:i\d+>>     IntConstant 2
  /// CHECK-DAG:     <<Int3:i\d+>>     IntConstant 3
  /// CHECK-DAG:     <<Int5:i\d+>>     IntConstant 5
  /// CHECK-DAG:     <<Int6:i\d+>>     IntConstant 6
  /// CHECK-DAG:     <<Phi:i\d+>>      Phi [<<Arg1:i\d+>>,<<Arg2:i\d+>>,<<Arg3:i\d+>>,<<Arg4:i\d+>>,<<Arg5:i\d+>>]
  /// CHECK-DAG:                       Return [<<Phi>>]
  /// CHECK-EVAL: set(["<<Arg1>>","<<Arg2>>","<<Arg3>>","<<Arg4>>","<<Arg5>>"]) == set(["<<Int1>>","<<Int2>>","<<Int3>>","<<Int5>>","<<Int6>>"])

  /// CHECK-START: int Main.test25(boolean, boolean, boolean) load_store_elimination (after)
  /// CHECK-NOT:                       NewInstance
  /// CHECK-NOT:                       InstanceFieldSet
  /// CHECK-NOT:                       InstanceFieldGet

  // Test heap value merging from nested branches.
  static int test25(boolean b, boolean c, boolean d) {
    TestClass obj = new TestClass();
    if (b) {
      if (c) {
        obj.i = 1;
      } else {
        if (d) {
          obj.i = 2;
        } else {
          obj.i = 3;
        }
      }
    } else {
      if (c) {
        obj.i = 5;
      } else {
        obj.i = 6;
      }
    }
    return obj.i;
  }

  /// CHECK-START: float Main.test26(int) load_store_elimination (before)
  /// CHECK-DAG:     <<Float0:f\d+>>   FloatConstant 0
  /// CHECK-DAG:     <<Float1:f\d+>>   FloatConstant 1
  /// CHECK-DAG:     <<Float2:f\d+>>   FloatConstant 2
  /// CHECK-DAG:     <<Float3:f\d+>>   FloatConstant 3
  /// CHECK-DAG:     <<Float8:f\d+>>   FloatConstant 8
  /// CHECK-DAG:     <<Obj:l\d+>>      NewInstance
  /// CHECK-DAG:                       InstanceFieldSet [<<Obj>>,<<Float8>>]
  /// CHECK-DAG:                       InstanceFieldSet [<<Obj>>,<<Float0>>]
  /// CHECK-DAG:                       InstanceFieldSet [<<Obj>>,<<Float1>>]
  /// CHECK-DAG:                       InstanceFieldSet [<<Obj>>,<<Float2>>]
  /// CHECK-DAG:                       InstanceFieldSet [<<Obj>>,<<Float3>>]
  /// CHECK-DAG:     <<GetField:f\d+>> InstanceFieldGet [<<Obj>>]
  /// CHECK-DAG:                       Return [<<GetField>>]

  /// CHECK-START: float Main.test26(int) load_store_elimination (after)
  /// CHECK-DAG:     <<Float0:f\d+>>   FloatConstant 0
  /// CHECK-DAG:     <<Float1:f\d+>>   FloatConstant 1
  /// CHECK-DAG:     <<Float2:f\d+>>   FloatConstant 2
  /// CHECK-DAG:     <<Float3:f\d+>>   FloatConstant 3
  /// CHECK-DAG:     <<Float8:f\d+>>   FloatConstant 8
  /// CHECK-DAG:     <<Phi:f\d+>>      Phi [<<Arg1:f\d+>>,<<Arg2:f\d+>>,<<Arg3:f\d+>>,<<Arg4:f\d+>>]
  /// CHECK-DAG:                       Return [<<Phi>>]
  /// CHECK-EVAL: set(["<<Arg1>>","<<Arg2>>","<<Arg3>>","<<Arg4>>"]) == set(["<<Float0>>","<<Float1>>","<<Float2>>","<<Float3>>"])

  /// CHECK-START: float Main.test26(int) load_store_elimination (after)
  /// CHECK-NOT:                       NewInstance
  /// CHECK-NOT:                       InstanceFieldSet
  /// CHECK-NOT:                       InstanceFieldGet

  // Test heap value merging from switch statement.
  static float test26(int b) {
    TestClass3 obj = new TestClass3();
    switch (b) {
      case 1:
        obj.floatField = 3.0f;
        break;
      case 2:
        obj.floatField = 2.0f;
        break;
      case 3:
        obj.floatField = 1.0f;
        break;
      default:
        obj.floatField = 0.0f;
        break;
    }
    return obj.floatField;
  }

  /// CHECK-START: int Main.test27(boolean, boolean) load_store_elimination (before)
  /// CHECK-DAG:   <<Int1:i\d+>>      IntConstant 1
  /// CHECK-DAG:   <<Obj:l\d+>>       NewInstance
  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<Int1>>]
  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<Int1>>]
  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<Int1>>]
  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<Int1>>]
  /// CHECK-DAG:   <<GetField:i\d+>>  InstanceFieldGet [<<Obj>>]
  /// CHECK-DAG:                      Return [<<GetField>>]

  /// CHECK-START: int Main.test27(boolean, boolean) load_store_elimination (after)
  /// CHECK-DAG:   <<Int1:i\d+>>      IntConstant 1
  /// CHECK-DAG:                      Return [<<Int1>>]

  /// CHECK-START: int Main.test27(boolean, boolean) load_store_elimination (after)
  /// CHECK-NOT:                      NewInstance
  /// CHECK-NOT:                      InstanceFieldSet
  /// CHECK-NOT:                      InstanceFieldGet
  /// CHECK-NOT:                      Phi

  // Test merging same value from nested branches.
  static int test27(boolean b, boolean c) {
    TestClass obj = new TestClass();
    if (b) {
      if (c) {
        obj.i = 1;
      } else {
        obj.i = 1;
      }
    } else {
      if (c) {
        obj.i = 1;
      } else {
        obj.i = 1;
      }
    }
    return obj.i;
  }

  /// CHECK-START: int Main.test28(boolean, boolean) load_store_elimination (before)
  /// CHECK-DAG:   <<Int0:i\d+>>      IntConstant 0
  /// CHECK-DAG:   <<Int5:i\d+>>      IntConstant 5
  /// CHECK-DAG:   <<Int6:i\d+>>      IntConstant 6
  /// CHECK-DAG:   <<Array:l\d+>>     NewArray
  /// CHECK-DAG:                      ArraySet [<<Array>>,<<Int0>>,<<Int5>>]
  /// CHECK-DAG:                      ArraySet [<<Array>>,<<Int0>>,<<Int6>>]
  /// CHECK-DAG:   <<GetIndex:i\d+>>  ArrayGet [<<Array>>,<<Int0>>]
  /// CHECK-DAG:                      Return [<<GetIndex>>]

  /// CHECK-START: int Main.test28(boolean, boolean) load_store_elimination (after)
  /// CHECK-DAG:   <<Int0:i\d+>>      IntConstant 0
  /// CHECK-DAG:   <<Int5:i\d+>>      IntConstant 5
  /// CHECK-DAG:   <<Int6:i\d+>>      IntConstant 6
  /// CHECK-DAG:   <<Phi:i\d+>>       Phi [<<Arg1:i\d+>>,<<Arg2:i\d+>>,<<Arg3:i\d+>>]
  /// CHECK-DAG:                      Return [<<Phi>>]
  /// CHECK-EVAL: set(["<<Arg1>>","<<Arg2>>","<<Arg3>>"]) == set(["<<Int0>>","<<Int5>>","<<Int6>>"])

  /// CHECK-START: int Main.test28(boolean, boolean) load_store_elimination (after)
  /// CHECK-NOT:                       NewArray
  /// CHECK-NOT:                       ArraySet
  /// CHECK-NOT:                       ArrayGet

  // Test merging array stores in branches.
  static int test28(boolean b, boolean c) {
    int[] array = new int[1];
    if (b) {
      if (c) {
        array[0] = 5;
      } else {
        array[0] = 6;
      }
    } else { /* Default value: 0. */ }
    return array[0];
  }

  /// CHECK-START: float Main.test29(boolean) load_store_elimination (before)
  /// CHECK-DAG:     <<Float2:f\d+>>   FloatConstant 2
  /// CHECK-DAG:     <<Float5:f\d+>>   FloatConstant 5
  /// CHECK-DAG:     <<Float8:f\d+>>   FloatConstant 8
  /// CHECK-DAG:     <<Obj:l\d+>>      NewInstance
  /// CHECK-DAG:                       InstanceFieldSet [<<Obj>>,<<Float8>>]
  /// CHECK-DAG:                       InstanceFieldSet [<<Obj>>,<<Float2>>]
  /// CHECK-DAG:                       InstanceFieldSet [<<Obj>>,<<Float5>>]
  /// CHECK-DAG:     <<GetField:f\d+>> InstanceFieldGet [<<Obj>>]
  /// CHECK-DAG:                       Return [<<GetField>>]

  /// CHECK-START: float Main.test29(boolean) load_store_elimination (after)
  /// CHECK-DAG:     <<Float2:f\d+>>   FloatConstant 2
  /// CHECK-DAG:     <<Float5:f\d+>>   FloatConstant 5
  /// CHECK-DAG:     <<Float8:f\d+>>   FloatConstant 8
  /// CHECK-DAG:     <<Phi:f\d+>>      Phi [<<Arg1:f\d+>>,<<Arg2:f\d+>>]
  /// CHECK-DAG:                       Return [<<Phi>>]
  /// CHECK-EVAL: set(["<<Arg1>>","<<Arg2>>"]) == set(["<<Float5>>","<<Float2>>"])

  /// CHECK-START: float Main.test29(boolean) load_store_elimination (after)
  /// CHECK-NOT:                       NewInstance
  /// CHECK-NOT:                       InstanceFieldSet
  /// CHECK-NOT:                       InstanceFieldGet

  // Test implicit type conversion in branches.
  static float test29(boolean b) {
    TestClass3 obj = new TestClass3();
    if (b) {
      obj.floatField = 5// Int
    } else {
      obj.floatField = 2L; // Long
    }
    return obj.floatField;
  }

  /// CHECK-START: int Main.test30(TestClass, boolean) load_store_elimination (before)
  /// CHECK-DAG:  <<Int1:i\d+>>      IntConstant 1
  /// CHECK-DAG:  <<Int2:i\d+>>      IntConstant 2
  /// CHECK-DAG:                     InstanceFieldSet [{{l\d+}},<<Int1>>]
  /// CHECK-DAG:                     InstanceFieldSet [{{l\d+}},<<Int2>>]
  /// CHECK-DAG:  <<GetField:i\d+>>  InstanceFieldGet [{{l\d+}}]
  /// CHECK-DAG:                     Return [<<GetField>>]

  /// CHECK-START: int Main.test30(TestClass, boolean) load_store_elimination (after)
  /// CHECK-DAG:  <<Int1:i\d+>>      IntConstant 1
  /// CHECK-DAG:  <<Int2:i\d+>>      IntConstant 2
  /// CHECK-DAG:                     InstanceFieldSet [{{l\d+}},<<Int1>>]
  /// CHECK-DAG:                     InstanceFieldSet [{{l\d+}},<<Int2>>]
  /// CHECK-DAG:  <<GetField:i\d+>>  InstanceFieldGet [{{l\d+}}]
  /// CHECK-DAG:                     Return [<<GetField>>]

  /// CHECK-START: int Main.test30(TestClass, boolean) load_store_elimination (after)
  /// CHECK-NOT: Phi

  // Don't merge different values in two branches for different variables.
  static int test30(TestClass obj, boolean b) {
    if (b) {
      obj.i = 1;
    } else {
      obj.j = 2;
    }
    return obj.i;
  }

  /// CHECK-START: int Main.test31(boolean, boolean) load_store_elimination (before)
  /// CHECK-DAG:  <<Int2:i\d+>>  IntConstant 2
  /// CHECK-DAG:  <<Int5:i\d+>>  IntConstant 5
  /// CHECK-DAG:  <<Int6:i\d+>>  IntConstant 6
  /// CHECK-DAG:                 InstanceFieldSet [{{l\d+}},<<Int5>>] field_name:{{.*TestClass.i}}
  /// CHECK-DAG:                 InstanceFieldSet [{{l\d+}},<<Int6>>] field_name:{{.*TestClass.i}}
  /// CHECK-DAG:  <<Get1:i\d+>>  InstanceFieldGet [{{l\d+}}] field_name:{{.*TestClass.i}}
  /// CHECK-DAG:                 InstanceFieldSet [{{l\d+}},<<Get1>>] field_name:{{.*TestClass.j}}
  /// CHECK-DAG:                 InstanceFieldSet [{{l\d+}},<<Int2>>] field_name:{{.*TestClass.i}}
  /// CHECK-DAG:  <<Get2:i\d+>>  InstanceFieldGet [{{l\d+}}]
  /// CHECK-DAG:                 Return [<<Get2>>]

  /// CHECK-START: int Main.test31(boolean, boolean) load_store_elimination (after)
  /// CHECK-DAG:  <<Int2:i\d+>>  IntConstant 2
  /// CHECK-DAG:  <<Int5:i\d+>>  IntConstant 5
  /// CHECK-DAG:  <<Int6:i\d+>>  IntConstant 6
  /// CHECK-DAG:  <<Phi1:i\d+>>  Phi [<<Int5>>,<<Int6>>]
  /// CHECK-DAG:  <<Phi2:i\d+>>  Phi [<<Phi1>>,<<Int2>>]
  /// CHECK-DAG:                 Return [<<Phi2>>]

  /// CHECK-START: int Main.test31(boolean, boolean) load_store_elimination (after)
  /// CHECK-NOT:                 NewInstance
  /// CHECK-NOT:                 InstanceFieldSet
  /// CHECK-NOT:                 InstanceFieldGet

  // Test nested branches that can't be flattened.
  static int test31(boolean b, boolean c) {
    TestClass obj = new TestClass();
    if (b) {
      if (c) {
        obj.i = 5;
      } else {
        obj.i = 6;
      }
      obj.j = obj.i;
    } else {
      obj.i = 2;
    }
    return obj.i;
  }

  /// CHECK-START: int Main.test32(int) load_store_elimination (before)
  /// CHECK-DAG:  <<Int1:i\d+>>      IntConstant 1
  /// CHECK-DAG:  <<Int10:i\d+>>     IntConstant 10
  /// CHECK-DAG:  InstanceFieldSet [{{l\d+}},<<Int1>>] field_name:{{.*TestClass2.i}}
  /// CHECK-DAG:  InstanceFieldSet [{{l\d+}},<<Int1>>] field_name:{{.*TestClass2.j}}
  /// CHECK-DAG:  InstanceFieldSet [{{l\d+}},<<Int1>>] field_name:{{.*TestClass2.k}}
  /// CHECK-DAG:  InstanceFieldSet [{{l\d+}},<<Int1>>] field_name:{{.*TestClass2.l}}
  /// CHECK-DAG:  InstanceFieldSet [{{l\d+}},<<Int1>>] field_name:{{.*TestClass2.m}}
  /// CHECK-DAG:                     Return [<<Int10>>]

  /// CHECK-START: int Main.test32(int) load_store_elimination (after)
  /// CHECK-DAG:  <<Int10:i\d+>>     IntConstant 10
  /// CHECK-DAG:                     Return [<<Int10>>]

  /// CHECK-START: int Main.test32(int) load_store_elimination (after)
  /// CHECK-NOT:                     NewInstance
  /// CHECK-NOT:                     InstanceFieldGet
  /// CHECK-NOT:                     InstanceFieldSet
  /// CHECK-NOT:                     Phi

  // Test no unused Phi instructions are created.
  static int test32(int i) {
    TestClass2 obj = new TestClass2();
    // By default, i/j/k/l/m are initialized to 0.
    switch (i) {
      case 1: obj.i = 1break;
      case 2: obj.j = 1break;
      case 3: obj.k = 1break;
      case 4: obj.l = 1break;
      case 5: obj.m = 1break;
    }
    // So here, each variable has value Phi [0,1,1,1,1,1].
    // But since no heap values are used, we should not be creating these Phis.
    return 10;
  }

  /// CHECK-START: int Main.test33(TestClass, boolean) load_store_elimination (before)
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG: <<Phi:i\d+>>        Phi
  /// CHECK-DAG:                     InstanceFieldSet [{{l\d+}},<<Phi>>]

  /// CHECK-START: int Main.test33(TestClass, boolean) load_store_elimination (after)
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG: <<Phi:i\d+>>        Phi

  /// CHECK-START: int Main.test33(TestClass, boolean) load_store_elimination (after)
  /// CHECK:                         InstanceFieldSet
  /// CHECK:                         InstanceFieldSet
  /// CHECK-NOT:                     InstanceFieldSet

  // Test that we are not eliminating the if/else sets to `obj.i`. We have `NullCheck`s on `obj`
  // when doing `obj.i`. Since `NullCheck` can throw, we save the stores.
  // The 3rd `obj.i` set is redundant and can be eliminated. It will have the same value and it is
  // not needed.
  static int test33(TestClass obj, boolean x) {
    int phi;
    if (x) {
      obj.i = 1;
      phi = 1;
    } else {
      obj.i = 2;
      phi = 2;
    }
    obj.i = phi;
    return phi;
  }

  /// CHECK-START: int Main.test34(TestClass, boolean, boolean) load_store_elimination (before)
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG: <<Phi:i\d+>>        Phi
  /// CHECK-DAG:                     InstanceFieldSet [{{l\d+}},<<Phi>>]

  /// CHECK-START: int Main.test34(TestClass, boolean, boolean) load_store_elimination (after)
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     Phi

  /// CHECK-START: int Main.test34(TestClass, boolean, boolean) load_store_elimination (after)
  /// CHECK:                         InstanceFieldSet
  /// CHECK:                         InstanceFieldSet
  /// CHECK-NOT:                     InstanceFieldSet

  // Test eliminating a store that writes a Phi equivalent to merged
  // heap values of observable stores.
  static int test34(TestClass obj, boolean x, boolean y) {
    int phi;
    if (x) {
      obj.i = 1;
      phi = 1;
      if (y) {
        return 3;
      }
    } else {
      obj.i = 2;
      phi = 2;
      if (y) {
        return 4;
      }
    }
    obj.i = phi;
    return phi;
  }

  /// CHECK-START: int Main.test35(TestClass, boolean, boolean) load_store_elimination (before)
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldGet

  /// CHECK-START: int Main.test35(TestClass, boolean, boolean) load_store_elimination (after)
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     Phi

  /// CHECK-START: int Main.test35(TestClass, boolean, boolean) load_store_elimination (after)
  /// CHECK-NOT:                     InstanceFieldGet

  // Test Phi creation for load elimination.
  static int test35(TestClass obj, boolean x, boolean y) {
    if (x) {
      obj.i = 1;
    } else {
      obj.i = 2;
    }
    if (y) {
      if (x) {
        obj.i = 3;
      }
      obj.j = 5;
    }
    return obj.i;
  }

  /// CHECK-START: int Main.test36(TestClass, boolean) load_store_elimination (before)
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     InstanceFieldGet

  /// CHECK-START: int Main.test36(TestClass, boolean) load_store_elimination (after)
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     Phi

  /// CHECK-START: int Main.test36(TestClass, boolean) load_store_elimination (after)
  /// CHECK-NOT:                     InstanceFieldGet

  /// CHECK-START: int Main.test36(TestClass, boolean) load_store_elimination (after)
  /// CHECK:                         Phi
  /// CHECK-NOT:                     Phi

  // Test Phi matching for load elimination.
  static int test36(TestClass obj, boolean x) {
    int phi;
    if (x) {
      obj.i = 1;
      phi = 1;
    } else {
      obj.i = 2;
      phi = 2;
    }
    // The load is replaced by the existing Phi instead of constructing a new one.
    return obj.i + phi;
  }

  /// CHECK-START: int Main.test37(TestClass, boolean) load_store_elimination (before)
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldGet
  /// CHECK-DAG:                     InstanceFieldSet

  /// CHECK-START: int Main.test37(TestClass, boolean) load_store_elimination (after)
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldGet
  /// CHECK-DAG:                     InstanceFieldSet

  // Test preserving observable stores.
  static int test37(TestClass obj, boolean x) {
    if (x) {
      obj.i = 1;
    }
    int tmp = obj.i;  // The store above must be kept.
    obj.i = 2;
    return tmp;
  }

  /// CHECK-START: int Main.test38(TestClass, boolean) load_store_elimination (before)
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldSet

  /// CHECK-START: int Main.test38(TestClass, boolean) load_store_elimination (after)
  /// CHECK:                         InstanceFieldSet
  /// CHECK-NOT:                     InstanceFieldSet

  // Test eliminating store of the same value after eliminating non-observable stores.
  static int test38(TestClass obj, boolean x) {
    obj.i = 1;
    if (x) {
      return 1;  // The store above must be kept.
    }
    obj.i = 2;  // Not observable, shall be eliminated.
    obj.i = 3;  // Not observable, shall be eliminated.
    obj.i = 1;  // After eliminating the non-observable stores above, this stores the
                // same value that is already stored in `obj.i` and shall be eliminated.
    return 2;
  }

  /// CHECK-START: int Main.test39(TestClass, boolean) load_store_elimination (before)
  /// CHECK-DAG:                     NewInstance
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     NewInstance
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldGet
  /// CHECK-DAG:                     InstanceFieldGet

  /// CHECK-START: int Main.test39(TestClass, boolean) load_store_elimination (after)
  /// CHECK-DAG:                     NewInstance
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     NewInstance
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     InstanceFieldGet

  /// CHECK-START: int Main.test39(TestClass, boolean) load_store_elimination (after)
  /// CHECK:                         InstanceFieldGet
  /// CHECK-NOT:                     InstanceFieldGet

  // Test creating a reference Phi for load elimination.
  static int test39(TestClass obj, boolean x) {
    obj.next = new TestClass(12);
    if (x) {
      obj.next = new SubTestClass();
    }
    return obj.next.i;
  }

  private static int test40() {
    int[] array = new int[1];
    try {
      $noinline$fillArrayTest40(array, 1000);
      System.out.println("UNREACHABLE");
    } catch (Throwable expected) {
    }
    assertIntEquals(array[0], 1);
    try {
      $noinline$fillArrayTest40(array, 1001);
      System.out.println("UNREACHABLE");
    } catch (Throwable expected) {
    }
    assertIntEquals(array[0], 2);
    $noinline$fillArrayTest40(array, 1002);
    assertIntEquals(array[0], 150);
    return array[0];
  }

  /// CHECK-START: void Main.$noinline$fillArrayTest40(int[], int, int) load_store_elimination (before)
  /// CHECK:                     ArraySet
  /// CHECK:                     DivZeroCheck
  /// CHECK:                     ArraySet
  /// CHECK:                     DivZeroCheck
  /// CHECK:                     ArraySet

  /// CHECK-START: void Main.$noinline$fillArrayTest40(int[], int, int) load_store_elimination (after)
  /// CHECK:                     ArraySet
  /// CHECK:                     DivZeroCheck
  /// CHECK:                     ArraySet
  /// CHECK:                     DivZeroCheck
  /// CHECK:                     ArraySet

  // Check that the stores to array[0] are not eliminated since we can throw in between the stores.
  private static void $noinline$fillArrayTest40(int[] array, int a, int b) {
    array[0] = 1;
    int x = a / b;
    array[0] = 2;
    int y = a / (b - 1);
    array[0] = x + y;
  }

  /// CHECK-START: int Main.$noinline$testConversion1(TestClass, int) load_store_elimination (before)
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldGet
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldGet

  /// CHECK-START: int Main.$noinline$testConversion1(TestClass, int) load_store_elimination (after)
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     TypeConversion
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     Phi

  /// CHECK-START: int Main.$noinline$testConversion1(TestClass, int) load_store_elimination (after)
  /// CHECK:                         Phi
  /// CHECK-NOT:                     Phi

  // Test tracking values containing type conversion.
  // Regression test for b/161521389 .
  static int $noinline$testConversion1(TestClass obj, int x) {
    obj.i = x;
    if ((x & 1) != 0) {
      obj.b = (byte) x;
      obj.i = obj.b;
    }
    return obj.i;
  }

  /// CHECK-START: int Main.$noinline$testConversion2(TestClass, int) load_store_elimination (before)
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldGet
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     TypeConversion
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     InstanceFieldGet

  /// CHECK-START: int Main.$noinline$testConversion2(TestClass, int) load_store_elimination (after)
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     TypeConversion
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     Phi

  /// CHECK-START: int Main.$noinline$testConversion2(TestClass, int) load_store_elimination (after)
  /// CHECK:                         Phi
  /// CHECK:                         Phi
  /// CHECK-NOT:                     Phi

  /// CHECK-START: int Main.$noinline$testConversion2(TestClass, int) load_store_elimination (after)
  /// CHECK:                         TypeConversion
  /// CHECK-NOT:                     TypeConversion

  /// CHECK-START: int Main.$noinline$testConversion2(TestClass, int) load_store_elimination (after)
  /// CHECK-NOT:                     InstanceFieldGet

  // Test moving type conversion when needed.
  static int $noinline$testConversion2(TestClass obj, int x) {
    int tmp = 0;
    obj.i = x;
    if ((x & 1) != 0) {
      // The instruction simplifier can remove this TypeConversion if there are
      // no environment uses. Currently, there is an environment use in NullCheck,
      // so this TypeConversion remains and GVN removes the second TypeConversion
      // below. Since we really want to test that the TypeConversion from below
      // can be moved and used for the load of `obj.b`, we have a similar test
      // written in smali in 530-checker-lse3, StoreLoad.test3(int), except that
      // it's using static fields (which would not help with the environment use).
      obj.b = (byte) x;
      obj.i = obj.b;
      tmp = (byte) x;
    }
    return obj.i + tmp;
  }

  /// CHECK-START: int Main.$noinline$testConversion3(TestClass, int) load_store_elimination (before)
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldGet
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldGet

  /// CHECK-START: int Main.$noinline$testConversion3(TestClass, int) load_store_elimination (after)
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     TypeConversion
  /// CHECK-DAG:                     InstanceFieldSet

  /// CHECK-START: int Main.$noinline$testConversion3(TestClass, int) load_store_elimination (after)
  /// CHECK:                         Phi
  /// CHECK:                         Phi
  /// CHECK-NOT:                     Phi

  /// CHECK-START: int Main.$noinline$testConversion3(TestClass, int) load_store_elimination (after)
  /// CHECK:                         TypeConversion
  /// CHECK-NOT:                     TypeConversion

  /// CHECK-START: int Main.$noinline$testConversion3(TestClass, int) load_store_elimination (after)
  /// CHECK-NOT:                     InstanceFieldGet

  // Test tracking values containing type conversion with loop.
  static int $noinline$testConversion3(TestClass obj, int x) {
    obj.i = x;
    for (int i = 0; i < x; ++i) {
      obj.b = (byte) i;
      obj.i = obj.b;
    }
    return obj.i;
  }

  /// CHECK-START: int Main.$noinline$testConversion4(TestClass, int) load_store_elimination (before)
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldGet
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     TypeConversion
  /// CHECK-DAG:                     InstanceFieldGet

  /// CHECK-START: int Main.$noinline$testConversion4(TestClass, int) load_store_elimination (after)
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     TypeConversion
  /// CHECK-DAG:                     InstanceFieldSet

  /// CHECK-START: int Main.$noinline$testConversion4(TestClass, int) load_store_elimination (after)
  /// CHECK:                         Phi
  /// CHECK:                         Phi
  /// CHECK-NOT:                     Phi

  /// CHECK-START: int Main.$noinline$testConversion4(TestClass, int) load_store_elimination (after)
  /// CHECK:                         TypeConversion
  /// CHECK-NOT:                     TypeConversion

  /// CHECK-START: int Main.$noinline$testConversion4(TestClass, int) load_store_elimination (after)
  /// CHECK-NOT:                     InstanceFieldGet

  // Test moving type conversion when needed with loop.
  static int $noinline$testConversion4(TestClass obj, int x) {
    int tmp = x;
    obj.i = x;
    for (int i = 0; i < x; ++i) {
      obj.b = (byte) i;
      obj.i = obj.b;
      tmp = (byte) i;
    }
    return obj.i + tmp;
  }

  /// CHECK-START: void Main.testFinalizable() load_store_elimination (before)
  /// CHECK: NewInstance
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldSet

  /// CHECK-START: void Main.testFinalizable() load_store_elimination (after)
  /// CHECK: NewInstance
  /// CHECK: InstanceFieldSet
  /// CHECK-NOT: InstanceFieldSet

  // Allocations of finalizable objects cannot be eliminated.
  static void testFinalizable() {
    Finalizable finalizable = new Finalizable();
    finalizable.i = Finalizable.VALUE2;
    finalizable.i = Finalizable.VALUE1;
  }

  static java.lang.ref.WeakReference<Object> getWeakReference() {
    return new java.lang.ref.WeakReference<>(new Object());
  }

  static void testFinalizableByForcingGc() {
    testFinalizable();
    java.lang.ref.WeakReference<Object> reference = getWeakReference();

    Runtime runtime = Runtime.getRuntime();
    for (int i = 0; i < 20; ++i) {
      runtime.gc();
      System.runFinalization();
      try {
        Thread.sleep(1);
      } catch (InterruptedException e) {
        throw new AssertionError(e);
      }

      // Check to see if the weak reference has been garbage collected.
      if (reference.get() == null) {
        // A little bit more sleep time to make sure.
        try {
          Thread.sleep(100);
        } catch (InterruptedException e) {
          throw new AssertionError(e);
        }
        if (!Finalizable.sVisited) {
          System.out.println("finalize() not called.");
        }
        return;
      }
    }
    System.out.println("testFinalizableByForcingGc() failed to force gc.");
  }

  /// CHECK-START: void Main.testFinalizable() load_store_elimination (before)
  /// CHECK: NewInstance
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldSet

  /// CHECK-START: void Main.testFinalizableWithLoop() load_store_elimination (after)
  /// CHECK: NewInstance
  /// CHECK: InstanceFieldSet
  /// CHECK-NOT: InstanceFieldSet

  // Allocations of finalizable objects cannot be eliminated.
  static void testFinalizableWithLoop() {
    for (int i = 0; i < 1000; ++i) {
      Finalizable finalizable = new Finalizable();
      finalizable.i = Finalizable.VALUE2;
      finalizable.i = Finalizable.VALUE1;
    }
  }

  static void testFinalizableWithLoopByForcingGc() {
    testFinalizableWithLoop();
    java.lang.ref.WeakReference<Object> reference = getWeakReference();

    Runtime runtime = Runtime.getRuntime();
    for (int i = 0; i < 20; ++i) {
      runtime.gc();
      System.runFinalization();
      try {
        Thread.sleep(1);
      } catch (InterruptedException e) {
        throw new AssertionError(e);
      }

      // Check to see if the weak reference has been garbage collected.
      if (reference.get() == null) {
        // A little bit more sleep time to make sure.
        try {
          Thread.sleep(100);
        } catch (InterruptedException e) {
          throw new AssertionError(e);
        }
        if (!Finalizable.sVisited) {
          System.out.println("finalize() not called.");
        }
        return;
      }
    }
    System.out.println("testFinalizableWithLoopByForcingGc() failed to force gc.");
  }

  /// CHECK-START: int Main.$noinline$testHSelect(boolean) load_store_elimination (before)
  /// CHECK: InstanceFieldSet
  /// CHECK: Select

  /// CHECK-START: int Main.$noinline$testHSelect(boolean) load_store_elimination (after)
  /// CHECK: InstanceFieldSet
  /// CHECK: Select

  // Test that HSelect creates alias.
  static int $noinline$testHSelect(boolean b) {
    TestClass obj = new TestClass();
    TestClass obj2 = null;
    obj.i = 0xdead;
    if (b) {
      obj2 = obj;
    }
    return obj2.i;
  }

  static int sumWithFilter(int[] array, Filter f) {
    int sum = 0;
    for (int i = 0; i < array.length; i++) {
      if (f.isValid(array[i])) {
        sum += array[i];
      }
    }
    return sum;
  }

  /// CHECK-START: int Main.sumWithinRange(int[], int, int) load_store_elimination (before)
  /// CHECK-DAG: NewInstance
  /// CHECK-DAG: InstanceFieldSet
  /// CHECK-DAG: InstanceFieldSet
  /// CHECK-DAG: InstanceFieldGet
  /// CHECK-DAG: InstanceFieldGet

  /// CHECK-START: int Main.sumWithinRange(int[], int, int) load_store_elimination (after)
  /// CHECK-NOT: NewInstance
  /// CHECK-NOT: InstanceFieldSet
  /// CHECK-NOT: InstanceFieldGet

  // A lambda-style allocation can be eliminated after inlining.
  static int sumWithinRange(int[] array, final int low, final int high) {
    Filter filter = new Filter() {
      public boolean isValid(int i) {
        return (i >= low) && (i <= high);
      }
    };
    return sumWithFilter(array, filter);
  }

  private static int mI = 0;
  private static float mF = 0f;

  /// CHECK-START: float Main.testAllocationEliminationWithLoops() load_store_elimination (before)
  /// CHECK: NewInstance
  /// CHECK: NewInstance
  /// CHECK: NewInstance

  /// CHECK-START: float Main.testAllocationEliminationWithLoops() load_store_elimination (after)
  /// CHECK-NOT: NewInstance

  private static float testAllocationEliminationWithLoops() {
    for (int i0 = 0; i0 < 5; i0++) {
      for (int i1 = 0; i1 < 5; i1++) {
        for (int i2 = 0; i2 < 5; i2++) {
          int lI0 = ((intnew Integer(((intnew Integer(mI))));
          if (((booleannew Boolean(false))) {
            for (int i3 = 576 - 1; i3 >= 0; i3--) {
              mF -= 976981405.0f;
            }
          }
        }
      }
    }
    return 1.0f;
  }

  /// CHECK-START: TestClass2 Main.testStoreStore() load_store_elimination (before)
  /// CHECK: NewInstance
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldSet

  /// CHECK-START: TestClass2 Main.testStoreStore() load_store_elimination (after)
  /// CHECK: NewInstance
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldSet
  /// CHECK-NOT: InstanceFieldSet

  private static TestClass2 testStoreStore() {
    TestClass2 obj = new TestClass2();
    obj.i = 41;
    obj.j = 42;
    obj.i = 41;
    obj.j = 43;
    return obj;
  }

  /// CHECK-START: void Main.testStoreStore2(TestClass2) load_store_elimination (before)
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldSet

  /// CHECK-START: void Main.testStoreStore2(TestClass2) load_store_elimination (after)
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldSet
  /// CHECK-NOT: InstanceFieldSet

  private static void testStoreStore2(TestClass2 obj) {
    obj.i = 41;
    obj.j = 42;
    obj.i = 43;
    obj.j = 44;
  }

  /// CHECK-START: void Main.testStoreStore3(TestClass2, boolean) load_store_elimination (before)
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldSet

  /// CHECK-START: void Main.testStoreStore3(TestClass2, boolean) load_store_elimination (after)
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldSet
  /// CHECK-NOT: InstanceFieldSet

  /// CHECK-START: void Main.testStoreStore3(TestClass2, boolean) load_store_elimination (after)
  /// CHECK-NOT: Phi

  private static void testStoreStore3(TestClass2 obj, boolean flag) {
    obj.i = 41;
    obj.j = 42;    // redundant since it's overwritten in both branches below.
    if (flag) {
      obj.j = 43;
    } else {
      obj.j = 44;
    }
  }

  /// CHECK-START: void Main.testStoreStore4() load_store_elimination (before)
  /// CHECK: StaticFieldSet
  /// CHECK: StaticFieldSet

  /// CHECK-START: void Main.testStoreStore4() load_store_elimination (after)
  /// CHECK: StaticFieldSet
  /// CHECK-NOT: StaticFieldSet

  private static void testStoreStore4() {
    TestClass.si = 61;
    TestClass.si = 62;
  }

  /// CHECK-START: int Main.testStoreStore5(TestClass2, TestClass2) load_store_elimination (before)
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldGet
  /// CHECK: InstanceFieldSet

  /// CHECK-START: int Main.testStoreStore5(TestClass2, TestClass2) load_store_elimination (after)
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldGet
  /// CHECK: InstanceFieldSet

  private static int testStoreStore5(TestClass2 obj1, TestClass2 obj2) {
    obj1.i = 71;      // This store is needed since obj2.i may load from it.
    int i = obj2.i;
    obj1.i = 72;
    return i;
  }

  /// CHECK-START: int Main.testStoreStore6(TestClass2, TestClass2) load_store_elimination (before)
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldGet
  /// CHECK: InstanceFieldSet

  /// CHECK-START: int Main.testStoreStore6(TestClass2, TestClass2) load_store_elimination (after)
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldGet
  /// CHECK: InstanceFieldSet

  private static int testStoreStore6(TestClass2 obj1, TestClass2 obj2) {
    obj1.i = 81// Even though the value in `obj1.i` will be overridden below, this store is needed
                 // since obj2.j has a NullCheck and can throw.
    int j = obj2.j;
    obj1.i = 82;
    return j;
  }

  /// CHECK-START: int Main.testNoSideEffects(int[]) load_store_elimination (before)
  /// CHECK: ArraySet
  /// CHECK: ArraySet
  /// CHECK: ArraySet
  /// CHECK: ArrayGet

  /// CHECK-START: int Main.testNoSideEffects(int[]) load_store_elimination (after)
  /// CHECK: ArraySet
  /// CHECK: ArraySet
  /// CHECK-NOT: ArraySet
  /// CHECK-NOT: ArrayGet

  private static int testNoSideEffects(int[] array) {
    array[0] = 101;
    array[1] = 102;
    int bitCount = Integer.bitCount(0x3456);
    array[1] = 103;
    return array[0] + bitCount;
  }

  /// CHECK-START: void Main.testThrow(TestClass2, java.lang.Exception) load_store_elimination (before)
  /// CHECK: InstanceFieldSet
  /// CHECK: Throw

  /// CHECK-START: void Main.testThrow(TestClass2, java.lang.Exception) load_store_elimination (after)
  /// CHECK: InstanceFieldSet
  /// CHECK: Throw

  // Make sure throw keeps the store.
  private static void testThrow(TestClass2 obj, Exception e) throws Exception {
    obj.i = 55;
    throw e;
  }

  /// CHECK-START: int Main.testStoreStoreWithDeoptimize(int[]) load_store_elimination (before)
  /// CHECK: NewInstance
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldSet
  /// CHECK: Deoptimize
  /// CHECK: ArraySet
  /// CHECK: ArraySet
  /// CHECK: ArraySet
  /// CHECK: ArraySet
  /// CHECK: ArrayGet
  /// CHECK: ArrayGet
  /// CHECK: ArrayGet
  /// CHECK: ArrayGet

  /// CHECK-START: int Main.testStoreStoreWithDeoptimize(int[]) load_store_elimination (after)
  /// CHECK: NewInstance
  /// CHECK: InstanceFieldSet
  /// CHECK: InstanceFieldSet
  /// CHECK-NOT: InstanceFieldSet
  /// CHECK: Deoptimize
  /// CHECK: ArraySet
  /// CHECK: ArraySet
  /// CHECK: ArraySet
  /// CHECK: ArraySet
  /// CHECK-NOT: ArrayGet

  private static int testStoreStoreWithDeoptimize(int[] arr) {
    TestClass2 obj = new TestClass2();
    obj.i = 41;
    obj.j = 42;
    obj.i = 41;
    obj.j = 43;
    arr[0] = 1;  // One HDeoptimize here.
    arr[1] = 1;
    arr[2] = 1;
    arr[3] = 1;
    return arr[0] + arr[1] + arr[2] + arr[3];
  }

  /// CHECK-START: double Main.getCircleArea(double, boolean) load_store_elimination (before)
  /// CHECK: NewInstance

  /// CHECK-START: double Main.getCircleArea(double, boolean) load_store_elimination (after)
  /// CHECK-NOT: NewInstance

  private static double getCircleArea(double radius, boolean b) {
    double area = 0d;
    if (b) {
      area = new Circle(radius).getArea();
    }
    return area;
  }

  /// CHECK-START: double Main.testDeoptimize(int[], double[], double) load_store_elimination (before)
  /// CHECK: Deoptimize
  /// CHECK: NewInstance
  /// CHECK: Deoptimize
  /// CHECK: NewInstance

  /// CHECK-START: double Main.testDeoptimize(int[], double[], double) load_store_elimination (after)
  /// CHECK: Deoptimize
  /// CHECK: NewInstance
  /// CHECK: Deoptimize
  /// CHECK-NOT: NewInstance

  private static double testDeoptimize(int[] iarr, double[] darr, double radius) {
    iarr[0] = 1;  // One HDeoptimize here. Not triggered.
    iarr[1] = 1;
    Circle circle1 = new Circle(radius);
    iarr[2] = 1;
    darr[0] = circle1.getRadius();  // One HDeoptimize here, which holds circle1 live. Triggered.
    darr[1] = circle1.getRadius();
    darr[2] = circle1.getRadius();
    darr[3] = circle1.getRadius();
    return new Circle(Math.PI).getArea();
  }

  /// CHECK-START: int Main.testAllocationEliminationOfArray1() load_store_elimination (before)
  /// CHECK: NewArray
  /// CHECK: ArraySet
  /// CHECK: ArraySet
  /// CHECK: ArrayGet
  /// CHECK: ArrayGet
  /// CHECK: ArrayGet
  /// CHECK: ArrayGet

  /// CHECK-START: int Main.testAllocationEliminationOfArray1() load_store_elimination (after)
  /// CHECK-NOT: NewArray
  /// CHECK-NOT: ArraySet
  /// CHECK-NOT: ArrayGet
  private static int testAllocationEliminationOfArray1() {
    int[] array = new int[4];
    array[2] = 4;
    array[3] = 7;
    return array[0] + array[1] + array[2] + array[3];
  }

  /// CHECK-START: int Main.testAllocationEliminationOfArray2() load_store_elimination (before)
  /// CHECK: NewArray
  /// CHECK: ArraySet
  /// CHECK: ArraySet
  /// CHECK: ArrayGet

  /// CHECK-START-{ARM64,X86,X86_64}: int Main.testAllocationEliminationOfArray2() load_store_elimination (after)
  /// CHECK-NOT: NewArray
  /// CHECK-NOT: ArraySet
  /// CHECK-NOT: ArraySet
  /// CHECK-NOT: ArrayGet

  // The loop optimization doesn't happen in ARM which leads to LSE not being able to optimize this
  // case.
  /// CHECK-START-ARM: int Main.testAllocationEliminationOfArray2() load_store_elimination (after)
  /// CHECK: NewArray
  /// CHECK: ArraySet
  /// CHECK: ArraySet
  /// CHECK: ArrayGet
  private static int testAllocationEliminationOfArray2() {
    // Array can be eliminated because LSE can reduce the array accesses into
    // integer constants.
    int[] array = new int[3];
    array[1] = 4;
    array[2] = 7;
    int sum = 0;
    for (int e : array) {
      sum += e;
    }
    return sum;
  }

  /// CHECK-START: int Main.testAllocationEliminationOfArray3(int) load_store_elimination (before)
  /// CHECK: NewArray
  /// CHECK: ArraySet
  /// CHECK: ArrayGet

  /// CHECK-START: int Main.testAllocationEliminationOfArray3(int) load_store_elimination (after)
  /// CHECK-NOT: NewArray
  /// CHECK-NOT: ArraySet
  /// CHECK-NOT: ArrayGet
  private static int testAllocationEliminationOfArray3(int i) {
    int[] array = new int[4];
    array[i] = 4;
    return array[i];
  }

  /// CHECK-START: int Main.testAllocationEliminationOfArray4(int) load_store_elimination (before)
  /// CHECK: NewArray
  /// CHECK: ArraySet
  /// CHECK: ArraySet
  /// CHECK: ArrayGet
  /// CHECK: ArrayGet

  /// CHECK-START: int Main.testAllocationEliminationOfArray4(int) load_store_elimination (after)
  /// CHECK: NewArray
  /// CHECK: ArraySet
  /// CHECK: ArraySet
  /// CHECK: ArrayGet
  /// CHECK-NOT: ArrayGet
  private static int testAllocationEliminationOfArray4(int i) {
    // Cannot eliminate array allocation due to index aliasing between 1 and i.
    int[] array = new int[4];
    array[1] = 2;
    array[i] = 4;
    return array[1] + array[i];
  }

  /// CHECK-START: int Main.testAllocationEliminationOfArray5(int) load_store_elimination (before)
  /// CHECK: NewArray
  /// CHECK: ArraySet
  /// CHECK: ArrayGet

  /// CHECK-START: int Main.testAllocationEliminationOfArray5(int) load_store_elimination (after)
  /// CHECK: NewArray
  /// CHECK-NOT: ArraySet
  /// CHECK-NOT: ArrayGet
  private static int testAllocationEliminationOfArray5(int i) {
    // Cannot eliminate array allocation due to unknown i that may
    // cause NegativeArraySizeException.
    int[] array = new int[i];
    array[1] = 12;
    return array[1];
  }

  /// CHECK-START: int Main.testAllocationEliminationOfArray6(boolean) load_store_elimination (before)
  /// CHECK: NewArray
  /// CHECK: ArraySet
  /// CHECK: ArraySet
  /// CHECK: ArrayGet

  /// CHECK-START: int Main.testAllocationEliminationOfArray6(boolean) load_store_elimination (after)
  /// CHECK: NewArray
  /// CHECK: ArraySet
  /// CHECK: ArraySet
  /// CHECK: ArrayGet
  private static int testAllocationEliminationOfArray6(boolean prevent_loop_opt) {
    // Cannot eliminate array allocation since array is accessed with non-constant
    // index (only 3 elements to prevent vectorization of the reduction).
    int[] array = new int[3];
    array[1] = 4;
    array[2] = 7;
    int sum = 0;
    for (int e : array) {
      sum += e;

      // Prevent the loop from being optimized away before LSE. This should
      // never be false.
      if (!prevent_loop_opt) {
        return -1;
      }
    }
    return sum;
  }

  /// CHECK-START: int Main.testExitMerge(boolean) load_store_elimination (before)
  /// CHECK-DAG: NewInstance
  /// CHECK-DAG: InstanceFieldSet field_name:TestClass.i
  /// CHECK-DAG: InstanceFieldGet field_name:TestClass.i
  /// CHECK-DAG: Return
  /// CHECK-DAG: InstanceFieldSet field_name:TestClass.i
  /// CHECK-DAG: Throw

  /// CHECK-START: int Main.testExitMerge(boolean) load_store_elimination (after)
  /// CHECK-DAG: Return
  /// CHECK-DAG: Throw

  /// CHECK-START: int Main.testExitMerge(boolean) load_store_elimination (after)
  /// CHECK-NOT: InstanceFieldSet field_name:TestClass.i
  /// CHECK-NOT: InstanceFieldGet field_name:TestClass.i

  /// CHECK-START: int Main.testExitMerge(boolean) load_store_elimination (after)
  /// CHECK: NewInstance
  /// CHECK-NOT: NewInstance
  private static int testExitMerge(boolean cond) {
    TestClass obj = new TestClass();
    if (cond) {
      obj.i = 1;
      return obj.i + 1;
    } else {
      obj.i = 2;
      throw new Error();  // Note: We have a NewInstance here.
    }
  }

  /// CHECK-START: int Main.testExitMerge2(boolean) load_store_elimination (before)
  /// CHECK-DAG: NewInstance
  /// CHECK-DAG: InstanceFieldSet
  /// CHECK-DAG: InstanceFieldGet
  /// CHECK-DAG: InstanceFieldSet
  /// CHECK-DAG: InstanceFieldGet

  /// CHECK-START: int Main.testExitMerge2(boolean) load_store_elimination (after)
  /// CHECK-NOT: NewInstance
  /// CHECK-NOT: InstanceFieldSet
  /// CHECK-NOT: InstanceFieldGet
  private static int testExitMerge2(boolean cond) {
    TestClass obj = new TestClass();
    int res;
    if (cond) {
      obj.i = 1;
      res = obj.i + 1;
    } else {
      obj.i = 2;
      res = obj.j + 2;
    }
    return res;
  }

  /// CHECK-START: void Main.testStoreSameValue() load_store_elimination (before)
  /// CHECK: NewArray
  /// CHECK: ArrayGet
  /// CHECK: ArraySet

  /// CHECK-START: void Main.testStoreSameValue() load_store_elimination (after)
  /// CHECK: NewArray
  /// CHECK-NOT: ArrayGet
  /// CHECK-NOT: ArraySet
  private static void testStoreSameValue() {
    Object[] array = new Object[2];
    sArray = array;
    Object obj = array[0];
    array[1] = obj;    // Store the same value as the default value.
  }

  /// CHECK-START: int Main.$noinline$testByteArrayDefaultValue() load_store_elimination (before)
  /// CHECK-DAG:                 NewArray
  /// CHECK-DAG: <<Value:b\d+>>  ArrayGet
  /// CHECK-DAG:                 Return [<<Value>>]

  /// CHECK-START: int Main.$noinline$testByteArrayDefaultValue() load_store_elimination (after)
  /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
  /// CHECK-DAG:                 Return [<<Const0>>]

  /// CHECK-START: int Main.$noinline$testByteArrayDefaultValue() load_store_elimination (after)
  /// CHECK-NOT:                 NewArray
  /// CHECK-NOT:                 ArrayGet
  /// CHECK-NOT:                 TypeConversion
  private static int $noinline$testByteArrayDefaultValue() {
    byte[] array = new byte[2];
    array[1] = 1;  // FIXME: Without any stores, LSA tells LSE not to run.
    return array[0];
  }

  static Object[] sArray;

  /// CHECK-START: int Main.testLocalArrayMerge1(boolean) load_store_elimination (before)
  /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
  /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
  /// CHECK-DAG: <<A:l\d+>>      NewArray
  /// CHECK-DAG:                 ArraySet [<<A>>,<<Const0>>,<<Const0>>]
  /// CHECK-DAG:                 ArraySet [<<A>>,<<Const0>>,<<Const1>>]
  /// CHECK-DAG:                 ArraySet [<<A>>,<<Const0>>,<<Const1>>]
  /// CHECK-DAG: <<Get:i\d+>>    ArrayGet [<<A>>,<<Const0>>]
  /// CHECK-DAG:                 Return [<<Get>>]
  //
  /// CHECK-START: int Main.testLocalArrayMerge1(boolean) load_store_elimination (after)
  /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
  /// CHECK-DAG:                 Return [<<Const1>>]
  //
  /// CHECK-START: int Main.testLocalArrayMerge1(boolean) load_store_elimination (after)
  /// CHECK-NOT:                 NewArray
  /// CHECK-NOT:                 ArraySet
  /// CHECK-NOT:                 ArrayGet
  private static int testLocalArrayMerge1(boolean x) {
    // The explicit store can be removed right away
    // since it is equivalent to the default.
    int[] a = { 0 };
    // The diamond pattern stores/load can be replaced
    // by the direct value.
    if (x) {
      a[0] = 1;
    } else {
      a[0] = 1;
    }
    return a[0];
  }

  /// CHECK-START: int Main.testLocalArrayMerge2(boolean) load_store_elimination (before)
  /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
  /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
  /// CHECK-DAG: <<Const2:i\d+>> IntConstant 2
  /// CHECK-DAG: <<Const3:i\d+>> IntConstant 3
  /// CHECK-DAG: <<A:l\d+>>      NewArray
  /// CHECK-DAG:                 ArraySet [<<A>>,<<Const0>>,<<Const1>>]
  /// CHECK-DAG:                 ArraySet [<<A>>,<<Const0>>,<<Const2>>]
  /// CHECK-DAG:                 ArraySet [<<A>>,<<Const0>>,<<Const3>>]
  /// CHECK-DAG: <<Get:i\d+>>    ArrayGet [<<A>>,<<Const0>>]
  /// CHECK-DAG:                 Return [<<Get>>]

  /// CHECK-START: int Main.testLocalArrayMerge2(boolean) load_store_elimination (after)
  /// CHECK-DAG: <<Const2:i\d+>> IntConstant 2
  /// CHECK-DAG: <<Const3:i\d+>> IntConstant 3
  /// CHECK-DAG: <<Phi:i\d+>>    Phi [<<Arg1:i\d+>>,<<Arg2:i\d+>>]
  /// CHECK-DAG:                 Return [<<Phi>>]
  /// CHECK-EVAL: set(["<<Arg1>>","<<Arg2>>"]) == set(["<<Const2>>","<<Const3>>"])

  /// CHECK-START: int Main.testLocalArrayMerge2(boolean) load_store_elimination (after)
  /// CHECK-NOT:                 NewArray
  /// CHECK-NOT:                 ArraySet
  /// CHECK-NOT:                 ArrayGet
  private static int testLocalArrayMerge2(boolean x) {
    // The explicit store can be removed eventually even
    // though it is not equivalent to the default.
    int[] a = { 1 };
    // The load after the diamond pattern is eliminated and replaced with a Phi,
    // stores are then also eliminated.
    if (x) {
      a[0] = 2;
    } else {
      a[0] = 3;
    }
    return a[0];
  }

  /// CHECK-START: int Main.testLocalArrayMerge3(boolean) load_store_elimination (before)
  /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
  /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
  /// CHECK-DAG: <<Const2:i\d+>> IntConstant 2
  /// CHECK-DAG: <<A:l\d+>>      NewArray
  /// CHECK-DAG:                 ArraySet [<<A>>,<<Const0>>,<<Const1>>]
  /// CHECK-DAG:                 ArraySet [<<A>>,<<Const0>>,<<Const2>>]
  /// CHECK-DAG: <<Get:i\d+>>    ArrayGet [<<A>>,<<Const0>>]
  /// CHECK-DAG:                 Return [<<Get>>]

  /// CHECK-START: int Main.testLocalArrayMerge3(boolean) load_store_elimination (after)
  /// CHECK-NOT:                 NewArray
  /// CHECK-NOT:                 ArraySet
  /// CHECK-NOT:                 ArrayGet
  private static int testLocalArrayMerge3(boolean x) {
    int[] a = { 1 };
    if (x) {
      a[0] = 2;
    }
    return a[0];
  }

  /// CHECK-START: int Main.testLocalArrayMerge4(boolean) load_store_elimination (before)
  /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
  /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
  /// CHECK-DAG: <<A:l\d+>>      NewArray
  /// CHECK-DAG:                 ArraySet [<<A>>,<<Const0>>,<<Const0>>]
  /// CHECK-DAG:                 ArraySet [<<A>>,<<Const0>>,<<Const1>>]
  /// CHECK-DAG:                 ArraySet [<<A>>,<<Const0>>,<<Const1>>]
  /// CHECK-DAG: <<Get1:b\d+>>   ArrayGet [<<A>>,<<Const0>>]
  /// CHECK-DAG: <<Get2:a\d+>>   ArrayGet [<<A>>,<<Const0>>]
  /// CHECK-DAG: <<Add:i\d+>>    Add [<<Get1>>,<<Get2>>]
  /// CHECK-DAG:                 Return [<<Add>>]
  //
  /// CHECK-START: int Main.testLocalArrayMerge4(boolean) load_store_elimination (after)
  /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
  /// CHECK-DAG: <<Cnv1:b\d+>>   TypeConversion [<<Const1>>]
  /// CHECK-DAG: <<Cnv2:a\d+>>   TypeConversion [<<Const1>>]
  /// CHECK-DAG: <<Add:i\d+>>    Add [<<Cnv1>>,<<Cnv2>>]
  /// CHECK-DAG:                 Return [<<Add>>]
  //
  /// CHECK-START: int Main.testLocalArrayMerge4(boolean) load_store_elimination (after)
  /// CHECK-NOT:                 NewArray
  /// CHECK-NOT:                 ArraySet
  /// CHECK-NOT:                 ArrayGet
  private static int testLocalArrayMerge4(boolean x) {
    byte[] a = { 0 };
    if (x) {
      a[0] = 1;
    } else {
      a[0] = 1;
    }
    // Differently typed (signed vs unsigned),
    // but same reference.
    return a[0] + (a[0] & 0xff);
  }

  /// CHECK-START: int Main.testLocalArrayMerge5(int[], boolean) load_store_elimination (before)
  /// CHECK:                     ArraySet
  /// CHECK:                     ArraySet
  /// CHECK:                     ArraySet

  /// CHECK-START: int Main.testLocalArrayMerge5(int[], boolean) load_store_elimination (after)
  /// CHECK-NOT:                 ArraySet

  // Test eliminating store of the same value after eliminating non-observable stores.
  private static int testLocalArrayMerge5(int[] a, boolean x) {
    int old = a[0];
    if (x) {
      a[0] = 1;
    } else {
      a[0] = 1;
    }
    // This store makes the stores above dead and they will be eliminated.
    // That makes this store unnecessary as we're storing the same value already
    // present in this location, so it shall also be eliminated.
    a[0] = old;
    return old;
  }

  /// CHECK-START: int Main.testLocalArrayMerge6(int[], boolean, boolean) load_store_elimination (before)
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArrayGet

  /// CHECK-START: int Main.testLocalArrayMerge6(int[], boolean, boolean) load_store_elimination (after)
  /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
  /// CHECK-DAG: <<Const2:i\d+>> IntConstant 2
  /// CHECK-DAG: <<Const3:i\d+>> IntConstant 3
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG: <<Sub:i\d+>>    Sub [<<Const3>>,<<Phi:i\d+>>]
  /// CHECK-DAG: <<Phi>>         Phi [<<PhiArg1:i\d+>>,<<PhiArg2:i\d+>>]
  // TODO: Due to missing flagging support in checker, this checker test is disabled.
  // Enable it when we implement flagging support or during the flag cleanup for
  // `com::android::art::rw::flags::packed_switch_simplification()`.
  // CHECK-DAG: <<Phi2:i\d+>>   Phi [<<Phi2Arg1:i\d+>>,<<Phi2Arg2:i\d+>>]
  // CHECK-EVAL: set(["<<PhiArg1>>","<<PhiArg2>>"]) == set(["<<Const1>>","<<Const2>>"])
  // CHECK-EVAL: set(["<<Phi2Arg1>>","<<Phi2Arg2>>"]) == set(["<<Phi>>","<<Sub>>"])

  /// CHECK-START: int Main.testLocalArrayMerge6(int[], boolean, boolean) load_store_elimination (after)
  /// CHECK:                     Phi
  // TODO: Due to missing flagging support in checker, this checker test is disabled.
  // Enable it when we implement flagging support or during the flag cleanup for
  // `com::android::art::rw::flags::packed_switch_simplification()`.
  // CHECK:                     Phi
  // CHECK-NOT:                 Phi

  /// CHECK-START: int Main.testLocalArrayMerge6(int[], boolean, boolean) load_store_elimination (after)
  /// CHECK-NOT:                 ArrayGet

  // Test that we create a single Phi for eliminating two loads in different blocks.
  private static int testLocalArrayMerge6(int[] a, boolean x, boolean y) {
    a[0] = 0;
    if (x) {
      a[0] = 1;
    } else {
      a[0] = 2;
    }
    // Phi for load elimination is created here.
    if (y) {
      return a[0];
    } else {
      return 3 - a[0];
    }
  }

  /// CHECK-START: int Main.testLocalArrayMerge7(int[], boolean, boolean) load_store_elimination (before)
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 ArrayGet

  /// CHECK-START: int Main.testLocalArrayMerge7(int[], boolean, boolean) load_store_elimination (after)
  /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0
  /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1
  /// CHECK-DAG: <<Const2:i\d+>> IntConstant 2
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 Return [<<Phi2:i\d+>>]
  /// CHECK-DAG: <<Phi2>>        Phi [<<Arg3:i\d+>>,<<Arg4:i\d+>>]
  /// CHECK-DAG: <<Phi1:i\d+>>   Phi [<<Arg1:i\d+>>,<<Arg2:i\d+>>]
  /// CHECK-EVAL: set(["<<Arg1>>","<<Arg2>>"]) == set(["<<Const1>>","<<Const2>>"])
  /// CHECK-EVAL: set(["<<Arg3>>","<<Arg4>>"]) == set(["<<Const0>>","<<Phi1>>"])

  /// CHECK-START: int Main.testLocalArrayMerge7(int[], boolean, boolean) load_store_elimination (after)
  /// CHECK-NOT:                 ArrayGet

  // Test Phi creation for load elimination.
  private static int testLocalArrayMerge7(int[] a, boolean x, boolean y) {
    a[1] = 0;
    if (x) {
      if (y) {
        a[0] = 1;
      } else {
        a[0] = 2;
      }
      a[1] = a[0];
    }
    return a[1];
  }

  /// CHECK-START: int Main.testLocalArrayMerge8(boolean) load_store_elimination (before)
  /// CHECK-DAG:                 NewArray
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArrayGet

  /// CHECK-START: int Main.testLocalArrayMerge8(boolean) load_store_elimination (after)
  /// CHECK-NOT:                 NewArray
  /// CHECK-NOT:                 ArraySet
  /// CHECK-NOT:                 ArrayGet

  // Test Merging default value and an identical value.
  private static int testLocalArrayMerge8(boolean x) {
    int[] a = new int[2];
    if (x) {
      a[0] = 1;  // Make sure the store below is not eliminated immediately as
                 // storing the same value already present in the heap location.
      a[0] = 0;  // Store the same value as default value to test merging with
                 // the default value from else-block.
    } else {
      // Do the same as then-block for a different heap location to avoid
      // relying on block ordering. (Test both `default+0` and `0+default`.)
      a[1] = 1;
      a[1] = 0;
    }
    return a[0] + a[1];
  }

  /// CHECK-START: void Main.$noinline$testThrowingArraySet(java.lang.Object[], java.lang.Object) load_store_elimination (before)
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 ArraySet

  /// CHECK-START: void Main.$noinline$testThrowingArraySet(java.lang.Object[], java.lang.Object) load_store_elimination (after)
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 ArraySet
  private static void $noinline$testThrowingArraySet(Object[] a, Object o) {
    Object olda0 = a[0];
    a[0] = null;
    a[1] = olda0;
    a[0] = o;
    a[1] = null;
  }

  /// CHECK-START: int Main.testLoop1(TestClass, int) load_store_elimination (before)
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldGet
  /// CHECK-DAG:                 Phi

  /// CHECK-START: int Main.testLoop1(TestClass, int) load_store_elimination (after)
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi

  /// CHECK-START: int Main.testLoop1(TestClass, int) load_store_elimination (after)
  /// CHECK-NOT:                 InstanceFieldGet

  // Test Phi creation for load elimination with loop.
  private static int testLoop1(TestClass obj, int n) {
    obj.i = 0;
    for (int i = 0; i < n; ++i) {
      obj.i = i;
    }
    return obj.i;
  }

  /// CHECK-START: int Main.testLoop2(TestClass, int) load_store_elimination (before)
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldGet
  /// CHECK-DAG:                 Phi

  /// CHECK-START: int Main.testLoop2(TestClass, int) load_store_elimination (after)
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldSet

  /// CHECK-START: int Main.testLoop2(TestClass, int) load_store_elimination (after)
  /// CHECK-NOT:                 InstanceFieldGet

  /// CHECK-START: int Main.testLoop2(TestClass, int) load_store_elimination (after)
  /// CHECK:                     Phi
  /// CHECK-NOT:                 Phi

  // Test that we do not create any Phis for load elimination when
  // the heap value was not modified in the loop.
  private static int testLoop2(TestClass obj, int n) {
    obj.i = 1;
    for (int i = 0; i < n; ++i) {
      obj.j = i;
    }
    return obj.i;
  }

  /// CHECK-START: int Main.testLoop3(TestClass, int) load_store_elimination (before)
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldGet

  /// CHECK-START: int Main.testLoop3(TestClass, int) load_store_elimination (after)
  /// CHECK:                     InstanceFieldSet
  /// CHECK-NOT:                 InstanceFieldSet

  /// CHECK-START: int Main.testLoop3(TestClass, int) load_store_elimination (after)
  /// CHECK-NOT:                 InstanceFieldGet

  // Test elimination of a store in the loop that stores the same value that was already
  // stored before the loop and eliminating the load of that value after the loop.
  private static int testLoop3(TestClass obj, int n) {
    obj.i = 1;
    for (int i = 0; i < n; ++i) {
      obj.i = 1;
    }
    return obj.i;
  }

  /// CHECK-START: int Main.testLoop4(TestClass, int) load_store_elimination (before)
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldSet

  /// CHECK-START: int Main.testLoop4(TestClass, int) load_store_elimination (after)
  /// CHECK:                     InstanceFieldSet
  /// CHECK-NOT:                 InstanceFieldSet

  /// CHECK-START: int Main.testLoop4(TestClass, int) load_store_elimination (after)
  /// CHECK-NOT:                 InstanceFieldGet

  // Test store elimination in the loop that stores the same value that was already
  // stored before the loop, without any loads of that value.
  private static int testLoop4(TestClass obj, int n) {
    obj.i = 1;
    for (int i = 0; i < n; ++i) {
      obj.i = 1;
    }
    return n;
  }

  /// CHECK-START: int Main.testLoop5(TestClass, int) load_store_elimination (before)
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldGet
  /// CHECK-DAG:                 InstanceFieldGet
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldGet

  /// CHECK-START: int Main.testLoop5(TestClass, int) load_store_elimination (after)
  /// CHECK:                     InstanceFieldSet
  /// CHECK:                     InstanceFieldSet
  /// CHECK-NOT:                 InstanceFieldSet

  /// CHECK-START: int Main.testLoop5(TestClass, int) load_store_elimination (after)
  /// CHECK-NOT:                 InstanceFieldGet

  // Test eliminating loads and stores that just shuffle the same value between
  // different heap locations.
  private static int testLoop5(TestClass obj, int n) {
    // Initialize both `obj.i` and `obj.j` to the same value and then swap these values
    // in the loop. We should be able to determine that the values are always the same.
    obj.i = n;
    obj.j = n;
    for (int i = 0; i < n; ++i) {
      if ((i & 1) != 0) {
        int tmp = obj.i;
        obj.i = obj.j;
        obj.j = tmp;
      }
    }
    return obj.i;
  }

  /// CHECK-START: int Main.testLoop6(TestClass, int) load_store_elimination (before)
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldGet
  /// CHECK-DAG:                 InstanceFieldGet
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldGet

  /// CHECK-START: int Main.testLoop6(TestClass, int) load_store_elimination (after)
  /// CHECK:                     InstanceFieldSet
  /// CHECK:                     InstanceFieldSet
  /// CHECK-NOT:                 InstanceFieldSet

  /// CHECK-START: int Main.testLoop6(TestClass, int) load_store_elimination (after)
  /// CHECK-NOT:                 InstanceFieldGet

  // Test eliminating loads and stores that just shuffle the same value between
  // different heap locations, or store the same value.
  private static int testLoop6(TestClass obj, int n) {
    // Initialize both `obj.i` and `obj.j` to the same value and then swap these values
    // in the loop or set `obj.i` to the same value. We should be able to determine
    // that the values are always the same.
    obj.i = n;
    obj.j = n;
    for (int i = 0; i < n; ++i) {
      if ((i & 1) != 0) {
        int tmp = obj.i;
        obj.i = obj.j;
        obj.j = tmp;
      } else {
        obj.i = n;
      }
    }
    return obj.i;
  }

  /// CHECK-START: int Main.testLoop7(int) load_store_elimination (before)
  /// CHECK-DAG:                 NewInstance
  /// CHECK-DAG:                 InstanceFieldGet
  /// CHECK-DAG:                 InstanceFieldGet
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldGet

  /// CHECK-START: int Main.testLoop7(int) load_store_elimination (after)
  /// CHECK-NOT:                 NewInstance
  /// CHECK-NOT:                 InstanceFieldSet
  /// CHECK-NOT:                 InstanceFieldGet

  // Test eliminating loads and stores that just shuffle the default value between
  // different heap locations, or store the same value.
  private static int testLoop7(int n) {
    // Leave both `obj.i` and `obj.j` initialized to the default value and then
    // swap these values in the loop or set some to the identical value 0.
    // We should be able to determine that the values are always the same.
    TestClass obj = new TestClass();
    for (int i = 0; i < n; ++i) {
      if ((i & 1) != 0) {
        int tmp = obj.i;
        obj.i = obj.j;
        obj.j = tmp;
      } else {
        obj.i = 0;
      }
    }
    return obj.i;
  }

  /// CHECK-START: int Main.testLoop8(int) load_store_elimination (before)
  /// CHECK-DAG:                 NewInstance
  /// CHECK-DAG:                 InstanceFieldGet
  /// CHECK-DAG:                 InstanceFieldGet
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldGet

  /// CHECK-START: int Main.testLoop8(int) load_store_elimination (after)
  /// CHECK-NOT:                 NewInstance
  /// CHECK-NOT:                 InstanceFieldSet
  /// CHECK-NOT:                 InstanceFieldGet

  /// CHECK-START: int Main.testLoop8(int) load_store_elimination (after)
  /// CHECK:                     Phi
  /// CHECK:                     Phi
  /// CHECK-NOT:                 Phi

  // Test eliminating loads and stores that just shuffle the same value between
  // different heap locations, or store the same value. The value is loaded
  // after conditionally setting a different value after the loop to test that
  // this does not cause creation of excessive Phis.
  private static int testLoop8(int n) {
    // Leave both `obj.i` and `obj.j` initialized to the default value and then
    // swap these values in the loop or set some to the identical value 0.
    // We should be able to determine that the values are always the same.
    TestClass obj = new TestClass();
    for (int i = 0; i < n; ++i) {
      if ((i & 1) != 0) {
        int tmp = obj.i;
        obj.i = obj.j;
        obj.j = tmp;
      } else {
        obj.i = 0;
      }
    }
    // Up to this point, `obj.i` is always 0 but the Phi placeholder below
    // must not be included in that determination despite using lazy search
    // for Phi placeholders triggered by the `obj.i` load below.
    if ((n & 1) == 0) {
      obj.i = 1;
    }
    return obj.i;
  }

  /// CHECK-START: int Main.testLoop9(TestClass, int) load_store_elimination (before)
  /// CHECK-DAG:                 NewInstance
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 InstanceFieldGet
  /// CHECK-DAG:                 InstanceFieldGet
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InvokeStaticOrDirect
  /// CHECK-DAG:                 InstanceFieldGet

  /// CHECK-START: int Main.testLoop9(TestClass, int) load_store_elimination (after)
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 InstanceFieldGet
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 Phi

  /// CHECK-START: int Main.testLoop9(TestClass, int) load_store_elimination (after)
  /// CHECK:                     InstanceFieldSet
  /// CHECK:                     InstanceFieldSet
  /// CHECK-NOT:                 InstanceFieldSet

  /// CHECK-START: int Main.testLoop9(TestClass, int) load_store_elimination (after)
  /// CHECK-NOT:                 NewInstance

  /// CHECK-START: int Main.testLoop9(TestClass, int) load_store_elimination (after)
  /// CHECK:                     InstanceFieldGet
  /// CHECK-NOT:                 InstanceFieldGet

  /// CHECK-START: int Main.testLoop9(TestClass, int) load_store_elimination (after)
  /// CHECK:                     Phi
  /// CHECK:                     Phi
  /// CHECK:                     Phi
  /// CHECK-NOT:                 Phi

  // Test that unknown value flowing through a loop back-edge prevents
  // elimination of a load but that load can be used as an input to a Phi
  // created to eliminate another load.
  private static int testLoop9(TestClass obj, int n) {
    TestClass obj0 = new TestClass();
    // Initialize both `obj.i` and `obj0.i` to the same value and then swap these values
    // in the loop or clobber `obj.i`. We should determine that the `obj.i` load in the
    // loop must be kept but the `obj0.i` load can be replaced by a Phi chain.
    obj0.i = n;
    obj.i = n;
    for (int i = 0; i < n; ++i) {
      if ((i & 1) != 0) {
        int tmp = obj0.i;
        obj0.i = obj.i;  // Load cannot be eliminated.
        obj.i = tmp;
      } else {
        $noinline$clobberObservables();  // Makes obj.i unknown.
      }
    }
    return obj0.i;
  }

  /// CHECK-START: int Main.testLoop10(TestClass, int) load_store_elimination (before)
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldGet
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldGet

  /// CHECK-START: int Main.testLoop10(TestClass, int) load_store_elimination (after)
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldGet
  /// CHECK-DAG:                 InstanceFieldSet

  /// CHECK-START: int Main.testLoop10(TestClass, int) load_store_elimination (after)
  /// CHECK:                     InstanceFieldGet
  /// CHECK-NOT:                 InstanceFieldGet

  // Test load elimination after finding a non-eliminated load depending
  // on loop Phi placeholder.
  private static int testLoop10(TestClass obj, int n) {
    obj.i = 1;
    for (int i = 0; i < n; ++i) {
      $noinline$clobberObservables();
    }
    int i1 = obj.i;
    obj.j = 2;  // Use write side effects to stop GVN from eliminating the load below.
    int i2 = obj.i;
    return i1 + i2;
  }

  /// CHECK-START: int Main.testLoop11(TestClass, int) load_store_elimination (before)
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldGet

  /// CHECK-START: int Main.testLoop11(TestClass, int) load_store_elimination (after)
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 Phi

  /// CHECK-START: int Main.testLoop11(TestClass, int) load_store_elimination (after)
  /// CHECK:                     Phi
  /// CHECK:                     Phi
  /// CHECK:                     Phi
  /// CHECK-NOT:                 Phi

  /// CHECK-START: int Main.testLoop11(TestClass, int) load_store_elimination (after)
  /// CHECK-NOT:                 InstanceFieldGet

  // Test load elimination creating two Phis that depend on each other.
  private static int testLoop11(TestClass obj, int n) {
    obj.i = 1;
    for (int i = 0; i < n; ++i) {
      if ((i & 1) != 0) {
        obj.i = 2;
      } else {
        obj.i = 3;
      }
      // There shall be a Phi created here for `obj.i` before the "++i".
      // This Phi and the loop Phi that shall be created for `obj.i` depend on each other.
    }
    return obj.i;
  }

  /// CHECK-START: int Main.testLoop12(TestClass, int) load_store_elimination (before)
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldGet

  /// CHECK-START: int Main.testLoop12(TestClass, int) load_store_elimination (after)
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldSet

  /// CHECK-START: int Main.testLoop12(TestClass, int) load_store_elimination (after)
  /// CHECK:                     Phi
  /// CHECK:                     Phi
  /// CHECK-NOT:                 Phi

  /// CHECK-START: int Main.testLoop12(TestClass, int) load_store_elimination (after)
  /// CHECK-NOT:                 InstanceFieldGet

  // Test load elimination creating a single Phi with more than 2 inputs.
  private static int testLoop12(TestClass obj, int n) {
    obj.i = 1;
    for (int i = 0; i < n; ) {
      // Do the loop variable increment first, so that there are back-edges
      // directly from the "then" and "else" blocks below.
      ++i;
      if ((i & 1) != 0) {
        obj.i = 2;
      } else {
        obj.i = 3;
      }
    }
    return obj.i;
  }

  /// CHECK-START: int Main.testLoop13(TestClass, int) load_store_elimination (before)
  /// CHECK-DAG:                 NewArray
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 InstanceFieldGet
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 ArrayGet

  /// CHECK-START: int Main.testLoop13(TestClass, int) load_store_elimination (after)
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 InstanceFieldGet

  /// CHECK-START: int Main.testLoop13(TestClass, int) load_store_elimination (after)
  /// CHECK-NOT:                 NewArray
  /// CHECK-NOT:                 ArrayGet
  /// CHECK-NOT:                 ArraySet

  /// CHECK-START: int Main.testLoop13(TestClass, int) load_store_elimination (after)
  /// CHECK:                     Phi
  /// CHECK:                     Phi
  /// CHECK:                     Phi
  /// CHECK:                     Phi
  /// CHECK-NOT:                 Phi

  // Test eliminating array allocation, loads and stores and creating loop Phis.
  private static int testLoop13(TestClass obj, int n) {
    int[] a = new int[3];
    for (int i = 0; i < n; ++i) {
      a[0] = a[1];
      a[1] = a[2];
      a[2] = obj.i;
    }
    return a[0];
  }

  /// CHECK-START: int Main.testLoop14(TestClass2, int) load_store_elimination (before)
  /// CHECK-DAG:                 NewArray
  /// CHECK-DAG:                 InstanceFieldSet field_name:TestClass2.i
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 InstanceFieldGet field_name:TestClass2.i
  /// CHECK-DAG:                 InstanceFieldSet field_name:TestClass2.j
  /// CHECK-DAG:                 InstanceFieldGet field_name:TestClass2.i
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 InstanceFieldSet field_name:TestClass2.k
  /// CHECK-DAG:                 InstanceFieldSet field_name:TestClass2.j
  /// CHECK-DAG:                 InstanceFieldGet field_name:TestClass2.i
  /// CHECK-DAG:                 InstanceFieldSet field_name:TestClass2.k
  /// CHECK-DAG:                 ArrayGet

  /// CHECK-START: int Main.testLoop14(TestClass2, int) load_store_elimination (after)
  /// CHECK-DAG:                 InstanceFieldSet field_name:TestClass2.i
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 InstanceFieldGet field_name:TestClass2.i
  /// CHECK-DAG:                 InstanceFieldSet field_name:TestClass2.j
  /// CHECK-DAG:                 InstanceFieldSet field_name:TestClass2.k
  /// CHECK-DAG:                 InstanceFieldSet field_name:TestClass2.j
  /// CHECK-DAG:                 InstanceFieldSet field_name:TestClass2.k

  /// CHECK-START: int Main.testLoop14(TestClass2, int) load_store_elimination (after)
  /// CHECK-NOT:                 NewArray

  /// CHECK-START: int Main.testLoop14(TestClass2, int) load_store_elimination (after)
  /// CHECK:                     InstanceFieldGet field_name:TestClass2.i
  /// CHECK-NOT:                 InstanceFieldGet field_name:TestClass2.i

  /// CHECK-START: int Main.testLoop14(TestClass2, int) load_store_elimination (after)
  /// CHECK:                     Phi
  /// CHECK:                     Phi
  /// CHECK:                     Phi
  /// CHECK:                     Phi
  /// CHECK-NOT:                 Phi

  // Test load elimination in a loop after determing that the first field load
  // (depending on loop Phi placeholder) cannot be eliminated.
  private static int testLoop14(TestClass2 obj, int n) {
    int[] a = new int[3];
    obj.i = 1;
    for (int i = 0; i < n; ++i) {
      a[0] = a[1];
      a[1] = a[2];
      int i1 = obj.i;
      obj.j = 2;  // Use write side effects to stop GVN from eliminating the load below.
      int i2 = obj.i;
      a[2] = i1;
      if ((i & 2) != 0) {
        obj.k = i2;
      } else {
        obj.j = 3;  // Use write side effects to stop GVN from eliminating the load below.
        obj.k = obj.i;
        $noinline$clobberObservables();  // Make obj.i unknown.
      }
    }
    return a[0];
  }

  /// CHECK-START: int Main.testLoop15(int) load_store_elimination (before)
  /// CHECK-DAG:                 NewArray
  /// CHECK-IF:     hasIsaFeature("sve") and os.environ.get('ART_FORCE_TRY_PREDICATED_SIMD') == 'true'
  //
  ///     CHECK-DAG:                 VecPredWhile
  ///     CHECK-DAG:                 VecStore
  //
  /// CHECK-ELSE:
  //
  ///     CHECK-DAG:                 ArraySet
  //
  /// CHECK-FI:
  //
  /// CHECK-DAG:                 ArrayGet

  /// CHECK-START: int Main.testLoop15(int) load_store_elimination (after)
  /// CHECK-DAG:                 NewArray
  /// CHECK-IF:     hasIsaFeature("sve") and os.environ.get('ART_FORCE_TRY_PREDICATED_SIMD') == 'true'
  //
  ///     CHECK-DAG:                 VecPredWhile
  ///     CHECK-DAG:                 VecStore
  //
  /// CHECK-ELSE:
  //
  ///     CHECK-DAG:                 ArraySet
  //
  /// CHECK-FI:
  //
  /// CHECK-DAG:                 ArrayGet
  // Test that aliasing array store in the loop is not eliminated
  // when a loop Phi placeholder is marked for keeping.
  private static int testLoop15(int n) {
    int[] a = new int[n + 1];
    for (int i = 0; i < n; ++i) {
      a[i] = 1;  // Cannot be eliminated due to aliasing.
    }
    return a[0];
  }

  /// CHECK-START: int Main.testLoop16(TestClass, int) load_store_elimination (before)
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldGet

  /// CHECK-START: int Main.testLoop16(TestClass, int) load_store_elimination (after)
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     InstanceFieldSet

  /// CHECK-START: int Main.testLoop16(TestClass, int) load_store_elimination (after)
  /// CHECK-NOT:                     InstanceFieldGet

  /// CHECK-START: int Main.testLoop16(TestClass, int) load_store_elimination (after)
  /// CHECK:                         Phi
  /// CHECK-NOT:                     Phi

  // Test that we match an existing loop Phi for eliminating a load.
  static int testLoop16(TestClass obj, int n) {
    obj.i = 0;
    for (int i = 0; i < n; ) {
      ++i;
      obj.i = i;
    }
    // The load is replaced by the existing Phi instead of constructing a new one.
    return obj.i;
  }

  /// CHECK-START: int Main.testLoop17(TestClass, int) load_store_elimination (before)
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     InstanceFieldGet

  /// CHECK-START: int Main.testLoop17(TestClass, int) load_store_elimination (after)
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     Phi

  /// CHECK-START: int Main.testLoop17(TestClass, int) load_store_elimination (after)
  /// CHECK-NOT:                     InstanceFieldGet

  /// CHECK-START: int Main.testLoop17(TestClass, int) load_store_elimination (after)
  /// CHECK:                         Phi
  /// CHECK:                         Phi
  /// CHECK-NOT:                     Phi

  // Test that we match an existing non-loop Phi for eliminating a load,
  // one input of the Phi being invariant across a preceding loop.
  static int testLoop17(TestClass obj, int n) {
    obj.i = 1;
    int phi = 1;
    for (int i = 0; i < n; ++i) {
      obj.j = 2;  // Unrelated.
    }
    if ((n & 1) != 0) {
      obj.i = 2;
      phi = 2;
    }
    // The load is replaced by the existing Phi instead of constructing a new one.
    return obj.i + phi;
  }

  /// CHECK-START: int Main.testLoop18(TestClass, int) load_store_elimination (before)
  /// CHECK-DAG:                     NewArray
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     ArrayGet
  /// CHECK-DAG:                     InstanceFieldSet

  /// CHECK-START: int Main.testLoop18(TestClass, int) load_store_elimination (after)
  /// CHECK-DAG:                     NewArray
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     InstanceFieldSet

  /// CHECK-START: int Main.testLoop18(TestClass, int) load_store_elimination (after)
  /// CHECK-NOT:                     ArrayGet

  // Test eliminating a load of the default value in a loop
  // with the array index being defined inside the loop.
  static int testLoop18(TestClass obj, int n) {
    // The NewArray is kept as it may throw for negative n.
    // TODO: Eliminate constructor fence even though the NewArray is kept.
    int[] a0 = new int[n];
    for (int i = 0; i < n; ++i) {
      obj.i = a0[i];
    }
    return n;
  }

  /// CHECK-START: int Main.testLoop19(TestClass, int) load_store_elimination (before)
  /// CHECK-DAG:                     NewArray
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     ArrayGet
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     ArraySet

  /// CHECK-START: int Main.testLoop19(TestClass, int) load_store_elimination (after)
  /// CHECK-DAG:                     NewArray
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     InstanceFieldSet

  /// CHECK-START: int Main.testLoop19(TestClass, int) load_store_elimination (after)
  /// CHECK-NOT:                     ArrayGet
  /// CHECK-NOT:                     ArraySet

  // Test eliminating a load of the default value and store of an identical value
  // in a loop with the array index being defined inside the loop.
  static int testLoop19(TestClass obj, int n) {
    // The NewArray is kept as it may throw for negative n.
    // TODO: Eliminate constructor fence even though the NewArray is kept.
    int[] a0 = new int[n];
    for (int i = 0; i < n; ++i) {
      obj.i = a0[i];
      a0[i] = 0;  // Store the same value as default.
    }
    return n;
  }

  /// CHECK-START: int Main.testLoop20(TestClass, int) load_store_elimination (before)
  /// CHECK-DAG:                     NewArray
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     ArrayGet
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     ArraySet

  /// CHECK-START: int Main.testLoop20(TestClass, int) load_store_elimination (after)
  /// CHECK-DAG:                     NewArray
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     InstanceFieldSet

  /// CHECK-START: int Main.testLoop20(TestClass, int) load_store_elimination (after)
  /// CHECK-NOT:                     ArrayGet
  /// CHECK-NOT:                     ArraySet

  // Test eliminating a load of the default value and a conditional store of an
  // identical value in a loop with the array index being defined inside the loop.
  static int testLoop20(TestClass obj, int n) {
    // The NewArray is kept as it may throw for negative n.
    // TODO: Eliminate constructor fence even though the NewArray is kept.
    int[] a0 = new int[n];
    for (int i = 0; i < n; ++i) {
      obj.i = a0[i];
      if ((i & 1) != 0) {
        a0[i] = 0;  // Store the same value as default.
      }
    }
    return n;
  }

  /// CHECK-START: int Main.testLoop21(TestClass, int) load_store_elimination (before)
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldGet
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldGet
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldGet
  /// CHECK-DAG:                     InstanceFieldSet

  /// CHECK-START: int Main.testLoop21(TestClass, int) load_store_elimination (before)
  /// CHECK-NOT:                     Phi

  /// CHECK-START: int Main.testLoop21(TestClass, int) load_store_elimination (after)
  /// CHECK-NOT:                     InstanceFieldGet

  /// CHECK-START: int Main.testLoop21(TestClass, int) load_store_elimination (after)
  /// CHECK:                         InstanceFieldSet
  /// CHECK:                         InstanceFieldSet
  /// CHECK:                         InstanceFieldSet
  /// CHECK-NOT:                     InstanceFieldSet

  /// CHECK-START: int Main.testLoop21(TestClass, int) load_store_elimination (after)
  /// CHECK:                         Phi
  /// CHECK-NOT:                     Phi

  // Test load elimination when an instance field is used as the loop variable.
  static int testLoop21(TestClass obj, int n) {
    for (obj.i = 0; obj.i < n; ++obj.i) {
      obj.j = 0;  // Use write side effects to stop GVN from eliminating the load below.
      obj.j = obj.i;
    }
    return n;
  }

  /// CHECK-START: int Main.testLoop22(TestClass, int) load_store_elimination (before)
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldGet
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldGet
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldGet
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldSet

  /// CHECK-START: int Main.testLoop22(TestClass, int) load_store_elimination (before)
  /// CHECK-NOT:                     Phi

  /// CHECK-START: int Main.testLoop22(TestClass, int) load_store_elimination (after)
  /// CHECK-NOT:                     InstanceFieldGet

  /// CHECK-START: int Main.testLoop22(TestClass, int) load_store_elimination (after)
  /// CHECK:                         InstanceFieldSet
  /// CHECK:                         InstanceFieldSet
  /// CHECK-NOT:                     InstanceFieldSet

  /// CHECK-START: int Main.testLoop22(TestClass, int) load_store_elimination (after)
  /// CHECK:                         Phi
  /// CHECK-NOT:                     Phi

  // Test load and store elimination when an instance field is used as the loop
  // variable and then overwritten after the loop.
  static int testLoop22(TestClass obj, int n) {
    for (obj.i = 0; obj.i < n; ++obj.i) {
      obj.j = 0;  // Use write side effects to stop GVN from eliminating the load below.
      obj.j = obj.i;
    }
    obj.i = 0;
    return n;
  }

  /// CHECK-START: int Main.testLoop23(TestClass, int) load_store_elimination (before)
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     InstanceFieldSet

  /// CHECK-START: int Main.testLoop23(TestClass, int) load_store_elimination (after)
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     InstanceFieldSet

  /// CHECK-START: int Main.testLoop23(TestClass, int) load_store_elimination (after)
  /// CHECK:                         InstanceFieldSet
  /// CHECK-NOT:                     InstanceFieldSet

  // Test elimination of non-observable stores.
  static int testLoop23(TestClass obj, int n) {
    obj.i = -1;
    int phi = -1;
    for (int i = 0; i < n; ++i) {
      obj.i = i;
      phi = i;
    }
    if ((n & 1) != 0) {
      obj.i = 2;
      phi = 2;
    }
    obj.i = phi;  // This store shall be kept, the stores above shall be eliminated.
    return phi;
  }

  /// CHECK-START: int Main.testLoop24(TestClass, int) load_store_elimination (before)
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     InstanceFieldSet

  /// CHECK-START: int Main.testLoop24(TestClass, int) load_store_elimination (after)
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     Phi

  /// CHECK-START: int Main.testLoop24(TestClass, int) load_store_elimination (after)
  /// CHECK:                         InstanceFieldSet
  /// CHECK:                         InstanceFieldSet
  /// CHECK:                         InstanceFieldSet
  /// CHECK-NOT:                     InstanceFieldSet

  // Test matching Phis for store elimination.
  static int testLoop24(TestClass obj, int n) {
    obj.i = -1;
    int phi = -1;
    for (int i = 0; i < n; ++i) {
      obj.i = i;
      phi = i;
    }
    if ((n & 1) != 0) {
      obj.i = 2;
      phi = 2;
    }
    if (n == 3) {
      return -2;  // Make the above stores observable.
    }
    // As the stores above are observable and kept, we match the merged
    // heap value with existing Phis and determine that we're storing
    // the same value that's already there, so we eliminate this store.
    obj.i = phi;
    return phi;
  }

  /// CHECK-START: int Main.testLoop25(TestClass, int) load_store_elimination (before)
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     InstanceFieldGet
  /// CHECK-DAG:                     InstanceFieldSet

  /// CHECK-START: int Main.testLoop25(TestClass, int) load_store_elimination (after)
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     InstanceFieldSet

  /// CHECK-START: int Main.testLoop25(TestClass, int) load_store_elimination (after)
  /// CHECK-NOT:                     InstanceFieldGet

  // Test that we do not match multiple dependent Phis for load and store elimination.
  static int testLoop25(TestClass obj, int n) {
    obj.i = 1;
    int phi = 1;
    for (int i = 0; i < n; ++i) {
      if ((i & 1) != 0) {
        obj.i = 2;
        phi = 2;
      }
      // There is a Phi here for the variable `phi` before the "++i".
      // This Phi and the loop Phi for `phi` depend on each other.
    }
    if (n == 3) {
      return -1;  // Make above stores observable.
    }
    // We're not matching multiple Phi placeholders to existing Phis. Therefore the load
    // below requires 2 extra Phis to be created and the store below shall not be eliminated
    // even though it stores the same value that's already present in the heap location.
    int tmp = obj.i;
    obj.i = phi;
    return tmp + phi;
  }

  /// CHECK-START: int Main.testLoop26(TestClass, int) load_store_elimination (before)
  /// CHECK-DAG:                     NewInstance
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     NewInstance
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldGet
  /// CHECK-DAG:                     InstanceFieldGet

  /// CHECK-START: int Main.testLoop26(TestClass, int) load_store_elimination (after)
  /// CHECK-DAG:                     NewInstance
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     NewInstance
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldGet

  /// CHECK-START: int Main.testLoop26(TestClass, int) load_store_elimination (after)
  /// CHECK:                         InstanceFieldGet
  /// CHECK-NOT:                     InstanceFieldGet

  // Test load elimination creating a reference Phi.
  static int testLoop26(TestClass obj, int n) {
    obj.next = new TestClass(12);
    for (int i = 0; i < n; ++i) {
      obj.next = new SubTestClass();
    }
    return obj.next.i;
  }

  /// CHECK-START: int Main.testLoop27(TestClass, int) load_store_elimination (before)
  /// CHECK-DAG:                     NewInstance
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     NewInstance
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldGet
  /// CHECK-DAG:                     InstanceFieldGet

  /// CHECK-START: int Main.testLoop27(TestClass, int) load_store_elimination (after)
  /// CHECK-DAG:                     NewInstance
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     NewInstance
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     InstanceFieldGet

  /// CHECK-START: int Main.testLoop27(TestClass, int) load_store_elimination (after)
  /// CHECK:                         InstanceFieldGet
  /// CHECK-NOT:                     InstanceFieldGet

  // Test load elimination creating two reference Phis that depend on each other.
  static int testLoop27(TestClass obj, int n) {
    obj.next = new TestClass(12);
    for (int i = 0; i < n; ++i) {
      if ((i & 1) != 0) {
        obj.next = new SubTestClass();
      }
      // There shall be a Phi created here for `obj.next` before the "++i".
      // This Phi and the loop Phi that shall be created for `obj.next` depend on each other.
    }
    return obj.next.i;
  }

  /// CHECK-START: int Main.testLoop28(TestClass, int) load_store_elimination (before)
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 NewArray
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 InstanceFieldGet
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 ArrayGet

  /// CHECK-START: int Main.testLoop28(TestClass, int) load_store_elimination (after)
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 InstanceFieldGet

  /// CHECK-START: int Main.testLoop28(TestClass, int) load_store_elimination (after)
  /// CHECK-NOT:                 NewArray
  /// CHECK-NOT:                 ArrayGet
  /// CHECK-NOT:                 ArraySet

  /// CHECK-START: int Main.testLoop28(TestClass, int) load_store_elimination (after)
  /// CHECK:                     Phi
  /// CHECK:                     Phi
  /// CHECK:                     Phi
  /// CHECK:                     Phi
  /// CHECK-NOT:                 Phi

  // Test eliminating array allocation, loads and stores and creating loop Phis
  // after determining that a field load depending on loop Phi placeholder cannot
  // be eliminated.
  private static int testLoop28(TestClass obj, int n) {
    obj.i = 1;
    int[] a = new int[3];
    for (int i = 0; i < n; ++i) {
      a[0] = a[1];
      a[1] = a[2];
      a[2] = obj.i;
      $noinline$clobberObservables();
    }
    return a[0];
  }

  /// CHECK-START: int Main.testLoop29(int) load_store_elimination (before)
  /// CHECK-DAG:                 NewArray
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArraySet

  /// CHECK-START: int Main.testLoop29(int) load_store_elimination (after)
  /// CHECK-DAG:                 NewArray
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArraySet

  // Test that ArraySet with non-default value prevents matching ArrayGet for
  // the same array to default value even when the ArraySet is using an index
  // offset by one, making LSA declare that the two heap locations do not alias.
  private static int testLoop29(int n) {
    int[] a = new int[4];
    int sum = 0;
    for (int i = 0; i < n; ) {
      int value = a[i] + 1;
      sum += value;
      ++i;
      a[i] = value;
    }
    return sum;
  }

  /// CHECK-START: int Main.testLoop30(int) load_store_elimination (before)
  /// CHECK-DAG:                 NewArray
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArraySet

  /// CHECK-START: int Main.testLoop30(int) load_store_elimination (after)
  /// CHECK-NOT:                 ArrayGet
  /// CHECK-NOT:                 ArraySet

  // Test that ArraySet with default value does not prevent matching ArrayGet
  // for the same array to the default value.
  private static int testLoop30(int n) {
    int[] a = new int[4];  // NewArray is kept due to environment use by Deoptimize.
    int sum = 0;
    for (int i = 0; i < n; ) {
      int value = a[i] + 1;
      sum += value;
      ++i;
      a[i] = 0;
    }
    return sum;
  }

  /// CHECK-START: int Main.testLoop31(int) load_store_elimination (before)
  /// CHECK-DAG:                 NewArray
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArraySet

  /// CHECK-START: int Main.testLoop31(int) load_store_elimination (after)
  /// CHECK-NOT:                 ArrayGet
  /// CHECK-NOT:                 ArraySet

  // Test that ArraySet with default value read from the array does not
  // prevent matching ArrayGet for the same array to the default value.
  private static int testLoop31(int n) {
    int[] a = new int[4];  // NewArray is kept due to environment use by Deoptimize.
    int sum = 0;
    for (int i = 0; i < n; ) {
      int value = a[i];
      sum += value;
      ++i;
      a[i] = value;
    }
    return sum;
  }

  /// CHECK-START: int Main.testLoop32(TestClass, int) load_store_elimination (before)
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     InstanceFieldSet

  /// CHECK-START: int Main.testLoop32(TestClass, int) load_store_elimination (after)
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     Phi
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     InstanceFieldSet
  /// CHECK-DAG:                     Phi

  /// CHECK-START: int Main.testLoop32(TestClass, int) load_store_elimination (after)
  /// CHECK:                         InstanceFieldSet
  /// CHECK:                         InstanceFieldSet
  /// CHECK:                         InstanceFieldSet
  /// CHECK-NOT:                     InstanceFieldSet

  // Test matching Phis for store elimination.
  static int testLoop32(TestClass obj, int n) {
    obj.i = -1;
    int phi = -1;
    for (int i = 0; i < n; ) {
      ++i;
      if ((i & 1) != 0) {
        obj.i = i;
        phi = i;
      }
    }
    if ((n & 1) != 0) {
      obj.i = 2;
      phi = 2;
    }
    if (n == 3) {
      return -2;  // Make the above stores observable.
    }
    // As the stores above are observable and kept, we match the merged
    // heap value with existing Phis and determine that we're storing
    // the same value that's already there, so we eliminate this store.
    obj.i = phi;
    return phi;
  }

  // CHECK-START: int Main.testLoop33(TestClass, int) load_store_elimination (before)
  // CHECK-DAG:                     InstanceFieldSet
  // CHECK-DAG:                     NewArray
  // CHECK-DAG:                     Phi
  // CHECK-DAG:                     ArrayGet
  // CHECK-DAG:                     InstanceFieldSet
  // CHECK-DAG:                     Phi
  // CHECK-DAG:                     ArrayGet
  // CHECK-DAG:                     InstanceFieldGet
  // CHECK-DAG:                     InstanceFieldSet
  // CHECK-DAG:                     InstanceFieldGet

  // CHECK-START: int Main.testLoop33(TestClass, int) load_store_elimination (after)
  // CHECK-DAG:                     InstanceFieldSet
  // CHECK-DAG:                     Phi
  // CHECK-DAG:                     InstanceFieldSet
  // CHECK-DAG:                     Phi
  // CHECK-DAG:                     InstanceFieldGet
  // CHECK-DAG:                     InstanceFieldSet
  // CHECK-DAG:                     InstanceFieldGet

  // CHECK-START: int Main.testLoop33(TestClass, int) load_store_elimination (after)
  // CHECK-NOT:                     ArrayGet

  // Test that when processing Phi placeholder with unknown input, we allow materialized
  // default value in pre-header for array location with index defined in the loop.
  static int testLoop33(TestClass obj, int n) {
    obj.i = 0;
    int[] a0 = new int[n];
    for (int i = 0; i < n; ++i) {
      obj.i = a0[i];
      $noinline$clobberObservables();  // Make `obj.i` unknown.
    }
    for (int i = 0; i < n; ++i) {
      int zero = a0[i];
      int unknown = obj.i;
      obj.j += zero + unknown;
    }
    return obj.j;
  }

  /// CHECK-START: int Main.testLoop34(int) load_store_elimination (before)
  /// CHECK-DAG:                 NewArray
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArraySet

  /// CHECK-START: int Main.testLoop34(int) load_store_elimination (after)
  /// CHECK-DAG:                 NewArray
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArraySet

  // Test that ArraySet with non-default value prevents matching ArrayGet for
  // the same array to default value even when the ArraySet is using an index
  // offset by one, making LSA declare that the two heap locations do not alias.
  // Also test that the ArraySet is not eliminated.
  private static int testLoop34(int n) {
    int[] a = new int[n + 1];
    int sum = 0;
    for (int i = 0; i < n; ) {
      int value = a[i] + 1;
      sum += value;
      ++i;
      a[i] = value;
    }
    return sum;
  }

  /// CHECK-START: int Main.testLoop35(int) load_store_elimination (before)
  /// CHECK-DAG:                 NewArray
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 ArraySet

  /// CHECK-START: int Main.testLoop35(int) load_store_elimination (after)
  /// CHECK-DAG:                 NewArray
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArraySet

  /// CHECK-START: int Main.testLoop35(int) load_store_elimination (after)
  /// CHECK:                     ArraySet
  /// CHECK-NOT:                 ArraySet

  // Test that ArraySet with non-default value prevents matching ArrayGet for
  // the same array to default value even when the ArraySet is using an index
  // offset by one, making LSA declare that the two heap locations do not alias.
  // Also test that the ArraySet is not eliminated and that a store after the
  // loop is eliminated.
  private static int testLoop35(int n) {
    int[] a = new int[n + 1];
    int sum = 0;
    for (int i = 0; i < n; ) {
      int value = a[i] + 1;
      sum += value;
      ++i;
      a[i] = value;
    }
    a[0] = 1;
    return sum;
  }

  /// CHECK-START: int Main.testLoop36(int) load_store_elimination (before)
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 Deoptimize
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArrayGet

  /// CHECK-START: int Main.testLoop36(int) load_store_elimination (before)
  /// CHECK-NOT:                 BoundsCheck

  /// CHECK-START: int Main.testLoop36(int) load_store_elimination (after)
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 Deoptimize
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArrayGet

  // Regression test for b/187487955.
  // We previously failed a DCHECK() during the search for kept stores when
  // we encountered two array locations for the same array and considered
  // non-aliasing by LSA when only one of the array locations had index
  // defined inside the loop. Note that this situation requires that BCE
  // eliminates BoundsCheck instructions, otherwise LSA considers those
  // locations aliasing.
  private static int testLoop36(int n) {
    int[] a = new int[n];
    int zero = 0;
    int i = 0;
    for (; i < n; ++i) {
      a[i] = i;
      // Extra instructions to avoid loop unrolling.
      zero = (((zero ^ 1) + 2) ^ 1) - 2;
      zero = (((zero ^ 4) + 8) ^ 4) - 8;
    }
    // Use 4 loads with consecutive fixed offsets from the loop Phi for `i`.
    // BCE shall replace BoundsChecks with Deoptimize, so that indexes here are
    // the Phi plus/minus a constant, something that LSA considers non-aliasing
    // with the Phi (LSA does not take different loop iterations into account)
    // but LSE must consider aliasing across dfferent loop iterations.
    return a[i - 1] + a[i - 2] + a[i - 3] + a[i - 4] + zero;
  }

  /// CHECK-START: int Main.testLoop37(int) load_store_elimination (before)
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 Deoptimize
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArrayGet

  /// CHECK-START: int Main.testLoop37(int) load_store_elimination (before)
  /// CHECK-NOT:                 BoundsCheck

  /// CHECK-START: int Main.testLoop37(int) load_store_elimination (after)
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 Deoptimize
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArrayGet

  // Similar to testLoop36 but the writes are done via a different reference to the same array.
  // We previously used a reference comparison for back-edge aliasing analysis but this test
  // has different references and therefore needs `HeapLocationCollector::CanReferencesAlias()`.
  private static int testLoop37(int n) {
    int[] a = new int[n];
    int[] b = $noinline$returnArg(a);
    int zero = 0;
    int i = 0;
    for (; i < n; ++i) {
      b[i] = i;
      // Extra instructions to avoid loop unrolling.
      zero = (((zero ^ 1) + 2) ^ 1) - 2;
      zero = (((zero ^ 4) + 8) ^ 4) - 8;
    }
    // Use 4 loads with consecutive fixed offsets from the loop Phi for `i`.
    // BCE shall replace BoundsChecks with Deoptimize, so that indexes here are
    // the Phi plus/minus a constant, something that LSA considers non-aliasing
    // with the Phi (LSA does not take different loop iterations into account)
    // but LSE must consider aliasing across dfferent loop iterations.
    return a[i - 1] + a[i - 2] + a[i - 3] + a[i - 4] + zero;
  }

  private static int[] $noinline$returnArg(int[] a) {
    return a;
  }

  /// CHECK-START: int Main.testLoop38(int, int[]) load_store_elimination (before)
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 Deoptimize
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArrayGet

  /// CHECK-START: int Main.testLoop38(int, int[]) load_store_elimination (before)
  /// CHECK-NOT:                 BoundsCheck

  /// CHECK-START: int Main.testLoop38(int, int[]) load_store_elimination (after)
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 Deoptimize

  /// CHECK-START: int Main.testLoop38(int, int[]) load_store_elimination (after)
  /// CHECK-NOT:                 ArrayGet

  // Similar to testLoop37 but writing to a different array that exists before allocating `a`,
  // so that `HeapLocationCollector::CanReferencesAlias()` returns false and all the ArrayGet
  // instructions are actually eliminated.
  private static int testLoop38(int n, int[] b) {
    int[] a = new int[n];
    int zero = 0;
    int i = 0;
    for (; i < n; ++i) {
      b[i] = i;
      // Extra instructions to avoid loop unrolling.
      zero = (((zero ^ 1) + 2) ^ 1) - 2;
      zero = (((zero ^ 4) + 8) ^ 4) - 8;
    }
    // Use 4 loads with consecutive fixed offsets from the loop Phi for `i`.
    // BCE shall replace BoundsChecks with Deoptimize, so that indexes here are
    // the Phi plus/minus a constant, something that LSA considers non-aliasing
    // with the Phi (LSA does not take different loop iterations into account)
    // but LSE must consider aliasing across dfferent loop iterations.
    return a[i - 1] + a[i - 2] + a[i - 3] + a[i - 4] + zero;
  }

  /// CHECK-START: int Main.testNestedLoop1(TestClass, int) load_store_elimination (before)
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldGet

  /// CHECK-START: int Main.testNestedLoop1(TestClass, int) load_store_elimination (after)
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldGet

  // Test heap value clobbering in nested loop.
  private static int testNestedLoop1(TestClass obj, int n) {
    obj.i = 1;
    for (int i = 0; i < n; ++i) {
      for (int j = i + 1; j < n; ++j) {
        $noinline$clobberObservables();
      }
    }
    return obj.i;
  }

  /// CHECK-START: int Main.testNestedLoop2(TestClass, int) load_store_elimination (before)
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 InstanceFieldGet
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldGet

  /// CHECK-START: int Main.testNestedLoop2(TestClass, int) load_store_elimination (after)
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 InstanceFieldGet
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 InstanceFieldSet

  /// CHECK-START: int Main.testNestedLoop2(TestClass, int) load_store_elimination (after)
  /// CHECK:                     InstanceFieldGet
  /// CHECK-NOT:                 InstanceFieldGet

  /// CHECK-START: int Main.testNestedLoop2(TestClass, int) load_store_elimination (after)
  /// CHECK:                     Phi
  /// CHECK:                     Phi
  /// CHECK:                     Phi
  /// CHECK-NOT:                 Phi

  // Test heap value clobbering in the nested loop and load elimination for a heap
  // location then set to known value before the end of the outer loop.
  private static int testNestedLoop2(TestClass obj, int n) {
    obj.i = 1;
    obj.j = 2;
    for (int i = 0; i < n; ++i) {
      int tmp = obj.j;
      for (int j = i + 1; j < n; ++j) {
        $noinline$clobberObservables();
      }
      obj.i = tmp;
    }
    return obj.i;
  }

  /// CHECK-START: int Main.testNestedLoop3(TestClass, int) load_store_elimination (before)
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 InstanceFieldGet
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldGet

  /// CHECK-START: int Main.testNestedLoop3(TestClass, int) load_store_elimination (after)
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 InstanceFieldGet
  /// CHECK-DAG:                 InstanceFieldSet

  /// CHECK-START: int Main.testNestedLoop3(TestClass, int) load_store_elimination (after)
  /// CHECK:                     InstanceFieldGet
  /// CHECK-NOT:                 InstanceFieldGet

  /// CHECK-START: int Main.testNestedLoop3(TestClass, int) load_store_elimination (after)
  /// CHECK:                     Phi
  /// CHECK:                     Phi
  /// CHECK:                     Phi
  /// CHECK-NOT:                 Phi

  // Test heap value clobbering in the nested loop and load elimination for a heap
  // location then set to known value before the end of the outer loop.
  private static int testNestedLoop3(TestClass obj, int n) {
    obj.i = 1;
    for (int i = 0; i < n; ++i) {
      obj.j = 2;
      for (int j = i + 1; j < n; ++j) {
        $noinline$clobberObservables();
      }
      obj.i = obj.j;
    }
    return obj.i;
  }

  /// CHECK-START: int Main.testNestedLoop4(TestClass, int) load_store_elimination (before)
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldGet

  /// CHECK-START: int Main.testNestedLoop4(TestClass, int) load_store_elimination (after)
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 InstanceFieldSet

  /// CHECK-START: int Main.testNestedLoop4(TestClass, int) load_store_elimination (after)
  /// CHECK-NOT:                 InstanceFieldGet

  /// CHECK-START: int Main.testNestedLoop4(TestClass, int) load_store_elimination (after)
  /// CHECK:                     Phi
  /// CHECK:                     Phi
  /// CHECK:                     Phi
  /// CHECK:                     Phi
  /// CHECK-NOT:                 Phi

  // Test creating loop Phis for both inner and outer loop to eliminate a load.
  private static int testNestedLoop4(TestClass obj, int n) {
    obj.i = 1;
    for (int i = 0; i < n; ++i) {
      for (int j = i + 1; j < n; ++j) {
        obj.i = 2;
      }
    }
    return obj.i;
  }

  /// CHECK-START: int Main.testNestedLoop5(TestClass, int) load_store_elimination (before)
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldGet

  /// CHECK-START: int Main.testNestedLoop5(TestClass, int) load_store_elimination (after)
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 InstanceFieldSet

  /// CHECK-START: int Main.testNestedLoop5(TestClass, int) load_store_elimination (after)
  /// CHECK-NOT:                 InstanceFieldGet

  /// CHECK-START: int Main.testNestedLoop5(TestClass, int) load_store_elimination (after)
  /// CHECK:                     Phi
  /// CHECK:                     Phi
  /// CHECK:                     Phi
  /// CHECK-NOT:                 Phi

  // Test creating a loop Phi for outer loop to eliminate a load.
  private static int testNestedLoop5(TestClass obj, int n) {
    obj.i = 1;
    for (int i = 0; i < n; ++i) {
      obj.i = 2;
      for (int j = i + 1; j < n; ++j) {
        obj.j = 3;  // Unrelated.
      }
    }
    return obj.i;
  }

  /// CHECK-START: int Main.testNestedLoop6(TestClass, int) load_store_elimination (before)
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 InstanceFieldGet
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldGet

  /// CHECK-START: int Main.testNestedLoop6(TestClass, int) load_store_elimination (after)
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 InstanceFieldGet
  /// CHECK-DAG:                 InstanceFieldSet

  /// CHECK-START: int Main.testNestedLoop6(TestClass, int) load_store_elimination (after)
  /// CHECK:                     InstanceFieldGet
  /// CHECK-NOT:                 InstanceFieldGet

  /// CHECK-START: int Main.testNestedLoop6(TestClass, int) load_store_elimination (after)
  /// CHECK:                     Phi
  /// CHECK:                     Phi
  /// CHECK:                     Phi
  /// CHECK:                     Phi
  /// CHECK-NOT:                 Phi

  // Test heap value clobbering in the nested loop and load elimination for a heap
  // location then set to known value before the end of that inner loop.
  private static int testNestedLoop6(TestClass obj, int n) {
    obj.i = 1;
    obj.j = 2;
    for (int i = 0; i < n; ++i) {
      for (int j = i + 1; j < n; ++j) {
        int tmp = obj.j;
        $noinline$clobberObservables();
        obj.i = tmp;
      }
    }
    return obj.i;
  }

  /// CHECK-START: int Main.testNestedLoop7(TestClass, int) load_store_elimination (before)
  /// CHECK-DAG:                 NewArray
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 InstanceFieldSet

  /// CHECK-START: int Main.testNestedLoop7(TestClass, int) load_store_elimination (after)
  /// CHECK-DAG:                 NewArray
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 InstanceFieldSet

  /// CHECK-START: int Main.testNestedLoop7(TestClass, int) load_store_elimination (after)
  /// CHECK-NOT:                 ArrayGet

  // Test load elimination in inner loop reading default value that is loop invariant
  // with an index defined inside the inner loop.
  private static int testNestedLoop7(TestClass obj, int n) {
    // The NewArray is kept as it may throw for negative n.
    // TODO: Eliminate constructor fence even though the NewArray is kept.
    int[] a0 = new int[n];
    for (int i = 0; i < n; ++i) {
      for (int j = i + 1; j < n; ++j) {
        obj.i = a0[j];
      }
    }
    return n;
  }

  /// CHECK-START: int Main.testNestedLoop8(TestClass, int) load_store_elimination (before)
  /// CHECK-DAG:                 NewInstance
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 NewInstance
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldGet
  /// CHECK-DAG:                 InstanceFieldGet

  /// CHECK-START: int Main.testNestedLoop8(TestClass, int) load_store_elimination (after)
  /// CHECK-DAG:                 NewInstance
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 Phi
  /// CHECK-DAG:                 NewInstance
  /// CHECK-DAG:                 InstanceFieldSet
  /// CHECK-DAG:                 InstanceFieldGet

  /// CHECK-START: int Main.testNestedLoop8(TestClass, int) load_store_elimination (after)
  /// CHECK:                     InstanceFieldGet
  /// CHECK-NOT:                 InstanceFieldGet

  // Test reference type propagation for Phis created for outer and inner loop.
  private static int testNestedLoop8(TestClass obj, int n) {
    obj.next = new SubTestClass();
    for (int i = 0; i < n; ++i) {
      for (int j = i + 1; j < n; ++j) {
        obj.next = new TestClass();
      }
    }
    // The Phis created in both loop headers for replacing `obj.next` depend on each other.
    return obj.next.i;
  }


  /// CHECK-START: long Main.testOverlapLoop(int) load_store_elimination (before)
  /// CHECK-DAG:                 NewArray
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 If
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 Goto

  /// CHECK-START: long Main.testOverlapLoop(int) load_store_elimination (after)
  /// CHECK-DAG:                 NewArray
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 If
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArrayGet
  /// CHECK-DAG:                 ArraySet
  /// CHECK-DAG:                 Goto
  /// CHECK-NOT:                 ArrayGet

  // Test that we don't incorrectly remove writes needed by later loop iterations
  // NB This is fibonacci numbers
  private static long testOverlapLoop(int cnt) {
    long[] w = new long[cnt];
    w[1] = 1;
    long t = 1;
    for (int i = 2; i < cnt; ++i) {
      w[i] = w[i - 1] + w[i - 2];
      t = w[i];
    }
    return t;
  }

  private static boolean $noinline$getBoolean(boolean val) {
    return val;
  }

  /// CHECK-START: int Main.$noinline$testPartialEscape1(TestClass, boolean) load_store_elimination (before)
  /// CHECK-DAG:     ParameterValue
  /// CHECK-DAG:     NewInstance
  /// CHECK-DAG:     InvokeStaticOrDirect
  /// CHECK-DAG:     InstanceFieldSet
  /// CHECK-DAG:     InvokeStaticOrDirect
  /// CHECK-DAG:     InstanceFieldGet
  /// CHECK-DAG:     InstanceFieldGet
  /// CHECK-DAG:     InstanceFieldSet
  /// CHECK-DAG:     InstanceFieldGet
  /// CHECK-DAG:     InstanceFieldGet
  /// CHECK-DAG:     Phi
  //
  /// CHECK-NOT:     NewInstance
  /// CHECK-NOT:     InvokeStaticOrDirect
  /// CHECK-NOT:     InstanceFieldSet
  /// CHECK-NOT:     InstanceFieldGet
  //
  /// CHECK-START: int Main.$noinline$testPartialEscape1(TestClass, boolean) load_store_elimination (after)
  /// CHECK-DAG:     ParameterValue
  /// CHECK-DAG:     NewInstance
  /// CHECK-DAG:     Phi
  //
  /// CHECK-START: int Main.$noinline$testPartialEscape1(TestClass, boolean) load_store_elimination (after)
  /// CHECK:         InvokeStaticOrDirect
  /// CHECK:         InvokeStaticOrDirect
  //
  /// CHECK-NOT:     InvokeStaticOrDirect

  /// CHECK-START: int Main.$noinline$testPartialEscape1(TestClass, boolean) load_store_elimination (after)
  /// CHECK:         InstanceFieldSet
  //
  // TODO: We should be able to remove this setter by realizing `i` only escapes in a branch.
  /// CHECK:         InstanceFieldSet
  /// CHECK-NOT:     InstanceFieldSet
  //
  /// CHECK-START: int Main.$noinline$testPartialEscape1(TestClass, boolean) load_store_elimination (after)
  /// CHECK:         InstanceFieldGet
  /// CHECK:         InstanceFieldGet
  /// CHECK:         InstanceFieldGet
  //
  /// CHECK-NOT:     InstanceFieldGet
  private static int $noinline$testPartialEscape1(TestClass obj, boolean escape) {
    TestClass i = new SubTestClass();
    int res;
    if ($noinline$getBoolean(escape)) {
      i.next = obj;
      $noinline$Escape(i);
      res = i.next.i;
    } else {
      i.next = obj;
      res = i.next.i;
    }
    return res;
  }

  private static void $noinline$clobberObservables() {}

  static void assertLongEquals(long result, long expected) {
    if (expected != result) {
      throw new Error("Expected: " + expected + ", found: " + result);
    }
  }

  static void assertIntEquals(int result, int expected) {
    if (expected != result) {
      throw new Error("Expected: " + expected + ", found: " + result);
    }
  }

  static void assertFloatEquals(float result, float expected) {
    if (expected != result) {
      throw new Error("Expected: " + expected + ", found: " + result);
    }
  }

  static void assertDoubleEquals(double result, double expected) {
    if (expected != result) {
      throw new Error("Expected: " + expected + ", found: " + result);
    }
  }

  public static void main(String[] args) {
    assertDoubleEquals(Math.PI * Math.PI * Math.PI, calcCircleArea(Math.PI));
    assertIntEquals(test1(new TestClass(), new TestClass()), 3);
    assertIntEquals(test2(new TestClass()), 1);
    TestClass obj1 = new TestClass();
    TestClass obj2 = new TestClass();
    obj1.next = obj2;
    assertIntEquals(test3(obj1), 10);
    assertIntEquals(test4(new TestClass(), true), 1);
    assertIntEquals(test4(new TestClass(), false), 1);
    assertIntEquals(test5(new TestClass(), true), 1);
    assertIntEquals(test5(new TestClass(), false), 2);
    assertIntEquals(test6(new TestClass(), new TestClass(), true), 4);
    assertIntEquals(test6(new TestClass(), new TestClass(), false), 2);
    assertIntEquals(test7(new TestClass()), 1);
    assertIntEquals(test8(), 1);
    obj1 = new TestClass();
    obj2 = new TestClass();
    obj1.next = obj2;
    assertIntEquals(test9(new TestClass()), 1);
    assertIntEquals(test10(new TestClass(34)), 3);
    assertIntEquals(TestClass.si, 3);
    assertIntEquals(test11(new TestClass()), 10);
    assertIntEquals(test12(new TestClass(), new TestClass()), 10);
    assertIntEquals(test13(new TestClass(), new TestClass2()), 3);
    SubTestClass obj3 = new SubTestClass();
    assertIntEquals(test14(obj3, obj3), 2);
    assertIntEquals(test15(), 2);
    assertIntEquals(test16(), 3);
    assertIntEquals(test17(), 0);
    assertIntEquals(test18(new TestClass()), 1);
    float[] fa1 = { 0.8f };
    float[] fa2 = { 1.8f };
    assertFloatEquals(test19(fa1, fa2), 1.8f);
    assertFloatEquals(test20().i, 0);
    test21(new TestClass());
    assertIntEquals(test22(), 13);
    assertIntEquals(test23(true), 4);
    assertIntEquals(test23(false), 5);
    assertFloatEquals(test24(), 8.0f);
    assertIntEquals(test25(falsetruetrue), 5);
    assertIntEquals(test25(truefalsetrue), 2);
    assertFloatEquals(test26(5), 0.0f);
    assertFloatEquals(test26(3), 1.0f);
    assertIntEquals(test27(falsetrue), 1);
    assertIntEquals(test27(truefalse), 1);
    assertIntEquals(test28(falsetrue), 0);
    assertIntEquals(test28(truetrue), 5);
    assertFloatEquals(test29(true), 5.0f);
    assertFloatEquals(test29(false), 2.0f);
    assertIntEquals(test30(new TestClass(), true), 1);
    assertIntEquals(test30(new TestClass(), false), 0);
    assertIntEquals(test31(truetrue), 5);
    assertIntEquals(test31(truefalse), 6);
    assertIntEquals(test32(1), 10);
    assertIntEquals(test32(2), 10);
    assertIntEquals(test33(new TestClass(), true), 1);
    assertIntEquals(test33(new TestClass(), false), 2);
    assertIntEquals(test34(new TestClass(), truetrue), 3);
    assertIntEquals(test34(new TestClass(), falsetrue), 4);
    assertIntEquals(test34(new TestClass(), truefalse), 1);
    assertIntEquals(test34(new TestClass(), falsefalse), 2);
    assertIntEquals(test35(new TestClass(), truetrue), 3);
    assertIntEquals(test35(new TestClass(), falsetrue), 2);
    assertIntEquals(test35(new TestClass(), truefalse), 1);
    assertIntEquals(test35(new TestClass(), falsefalse), 2);
    assertIntEquals(test36(new TestClass(), true), 2);
    assertIntEquals(test36(new TestClass(), false), 4);
    assertIntEquals(test37(new TestClass(), true), 1);
    assertIntEquals(test37(new TestClass(), false), 0);
    assertIntEquals(test38(new TestClass(), true), 1);
    assertIntEquals(test38(new TestClass(), false), 2);
    assertIntEquals(test39(new TestClass(), true), 0);
    assertIntEquals(test39(new TestClass(), false), 1);
    assertIntEquals(test40(), 150);

    testFinalizableByForcingGc();
    testFinalizableWithLoopByForcingGc();
    assertIntEquals($noinline$testHSelect(true), 0xdead);
    int[] array = {259, -1, -31084};
    assertIntEquals(sumWithinRange(array, 15), 11);
    assertFloatEquals(testAllocationEliminationWithLoops(), 1.0f);
    assertFloatEquals(mF, 0f);
    assertDoubleEquals(Math.PI * Math.PI * Math.PI, getCircleArea(Math.PI, true));
    assertDoubleEquals(0d, getCircleArea(Math.PI, false));

    assertIntEquals($noinline$testConversion1(new TestClass(), 300), 300);
    assertIntEquals($noinline$testConversion1(new TestClass(), 301), 45);
    assertIntEquals($noinline$testConversion2(new TestClass(), 300), 300);
    assertIntEquals($noinline$testConversion2(new TestClass(), 301), 90);
    assertIntEquals($noinline$testConversion3(new TestClass(), 0), 0);
    assertIntEquals($noinline$testConversion3(new TestClass(), 1), 0);
    assertIntEquals($noinline$testConversion3(new TestClass(), 128), 127);
    assertIntEquals($noinline$testConversion3(new TestClass(), 129), -128);
    assertIntEquals($noinline$testConversion4(new TestClass(), 0), 0);
    assertIntEquals($noinline$testConversion4(new TestClass(), 1), 0);
    assertIntEquals($noinline$testConversion4(new TestClass(), 128), 254);
    assertIntEquals($noinline$testConversion4(new TestClass(), 129), -256);

    int[] iarray = {000};
    double[] darray = {0d, 0d, 0d};
    try {
      assertDoubleEquals(Math.PI * Math.PI * Math.PI, testDeoptimize(iarray, darray, Math.PI));
    } catch (Exception e) {
      System.out.println(e.getClass().getName());
    }
    assertIntEquals(iarray[0], 1);
    assertIntEquals(iarray[1], 1);
    assertIntEquals(iarray[2], 1);
    assertDoubleEquals(darray[0], Math.PI);
    assertDoubleEquals(darray[1], Math.PI);
    assertDoubleEquals(darray[2], Math.PI);

    assertIntEquals(testAllocationEliminationOfArray1(), 11);
    assertIntEquals(testAllocationEliminationOfArray2(), 11);
    assertIntEquals(testAllocationEliminationOfArray3(2), 4);
    assertIntEquals(testAllocationEliminationOfArray4(2), 6);
    assertIntEquals(testAllocationEliminationOfArray5(2), 12);
    try {
      testAllocationEliminationOfArray5(-2);
    } catch (NegativeArraySizeException e) {
      System.out.println("Got NegativeArraySizeException.");
    }
    assertIntEquals(testAllocationEliminationOfArray6(true), 11);

    assertIntEquals(testStoreStore().i, 41);
    assertIntEquals(testStoreStore().j, 43);

    assertIntEquals(testExitMerge(true), 2);
    assertIntEquals(testExitMerge2(true), 2);
    assertIntEquals(testExitMerge2(false), 2);

    TestClass2 testclass2 = new TestClass2();
    testStoreStore2(testclass2);
    assertIntEquals(testclass2.i, 43);
    assertIntEquals(testclass2.j, 44);

    testStoreStore3(testclass2, true);
    assertIntEquals(testclass2.i, 41);
    assertIntEquals(testclass2.j, 43);
    testStoreStore3(testclass2, false);
    assertIntEquals(testclass2.i, 41);
    assertIntEquals(testclass2.j, 44);

    testStoreStore4();
    assertIntEquals(TestClass.si, 62);

    int ret = testStoreStore5(testclass2, testclass2);
    assertIntEquals(testclass2.i, 72);
    assertIntEquals(ret, 71);

    testclass2.j = 88;
    ret = testStoreStore6(testclass2, testclass2);
    assertIntEquals(testclass2.i, 82);
    assertIntEquals(ret, 88);

    ret = testNoSideEffects(iarray);
    assertIntEquals(iarray[0], 101);
    assertIntEquals(iarray[1], 103);
    assertIntEquals(ret, 108);

    try {
      testThrow(testclass2, new Exception());
    } catch (Exception e) {}
    assertIntEquals(testclass2.i, 55);

    assertIntEquals(testStoreStoreWithDeoptimize(new int[4]), 4);

    assertIntEquals($noinline$testByteArrayDefaultValue(), 0);

    assertIntEquals(testLocalArrayMerge1(true), 1);
    assertIntEquals(testLocalArrayMerge1(false), 1);
    assertIntEquals(testLocalArrayMerge2(true), 2);
    assertIntEquals(testLocalArrayMerge2(false), 3);
    assertIntEquals(testLocalArrayMerge3(true), 2);
    assertIntEquals(testLocalArrayMerge3(false), 1);
    assertIntEquals(testLocalArrayMerge4(true), 2);
    assertIntEquals(testLocalArrayMerge4(false), 2);
    assertIntEquals(testLocalArrayMerge5(new int[]{ 7 }, true), 7);
    assertIntEquals(testLocalArrayMerge5(new int[]{ 9 }, false), 9);
    assertIntEquals(testLocalArrayMerge6(new int[1], truetrue), 1);
    assertIntEquals(testLocalArrayMerge6(new int[1], truefalse), 2);
    assertIntEquals(testLocalArrayMerge6(new int[1], falsetrue), 2);
    assertIntEquals(testLocalArrayMerge6(new int[1], falsefalse), 1);
    assertIntEquals(testLocalArrayMerge7(new int[2], truetrue), 1);
    assertIntEquals(testLocalArrayMerge7(new int[2], truefalse), 2);
    assertIntEquals(testLocalArrayMerge7(new int[2], falsetrue), 0);
    assertIntEquals(testLocalArrayMerge7(new int[2], falsefalse), 0);
    assertIntEquals(testLocalArrayMerge8(true), 0);
    assertIntEquals(testLocalArrayMerge8(false), 0);

    TestClass[] tca = new TestClass[] { new TestClass(), null };
    try {
      $noinline$testThrowingArraySet(tca, new TestClass2());
    } catch (ArrayStoreException expected) {
      if (tca[0] != null) {
        throw new Error("tca[0] is not null");
      }
      if (tca[1] == null) {
        throw new Error("tca[1] is null");
      }
    }

    assertIntEquals(testLoop1(new TestClass(), 0), 0);
    assertIntEquals(testLoop1(new TestClass(), 1), 0);
    assertIntEquals(testLoop1(new TestClass(), 2), 1);
    assertIntEquals(testLoop1(new TestClass(), 3), 2);
    assertIntEquals(testLoop2(new TestClass(), 0), 1);
    assertIntEquals(testLoop2(new TestClass(), 1), 1);
    assertIntEquals(testLoop2(new TestClass(), 2), 1);
    assertIntEquals(testLoop2(new TestClass(), 3), 1);
    assertIntEquals(testLoop3(new TestClass(), 0), 1);
    assertIntEquals(testLoop3(new TestClass(), 1), 1);
    assertIntEquals(testLoop3(new TestClass(), 2), 1);
    assertIntEquals(testLoop3(new TestClass(), 3), 1);
    assertIntEquals(testLoop4(new TestClass(), 0), 0);
    assertIntEquals(testLoop4(new TestClass(), 1), 1);
    assertIntEquals(testLoop4(new TestClass(), 2), 2);
    assertIntEquals(testLoop4(new TestClass(), 3), 3);
    assertIntEquals(testLoop5(new TestClass(), 0), 0);
    assertIntEquals(testLoop5(new TestClass(), 1), 1);
    assertIntEquals(testLoop5(new TestClass(), 2), 2);
    assertIntEquals(testLoop5(new TestClass(), 3), 3);
    assertIntEquals(testLoop6(new TestClass(), 0), 0);
    assertIntEquals(testLoop6(new TestClass(), 1), 1);
    assertIntEquals(testLoop6(new TestClass(), 2), 2);
    assertIntEquals(testLoop6(new TestClass(), 3), 3);
    assertIntEquals(testLoop7(0), 0);
    assertIntEquals(testLoop7(1), 0);
    assertIntEquals(testLoop7(2), 0);
    assertIntEquals(testLoop7(3), 0);
    assertIntEquals(testLoop8(0), 1);
    assertIntEquals(testLoop8(1), 0);
    assertIntEquals(testLoop8(2), 1);
    assertIntEquals(testLoop8(3), 0);
    assertIntEquals(testLoop9(new TestClass(), 0), 0);
    assertIntEquals(testLoop9(new TestClass(), 1), 1);
    assertIntEquals(testLoop9(new TestClass(), 2), 2);
    assertIntEquals(testLoop9(new TestClass(), 3), 3);
    assertIntEquals(testLoop10(new TestClass(), 0), 2);
    assertIntEquals(testLoop10(new TestClass(), 1), 2);
    assertIntEquals(testLoop10(new TestClass(), 2), 2);
    assertIntEquals(testLoop10(new TestClass(), 3), 2);
    assertIntEquals(testLoop11(new TestClass(), 0), 1);
    assertIntEquals(testLoop11(new TestClass(), 1), 3);
    assertIntEquals(testLoop11(new TestClass(), 2), 2);
    assertIntEquals(testLoop11(new TestClass(), 3), 3);
    assertIntEquals(testLoop12(new TestClass(), 0), 1);
    assertIntEquals(testLoop12(new TestClass(), 1), 2);
    assertIntEquals(testLoop12(new TestClass(), 2), 3);
    assertIntEquals(testLoop12(new TestClass(), 3), 2);
    assertIntEquals(testLoop13(new TestClass(12), 0), 0);
    assertIntEquals(testLoop13(new TestClass(12), 1), 0);
    assertIntEquals(testLoop13(new TestClass(12), 2), 0);
    assertIntEquals(testLoop13(new TestClass(12), 3), 1);
    assertIntEquals(testLoop14(new TestClass2(), 0), 0);
    assertIntEquals(testLoop14(new TestClass2(), 1), 0);
    assertIntEquals(testLoop14(new TestClass2(), 2), 0);
    assertIntEquals(testLoop14(new TestClass2(), 3), 1);
    assertIntEquals(testLoop15(0), 0);
    assertIntEquals(testLoop15(1), 1);
    assertIntEquals(testLoop15(2), 1);
    assertIntEquals(testLoop15(3), 1);
    assertIntEquals(testLoop16(new TestClass(), 0), 0);
    assertIntEquals(testLoop16(new TestClass(), 1), 1);
    assertIntEquals(testLoop16(new TestClass(), 2), 2);
    assertIntEquals(testLoop16(new TestClass(), 3), 3);
    assertIntEquals(testLoop17(new TestClass(), 0), 2);
    assertIntEquals(testLoop17(new TestClass(), 1), 4);
    assertIntEquals(testLoop17(new TestClass(), 2), 2);
    assertIntEquals(testLoop17(new TestClass(), 3), 4);
    assertIntEquals(testLoop18(new TestClass(), 0), 0);
    assertIntEquals(testLoop18(new TestClass(), 1), 1);
    assertIntEquals(testLoop18(new TestClass(), 2), 2);
    assertIntEquals(testLoop18(new TestClass(), 3), 3);
    assertIntEquals(testLoop19(new TestClass(), 0), 0);
    assertIntEquals(testLoop19(new TestClass(), 1), 1);
    assertIntEquals(testLoop19(new TestClass(), 2), 2);
    assertIntEquals(testLoop19(new TestClass(), 3), 3);
    assertIntEquals(testLoop20(new TestClass(), 0), 0);
    assertIntEquals(testLoop20(new TestClass(), 1), 1);
    assertIntEquals(testLoop20(new TestClass(), 2), 2);
    assertIntEquals(testLoop20(new TestClass(), 3), 3);
    assertIntEquals(testLoop21(new TestClass(), 0), 0);
    assertIntEquals(testLoop21(new TestClass(), 1), 1);
    assertIntEquals(testLoop21(new TestClass(), 2), 2);
    assertIntEquals(testLoop21(new TestClass(), 3), 3);
    assertIntEquals(testLoop22(new TestClass(), 0), 0);
    assertIntEquals(testLoop22(new TestClass(), 1), 1);
    assertIntEquals(testLoop22(new TestClass(), 2), 2);
    assertIntEquals(testLoop22(new TestClass(), 3), 3);
    assertIntEquals(testLoop23(new TestClass(), 0), -1);
    assertIntEquals(testLoop23(new TestClass(), 1), 2);
    assertIntEquals(testLoop23(new TestClass(), 2), 1);
    assertIntEquals(testLoop23(new TestClass(), 3), 2);
    assertIntEquals(testLoop24(new TestClass(), 0), -1);
    assertIntEquals(testLoop24(new TestClass(), 1), 2);
    assertIntEquals(testLoop24(new TestClass(), 2), 1);
    assertIntEquals(testLoop24(new TestClass(), 3), -2);
    assertIntEquals(testLoop25(new TestClass(), 0), 2);
    assertIntEquals(testLoop25(new TestClass(), 1), 2);
    assertIntEquals(testLoop25(new TestClass(), 2), 4);
    assertIntEquals(testLoop25(new TestClass(), 3), -1);
    assertIntEquals(testLoop26(new TestClass(), 0), 1);
    assertIntEquals(testLoop26(new TestClass(), 1), 0);
    assertIntEquals(testLoop26(new TestClass(), 2), 0);
    assertIntEquals(testLoop26(new TestClass(), 3), 0);
    assertIntEquals(testLoop27(new TestClass(), 0), 1);
    assertIntEquals(testLoop27(new TestClass(), 1), 1);
    assertIntEquals(testLoop27(new TestClass(), 2), 0);
    assertIntEquals(testLoop27(new TestClass(), 3), 0);
    assertIntEquals(testLoop28(new TestClass(12), 0), 0);
    assertIntEquals(testLoop28(new TestClass(12), 1), 0);
    assertIntEquals(testLoop28(new TestClass(12), 2), 0);
    assertIntEquals(testLoop28(new TestClass(12), 3), 1);
    assertIntEquals(testLoop29(0), 0);
    assertIntEquals(testLoop29(1), 1);
    assertIntEquals(testLoop29(2), 3);
    assertIntEquals(testLoop29(3), 6);
    assertIntEquals(testLoop30(0), 0);
    assertIntEquals(testLoop30(1), 1);
    assertIntEquals(testLoop30(2), 2);
    assertIntEquals(testLoop30(3), 3);
    assertIntEquals(testLoop31(0), 0);
    assertIntEquals(testLoop31(1), 0);
    assertIntEquals(testLoop31(2), 0);
    assertIntEquals(testLoop31(3), 0);
    assertIntEquals(testLoop32(new TestClass(), 0), -1);
    assertIntEquals(testLoop32(new TestClass(), 1), 2);
    assertIntEquals(testLoop32(new TestClass(), 2), 1);
    assertIntEquals(testLoop32(new TestClass(), 3), -2);
    assertIntEquals(testLoop33(new TestClass(), 0), 0);
    assertIntEquals(testLoop33(new TestClass(), 1), 0);
    assertIntEquals(testLoop33(new TestClass(), 2), 0);
    assertIntEquals(testLoop33(new TestClass(), 3), 0);
    assertIntEquals(testLoop34(0), 0);
    assertIntEquals(testLoop34(1), 1);
    assertIntEquals(testLoop34(2), 3);
    assertIntEquals(testLoop34(3), 6);
    assertIntEquals(testLoop35(0), 0);
    assertIntEquals(testLoop35(1), 1);
    assertIntEquals(testLoop35(2), 3);
    assertIntEquals(testLoop35(3), 6);
    assertIntEquals(testLoop36(4), 6);
    assertIntEquals(testLoop37(4), 6);
    assertIntEquals(testLoop38(4new int[4]), 0);

    assertIntEquals(testNestedLoop1(new TestClass(), 0), 1);
    assertIntEquals(testNestedLoop1(new TestClass(), 1), 1);
    assertIntEquals(testNestedLoop1(new TestClass(), 2), 1);
    assertIntEquals(testNestedLoop1(new TestClass(), 3), 1);
    assertIntEquals(testNestedLoop2(new TestClass(), 0), 1);
    assertIntEquals(testNestedLoop2(new TestClass(), 1), 2);
    assertIntEquals(testNestedLoop2(new TestClass(), 2), 2);
    assertIntEquals(testNestedLoop2(new TestClass(), 3), 2);
    assertIntEquals(testNestedLoop3(new TestClass(), 0), 1);
    assertIntEquals(testNestedLoop3(new TestClass(), 1), 2);
    assertIntEquals(testNestedLoop3(new TestClass(), 2), 2);
    assertIntEquals(testNestedLoop3(new TestClass(), 3), 2);
    assertIntEquals(testNestedLoop4(new TestClass(), 0), 1);
    assertIntEquals(testNestedLoop4(new TestClass(), 1), 1);
    assertIntEquals(testNestedLoop4(new TestClass(), 2), 2);
    assertIntEquals(testNestedLoop4(new TestClass(), 3), 2);
    assertIntEquals(testNestedLoop5(new TestClass(), 0), 1);
    assertIntEquals(testNestedLoop5(new TestClass(), 1), 2);
    assertIntEquals(testNestedLoop5(new TestClass(), 2), 2);
    assertIntEquals(testNestedLoop5(new TestClass(), 3), 2);
    assertIntEquals(testNestedLoop6(new TestClass(), 0), 1);
    assertIntEquals(testNestedLoop6(new TestClass(), 1), 1);
    assertIntEquals(testNestedLoop6(new TestClass(), 2), 2);
    assertIntEquals(testNestedLoop6(new TestClass(), 3), 2);
    assertIntEquals(testNestedLoop7(new TestClass(), 0), 0);
    assertIntEquals(testNestedLoop7(new TestClass(), 1), 1);
    assertIntEquals(testNestedLoop7(new TestClass(), 2), 2);
    assertIntEquals(testNestedLoop7(new TestClass(), 3), 3);
    assertIntEquals(testNestedLoop8(new TestClass(), 0), 0);
    assertIntEquals(testNestedLoop8(new TestClass(), 1), 0);
    assertIntEquals(testNestedLoop8(new TestClass(), 2), 0);
    assertIntEquals(testNestedLoop8(new TestClass(), 3), 0);
    assertLongEquals(testOverlapLoop(10), 34l);
    assertLongEquals(testOverlapLoop(50), 7778742049l);
    assertIntEquals($noinline$testPartialEscape1(new TestClass(), true), 1);
    assertIntEquals($noinline$testPartialEscape1(new TestClass(), false), 0);

    TypeConversions.main();
  }
}

Messung V0.5 in Prozent
C=77 H=90 G=83

¤ Dauer der Verarbeitung: 0.91 Sekunden  (vorverarbeitet am  2026-06-29) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.