diff --git a/compiler/CHANGELOG.md b/compiler/CHANGELOG.md index 9dbdd4837d9d..988903eb9dfd 100644 --- a/compiler/CHANGELOG.md +++ b/compiler/CHANGELOG.md @@ -2,6 +2,11 @@ This changelog summarizes newly introduced optimizations that may be relevant to other teams. +## Version 22.1.0 +* (GR-36751): Removed the `DuplicateIrreducibleLoops` option. To disable irreducible loop handling, set + `-Dgraal.MaxDuplicationFactor` to a value less than or equal to 1. For AOT compilations, the effort + spent to handle irreducible loops is boosted to let Native Image support more programs with irreducible loops. + ## Version 22.0.0 * (GR-22707) (GR-30838): New, inner loops first, reverse post order and loop frequency calculations for the compiler. diff --git a/compiler/src/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BciBlockMapping.java b/compiler/src/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BciBlockMapping.java index e9e3f3b43065..1ca750d604f4 100644 --- a/compiler/src/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BciBlockMapping.java +++ b/compiler/src/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BciBlockMapping.java @@ -228,6 +228,7 @@ import static org.graalvm.compiler.bytecode.Bytecodes.TABLESWITCH; import static org.graalvm.compiler.bytecode.Bytecodes.WIDE; import static org.graalvm.compiler.core.common.GraalOptions.SupportJsrBytecodes; +import static org.graalvm.compiler.java.BciBlockMapping.Options.MaxDuplicationFactor; import java.util.ArrayDeque; import java.util.ArrayList; @@ -291,9 +292,9 @@ * maximum subroutine nesting of 4. Otherwise, a bailout is thrown. *
* Loops in the methods are detected. If a method contains an irreducible loop (a loop with more - * than one entry), a bailout is thrown or block duplication is attempted to make the loop - * reducible. This simplifies the compiler later on since only structured loops need to be - * supported. + * than one entry), a bailout is thrown or, if {@link Options#MaxDuplicationFactor} {@code > 1}, + * block duplication is attempted to make the loop reducible. This simplifies the compiler later on + * since only structured loops need to be supported. *
* A data flow analysis computes the live local variables from the point of view of the interpreter.
* The result is used later to prune frame states, i.e., remove local variable entries that are
@@ -304,9 +305,8 @@
*/
public class BciBlockMapping implements JavaMethodContext {
public static class Options {
- @Option(help = "When enabled, some limited amount of duplication will be performed in order compile code containing irreducible loops.")//
- public static final OptionKey
* Since loops are marked eagerly, forward entries into an existing loop without going through
* the loop header (i.e., irreducible loops) can be detected easily. In this case, if
- * {@link Options#DuplicateIrreducibleLoops} is enabled, the traversal starts to duplicate
+ * {@link Options#MaxDuplicationFactor} is greater than 1, the traversal starts to duplicate
* blocks until it either exits the loop or reaches the header. Since this is a depth-first
* traversal and the loop header is not active, we know that the loop and its inner-loops were
- * until then reducible.
+ * reducible until then.
*
* This is not recursive to avoid stack overflow issues.
*/
@@ -1666,7 +1682,7 @@ private void computeBlockOrder(BciBlock initialBlock) {
for (int pos = -1; (pos = checkBits.nextSetBit(pos + 1)) >= 0;) {
int id = pos;
if (!loopHeaders[id].active) {
- if (!Options.DuplicateIrreducibleLoops.getValue(debug.getOptions())) {
+ if (Options.MaxDuplicationFactor.getValue(debug.getOptions()) <= 1.0D) {
throw new PermanentBailoutException("Irreducible");
} else if (outermostInactiveLoopId == -1 || !loopHeaders[id].loops.get(outermostInactiveLoopId)) {
outermostInactiveLoopId = id;
@@ -1710,10 +1726,12 @@ private void computeBlockOrder(BciBlock initialBlock) {
blocksNotYetAssignedId--;
if (blocksNotYetAssignedId < 0) {
// this should only happen if duplication is active
- assert Options.DuplicateIrreducibleLoops.getValue(debug.getOptions());
+ OptionValues options = debug.getOptions();
+ double factor = MaxDuplicationFactor.getValue(options);
duplicateBlocks += newDuplicateBlocks;
- if (duplicateBlocks > postJsrBlockCount * Options.MaxDuplicationFactor.getValue(debug.getOptions())) {
- throw new PermanentBailoutException("Non-reducible loop requires too much duplication");
+ if (duplicateBlocks > postJsrBlockCount * factor * maxDuplicationBoost) {
+ throw new PermanentBailoutException("Non-reducible loop requires too much duplication. " +
+ "Setting " + MaxDuplicationFactor.getName() + " to a value higher than " + factor + " may resolve this.");
}
// there are new duplicate blocks, re-number
debug.log(DebugContext.INFO_LEVEL, "Re-numbering blocks to make room for duplicates (old length: %d; new blocks: %d)", blocks.length, newDuplicateBlocks);
@@ -1754,7 +1772,11 @@ private boolean checkBlocks(int start, BciBlock inserting) {
}
public static BciBlockMapping create(BytecodeStream stream, Bytecode code, OptionValues options, DebugContext debug, boolean hasAsyncExceptions) {
- BciBlockMapping map = new BciBlockMapping(code, debug);
+ return create(stream, code, options, debug, hasAsyncExceptions, 1);
+ }
+
+ public static BciBlockMapping create(BytecodeStream stream, Bytecode code, OptionValues options, DebugContext debug, boolean hasAsyncExceptions, int maxDuplicationBoost) {
+ BciBlockMapping map = new BciBlockMapping(code, debug, maxDuplicationBoost);
buildMap(stream, code, options, debug, map, hasAsyncExceptions);
return map;
}
diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/HostedGraphBuilderPhase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/HostedGraphBuilderPhase.java
index e7358d5ac83d..9a1e2b51729f 100644
--- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/HostedGraphBuilderPhase.java
+++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/HostedGraphBuilderPhase.java
@@ -124,14 +124,18 @@ protected boolean asyncExceptionLiveness() {
@Override
protected BciBlockMapping generateBlockMap() {
+ // Double effort expended to handle irreducible loops in AOT compilation
+ // since failure means native-image fails.
+ int maxDuplicationBoost = 2;
+
if (isDeoptimizationEnabled() && isMethodDeoptTarget()) {
/*
* Need to add blocks representing where deoptimization entrypoint nodes will be
* inserted.
*/
- return HostedBciBlockMapping.create(stream, code, options, graph.getDebug(), false);
+ return HostedBciBlockMapping.create(stream, code, options, graph.getDebug(), false, maxDuplicationBoost);
} else {
- return BciBlockMapping.create(stream, code, options, graph.getDebug(), asyncExceptionLiveness());
+ return BciBlockMapping.create(stream, code, options, graph.getDebug(), asyncExceptionLiveness(), maxDuplicationBoost);
}
}
@@ -300,8 +304,8 @@ final class HostedBciBlockMapping extends BciBlockMapping {
*/
private final Set