Fix inlining loops in OSR mode.
When compiling a method in OSR mode and the method does not
contain a loop (arguably, a very odd case) but we inline
another method with a loop and then the final DCE re-runs
the loop identification, the inlined loop would previously
be marked as irreducible. However, the SSA liveness analysis
expects irreducible loop to have extra loop Phis which were
already eliminated from the loop before the inner graph was
inlined to the outer graph, so we would fail a DCHECK().
We fix this by not marking inlined loops as irreducible when
compiling in OSR mode.
Bug: 28210356
Change-Id: If10057ed883333c62a878ed2ae3fe01bb5280e33
diff --git a/test/570-checker-osr/src/Main.java b/test/570-checker-osr/src/Main.java
index 6514334..f22a0c1 100644
--- a/test/570-checker-osr/src/Main.java
+++ b/test/570-checker-osr/src/Main.java
@@ -63,6 +63,9 @@
$noinline$stackOverflow(new Main(), /* isSecondInvocation */ false);
$noinline$stackOverflow(new SubMain(), /* isSecondInvocation */ true);
+
+ $opt$noinline$testOsrInlineLoop(null);
+ System.out.println("b28210356 passed.");
}
public static int $noinline$returnInt() {
@@ -70,7 +73,7 @@
int i = 0;
for (; i < 100000; ++i) {
}
- while (!ensureInOsrCode()) {}
+ while (!isInOsrCode("$noinline$returnInt")) {}
System.out.println(i);
return 53;
}
@@ -80,7 +83,7 @@
int i = 0;
for (; i < 200000; ++i) {
}
- while (!ensureInOsrCode()) {}
+ while (!isInOsrCode("$noinline$returnFloat")) {}
System.out.println(i);
return 42.2f;
}
@@ -90,7 +93,7 @@
int i = 0;
for (; i < 300000; ++i) {
}
- while (!ensureInOsrCode()) {}
+ while (!isInOsrCode("$noinline$returnDouble")) {}
System.out.println(i);
return Double.longBitsToDouble(0xF000000000001111L);
}
@@ -100,7 +103,7 @@
int i = 0;
for (; i < 400000; ++i) {
}
- while (!ensureInOsrCode()) {}
+ while (!isInOsrCode("$noinline$returnLong")) {}
System.out.println(i);
return 0xFFFF000000001111L;
}
@@ -110,14 +113,14 @@
int i = 0;
for (; i < 100000; ++i) {
}
- while (!ensureInOsrCode()) {}
+ while (!isInOsrCode("$noinline$deopt")) {}
DeoptimizationController.startDeoptimization();
}
public static Class $noinline$inlineCache(Main m, boolean isSecondInvocation) {
// If we are running in non-JIT mode, or were unlucky enough to get this method
// already JITted, just return the expected value.
- if (!ensureInInterpreter()) {
+ if (!isInInterpreter("$noinline$inlineCache")) {
return SubMain.class;
}
@@ -125,7 +128,7 @@
// Ensure that we have OSR code to jump to.
if (isSecondInvocation) {
- ensureHasOsrCode();
+ ensureHasOsrCode("$noinline$inlineCache");
}
// This call will be optimized in the OSR compiled code
@@ -137,7 +140,7 @@
// code we are jumping to will have wrongly optimize other as being a
// 'Main'.
if (isSecondInvocation) {
- while (!ensureInOsrCode()) {}
+ while (!isInOsrCode("$noinline$inlineCache")) {}
}
// We used to wrongly optimize this call and assume 'other' was a 'Main'.
@@ -159,7 +162,7 @@
public static void $noinline$stackOverflow(Main m, boolean isSecondInvocation) {
// If we are running in non-JIT mode, or were unlucky enough to get this method
// already JITted, just return the expected value.
- if (!ensureInInterpreter()) {
+ if (!isInInterpreter("$noinline$stackOverflow")) {
return;
}
@@ -168,7 +171,7 @@
if (isSecondInvocation) {
// Ensure we have an OSR code and we jump to it.
- while (!ensureInOsrCode()) {}
+ while (!isInOsrCode("$noinline$stackOverflow")) {}
}
for (int i = 0; i < (isSecondInvocation ? 10000000 : 1); ++i) {
@@ -179,10 +182,45 @@
}
}
- public static native boolean ensureInInterpreter();
- public static native boolean ensureInOsrCode();
+ public static void $opt$noinline$testOsrInlineLoop(String[] args) {
+ // Regression test for inlining a method with a loop to a method without a loop in OSR mode.
+ if (doThrow) throw new Error();
+ assertIntEquals(12, $opt$inline$testRemoveSuspendCheck(12, 5));
+ // Since we cannot have a loop directly in this method, we need to force the OSR
+ // compilation from native code.
+ ensureHasOsrCode("$opt$noinline$testOsrInlineLoop");
+ }
+
+ public static int $opt$inline$testRemoveSuspendCheck(int x, int y) {
+ // For this test we need an inlined loop and have DCE re-run loop analysis
+ // after inlining.
+ while (y > 0) {
+ while ($opt$inline$inlineFalse() || !$opt$inline$inlineTrue()) {
+ x++;
+ }
+ y--;
+ }
+ return x;
+ }
+
+ public static boolean $opt$inline$inlineTrue() {
+ return true;
+ }
+
+ public static boolean $opt$inline$inlineFalse() {
+ return false;
+ }
+
+ public static void assertIntEquals(int expected, int result) {
+ if (expected != result) {
+ throw new Error("Expected: " + expected + ", found: " + result);
+ }
+ }
+
+ public static native boolean isInOsrCode(String methodName);
+ public static native boolean isInInterpreter(String methodName);
public static native void ensureHasProfilingInfo();
- public static native void ensureHasOsrCode();
+ public static native void ensureHasOsrCode(String methodName);
public static boolean doThrow = false;
}