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);