8297642: PhaseIdealLoop::only_has_infinite_loops must detect all loops that never lead to termination#11473
8297642: PhaseIdealLoop::only_has_infinite_loops must detect all loops that never lead to termination#11473eme64 wants to merge 2 commits intoopenjdk:masterfrom
Conversation
…s that never lead to termination
|
👋 Welcome back epeter! A progress list of the required criteria for merging this PR into |
Webrevs
|
TobiHartmann
left a comment
There was a problem hiding this comment.
Nice summary. Looks good to me otherwise. @rwestrel should also have a look.
| * @bug 8297642 | ||
| * @compile TestOnlyInfiniteLoops.jasm | ||
| * @summary Nested irreducible loops, where the inner loop floats out of the outer | ||
| * @run main/othervm -XX:+UnlockExperimentalVMOptions |
There was a problem hiding this comment.
-XX:+UnlockExperimentalVMOptions is not required in both @run, right?
| * @summary Nested irreducible loops, where the inner loop floats out of the outer | ||
| * @run main/othervm -XX:+UnlockExperimentalVMOptions | ||
| * -XX:CompileCommand=compileonly,TestOnlyInfiniteLoops::test* | ||
| * -XX:-TieredCompilation -Xbatch -Xcomp |
There was a problem hiding this comment.
-Xcomp implies -Xbatch:
jdk/src/hotspot/share/runtime/arguments.cpp
Lines 1445 to 1447 in 4458de9
|
@eme64 This change now passes all automated pre-integration checks. ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details. After integration, the commit message for the final commit will be: You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed. At the time when this comment was updated there had been 144 new commits pushed to the
As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details. ➡️ To integrate this PR with the above commit message to the |
rwestrel
left a comment
There was a problem hiding this comment.
Looks reasonable to me.
test/hotspot/jtreg/compiler/loopopts/TestOnlyInfiniteLoopsMain.java
Outdated
Show resolved
Hide resolved
test/hotspot/jtreg/compiler/loopopts/TestOnlyInfiniteLoopsMain.java
Outdated
Show resolved
Hide resolved
Thanks Tobias for the suggestion Co-authored-by: Tobias Hartmann <tobias.hartmann@oracle.com>
|
Thanks @rwestrel and @TobiHartmann for the help and reviews! |
|
Going to push as commit d562d3f.
Your commit was automatically rebased without conflicts. |
The bug was a regression-fix for JDK-8294217. The problem is only a not-quite-correct assert. But the problem is not limited to infinite loops, as the example below shows it can happen with reducible loops.
Background:
We have an assert that checks that
has_loopsis true when it should be. If we havehas_loops == falseeven though there are loops, we will not perform loop-opts inCompile::Optimize.jdk/src/hotspot/share/opto/loopnode.cpp
Lines 4285 to 4293 in 8c472e4
Generally, we want to verify, that if we just found loops (
_ltree_root->_child != NULL) thathas_loops == true.There are a few cases where we do not care if we miss loop-opts:
only_has_infinite_loops()). Infinite loops never terminate anyway, so why make them faster? Plus, a loop is only infinite if it has no loop-exit other than aNeverBranchexit, even uncommon traps, loop-limit checks etc are exits. Thus, if a loop does anything interesting, it probably is not such a "true infinite loop". They can be more easily forced to occur by setting-XX:PerMethodTrapLimit=0.Note that once we check the assert, we update
has_loops. So if all loops disappeared, we avoid doing loop-opts henceforth.Current implementation of PhaseIdealLoop::only_has_infinite_loops
jdk/src/hotspot/share/opto/loopnode.cpp
Lines 4183 to 4185 in 8c472e4
We check for loop exits, if there is one the loop should not be infinite.
The Problem
An infinte loop can have an inner loop, that subsequently loses its exit. It becomes its own infinite loop, and floats out of the outer loop. Where the outer loop enters into the former inner loop, we now have a loop-exit for the outer loop. The next time we run
build_loop_treeand check the assert, it can fail, asPhaseIdealLoop::only_has_infinite_loopsfinds that new loop-exit from outer to inner loop.Example:
TestOnlyInfiniteLoops::test_simple(click on images to see them larger)Nested infinite loop before loop-opts:

After

build_loop_tree, the outer loop is detected as infinite, andNeverBranchis inserted. No loop is attached to loop-tree, as we do not attach newly discovered infinite loops. We will sethas_loops == falseafter first loop-opts round.During IGVN of first loop-opts round, some edges die.

88 IfTrueis dominated by52 IfTrue(dominator info only becomes present during loop-opts). The outer loop now exits into the inner loop.The second loop-opts round detects the former inner loop as an infinite loop, inserts NeverBranch. Once we run the assert, we see that we have

has_loops == false, butPhaseIdealLoop::only_has_infinite_loopsfinds the former outer loop's exit.Solution
If we ever only have infinite loops, then there will never be a way to get from any of those loops down to Root, except through a NeverBranch exit. So even if such an (outer) infinite loop ever has an exit, that exit cannot ever lead to Root, other than a NeverBranch exit. Thus, it is ok to still consider that loop as "infinite", even though it itself has an exit - that exit will never lead to termination.
Thus, I changed the
PhaseIdealLoop::only_has_infinite_loopsto check if any of the loops ever connect down to Root, except through NeverBranch nodes.Alternative Fix
An alternative idea to my fix here: just replace the infinite loop with a uncommon trap, and if the infinite loop is ever hit revert back to the interpreter. If we do not care to optimize infinite loops, then why even compile them?
Advantages of that idea: No need for
NeverBranch, no need for special-casing infinite loops.I have another bug where assumptions are not true, because of infinite loops, and especially infinite loops not being attached to the loop-tree JDK-8296318
I'm looking forward to your feedback,
Emanuel
Progress
Issue
Reviewers
Reviewing
Using
gitCheckout this PR locally:
$ git fetch https://git.openjdk.org/jdk pull/11473/head:pull/11473$ git checkout pull/11473Update a local copy of the PR:
$ git checkout pull/11473$ git pull https://git.openjdk.org/jdk pull/11473/headUsing Skara CLI tools
Checkout this PR locally:
$ git pr checkout 11473View PR using the GUI difftool:
$ git pr show -t 11473Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/11473.diff