ART: Remove DCHECKs for boolean type

Since bool and int are interchangeable types, checking whether an
input is kPrimBoolean can fail when replaced with 0/1 constant or
a phi. This patch removes the problematic DCHECKs, adds a best-effort
verification into SSAChecker but leaves the phi case empty until a
suitable analysis is implemented.

Change-Id: I31e8daf27dd33d2fd74049b82bed1cb7c240c8c6
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 507b3cd..2ea9203 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -2673,7 +2673,6 @@
 }
 
 void InstructionCodeGeneratorARM::VisitBooleanNot(HBooleanNot* bool_not) {
-  DCHECK_EQ(bool_not->InputAt(0)->GetType(), Primitive::kPrimBoolean);
   LocationSummary* locations = bool_not->GetLocations();
   Location out = locations->Out();
   Location in = locations->InAt(0);
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index f6ec729..efc41e7 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -2286,7 +2286,6 @@
 }
 
 void InstructionCodeGeneratorARM64::VisitBooleanNot(HBooleanNot* instruction) {
-  DCHECK_EQ(instruction->InputAt(0)->GetType(), Primitive::kPrimBoolean);
   __ Eor(OutputRegister(instruction), InputRegisterAt(instruction, 0), vixl::Operand(1));
 }
 
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 0cc377c..879216d 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -2931,7 +2931,6 @@
 }
 
 void InstructionCodeGeneratorX86::VisitBooleanNot(HBooleanNot* bool_not) {
-  DCHECK_EQ(bool_not->InputAt(0)->GetType(), Primitive::kPrimBoolean);
   LocationSummary* locations = bool_not->GetLocations();
   Location in = locations->InAt(0);
   Location out = locations->Out();
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index fb0f4ca..a3d3490 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -2986,7 +2986,6 @@
 }
 
 void InstructionCodeGeneratorX86_64::VisitBooleanNot(HBooleanNot* bool_not) {
-  DCHECK_EQ(bool_not->InputAt(0)->GetType(), Primitive::kPrimBoolean);
   LocationSummary* locations = bool_not->GetLocations();
   DCHECK_EQ(locations->InAt(0).AsRegister<CpuRegister>().AsRegister(),
             locations->Out().AsRegister<CpuRegister>().AsRegister());
diff --git a/compiler/optimizing/graph_checker.cc b/compiler/optimizing/graph_checker.cc
index 7c3c2bf..906c8e8 100644
--- a/compiler/optimizing/graph_checker.cc
+++ b/compiler/optimizing/graph_checker.cc
@@ -369,26 +369,40 @@
   }
 }
 
-void SSAChecker::VisitIf(HIf* instruction) {
-  VisitInstruction(instruction);
-  HInstruction* input = instruction->InputAt(0);
+void SSAChecker::HandleBooleanInput(HInstruction* instruction, size_t input_index) {
+  HInstruction* input = instruction->InputAt(input_index);
   if (input->IsIntConstant()) {
-    int value = input->AsIntConstant()->GetValue();
+    int32_t value = input->AsIntConstant()->GetValue();
     if (value != 0 && value != 1) {
       AddError(StringPrintf(
-          "If instruction %d has a non-Boolean constant input "
-          "whose value is: %d.",
+          "%s instruction %d has a non-Boolean constant input %d whose value is: %d.",
+          instruction->DebugName(),
           instruction->GetId(),
+          static_cast<int>(input_index),
           value));
     }
-  } else if (instruction->InputAt(0)->GetType() != Primitive::kPrimBoolean) {
+  } else if (input->GetType() == Primitive::kPrimInt && input->IsPhi()) {
+    // TODO: We need a data-flow analysis which determines if the Phi is boolean.
+  } else if (input->GetType() != Primitive::kPrimBoolean) {
     AddError(StringPrintf(
-        "If instruction %d has a non-Boolean input type: %s.",
+        "%s instruction %d has a non-Boolean input %d whose type is: %s.",
+        instruction->DebugName(),
         instruction->GetId(),
-        Primitive::PrettyDescriptor(instruction->InputAt(0)->GetType())));
+        static_cast<int>(input_index),
+        Primitive::PrettyDescriptor(input->GetType())));
   }
 }
 
