Improvements in induction range analysis.
Rationale:
Uses range analysis while determining whether trip-counts
are "safe", which improves analysis of triangular loops.
Also implements more effective triangular loop analysis
by evaluating induction information only once and using
a top level hint (instead of the "iterative refinement"
that was used earlier). Also fixes analysis of triangular
trip counts that may wrap-around. All with tests.
Test: see induction_var_range_test/530-checker-loops*
BUG=27151190
Change-Id: I1877c8ce0c9a52005900eb9dfdbb1918df100278
diff --git a/test/530-checker-loops1/src/Main.java b/test/530-checker-loops1/src/Main.java
index 948a7b7..dde4d62 100644
--- a/test/530-checker-loops1/src/Main.java
+++ b/test/530-checker-loops1/src/Main.java
@@ -562,7 +562,7 @@
//
/// CHECK-START: void Main.linearTriangularOnTwoArrayLengths(int) BCE (after)
/// CHECK-NOT: BoundsCheck
- // TODO: also CHECK-NOT: Deoptimize, see b/27151190
+ /// CHECK-NOT: Deoptimize
private static void linearTriangularOnTwoArrayLengths(int n) {
int[] a = new int[n];
for (int i = 0; i < a.length; i++) {
@@ -604,7 +604,7 @@
//
/// CHECK-START: void Main.linearTriangularOnParameter(int) BCE (after)
/// CHECK-NOT: BoundsCheck
- // TODO: also CHECK-NOT: Deoptimize, see b/27151190
+ /// CHECK-NOT: Deoptimize
private static void linearTriangularOnParameter(int n) {
int[] a = new int[n];
for (int i = 0; i < n; i++) {
@@ -619,56 +619,56 @@
}
}
- /// CHECK-START: void Main.linearTriangularVariationsInnerStrict(int) BCE (before)
+ /// CHECK-START: void Main.linearTriangularStrictLower(int) BCE (before)
/// CHECK-DAG: BoundsCheck
/// CHECK-DAG: BoundsCheck
/// CHECK-DAG: BoundsCheck
/// CHECK-DAG: BoundsCheck
//
- /// CHECK-START: void Main.linearTriangularVariationsInnerStrict(int) BCE (after)
+ /// CHECK-START: void Main.linearTriangularStrictLower(int) BCE (after)
/// CHECK-NOT: BoundsCheck
- // TODO: also CHECK-NOT: Deoptimize, see b/27151190
- private static void linearTriangularVariationsInnerStrict(int n) {
+ /// CHECK-NOT: Deoptimize
+ private static void linearTriangularStrictLower(int n) {
int[] a = new int[n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < i; j++) {
a[j] += 1;
}
- for (int j = i - 1; j > -1; j--) {
+ for (int j = i - 1; j >= 0; j--) {
a[j] += 1;
}
for (int j = i; j < n; j++) {
a[j] += 1;
}
- for (int j = n - 1; j > i - 1; j--) {
+ for (int j = n - 1; j >= i; j--) {
a[j] += 1;
}
}
verifyTriangular(a);
}
- /// CHECK-START: void Main.linearTriangularVariationsInnerNonStrict(int) BCE (before)
+ /// CHECK-START: void Main.linearTriangularStrictUpper(int) BCE (before)
/// CHECK-DAG: BoundsCheck
/// CHECK-DAG: BoundsCheck
/// CHECK-DAG: BoundsCheck
/// CHECK-DAG: BoundsCheck
//
- /// CHECK-START: void Main.linearTriangularVariationsInnerNonStrict(int) BCE (after)
+ /// CHECK-START: void Main.linearTriangularStrictUpper(int) BCE (after)
/// CHECK-NOT: BoundsCheck
- // TODO: also CHECK-NOT: Deoptimize, see b/27151190
- private static void linearTriangularVariationsInnerNonStrict(int n) {
+ /// CHECK-NOT: Deoptimize
+ private static void linearTriangularStrictUpper(int n) {
int[] a = new int[n];
for (int i = 0; i < n; i++) {
- for (int j = 0; j <= i - 1; j++) {
+ for (int j = 0; j <= i; j++) {
a[j] += 1;
}
- for (int j = i - 1; j >= 0; j--) {
+ for (int j = i; j >= 0; j--) {
a[j] += 1;
}
- for (int j = i; j <= n - 1; j++) {
+ for (int j = i + 1; j < n; j++) {
a[j] += 1;
}
- for (int j = n - 1; j >= i; j--) {
+ for (int j = n - 1; j >= i + 1; j--) {
a[j] += 1;
}
}
@@ -802,8 +802,8 @@
linearTriangularOnTwoArrayLengths(10);
linearTriangularOnOneArrayLength(10);
linearTriangularOnParameter(10);
- linearTriangularVariationsInnerStrict(10);
- linearTriangularVariationsInnerNonStrict(10);
+ linearTriangularStrictLower(10);
+ linearTriangularStrictUpper(10);
{
int[] t = linearTriangularOOB();
for (int i = 0; i < 200; i++) {
diff --git a/test/530-checker-loops2/src/Main.java b/test/530-checker-loops2/src/Main.java
index b12fbd6..7acf008 100644
--- a/test/530-checker-loops2/src/Main.java
+++ b/test/530-checker-loops2/src/Main.java
@@ -31,7 +31,7 @@
//
/// CHECK-START: void Main.bubble(int[]) BCE (after)
/// CHECK-NOT: BoundsCheck
- // TODO: also CHECK-NOT: Deoptimize, see b/27151190
+ /// CHECK-NOT: Deoptimize
private static void bubble(int[] a) {
for (int i = a.length; --i >= 0;) {
for (int j = 0; j < i; j++) {
@@ -301,6 +301,53 @@
} while (-1 <= i);
}
+ /// CHECK-START: void Main.justRightTriangular1() BCE (before)
+ /// CHECK-DAG: BoundsCheck
+ //
+ /// CHECK-START: void Main.justRightTriangular1() BCE (after)
+ /// CHECK-NOT: BoundsCheck
+ /// CHECK-NOT: Deoptimize
+ private static void justRightTriangular1() {
+ int[] a = { 1 } ;
+ for (int i = Integer.MIN_VALUE + 5; i <= Integer.MIN_VALUE + 10; i++) {
+ for (int j = Integer.MIN_VALUE + 4; j < i - 5; j++) {
+ sResult += a[j - (Integer.MIN_VALUE + 4)];
+ }
+ }
+ }
+
+ /// CHECK-START: void Main.justRightTriangular2() BCE (before)
+ /// CHECK-DAG: BoundsCheck
+ //
+ /// CHECK-START: void Main.justRightTriangular2() BCE (after)
+ /// CHECK-NOT: BoundsCheck
+ /// CHECK-NOT: Deoptimize
+ private static void justRightTriangular2() {
+ int[] a = { 1 } ;
+ for (int i = Integer.MIN_VALUE + 5; i <= 10; i++) {
+ for (int j = 4; j < i - 5; j++) {
+ sResult += a[j - 4];
+ }
+ }
+ }
+
+ /// CHECK-START: void Main.justOOBTriangular() BCE (before)
+ /// CHECK-DAG: BoundsCheck
+ //
+ /// CHECK-START: void Main.justOOBTriangular() BCE (after)
+ /// CHECK-DAG: Deoptimize
+ //
+ /// CHECK-START: void Main.justOOBTriangular() BCE (after)
+ /// CHECK-NOT: BoundsCheck
+ private static void justOOBTriangular() {
+ int[] a = { 1 } ;
+ for (int i = Integer.MIN_VALUE + 4; i <= 10; i++) {
+ for (int j = 4; j < i - 5; j++) {
+ sResult += a[j - 4];
+ }
+ }
+ }
+
/// CHECK-START: void Main.hiddenOOB1(int) BCE (before)
/// CHECK-DAG: BoundsCheck
//
@@ -315,7 +362,6 @@
// Dangerous loop where careless static range analysis would yield strict upper bound
// on index j of 5. When, for instance, lo and thus i = -2147483648, the upper bound
// becomes really positive due to arithmetic wrap-around, causing OOB.
- // Dynamic BCE is feasible though, since it checks the range.
for (int j = 4; j < i - 5; j++) {
sResult += a[j - 4];
}
@@ -336,13 +382,32 @@
// Dangerous loop where careless static range analysis would yield strict lower bound
// on index j of 5. When, for instance, hi and thus i = 2147483647, the upper bound
// becomes really negative due to arithmetic wrap-around, causing OOB.
- // Dynamic BCE is feasible though, since it checks the range.
for (int j = 6; j > i + 5; j--) {
sResult += a[j - 6];
}
}
}
+ /// CHECK-START: void Main.hiddenOOB3(int) BCE (before)
+ /// CHECK-DAG: BoundsCheck
+ //
+ /// CHECK-START: void Main.hiddenOOB3(int) BCE (after)
+ /// CHECK-DAG: Deoptimize
+ //
+ /// CHECK-START: void Main.hiddenOOB3(int) BCE (after)
+ /// CHECK-NOT: BoundsCheck
+ private static void hiddenOOB3(int hi) {
+ int[] a = { 11 } ;
+ for (int i = -1; i <= hi; i++) {
+ // Dangerous loop where careless static range analysis would yield strict lower bound
+ // on index j of 0. For large i, the initial value of j becomes really negative due
+ // to arithmetic wrap-around, causing OOB.
+ for (int j = i + 1; j < 1; j++) {
+ sResult += a[j];
+ }
+ }
+ }
+
/// CHECK-START: void Main.hiddenInfiniteOOB() BCE (before)
/// CHECK-DAG: BoundsCheck
//
@@ -376,7 +441,6 @@
for (int i = -1; i <= 0; i++) {
// Dangerous loop similar as above where the loop is now finite, but the
// loop still goes out of bounds for i = -1 due to the large upper bound.
- // Dynamic BCE is feasible though, since it checks the range.
for (int j = -4; j < 2147483646 * i - 3; j++) {
sResult += a[j + 4];
}
@@ -432,6 +496,25 @@
}
}
+ /// CHECK-START: int Main.doNotHoist(int[]) BCE (before)
+ /// CHECK-DAG: BoundsCheck
+ //
+ /// CHECK-START: int Main.doNotHoist(int[]) BCE (after)
+ /// CHECK-NOT: BoundsCheck
+ public static int doNotHoist(int[] a) {
+ int n = a.length;
+ int x = 0;
+ // BCE applies, but hoisting would crash the loop.
+ for (int i = -10000; i < 10000; i++) {
+ for (int j = 0; j <= 1; j++) {
+ if (0 <= i && i < n)
+ x += a[i];
+ }
+ }
+ return x;
+ }
+
+
/// CHECK-START: int[] Main.add() BCE (before)
/// CHECK-DAG: BoundsCheck
//
@@ -687,7 +770,7 @@
/// CHECK-START: int Main.dynamicBCEAndConstantIndices(int[], int[][], int, int) BCE (after)
// Order matters:
/// CHECK: Deoptimize loop:<<Loop:B\d+>>
- // CHECK-NOT: Goto loop:<<Loop>>
+ /// CHECK-NOT: Goto loop:<<Loop>>
/// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop>>
/// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop>>
/// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop>>
@@ -839,6 +922,8 @@
expectEquals(55, justRightDown1());
expectEquals(55, justRightDown2());
expectEquals(55, justRightDown3());
+
+ // Large bounds OOB.
sResult = 0;
try {
justOOBUp();
@@ -890,6 +975,23 @@
}
expectEquals(1055, sResult);
+ // Triangular.
+ sResult = 0;
+ justRightTriangular1();
+ expectEquals(1, sResult);
+ if (HEAVY) {
+ sResult = 0;
+ justRightTriangular2();
+ expectEquals(1, sResult);
+ }
+ sResult = 0;
+ try {
+ justOOBTriangular();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ sResult += 1000;
+ }
+ expectEquals(1001, sResult);
+
// Hidden OOB.
sResult = 0;
try {
@@ -912,6 +1014,15 @@
sResult += 1000;
}
expectEquals(1, sResult);
+ sResult = 0;
+ try {
+ hiddenOOB3(-1); // no OOB
+ } catch (ArrayIndexOutOfBoundsException e) {
+ sResult += 1000;
+ }
+ expectEquals(11, sResult);
+
+ // Expensive hidden OOB test.
if (HEAVY) {
sResult = 0;
try {
@@ -920,7 +1031,16 @@
sResult += 1000;
}
expectEquals(1002, sResult);
+ sResult = 0;
+ try {
+ hiddenOOB3(2147483647); // OOB
+ } catch (ArrayIndexOutOfBoundsException e) {
+ sResult += 1000;
+ }
+ expectEquals(1011, sResult);
}
+
+ // More hidden OOB.
sResult = 0;
try {
hiddenInfiniteOOB();
@@ -966,6 +1086,9 @@
expectEquals(i < 128 ? i : 0, a200[i]);
}
+ // No hoisting after BCE.
+ expectEquals(110, doNotHoist(x));
+
// Addition.
{
int[] e1 ={ 1, 2, 3, 4, 4, 4, 4, 3, 2, 1 };