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;
+  }
 }