ART: Extend the range of clonable instructions.

Make a bunch of instructions clonable: DivZeroCheck,
TypeConversion, InstanceOf, CheckCast.

Test: with forced peeling and unrolling (applied to every clonable
loop) all the test pass and device boots to GUI.

Test: angler boots to GUI.
Test: test-art-target, test-art-host.
Test: 530-checker-peel-unroll.

Change-Id: Id056b998e0a656dbada6958e7c667b7331047059
diff --git a/compiler/optimizing/loop_analysis.h b/compiler/optimizing/loop_analysis.h
index c09d3ff..7f321b7 100644
--- a/compiler/optimizing/loop_analysis.h
+++ b/compiler/optimizing/loop_analysis.h
@@ -113,9 +113,7 @@
         instruction->IsUnresolvedStaticFieldGet() ||
         instruction->IsUnresolvedStaticFieldSet() ||
         // TODO: Support loops with intrinsified invokes.
-        instruction->IsInvoke() ||
-        // TODO: Support loops with ClinitChecks.
-        instruction->IsClinitCheck());
+        instruction->IsInvoke());
   }
 };
 
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 975ad1c..8257799 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -5155,6 +5155,7 @@
     SetRawInputAt(0, value);
   }
 
+  bool IsClonable() const OVERRIDE { return true; }
   bool CanBeMoved() const OVERRIDE { return true; }
 
   bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
@@ -5606,6 +5607,7 @@
   DataType::Type GetInputType() const { return GetInput()->GetType(); }
   DataType::Type GetResultType() const { return GetType(); }
 
+  bool IsClonable() const OVERRIDE { return true; }
   bool CanBeMoved() const OVERRIDE { return true; }
   bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
     return true;
@@ -6641,8 +6643,7 @@
             dex_pc) {
     SetRawInputAt(0, constant);
   }
-
-  bool IsClonable() const OVERRIDE { return true; }
+  // TODO: Make ClinitCheck clonable.
   bool CanBeMoved() const OVERRIDE { return true; }
   bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
     return true;
@@ -7112,6 +7113,8 @@
                               bitstring_mask,
                               SideEffectsForArchRuntimeCalls(check_kind)) {}
 
+  bool IsClonable() const OVERRIDE { return true; }
+
   bool NeedsEnvironment() const OVERRIDE {
     return CanCallRuntime(GetTypeCheckKind());
   }
@@ -7201,6 +7204,7 @@
                               bitstring_mask,
                               SideEffects::CanTriggerGC()) {}
 
+  bool IsClonable() const OVERRIDE { return true; }
   bool NeedsEnvironment() const OVERRIDE {
     // Instruction may throw a CheckCastError.
     return true;
diff --git a/test/530-checker-peel-unroll/src/Main.java b/test/530-checker-peel-unroll/src/Main.java
index 804c9fe..11c2964 100644
--- a/test/530-checker-peel-unroll/src/Main.java
+++ b/test/530-checker-peel-unroll/src/Main.java
@@ -53,11 +53,17 @@
   }
 
   private static final void initIntArray(int[] a) {
-    for (int i = 0; i < LENGTH; i++) {
+    for (int i = 0; i < a.length; i++) {
       a[i] = i % 4;
     }
   }
 
+  private static final void initDoubleArray(double[] a) {
+    for (int i = 0; i < a.length; i++) {
+      a[i] = (double)(i % 4);
+    }
+  }
+
   /// CHECK-START: void Main.unrollingLoadStoreElimination(int[]) loop_optimization (before)
   /// CHECK-DAG: <<Array:l\d+>>   ParameterValue                            loop:none
   /// CHECK-DAG: <<Const1:i\d+>>  IntConstant 1                             loop:none
@@ -684,6 +690,96 @@
     return s + t;
   }
 
