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 .0 f;
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 .0 f;
double doubleField = -3 .0 d;
short shortField = -3 ;
int intField = -3 ;
byte byteField = -3 ;
long longField = -3 l;
}
class Finalizable {
static boolean sVisited = false ;
static final int VALUE1 = 0 xbeef;
static final int VALUE2 = 0 xcafe;
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 .0 f;
o.doubleField += 1 .0 d;
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(1 , 2 );
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(0 , 0 ) + str2.substring(0 , 0 ));
}
/// 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 .0 f;
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 .0 f;
break ;
case 2 :
obj.floatField = 2 .0 f;
break ;
case 3 :
obj.floatField = 1 .0 f;
break ;
default :
obj.floatField = 0 .0 f;
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 = 2 L; // 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 = 1 ; break ;
case 2 : obj.j = 1 ; break ;
case 3 : obj.k = 1 ; break ;
case 4 : obj.l = 1 ; break ;
case 5 : obj.m = 1 ; break ;
}
// 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(1 , 2 );
if (x) {
obj.next = new SubTestClass();
}
return obj.next.i;
}
private static int test40() {
int [] array = new int [1 ];
try {
$noinline$fillArrayTest40(array, 100 , 0 );
System.out.println("UNREACHABLE" );
} catch (Throwable expected) {
}
assertIntEquals(array[0 ], 1 );
try {
$noinline$fillArrayTest40(array, 100 , 1 );
System.out.println("UNREACHABLE" );
} catch (Throwable expected) {
}
assertIntEquals(array[0 ], 2 );
$noinline$fillArrayTest40(array, 100 , 2 );
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 = 0 xdead;
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 = 0 f;
/// 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 = ((int ) new Integer(((int ) new Integer(mI))));
if (((boolean ) new Boolean (false ))) {
for (int i3 = 576 - 1 ; i3 >= 0 ; i3--) {
mF -= 976981405 .0 f;
}
}
}
}
}
return 1 .0 f;
}
/// 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(0 x3456);
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 = 0 d;
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 ] & 0 xff);
}
/// 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(1 , 2 );
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(1 , 2 );
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(3 , 4 )), 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 .8 f };
float [] fa2 = { 1 .8 f };
assertFloatEquals(test19(fa1, fa2), 1 .8 f);
assertFloatEquals(test20().i, 0 );
test21(new TestClass());
assertIntEquals(test22(), 13 );
assertIntEquals(test23(true ), 4 );
assertIntEquals(test23(false ), 5 );
assertFloatEquals(test24(), 8 .0 f);
assertIntEquals(test25(false , true , true ), 5 );
assertIntEquals(test25(true , false , true ), 2 );
assertFloatEquals(test26(5 ), 0 .0 f);
assertFloatEquals(test26(3 ), 1 .0 f);
assertIntEquals(test27(false , true ), 1 );
assertIntEquals(test27(true , false ), 1 );
assertIntEquals(test28(false , true ), 0 );
assertIntEquals(test28(true , true ), 5 );
assertFloatEquals(test29(true ), 5 .0 f);
assertFloatEquals(test29(false ), 2 .0 f);
assertIntEquals(test30(new TestClass(), true ), 1 );
assertIntEquals(test30(new TestClass(), false ), 0 );
assertIntEquals(test31(true , true ), 5 );
assertIntEquals(test31(true , false ), 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(), true , true ), 3 );
assertIntEquals(test34(new TestClass(), false , true ), 4 );
assertIntEquals(test34(new TestClass(), true , false ), 1 );
assertIntEquals(test34(new TestClass(), false , false ), 2 );
assertIntEquals(test35(new TestClass(), true , true ), 3 );
assertIntEquals(test35(new TestClass(), false , true ), 2 );
assertIntEquals(test35(new TestClass(), true , false ), 1 );
assertIntEquals(test35(new TestClass(), false , false ), 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 ), 0 xdead);
int [] array = {2 , 5 , 9 , -1 , -3 , 10 , 8 , 4 };
assertIntEquals(sumWithinRange(array, 1 , 5 ), 11 );
assertFloatEquals(testAllocationEliminationWithLoops(), 1 .0 f);
assertFloatEquals(mF, 0 f);
assertDoubleEquals(Math.PI * Math.PI * Math.PI, getCircleArea(Math.PI, true ));
assertDoubleEquals(0 d, 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 = {0 , 0 , 0 };
double [] darray = {0 d, 0 d, 0 d};
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 ], true , true ), 1 );
assertIntEquals(testLocalArrayMerge6(new int [1 ], true , false ), 2 );
assertIntEquals(testLocalArrayMerge6(new int [1 ], false , true ), 2 );
assertIntEquals(testLocalArrayMerge6(new int [1 ], false , false ), 1 );
assertIntEquals(testLocalArrayMerge7(new int [2 ], true , true ), 1 );
assertIntEquals(testLocalArrayMerge7(new int [2 ], true , false ), 2 );
assertIntEquals(testLocalArrayMerge7(new int [2 ], false , true ), 0 );
assertIntEquals(testLocalArrayMerge7(new int [2 ], false , false ), 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(1 , 2 ), 0 ), 0 );
assertIntEquals(testLoop13(new TestClass(1 , 2 ), 1 ), 0 );
assertIntEquals(testLoop13(new TestClass(1 , 2 ), 2 ), 0 );
assertIntEquals(testLoop13(new TestClass(1 , 2 ), 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(1 , 2 ), 0 ), 0 );
assertIntEquals(testLoop28(new TestClass(1 , 2 ), 1 ), 0 );
assertIntEquals(testLoop28(new TestClass(1 , 2 ), 2 ), 0 );
assertIntEquals(testLoop28(new TestClass(1 , 2 ), 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(4 , new 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 ), 34 l);
assertLongEquals(testOverlapLoop(50 ), 7778742049 l);
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
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.90Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-06-29)
¤
*Eine klare Vorstellung vom Zielzustand
2026-07-09