Constant fold Equal/NotEqual between null and non-null.
Test: Add new test cases to 442-checker-constant-folding.
Test: m test-art-host
Change-Id: I14509d5e13d30a66b3c2ac3d76d514f58501c9ab
diff --git a/compiler/optimizing/constant_folding.cc b/compiler/optimizing/constant_folding.cc
index 0614945..5f39a49 100644
--- a/compiler/optimizing/constant_folding.cc
+++ b/compiler/optimizing/constant_folding.cc
@@ -47,6 +47,9 @@
private:
void VisitShift(HBinaryOperation* shift);
+ void VisitEqual(HEqual* instruction) OVERRIDE;
+ void VisitNotEqual(HNotEqual* instruction) OVERRIDE;
+
void VisitAbove(HAbove* instruction) OVERRIDE;
void VisitAboveOrEqual(HAboveOrEqual* instruction) OVERRIDE;
void VisitBelow(HBelow* instruction) OVERRIDE;
@@ -140,6 +143,30 @@
}
}
+void InstructionWithAbsorbingInputSimplifier::VisitEqual(HEqual* instruction) {
+ if ((instruction->GetLeft()->IsNullConstant() && !instruction->GetRight()->CanBeNull()) ||
+ (instruction->GetRight()->IsNullConstant() && !instruction->GetLeft()->CanBeNull())) {
+ // Replace code looking like
+ // EQUAL lhs, null
+ // where lhs cannot be null with
+ // CONSTANT false
+ instruction->ReplaceWith(GetGraph()->GetConstant(Primitive::kPrimBoolean, 0));
+ instruction->GetBlock()->RemoveInstruction(instruction);
+ }
+}
+
+void InstructionWithAbsorbingInputSimplifier::VisitNotEqual(HNotEqual* instruction) {
+ if ((instruction->GetLeft()->IsNullConstant() && !instruction->GetRight()->CanBeNull()) ||
+ (instruction->GetRight()->IsNullConstant() && !instruction->GetLeft()->CanBeNull())) {
+ // Replace code looking like
+ // NOT_EQUAL lhs, null
+ // where lhs cannot be null with
+ // CONSTANT true
+ instruction->ReplaceWith(GetGraph()->GetConstant(Primitive::kPrimBoolean, 1));
+ instruction->GetBlock()->RemoveInstruction(instruction);
+ }
+}
+
void InstructionWithAbsorbingInputSimplifier::VisitAbove(HAbove* instruction) {
if (instruction->GetLeft()->IsConstant() &&
instruction->GetLeft()->AsConstant()->IsArithmeticZero()) {
diff --git a/test/442-checker-constant-folding/src/Main.java b/test/442-checker-constant-folding/src/Main.java
index 33ef10b..64180d5 100644
--- a/test/442-checker-constant-folding/src/Main.java
+++ b/test/442-checker-constant-folding/src/Main.java
@@ -27,6 +27,12 @@
}
}
+ public static void assertTrue(boolean condition) {
+ if (!condition) {
+ throw new Error();
+ }
+ }
+
public static void assertIntEquals(int expected, int result) {
if (expected != result) {
throw new Error("Expected: " + expected + ", found: " + result);
@@ -1322,6 +1328,58 @@
/**
+ * Test optimizations of comparisons with null yielding a constant result.
+ */
+
+ /// CHECK-START: boolean Main.ConstStringEqualsNull() constant_folding$after_inlining (before)
+ /// CHECK-DAG: <<ConstStr:l\d+>> LoadString
+ /// CHECK-DAG: <<Null:l\d+>> NullConstant
+ /// CHECK-DAG: <<Eq:z\d+>> Equal [<<ConstStr>>,<<Null>>]
+ /// CHECK-DAG: If [<<Eq>>]
+
+ /// CHECK-START: boolean Main.ConstStringEqualsNull() constant_folding$after_inlining (after)
+ /// CHECK-DAG: <<False:i\d+>> IntConstant 0
+ /// CHECK-DAG: If [<<False>>]
+
+ /// CHECK-START: boolean Main.ConstStringEqualsNull() constant_folding$after_inlining (after)
+ /// CHECK-NOT: Equal
+
+ public static boolean ConstStringEqualsNull() {
+ // Due to Jack emitting code using the opposite condition, use != to generate Equal.
+ if ($inline$ConstString() != null) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /// CHECK-START: boolean Main.ConstStringNotEqualsNull() constant_folding$after_inlining (before)
+ /// CHECK-DAG: <<ConstStr:l\d+>> LoadString
+ /// CHECK-DAG: <<Null:l\d+>> NullConstant
+ /// CHECK-DAG: <<Ne:z\d+>> NotEqual [<<ConstStr>>,<<Null>>]
+ /// CHECK-DAG: If [<<Ne>>]
+
+ /// CHECK-START: boolean Main.ConstStringNotEqualsNull() constant_folding$after_inlining (after)
+ /// CHECK-DAG: <<True:i\d+>> IntConstant 1
+ /// CHECK-DAG: If [<<True>>]
+
+ /// CHECK-START: boolean Main.ConstStringNotEqualsNull() constant_folding$after_inlining (after)
+ /// CHECK-NOT: NotEqual
+
+ public static boolean ConstStringNotEqualsNull() {
+ // Due to Jack emitting code using the opposite condition, use == to generate NotEqual.
+ if ($inline$ConstString() == null) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ public static String $inline$ConstString() {
+ return "";
+ }
+
+ /**
* Exercise constant folding on type conversions.
*/
@@ -1601,6 +1659,9 @@
assertFalse(CmpFloatGreaterThanNaN(arbitrary));
assertFalse(CmpDoubleLessThanNaN(arbitrary));
+ assertFalse(ConstStringEqualsNull());
+ assertTrue(ConstStringNotEqualsNull());
+
Main main = new Main();
assertIntEquals(1, main.smaliCmpLongConstants());
assertIntEquals(-1, main.smaliCmpGtFloatConstants());
diff --git a/test/563-checker-fakestring/smali/TestCase.smali b/test/563-checker-fakestring/smali/TestCase.smali
index 54312a4..9f86352 100644
--- a/test/563-checker-fakestring/smali/TestCase.smali
+++ b/test/563-checker-fakestring/smali/TestCase.smali
@@ -42,16 +42,19 @@
# Test usage of String new-instance before it is initialized.
## CHECK-START: void TestCase.compareNewInstance() register (after)
-## CHECK-DAG: <<Null:l\d+>> NullConstant
+## CHECK-DAG: <<Null:l\d+>> InvokeStaticOrDirect method_name:Main.$noinline$HiddenNull
## CHECK-DAG: <<String:l\d+>> NewInstance
-## CHECK-DAG: <<Cond:z\d+>> NotEqual [<<String>>,<<Null>>]
+## CHECK-DAG: <<Cond:z\d+>> NotEqual [<<Null>>,<<String>>]
## CHECK-DAG: If [<<Cond>>]
.method public static compareNewInstance()V
.registers 3
+ invoke-static {}, LMain;->$noinline$HiddenNull()Ljava/lang/Object;
+ move-result-object v1
+
new-instance v0, Ljava/lang/String;
- if-nez v0, :return
+ if-ne v0, v1, :return
# Will throw NullPointerException if this branch is taken.
const v1, 0x0
diff --git a/test/563-checker-fakestring/src/Main.java b/test/563-checker-fakestring/src/Main.java
index 1ac8a5b..78cb37a 100644
--- a/test/563-checker-fakestring/src/Main.java
+++ b/test/563-checker-fakestring/src/Main.java
@@ -79,4 +79,11 @@
assertEqual(testString, result);
}
}
+
+ public static boolean doThrow = false;
+
+ public static Object $noinline$HiddenNull() {
+ if (doThrow) { throw new Error(); }
+ return null;
+ }
}