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
8251925: C2: RenaissanceStressTest fails with assert(!had_error): bad dominance #954
Conversation
👋 Welcome back chagedorn! A progress list of the required criteria for merging this PR into |
@chhagedorn The following label will be automatically applied to this pull request:
When this pull request is ready to be reviewed, an "RFR" email will be sent to the corresponding mailing list. If you would like to change these labels, use the /label pull request command. |
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.
I would also suggest to run locally next jtreg command and compare number of created vector nodes to make sure your changes did not affect common cases:
$ jtreg -testjdk:/my_jdk/ -va -javaoptions:'-server -Xbatch -XX:-TieredCompilation -XX:CICompilerCount=1 -XX:+TraceNewVectors' -J-Djavatest.maxOutputSize=1000000 compiler/c2/cr6340864/ compiler/codegen/ compiler/loopopts/superword/ compiler/vectorization >new_vects.log
$ grep "new Vector node:" new_vects.log|wc
src/hotspot/share/opto/superword.cpp
Outdated
CountedLoopEndNode* pre_end = get_pre_loop_end(main_head); | ||
assert(lp()->is_main_loop(), ""); | ||
CountedLoopEndNode* pre_end = cached_pre_loop_end(); | ||
assert(get_pre_loop_end(lp()), "pre loop end must still be found"); |
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.
You already have similar assert check inside cached_pre_loop_end().
src/hotspot/share/opto/superword.cpp
Outdated
@@ -911,7 +917,8 @@ bool SuperWord::ref_is_alignable(SWPointer& p) { | |||
if (!p.has_iv()) { | |||
return true; // no induction variable | |||
} | |||
CountedLoopEndNode* pre_end = get_pre_loop_end(lp()->as_CountedLoop()); | |||
CountedLoopEndNode* pre_end = cached_pre_loop_end(); | |||
assert(get_pre_loop_end(lp()), "pre loop end must still be found"); |
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.
You already have similar assert check inside cached_pre_loop_end().
src/hotspot/share/opto/superword.hpp
Outdated
CountedLoopEndNode* cached_pre_loop_end() { | ||
#ifdef ASSERT | ||
Node* pre_end = get_pre_loop_end(_lp); | ||
assert(_lp != NULL && (pre_end == NULL || pre_end == _cached_pre_loop_end) , "real CLE either not found anymore (NULL) or unchanged"); |
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.
Check _lp != NULL should be before it use in previous line.
src/hotspot/share/opto/superword.hpp
Outdated
#ifdef ASSERT | ||
Node* pre_end = get_pre_loop_end(_lp); | ||
assert(_lp != NULL && (pre_end == NULL || pre_end == _cached_pre_loop_end) , "real CLE either not found anymore (NULL) or unchanged"); | ||
assert(_cached_pre_loop_end != NULL, "should be set when fetched"); |
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.
This should be very first assert in this method.
src/hotspot/share/opto/superword.hpp
Outdated
_cached_pre_loop_end = cached_pre_loop_end; | ||
} | ||
|
||
int iv_stride() { return lp()->stride_con(); } |
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.
Can you move this method right after set_lp() as originally?
src/hotspot/share/opto/superword.cpp
Outdated
NOT_PRODUCT(_tracer.invariant_1(n, n_c);) | ||
return !lpt()->is_member(phase()->get_loop(n_c)); | ||
} | ||
|
||
bool SWPointer::invariant_not_dominated_by_pre_loop_end(Node* n) { |
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.
I think we should have only one invariant() method which does this additional check.
And have separate method is_main_loop_member() where currently we check !invariant().
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.
That's a good idea, fixed.
src/hotspot/share/opto/superword.cpp
Outdated
// Check that pre loop end node does not dominate n_c. If it does, then we cannot use n as invariant in the pre loop. | ||
// This happens, for example, when n_c is a CastII node that prevents data nodes to flow above the main loop and into | ||
// the pre loop. Use the cached version as the real pre loop end might not be found anymore with get_pre_loop_end(). | ||
return !phase()->is_dominator(_slp->cached_pre_loop_end(), n_c); |
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.
I think it is not enough. We don't want invariant be inside pre-loop.
Invariant should be node outside original loop (before splitting and unrolling).
We should check that n_c dominates pre-loop head.
What do you think?
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.
I think that makes sense. I updated that. Tests still pass.
@vnkozlov Thanks for your review!
I ran that with the new commit - there is no difference between the fix and base without fix: |
You have 2 more new vectors with fix! 9439 vs 9437 Good - no regression. |
@@ -3970,20 +3986,24 @@ bool SWPointer::offset_plus_k(Node* n, bool negate) { | |||
return true; | |||
} | |||
} | |||
if (invariant(n)) { | |||
if (!is_main_loop_member(n)) { |
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.
Please, add comment here explaining why !is_main_loop_member() is used in this case instead of invariant().
Other places looks good.
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.
I updated it and also moved the following invariant()
check into the if block as it can only hold if !is_main_loop_member()
is true.
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.
Updated changes looks good
@chhagedorn 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 42 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 |
@vnkozlov Thanks a lot for the careful review! |
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.
Otherwise looks good to me.
src/hotspot/share/opto/superword.cpp
Outdated
@@ -69,7 +69,9 @@ SuperWord::SuperWord(PhaseIdealLoop* phase) : | |||
_nlist(arena(), 8, 0, NULL), // scratch list of nodes | |||
_stk(arena(), 8, 0, NULL), // scratch stack of nodes | |||
_lpt(NULL), // loop tree node | |||
_lp(NULL), // LoopNode | |||
_lp(NULL), // CountedLoopNode | |||
_pre_loop_head(NULL), // Pre loop CountedLoopNode |
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.
Is this field really needed? Can't we just retrieve the pre-loop head via _pre_loop_end->loopnode()
?
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.
You're right, it is not really needed. I removed it.
6eff991
to
bcab625
Compare
@TobiHartmann Thanks for your review! |
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.
Unfortunately with forced push I can't see incremental update.
Based on last update comments changes are reasonable.
@vnkozlov Thanks for reviewing again! Yes, that's unfortunate, I wasn't aware of that. I will try to do a merge next time. |
This was the new commit: bcab625, the other commits are identical. |
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.
Thanks for making these changes. Looks good to me!
@TobiHartmann Thanks for your review! |
/integrate |
@chhagedorn Since your change was applied there have been 79 commits pushed to the
Your commit was automatically rebased without conflicts. Pushed as commit e4a32be. 💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored. |
… dominance Reviewed-by: kvn, thartmann
The dominance failures start to occur after the fix for JDK-8249749 which enabled the method
SWPointer::scaled_iv_plus_offset
to call itself recursively and walk the graph to match more instead of stopping immediately (no recursion):092389e#diff-8f29dd005a0f949d108687dabb7379c73dfd85cd782da453509dc9b6cb8c9f81L3789-R3812
We check in
SWPointer::offset_plus_k
if a node is invariant and if so then we choose it as invariant. However, we now have cases in the Renaissance benchmarks where we select an invariant that is pinned to aCastIINode
between the main and pre loop. An example is shown in the attached image. 5913 SubI is found as an invariant with the improved recursive search enabled by JDK-8249749. The control of 5913 SubI (withget_ctrl
) is 5298 CastII. The problem is now that we use the invariant 5913 SubI in the pre loop limit check of 5281 CountedLoopEnd (done inSuperWord::align_initial_loop_index
) because we assume that since the invariant is not part of the main loop, it can float into the pre loop. But this is prevented by 5298 CastII. This results in the dominance assertion failure when checking if the earliest control of 5270 Bool in the pre loop (5297 IfTrue because of 5913 SubI that is used by 5270 Bool) dominates the LCA of 5270 Bool (the pre loop header node).My suggestion is to improve the invariant check in

SWPointer::offset_plus_k
to also check if the found invariant is not dominated by the pre loop end node. Repeated testing of the RenaissanceStressTest has not resulted in any dominance failures anymore.Progress
Testing
Issue
Reviewers
Download
$ git fetch https://git.openjdk.java.net/jdk pull/954/head:pull/954
$ git checkout pull/954