-
Notifications
You must be signed in to change notification settings - Fork 5.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
8297642: PhaseIdealLoop::only_has_infinite_loops must detect all loops that never lead to termination #11473
Conversation
…s that never lead to termination
👋 Welcome back epeter! A progress list of the required criteria for merging this PR into |
Webrevs
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-Xcomp
implies -Xbatch
:
jdk/src/hotspot/share/runtime/arguments.cpp
Lines 1445 to 1447 in 4458de9
case _comp: | |
UseInterpreter = false; | |
BackgroundCompilation = false; |
@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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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_loops
is true when it should be. If we havehas_loops == false
even 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 aNeverBranch
exit, 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_tree
and check the assert, it can fail, asPhaseIdealLoop::only_has_infinite_loops
finds 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, andNeverBranch
is inserted. No loop is attached to loop-tree, as we do not attach newly discovered infinite loops. We will sethas_loops == false
after first loop-opts round.During IGVN of first loop-opts round, some edges die.
88 IfTrue
is 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_loops
finds 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_loops
to 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
git
Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk pull/11473/head:pull/11473
$ git checkout pull/11473
Update a local copy of the PR:
$ git checkout pull/11473
$ git pull https://git.openjdk.org/jdk pull/11473/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 11473
View PR using the GUI difftool:
$ git pr show -t 11473
Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/11473.diff