-
Notifications
You must be signed in to change notification settings - Fork 6.2k
8302459: Missing late inline cleanup causes compiler/vectorapi/VectorLogicalOpIdentityTest.java IR failure #21682
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
Conversation
…ed with "IRViolationException: There were one or multiple IR rule failures"
|
👋 Welcome back dfenacci! A progress list of the required criteria for merging this PR into |
|
@dafedafe 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 454 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 |
This reverts commit a78798c.
This reverts commit f29f7a8.
This reverts commit 4131271.
This reverts commit 7ec8069.
This reverts commit 80901d4.
This reverts commit 3ba3823.
…ava failed with "IRViolationException: There were one or multiple IR rule failures"" This reverts commit 2f10a92.
…ctorLogicalOpIdentityTest.java IR failure
|
@dafedafe this pull request can not be integrated into git checkout JDK-8302459-new
git fetch https://git.openjdk.org/jdk.git master
git merge FETCH_HEAD
# resolve conflicts and follow the instructions given by git merge
git commit -m "Merge master"
git push |
Webrevs
|
|
Would it be better to trigger cleanup based on the presence of nodes like CastPP/CheckCastPP instead? |
iwanowww
left a comment
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! Overall, looks good.
Some minor comments/suggestions.
src/hotspot/share/opto/callnode.cpp
Outdated
| phase->C->inline_printer()->record(cg->method(), cg->call_node()->jvms(), InliningResult::FAILURE, | ||
| "static call node changed: trying again"); | ||
| } | ||
| phase->C->prepend_late_inline(cg); |
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.
There are 4 occurrences of prepend_late_inline followed by set_generator(nullptr). Does it deserve a helper method?
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.
It surely does. I added it.
src/hotspot/share/opto/compile.cpp
Outdated
| print_method(PHASE_INCREMENTAL_INLINE_STEP, 3, cg->call_node()); | ||
| break; // process one call site at a time | ||
| } else { | ||
| if (C->igvn_worklist()->member(cg->call_node()) == is_scheduled_for_igvn_before) { // avoid potential infinite loop |
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 remind me, please, what exactly we are trying to catch here?
I remember I expressed concerns about the call node being scheduled for IGVN during incremental inlining attempt causing infinite loop during incremental inlining. Does the same apply if the node disappears from IGVN work list during incremental inlining attempt?
(It took me some time to recollect what's going on here. Maybe introduce is_scheduled_for_igvn_after local and add a comment why both mismatches - false -> true and true -> false - are problematic?)
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 a lot for having a look @iwanowww!
I took me a while to recollect it too (and I remember having a hard time figuring out if that could be an issue back then 😉). Anyway the concern, as you said, was that there might be an infinite loop between IGVN and incremental inlining (presumably because during incremental inlining the call node could potentially slip back into the working list, right?).
If that is the root of the problem, the issue would only exist in the false -> true case. In the (potential) true -> false case the call node wouldn't be scheduled for IGVN in the next round, so there wouldn't be any loop. Maybe we could even transform the statement into something like:
if (C->igvn_worklist()->member(cg->call_node()) && is_scheduled_for_igvn_before) {
cg->call_node()->set_generator(cg);
}
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.
So, since current logic for generic (non-MH case) case conservatively assumes that any change in inputs may benefit inlining (and unconditionally schedules such call nodes for another inlining attempt during IGVN), we want to avoid the situation when call node gets scheduled for IGVN during failed inlining attempt.
I'd shape it as follows:
if (!is_scheduled_for_igvn_before && is_scheduled_for_igvn_after) { // avoid potential infinite loop
assert(false, "scheduled for IGVN during inlining attempt");
} else {
assert(is_scheduled_for_igvn_before == is_scheduled_for_igvn_after, "interesting"); // removed from IGVN list during inlining pass?
cg->call_node()->set_generator(cg); // wait for another opportunity
}
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.
Fair enough. I reshaped it following your suggestion. Thanks!
src/hotspot/share/opto/callnode.cpp
Outdated
| } | ||
| #endif | ||
|
|
||
| void CallJavaNode::prepend_and_reset_generator(PhaseGVN* phase, CallGenerator* cg) { |
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.
prepend_and_reset_generator sounds way too verbose. Maybe register_for_late_inline instead?
Also, CallGenertaor* cg argument is redundant. And phase is used just to extract Compile*.
Either
void CallJavaNode::register_for_late_inline(Compile* C) {
if (generator() != nullptr) {
C->prepend_late_inline(generator());
set_generator(nullptr);
} else {
assert(false, "repeated attempt");
}
}
Or even drop Compile* C and use Compile::current().
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.
prepend_and_reset_generatorsounds way too verbose. Mayberegister_for_late_inlineinstead?
👍
Or even drop
Compile* Cand useCompile::current().
I got rid of all the arguments. Thanks Vladimir.
iwanowww
left a comment
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 good!
TobiHartmann
left a comment
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 was a tricky one to narrow down, good job Damon! 🙂
I added a few code style comments, looks good otherwise.
| assert(cg->method()->is_method_handle_intrinsic() == false, "required"); | ||
| if (phase->C->print_inlining()) { | ||
| phase->C->inline_printer()->record(cg->method(), cg->call_node()->jvms(), InliningResult::FAILURE, | ||
| "static call node changed: trying again"); |
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.
FTR, could you share how the PrintInlining output looks now when this code is triggered?
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.
It looks like this:
@ 192 jdk.internal.vm.vector.VectorSupport::binaryOp (38 bytes) failed to inline: failed to inline (intrinsic) failed to inline: static call node changed: trying again (intrinsic) late inline succeeded
It seems a bit redundant: the first failed to inline: failed to inline (intrinsic) doesn't seem to be needed.
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.
Actually it is a bit verbose but I would probably leave it like this: the first (failed to inline: failed to inline (intrinsic)) is for the failure and the second (failed to inline: static call node changed: trying again (intrinsic)) is for the retry.
| } else { | ||
| assert(is_scheduled_for_igvn_before == is_scheduled_for_igvn_after, "call node removed from IGVN list during inlining pass"); | ||
| cg->call_node()->set_generator(cg); | ||
| } |
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 find this a bit hard to read. Wouldn't it be semantically equivalent to this?
if (is_scheduled_for_igvn_before == is_scheduled_for_igvn_after) {
cg->call_node()->set_generator(cg);
} else {
assert(false, "Some useful message");
}
We wouldn't have separate asserts for the two cases, but I think that's fine since one can easily figure it out from the boolean values.
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.
The difference is whether a call can be scheduled for a repeated inlining attempt in the future.
cg->call_node()->set_generator(cg) reinitializes cg in CallNode and lets IGVN to submit it for incremental inlining during future passes.
The first check guards against a situation when the call node is already on IGVN list (so, it will be automatically rescheduled for inlining during the next IGVN pass causing an infinite loop in incremental inlining).
The second assert catches a suspicious situation when the call node disappears from IGVN worklist during failed inlining attempt. IMO it should not happens, hence the assert. But it is benign to allow repeated inlining in such case.
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.
Okay, thanks for the background. If we keep both asserts, some comments explaining this would be helpful.
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 the suggestion!
I've added a couple of comments to the asserts.
I've also changed the second assert into assert(!is_scheduled_for_igvn_before || is_scheduled_for_igvn_after, "call node removed from IGVN list during inlining pass");. The final result is the same but the expression matches what the message says 1-1.
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 good to me, thanks!
Co-authored-by: Tobias Hartmann <tobias.hartmann@oracle.com>
Co-authored-by: Tobias Hartmann <tobias.hartmann@oracle.com>
|
@iwanowww, @TobiHartmann thanks so much for your reviews! |
|
/integrate |
|
Going to push as commit 2e4d7d1.
Your commit was automatically rebased without conflicts. |
Issue
The
compiler/vectorapi/VectorLogicalOpIdentityTest.javahas been failing because C2 compiling the testtestAndMaskSameValue1expects to have 1AndVnodes but it has none.Cause
The issue has to do with the criteria that trigger a cleanup when performing late inlining. In the failing test, when the compiler tries to inline a


jdk.internal.vm.vector.VectorSupport::binaryOpcall, it fails because its argument is of the wrong type, mainly because some cast nodes “hide” the more “precise” type.The graph that leads to the issue looks like this:
The compiler tries to inline
jdk.internal.vm.vector.VectorSupport::loadand it succeeds:The node
3027 VectorBoxhas typeIntMaxVector.912 CastPPand934 CheckCastPPhave typeIntVectorinstead.The compiler then tries to inline one of the 2
bynaryOpcalls but it fails because it needs an argument of typeIntMaxVectorand the argument it is given, which is node934 CheckCastPP, has typeIntVector.This would not happen if between the 2 inlining attempts a cleanup was triggered. IGVN would run and the 2 nodes
912 CastPPand934 CheckCastPPwould be folded away.binaryOpcould then be inlined since the types would match.Solution
Instead of fixing this specific case we try a more generic approach: when late inlining we keep track of failed intrinsics and re-examine them during IGVN. If the
Idealmethod for their call node is called, we reschedule the intrinsic attempt for that call.Testing
Additional test runs with
-XX:-TieredCompilationare added toVectorLogicalOpIdentityTest.javaandVectorGatherMaskFoldingTest.javaas regression tests and-XX:+IncrementalInlineForceCleanupis removed fromVectorGatherMaskFoldingTest.java(previously added as workaround for this issue)Tests: Tier 1-4 (windows-x64, linux-x64/aarch64, and macosx-x64/aarch64; release and debug mode)
Progress
Issue
Reviewers
Contributors
<vlivanov@openjdk.org>Reviewing
Using
gitCheckout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/21682/head:pull/21682$ git checkout pull/21682Update a local copy of the PR:
$ git checkout pull/21682$ git pull https://git.openjdk.org/jdk.git pull/21682/headUsing Skara CLI tools
Checkout this PR locally:
$ git pr checkout 21682View PR using the GUI difftool:
$ git pr show -t 21682Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/21682.diff
Using Webrev
Link to Webrev Comment