+void SSAChecker::VisitIf(HIf* instruction) {
+  VisitInstruction(instruction);
+  HandleBooleanInput(instruction, 0);
+}
+
+void SSAChecker::VisitBooleanNot(HBooleanNot* instruction) {
+  VisitInstruction(instruction);
+  HandleBooleanInput(instruction, 0);
+}
+
 void SSAChecker::VisitCondition(HCondition* op) {
   VisitInstruction(op);
   if (op->GetType() != Primitive::kPrimBoolean) {
diff --git a/compiler/optimizing/graph_checker.h b/compiler/optimizing/graph_checker.h
index 89fea0a..4568a5e 100644
--- a/compiler/optimizing/graph_checker.h
+++ b/compiler/optimizing/graph_checker.h
@@ -107,8 +107,11 @@
   void VisitBinaryOperation(HBinaryOperation* op) OVERRIDE;
   void VisitCondition(HCondition* op) OVERRIDE;
   void VisitIf(HIf* instruction) OVERRIDE;
+  void VisitBooleanNot(HBooleanNot* instruction) OVERRIDE;
   void VisitConstant(HConstant* instruction) OVERRIDE;
 
+  void HandleBooleanInput(HInstruction* instruction, size_t input_index);
+
  private:
   DISALLOW_COPY_AND_ASSIGN(SSAChecker);
 };
diff --git a/test/474-checker-boolean-input/expected.txt b/test/474-checker-boolean-input/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/474-checker-boolean-input/expected.txt
diff --git a/test/474-checker-boolean-input/info.txt b/test/474-checker-boolean-input/info.txt
new file mode 100644
index 0000000..8ec946b
--- /dev/null
+++ b/test/474-checker-boolean-input/info.txt
@@ -0,0 +1 @@
+Tests if zero/one constants and integer Phis are accepted as boolean values.
\ No newline at end of file
diff --git a/test/474-checker-boolean-input/src/Main.java b/test/474-checker-boolean-input/src/Main.java
new file mode 100644
index 0000000..91e8d4f
--- /dev/null
+++ b/test/474-checker-boolean-input/src/Main.java
@@ -0,0 +1,75 @@
+/*
+* 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.
+*/
+
+public class Main {
+
+  public static void assertBoolEquals(boolean expected, boolean result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  /*
+   * Test that zero/one constants are accepted as boolean inputs.
+   */
+
+  // CHECK-START: boolean Main.TestIntAsBoolean() inliner (before)
+  // CHECK-DAG:     [[Invoke:z\d+]]  InvokeStaticOrDirect
+  // CHECK-DAG:                      BooleanNot [ [[Invoke]] ]
+
+  // CHECK-START: boolean Main.TestIntAsBoolean() inliner (after)
+  // CHECK-DAG:     [[Const:i\d+]]   IntConstant 1
+  // CHECK-DAG:                      BooleanNot [ [[Const]] ]
+
+  public static boolean InlineConst() {
+    return true;
+  }
+
+  public static boolean TestIntAsBoolean() {
+    return InlineConst() != true ? true : false;
+  }
+
+  /*
+   * Test that integer Phis are accepted as boolean inputs until we implement
+   * a suitable type analysis.
+   */
+
+  // CHECK-START: boolean Main.TestPhiAsBoolean(int) inliner (before)
+  // CHECK-DAG:     [[Invoke:z\d+]]  InvokeStaticOrDirect
+  // CHECK-DAG:                      BooleanNot [ [[Invoke]] ]
+
+  // CHECK-START: boolean Main.TestPhiAsBoolean(int) inliner (after)
+  // CHECK-DAG:     [[Phi:i\d+]]     Phi
+  // CHECK-DAG:                      BooleanNot [ [[Phi]] ]
+
+  public static boolean f1;
+  public static boolean f2;
+
+  public static boolean InlinePhi(int x) {
+    return (x == 42) ? f1 : f2;
+  }
+
+  public static boolean TestPhiAsBoolean(int x) {
+    return InlinePhi(x) != true ? true : false;
+  }
+
+  public static void main(String[] args) {
+    f1 = true;
+    f2 = false;
+    assertBoolEquals(true, TestPhiAsBoolean(0));
+    assertBoolEquals(false, TestPhiAsBoolean(42));
+  }
+}