+  /// CHECK-START: void Main.unrollingInstanceOf(int[], java.lang.Object[]) loop_optimization (before)
+  /// CHECK-DAG: <<Const0:i\d+>>   IntConstant 0                             loop:none
+  /// CHECK-DAG:                   Phi [<<Const0>>,{{i\d+}}]                 loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG:                   InstanceOf                                loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-NOT:                   InstanceOf
+
+  /// CHECK-START: void Main.unrollingInstanceOf(int[], java.lang.Object[]) loop_optimization (after)
+  /// CHECK-DAG: <<Const0:i\d+>>   IntConstant 0                             loop:none
+  /// CHECK-DAG:                   Phi [<<Const0>>,{{i\d+}}]                 loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG:                   InstanceOf                                loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                   InstanceOf                                loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-NOT:                   InstanceOf
+  public void unrollingInstanceOf(int[] a, Object[] obj_array) {
+    for (int i = 0; i < LENGTH_B; i++) {
+      if (obj_array[i] instanceof Integer) {
+        a[i] += 1;
+      }
+    }
+  }
+
+  /// CHECK-START: void Main.unrollingDivZeroCheck(int[], int) loop_optimization (before)
+  /// CHECK-DAG: <<Const0:i\d+>>   IntConstant 0                             loop:none
+  /// CHECK-DAG:                   Phi [<<Const0>>,{{i\d+}}]                 loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG:                   DivZeroCheck                              loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-NOT:                   DivZeroCheck
+
+  /// CHECK-START: void Main.unrollingDivZeroCheck(int[], int) loop_optimization (after)
+  /// CHECK-DAG: <<Const0:i\d+>>   IntConstant 0                             loop:none
+  /// CHECK-DAG:                   Phi [<<Const0>>,{{i\d+}}]                 loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG:                   DivZeroCheck                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                   DivZeroCheck                              loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-NOT:                   DivZeroCheck
+  public void unrollingDivZeroCheck(int[] a, int r) {
+    for (int i = 0; i < LENGTH_B; i++) {
+      a[i] += a[i] / r;
+    }
+  }
+
+  /// CHECK-START: void Main.unrollingTypeConversion(int[], double[]) loop_optimization (before)
+  /// CHECK-DAG: <<Const0:i\d+>>   IntConstant 0                             loop:none
+  /// CHECK-DAG:                   Phi [<<Const0>>,{{i\d+}}]                 loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG:                   TypeConversion                            loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-NOT:                   TypeConversion
+
+  /// CHECK-START: void Main.unrollingTypeConversion(int[], double[]) loop_optimization (after)
+  /// CHECK-DAG: <<Const0:i\d+>>   IntConstant 0                             loop:none
+  /// CHECK-DAG:                   Phi [<<Const0>>,{{i\d+}}]                 loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG:                   TypeConversion                            loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                   TypeConversion                            loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-NOT:                   TypeConversion
+  public void unrollingTypeConversion(int[] a, double[] b) {
+    for (int i = 0; i < LENGTH_B; i++) {
+      a[i] = (int) b[i];
+    }
+  }
+
+  interface Itf {
+  }
+
+  class SubMain extends Main implements Itf {
+  }
+
+  /// CHECK-START: void Main.unrollingCheckCast(int[], java.lang.Object) loop_optimization (before)
+  /// CHECK-DAG: <<Const0:i\d+>>   IntConstant 0                             loop:none
+  /// CHECK-DAG:                   Phi [<<Const0>>,{{i\d+}}]                 loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG:                   CheckCast                                 loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-NOT:                   CheckCast
+
+  /// CHECK-START: void Main.unrollingCheckCast(int[], java.lang.Object) loop_optimization (after)
+  /// CHECK-DAG: <<Const0:i\d+>>   IntConstant 0                             loop:none
+  /// CHECK-DAG:                   Phi [<<Const0>>,{{i\d+}}]                 loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG:                   CheckCast                                 loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:                   CheckCast                                 loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-NOT:                   CheckCast
+  public void unrollingCheckCast(int[] a, Object o) {
+    for (int i = 0; i < LENGTH_B; i++) {
+      if (((SubMain)o) == o) {
+        a[i] = i;
+      }
+    }
+  }
+
   /// CHECK-START: void Main.noUnrollingOddTripCount(int[]) loop_optimization (before)
   /// CHECK-DAG: <<Array:l\d+>>   ParameterValue                            loop:none
   /// CHECK-DAG: <<Const1:i\d+>>  IntConstant 1                             loop:none
@@ -985,9 +1081,17 @@
     initMatrix(mB);
     initMatrix(mC);
 
-    int expected = 174291419;
+    int expected = 174291515;
     int found = 0;
 
+    double[] doubleArray = new double[LENGTH_B];
+    initDoubleArray(doubleArray);
+
+    unrollingInstanceOf(a, new Integer[LENGTH_B]);
+    unrollingDivZeroCheck(a, 15);
+    unrollingTypeConversion(a, doubleArray);
+    unrollingCheckCast(a, new SubMain());
+
     unrollingWhile(a);
     unrollingLoadStoreElimination(a);
     unrollingSwitch(a);