Optimize comparisons where lhs and rhs are the same

Test: art/test/testrunner/testrunner.py --host --64 --optimizing -b
Change-Id: Ia9001e9f3a32c3979f78c76bc0b8b86fe6119ecd
diff --git a/compiler/optimizing/constant_folding.cc b/compiler/optimizing/constant_folding.cc
index 489b62d..bd9c899 100644
--- a/compiler/optimizing/constant_folding.cc
+++ b/compiler/optimizing/constant_folding.cc
@@ -63,6 +63,11 @@
   void VisitBelow(HBelow* instruction) override;
   void VisitBelowOrEqual(HBelowOrEqual* instruction) override;
 
+  void VisitGreaterThan(HGreaterThan* instruction) override;
+  void VisitGreaterThanOrEqual(HGreaterThanOrEqual* instruction) override;
+  void VisitLessThan(HLessThan* instruction) override;
+  void VisitLessThanOrEqual(HLessThanOrEqual* instruction) override;
+
   void VisitAnd(HAnd* instruction) override;
   void VisitCompare(HCompare* instruction) override;
   void VisitMul(HMul* instruction) override;
@@ -284,8 +289,17 @@
 }
 
 void InstructionWithAbsorbingInputSimplifier::VisitEqual(HEqual* instruction) {
-  if ((instruction->GetLeft()->IsNullConstant() && !instruction->GetRight()->CanBeNull()) ||
-      (instruction->GetRight()->IsNullConstant() && !instruction->GetLeft()->CanBeNull())) {
+  if (instruction->GetLeft() == instruction->GetRight() &&
+      !DataType::IsFloatingPointType(instruction->GetLeft()->GetType())) {
+    // Replace code looking like
+    //    EQUAL lhs, lhs
+    //    CONSTANT true
+    // We don't perform this optimizations for FP types since Double.NaN != Double.NaN, which is the
+    // opposite value.
+    instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
+    instruction->GetBlock()->RemoveInstruction(instruction);
+  } else 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
@@ -296,8 +310,17 @@
 }
 
 void InstructionWithAbsorbingInputSimplifier::VisitNotEqual(HNotEqual* instruction) {
-  if ((instruction->GetLeft()->IsNullConstant() && !instruction->GetRight()->CanBeNull()) ||
-      (instruction->GetRight()->IsNullConstant() && !instruction->GetLeft()->CanBeNull())) {
+  if (instruction->GetLeft() == instruction->GetRight() &&
+      !DataType::IsFloatingPointType(instruction->GetLeft()->GetType())) {
+    // Replace code looking like
+    //    NOT_EQUAL lhs, lhs
+    //    CONSTANT false
+    // We don't perform this optimizations for FP types since Double.NaN != Double.NaN, which is the
+    // opposite value.
+    instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
+    instruction->GetBlock()->RemoveInstruction(instruction);
+  } else 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
@@ -308,8 +331,14 @@
 }
 
 void InstructionWithAbsorbingInputSimplifier::VisitAbove(HAbove* instruction) {
-  if (instruction->GetLeft()->IsConstant() &&
-      instruction->GetLeft()->AsConstant()->IsArithmeticZero()) {
+  if (instruction->GetLeft() == instruction->GetRight()) {
+    // Replace code looking like
+    //    ABOVE lhs, lhs
+    //    CONSTANT false
+    instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
+    instruction->GetBlock()->RemoveInstruction(instruction);
+  } else if (instruction->GetLeft()->IsConstant() &&
+             instruction->GetLeft()->AsConstant()->IsArithmeticZero()) {
     // Replace code looking like
     //    ABOVE dst, 0, src  // unsigned 0 > src is always false
     // with
@@ -320,8 +349,14 @@
 }
 
 void InstructionWithAbsorbingInputSimplifier::VisitAboveOrEqual(HAboveOrEqual* instruction) {
-  if (instruction->GetRight()->IsConstant() &&
-      instruction->GetRight()->AsConstant()->IsArithmeticZero()) {
+  if (instruction->GetLeft() == instruction->GetRight()) {
+    // Replace code looking like
+    //    ABOVE_OR_EQUAL lhs, lhs
+    //    CONSTANT true
+    instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
+    instruction->GetBlock()->RemoveInstruction(instruction);
+  } else if (instruction->GetRight()->IsConstant() &&
+             instruction->GetRight()->AsConstant()->IsArithmeticZero()) {
     // Replace code looking like
     //    ABOVE_OR_EQUAL dst, src, 0  // unsigned src >= 0 is always true
     // with
@@ -332,8 +367,14 @@
 }
 
 void InstructionWithAbsorbingInputSimplifier::VisitBelow(HBelow* instruction) {
-  if (instruction->GetRight()->IsConstant() &&
-      instruction->GetRight()->AsConstant()->IsArithmeticZero()) {
+  if (instruction->GetLeft() == instruction->GetRight()) {
+    // Replace code looking like
+    //    BELOW lhs, lhs
+    //    CONSTANT false
+    instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
+    instruction->GetBlock()->RemoveInstruction(instruction);
+  } else if (instruction->GetRight()->IsConstant() &&
+             instruction->GetRight()->AsConstant()->IsArithmeticZero()) {
     // Replace code looking like
     //    BELOW dst, src, 0  // unsigned src < 0 is always false
     // with
@@ -344,8 +385,14 @@
 }
 
 void InstructionWithAbsorbingInputSimplifier::VisitBelowOrEqual(HBelowOrEqual* instruction) {
-  if (instruction->GetLeft()->IsConstant() &&
-      instruction->GetLeft()->AsConstant()->IsArithmeticZero()) {
+  if (instruction->GetLeft() == instruction->GetRight()) {
+    // Replace code looking like
+    //    BELOW_OR_EQUAL lhs, lhs
+    //    CONSTANT true
+    instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
+    instruction->GetBlock()->RemoveInstruction(instruction);
+  } else if (instruction->GetLeft()->IsConstant() &&
+             instruction->GetLeft()->AsConstant()->IsArithmeticZero()) {
     // Replace code looking like
     //    BELOW_OR_EQUAL dst, 0, src  // unsigned 0 <= src is always true
     // with
@@ -355,6 +402,55 @@
   }
 }
 
+void InstructionWithAbsorbingInputSimplifier::VisitGreaterThan(HGreaterThan* instruction) {
+  if (instruction->GetLeft() == instruction->GetRight() &&
+      (!DataType::IsFloatingPointType(instruction->GetLeft()->GetType()) ||
+       instruction->IsLtBias())) {
+    // Replace code looking like
+    //    GREATER_THAN lhs, lhs
+    //    CONSTANT false
+    instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
+    instruction->GetBlock()->RemoveInstruction(instruction);
+  }
+}
+
+void InstructionWithAbsorbingInputSimplifier::VisitGreaterThanOrEqual(
+    HGreaterThanOrEqual* instruction) {
+  if (instruction->GetLeft() == instruction->GetRight() &&
+      (!DataType::IsFloatingPointType(instruction->GetLeft()->GetType()) ||
+       instruction->IsGtBias())) {
+    // Replace code looking like
+    //    GREATER_THAN_OR_EQUAL lhs, lhs
+    //    CONSTANT true
+    instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
+    instruction->GetBlock()->RemoveInstruction(instruction);
+  }
+}
+
+void InstructionWithAbsorbingInputSimplifier::VisitLessThan(HLessThan* instruction) {
+  if (instruction->GetLeft() == instruction->GetRight() &&
+      (!DataType::IsFloatingPointType(instruction->GetLeft()->GetType()) ||
+       instruction->IsGtBias())) {
+    // Replace code looking like
+    //    LESS_THAN lhs, lhs
+    //    CONSTANT false
+    instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 0));
+    instruction->GetBlock()->RemoveInstruction(instruction);
+  }
+}
+
+void InstructionWithAbsorbingInputSimplifier::VisitLessThanOrEqual(HLessThanOrEqual* instruction) {
+  if (instruction->GetLeft() == instruction->GetRight() &&
+      (!DataType::IsFloatingPointType(instruction->GetLeft()->GetType()) ||
+       instruction->IsLtBias())) {
+    // Replace code looking like
+    //    LESS_THAN_OR_EQUAL lhs, lhs
+    //    CONSTANT true
+    instruction->ReplaceWith(GetGraph()->GetConstant(DataType::Type::kBool, 1));
+    instruction->GetBlock()->RemoveInstruction(instruction);
+  }
+}
+
 void InstructionWithAbsorbingInputSimplifier::VisitAnd(HAnd* instruction) {
   DataType::Type type = instruction->GetType();
   HConstant* input_cst = instruction->GetConstantRight();
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc
index 6abe2cb..73bdd1e 100644
--- a/compiler/optimizing/graph_visualizer.cc
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -490,6 +490,10 @@
     StartAttributeStream("bias") << compare->GetBias();
   }
 
+  void VisitCondition(HCondition* condition) override {
+    StartAttributeStream("bias") << condition->GetBias();
+  }
+
   void VisitInvoke(HInvoke* invoke) override {
     StartAttributeStream("dex_file_index") << invoke->GetMethodReference().index;
     ArtMethod* method = invoke->GetResolvedMethod();
diff --git a/test/2046-checker-comparison/expected-stderr.txt b/test/2046-checker-comparison/expected-stderr.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/2046-checker-comparison/expected-stderr.txt
diff --git a/test/2046-checker-comparison/expected-stdout.txt b/test/2046-checker-comparison/expected-stdout.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/2046-checker-comparison/expected-stdout.txt
diff --git a/test/2046-checker-comparison/info.txt b/test/2046-checker-comparison/info.txt
new file mode 100644
index 0000000..ead1764
--- /dev/null
+++ b/test/2046-checker-comparison/info.txt
@@ -0,0 +1 @@
+Tests that we optimize comparisons where lhs and rhs are the same.
diff --git a/test/2046-checker-comparison/src/Main.java b/test/2046-checker-comparison/src/Main.java
new file mode 100644
index 0000000..9caa727
--- /dev/null
+++ b/test/2046-checker-comparison/src/Main.java
@@ -0,0 +1,441 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+public class Main {
+    public static void main(String[] args) {
+        assertEquals(1, $noinline$testEqualBool(true));
+        assertEquals(0, $noinline$testNotEqualBool(true));
+        // Other comparisons e.g. `<` don't exists for boolean values.
+
+        assertEquals(1, $noinline$testEqualInt(0));
+        assertEquals(0, $noinline$testNotEqualInt(0));
+        assertEquals(0, $noinline$testGreaterThanInt(0));
+        assertEquals(1, $noinline$testGreaterThanOrEqualInt(0));
+        assertEquals(0, $noinline$testLessThanInt(0));
+        assertEquals(1, $noinline$testLessThanOrEqualInt(0));
+
+        assertEquals(1, $noinline$testEqualLong(0L));
+        assertEquals(0, $noinline$testNotEqualLong(0L));
+        assertEquals(0, $noinline$testGreaterThanLong(0L));
+        assertEquals(1, $noinline$testGreaterThanOrEqualLong(0L));
+        assertEquals(0, $noinline$testLessThanLong(0L));
+        assertEquals(1, $noinline$testLessThanOrEqualLong(0L));
+
+        // We cannot perform the optimization on unknown float/doubles since equality for NaN
+        // returns the opposite as for normal numbers.
+        assertEquals(1, $noinline$testEqualFloat(0f));
+        assertEquals(0, $noinline$testEqualFloat(Float.NaN));
+        assertEquals(1, $noinline$testEqualFloat(Float.NEGATIVE_INFINITY));
+        assertEquals(1, $noinline$testEqualFloat(Float.POSITIVE_INFINITY));
+        assertEquals(0, $noinline$testNotEqualFloat(0f));
+        assertEquals(1, $noinline$testNotEqualFloat(Float.NaN));
+        assertEquals(0, $noinline$testNotEqualFloat(Float.NEGATIVE_INFINITY));
+        assertEquals(0, $noinline$testNotEqualFloat(Float.POSITIVE_INFINITY));
+        assertEquals(0, $noinline$testGreaterThanFloat(0f));
+        assertEquals(0, $noinline$testGreaterThanFloat(Float.NaN));
+        assertEquals(0, $noinline$testGreaterThanFloat(Float.NEGATIVE_INFINITY));
+        assertEquals(0, $noinline$testGreaterThanFloat(Float.POSITIVE_INFINITY));
+        assertEquals(1, $noinline$testGreaterThanOrEqualFloat(0f));
+        assertEquals(0, $noinline$testGreaterThanOrEqualFloat(Float.NaN));
+        assertEquals(1, $noinline$testGreaterThanOrEqualFloat(Float.NEGATIVE_INFINITY));
+        assertEquals(1, $noinline$testGreaterThanOrEqualFloat(Float.POSITIVE_INFINITY));
+        assertEquals(0, $noinline$testLessThanFloat(0f));
+        assertEquals(0, $noinline$testLessThanFloat(Float.NaN));
+        assertEquals(0, $noinline$testLessThanFloat(Float.NEGATIVE_INFINITY));
+        assertEquals(0, $noinline$testLessThanFloat(Float.POSITIVE_INFINITY));
+        assertEquals(1, $noinline$testLessThanOrEqualFloat(0f));
+        assertEquals(0, $noinline$testLessThanOrEqualFloat(Float.NaN));
+        assertEquals(1, $noinline$testLessThanOrEqualFloat(Float.NEGATIVE_INFINITY));
+        assertEquals(1, $noinline$testLessThanOrEqualFloat(Float.POSITIVE_INFINITY));
+
+        assertEquals(1, $noinline$testEqualDouble(0d));
+        assertEquals(0, $noinline$testEqualDouble(Double.NaN));
+        assertEquals(1, $noinline$testEqualDouble(Double.NEGATIVE_INFINITY));
+        assertEquals(1, $noinline$testEqualDouble(Double.POSITIVE_INFINITY));
+        assertEquals(0, $noinline$testNotEqualDouble(0d));
+        assertEquals(1, $noinline$testNotEqualDouble(Double.NaN));
+        assertEquals(0, $noinline$testNotEqualDouble(Double.NEGATIVE_INFINITY));
+        assertEquals(0, $noinline$testNotEqualDouble(Double.POSITIVE_INFINITY));
+        assertEquals(0, $noinline$testGreaterThanDouble(0d));
+        assertEquals(0, $noinline$testGreaterThanDouble(Double.NaN));
+        assertEquals(0, $noinline$testGreaterThanDouble(Double.NEGATIVE_INFINITY));
+        assertEquals(0, $noinline$testGreaterThanDouble(Double.POSITIVE_INFINITY));
+        assertEquals(1, $noinline$testGreaterThanOrEqualDouble(0d));
+        assertEquals(0, $noinline$testGreaterThanOrEqualDouble(Double.NaN));
+        assertEquals(1, $noinline$testGreaterThanOrEqualDouble(Double.NEGATIVE_INFINITY));
+        assertEquals(1, $noinline$testGreaterThanOrEqualDouble(Double.POSITIVE_INFINITY));
+        assertEquals(0, $noinline$testLessThanDouble(0d));
+        assertEquals(0, $noinline$testLessThanDouble(Double.NaN));
+        assertEquals(0, $noinline$testLessThanDouble(Double.NEGATIVE_INFINITY));
+        assertEquals(0, $noinline$testLessThanDouble(Double.POSITIVE_INFINITY));
+        assertEquals(1, $noinline$testLessThanOrEqualDouble(0d));
+        assertEquals(0, $noinline$testLessThanOrEqualDouble(Double.NaN));
+        assertEquals(1, $noinline$testLessThanOrEqualDouble(Double.NEGATIVE_INFINITY));
+        assertEquals(1, $noinline$testLessThanOrEqualDouble(Double.POSITIVE_INFINITY));
+
+        assertEquals(1, $noinline$testEqualObject(null));
+        assertEquals(1, $noinline$testEqualObject(new Object()));
+        assertEquals(0, $noinline$testNotEqualObject(null));
+        assertEquals(0, $noinline$testNotEqualObject(new Object()));
+        // Other comparisons e.g. `<` don't exists for references.
+    }
+
+    /// CHECK-START: int Main.$noinline$testEqualBool(boolean) register (after)
+    /// CHECK: <<Const1:i\d+>> IntConstant 1
+    /// CHECK:                 Return [<<Const1>>]
+    private static int $noinline$testEqualBool(boolean a) {
+        if (a == $inline$returnValueBool(a)) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    /// CHECK-START: int Main.$noinline$testNotEqualBool(boolean) register (after)
+    /// CHECK: <<Const0:i\d+>> IntConstant 0
+    /// CHECK:                 Return [<<Const0>>]
+    private static int $noinline$testNotEqualBool(boolean a) {
+        if (a != $inline$returnValueBool(a)) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    private static boolean $inline$returnValueBool(boolean a) {
+        return a;
+    }
+
+    /// CHECK-START: int Main.$noinline$testEqualInt(int) register (after)
+    /// CHECK: <<Const1:i\d+>> IntConstant 1
+    /// CHECK:                 Return [<<Const1>>]
+    private static int $noinline$testEqualInt(int a) {
+        if (a == $inline$returnValueInt(a)) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    /// CHECK-START: int Main.$noinline$testNotEqualInt(int) register (after)
+    /// CHECK: <<Const0:i\d+>> IntConstant 0
+    /// CHECK:                 Return [<<Const0>>]
+    private static int $noinline$testNotEqualInt(int a) {
+        if (a != $inline$returnValueInt(a)) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    /// CHECK-START: int Main.$noinline$testGreaterThanInt(int) register (after)
+    /// CHECK: <<Const0:i\d+>> IntConstant 0
+    /// CHECK:                 Return [<<Const0>>]
+    private static int $noinline$testGreaterThanInt(int a) {
+        if (a > $inline$returnValueInt(a)) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    /// CHECK-START: int Main.$noinline$testGreaterThanOrEqualInt(int) register (after)
+    /// CHECK: <<Const1:i\d+>> IntConstant 1
+    /// CHECK:                 Return [<<Const1>>]
+    private static int $noinline$testGreaterThanOrEqualInt(int a) {
+        if (a >= $inline$returnValueInt(a)) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    /// CHECK-START: int Main.$noinline$testLessThanInt(int) register (after)
+    /// CHECK: <<Const0:i\d+>> IntConstant 0
+    /// CHECK:                 Return [<<Const0>>]
+    private static int $noinline$testLessThanInt(int a) {
+        if (a < $inline$returnValueInt(a)) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    /// CHECK-START: int Main.$noinline$testLessThanOrEqualInt(int) register (after)
+    /// CHECK: <<Const1:i\d+>> IntConstant 1
+    /// CHECK:                 Return [<<Const1>>]
+    private static int $noinline$testLessThanOrEqualInt(int a) {
+        if (a <= $inline$returnValueInt(a)) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    private static int $inline$returnValueInt(int a) {
+        return a;
+    }
+
+    /// CHECK-START: int Main.$noinline$testEqualLong(long) register (after)
+    /// CHECK: <<Const1:i\d+>> IntConstant 1
+    /// CHECK:                 Return [<<Const1>>]
+    private static int $noinline$testEqualLong(long a) {
+        if (a == $inline$returnValueLong(a)) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    /// CHECK-START: int Main.$noinline$testNotEqualLong(long) register (after)
+    /// CHECK: <<Const0:i\d+>> IntConstant 0
+    /// CHECK:                 Return [<<Const0>>]
+    private static int $noinline$testNotEqualLong(long a) {
+        if (a != $inline$returnValueLong(a)) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    /// CHECK-START: int Main.$noinline$testGreaterThanLong(long) register (after)
+    /// CHECK: <<Const0:i\d+>> IntConstant 0
+    /// CHECK:                 Return [<<Const0>>]
+    private static int $noinline$testGreaterThanLong(long a) {
+        if (a > $inline$returnValueLong(a)) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    /// CHECK-START: int Main.$noinline$testGreaterThanOrEqualLong(long) register (after)
+    /// CHECK: <<Const1:i\d+>> IntConstant 1
+    /// CHECK:                 Return [<<Const1>>]
+    private static int $noinline$testGreaterThanOrEqualLong(long a) {
+        if (a >= $inline$returnValueLong(a)) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    /// CHECK-START: int Main.$noinline$testLessThanLong(long) register (after)
+    /// CHECK: <<Const0:i\d+>> IntConstant 0
+    /// CHECK:                 Return [<<Const0>>]
+    private static int $noinline$testLessThanLong(long a) {
+        if (a < $inline$returnValueLong(a)) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    /// CHECK-START: int Main.$noinline$testLessThanOrEqualLong(long) register (after)
+    /// CHECK: <<Const1:i\d+>> IntConstant 1
+    /// CHECK:                 Return [<<Const1>>]
+    private static int $noinline$testLessThanOrEqualLong(long a) {
+        if (a <= $inline$returnValueLong(a)) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    private static long $inline$returnValueLong(long a) {
+        return a;
+    }
+
+    /// CHECK-START: int Main.$noinline$testEqualFloat(float) register (after)
+    /// CHECK: <<NotEqual:z\d+>> NotEqual
+    /// CHECK: <<BNot:z\d+>>     BooleanNot [<<NotEqual>>]
+    /// CHECK:                   Return [<<BNot>>]
+    private static int $noinline$testEqualFloat(float a) {
+        if (a == $inline$returnValueFloat(a)) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    /// CHECK-START: int Main.$noinline$testNotEqualFloat(float) register (after)
+    /// CHECK: <<Equal:z\d+>>    Equal
+    /// CHECK: <<BNot:z\d+>>     BooleanNot [<<Equal>>]
+    /// CHECK:                   Return [<<BNot>>]
+    private static int $noinline$testNotEqualFloat(float a) {
+        if (a != $inline$returnValueFloat(a)) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    /// CHECK-START: int Main.$noinline$testGreaterThanFloat(float) register (after)
+    /// CHECK: <<Const0:i\d+>> IntConstant 0
+    /// CHECK:                 Return [<<Const0>>]
+    private static int $noinline$testGreaterThanFloat(float a) {
+        if (a > $inline$returnValueFloat(a)) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    /// CHECK-START: int Main.$noinline$testGreaterThanOrEqualFloat(float) register (after)
+    /// CHECK: <<LessThan:z\d+>> LessThan
+    /// CHECK: <<BNot:z\d+>>     BooleanNot [<<LessThan>>]
+    /// CHECK:                   Return [<<BNot>>]
+    private static int $noinline$testGreaterThanOrEqualFloat(float a) {
+        if (a >= $inline$returnValueFloat(a)) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    /// CHECK-START: int Main.$noinline$testLessThanFloat(float) register (after)
+    /// CHECK: <<Const0:i\d+>> IntConstant 0
+    /// CHECK:                 Return [<<Const0>>]
+    private static int $noinline$testLessThanFloat(float a) {
+        if (a < $inline$returnValueFloat(a)) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    /// CHECK-START: int Main.$noinline$testLessThanOrEqualFloat(float) register (after)
+    /// CHECK: <<GreaterThan:z\d+>> GreaterThan
+    /// CHECK: <<BNot:z\d+>>        BooleanNot [<<GreaterThan>>]
+    /// CHECK:                      Return [<<BNot>>]
+    private static int $noinline$testLessThanOrEqualFloat(float a) {
+        if (a <= $inline$returnValueFloat(a)) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    private static float $inline$returnValueFloat(float a) {
+        return a;
+    }
+
+    /// CHECK-START: int Main.$noinline$testEqualDouble(double) register (after)
+    /// CHECK: <<NotEqual:z\d+>> NotEqual
+    /// CHECK: <<BNot:z\d+>>     BooleanNot [<<NotEqual>>]
+    /// CHECK:                   Return [<<BNot>>]
+    private static int $noinline$testEqualDouble(double a) {
+        if (a == $inline$returnValueDouble(a)) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    /// CHECK-START: int Main.$noinline$testNotEqualDouble(double) register (after)
+    /// CHECK: <<Equal:z\d+>>    Equal
+    /// CHECK: <<BNot:z\d+>>     BooleanNot [<<Equal>>]
+    /// CHECK:                   Return [<<BNot>>]
+    private static int $noinline$testNotEqualDouble(double a) {
+        if (a != $inline$returnValueDouble(a)) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    /// CHECK-START: int Main.$noinline$testGreaterThanDouble(double) register (after)
+    /// CHECK: <<Const0:i\d+>> IntConstant 0
+    /// CHECK:                 Return [<<Const0>>]
+    private static int $noinline$testGreaterThanDouble(double a) {
+        if (a > $inline$returnValueDouble(a)) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    /// CHECK-START: int Main.$noinline$testGreaterThanOrEqualDouble(double) register (after)
+    /// CHECK: <<LessThan:z\d+>> LessThan
+    /// CHECK: <<BNot:z\d+>>     BooleanNot [<<LessThan>>]
+    /// CHECK:                   Return [<<BNot>>]
+    private static int $noinline$testGreaterThanOrEqualDouble(double a) {
+        if (a >= $inline$returnValueDouble(a)) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    /// CHECK-START: int Main.$noinline$testLessThanDouble(double) register (after)
+    /// CHECK: <<Const0:i\d+>> IntConstant 0
+    /// CHECK:                 Return [<<Const0>>]
+    private static int $noinline$testLessThanDouble(double a) {
+        if (a < $inline$returnValueDouble(a)) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    /// CHECK-START: int Main.$noinline$testLessThanOrEqualDouble(double) register (after)
+    /// CHECK: <<GreaterThan:z\d+>> GreaterThan
+    /// CHECK: <<BNot:z\d+>>        BooleanNot [<<GreaterThan>>]
+    /// CHECK:                      Return [<<BNot>>]
+    private static int $noinline$testLessThanOrEqualDouble(double a) {
+        if (a <= $inline$returnValueDouble(a)) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    private static double $inline$returnValueDouble(double a) {
+        return a;
+    }
+
+    /// CHECK-START: int Main.$noinline$testEqualObject(java.lang.Object) register (after)
+    /// CHECK: <<Const1:i\d+>> IntConstant 1
+    /// CHECK:                 Return [<<Const1>>]
+    private static int $noinline$testEqualObject(Object a) {
+        if (a == $inline$returnValueObject(a)) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    /// CHECK-START: int Main.$noinline$testNotEqualObject(java.lang.Object) register (after)
+    /// CHECK: <<Const0:i\d+>> IntConstant 0
+    /// CHECK:                 Return [<<Const0>>]
+    private static int $noinline$testNotEqualObject(Object a) {
+        if (a != $inline$returnValueObject(a)) {
+            return 1;
+        } else {
+            return 0;
+        }
+    }
+
+    private static Object $inline$returnValueObject(Object a) {
+        return a;
+    }
+
+    static void assertEquals(int expected, int actual) {
+        if (expected != actual) {
+            throw new AssertionError("Expected " + expected + " got " + actual);
+        }
+    }
+}