8354282: C2: more crashes in compiled code because of dependency on removed range check CastIIs#24575
8354282: C2: more crashes in compiled code because of dependency on removed range check CastIIs#24575rwestrel wants to merge 19 commits intoopenjdk:masterfrom
Conversation
|
👋 Welcome back roland! A progress list of the required criteria for merging this PR into |
|
@rwestrel 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 173 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 |
Webrevs
|
|
If a |
eme64
left a comment
There was a problem hiding this comment.
@rwestrel thanks for looking into this one!
I have not yet deeply studied the PR, but am feeling some confusion about the naming.
I think the DependencyType is really a good step into the right direction, it helps clean things up.
I'm wondering if we should pick either depends_only_on_test or pinned, and use it everywhere consistently. Having both around as near synonymes (antonymes?) is a bit confusing for me.
I'll look into the code more later.
src/hotspot/share/opto/castnode.cpp
Outdated
| const ConstraintCastNode::DependencyType ConstraintCastNode::RegularDependency(true, true, "regular dependency"); // not pinned, narrows type | ||
| const ConstraintCastNode::DependencyType ConstraintCastNode::WidenTypeDependency(true, false, "widen type dependency"); // not pinned, doesn't narrow type | ||
| const ConstraintCastNode::DependencyType ConstraintCastNode::StrongDependency(false, true, "strong dependency"); // pinned, narrows type | ||
| const ConstraintCastNode::DependencyType ConstraintCastNode::UnconditionalDependency(false, false, "unconditional dependency"); // pinned, doesn't narrow type |
There was a problem hiding this comment.
Is there really a good reason to have the names Regular, WidenType, Strong and Unconditional? Did we just get used to these names over time, or do they really have a good reason for existance. They just don't really mean that much to me. Calling them (non)pinned and (non)narrowing would make more sense to me.
There was a problem hiding this comment.
So NonPinnedNarrowingDependency, NonPinnedNonNarrowingDependeny, PinnedNarrowingDependency and NonPinnedNonNarrowingDependency?
Or to avoid using a negation for the one that's the weakest dependency:
FloatingNarrowingDependency, FloatingNonNarrowingDependency, NonFloatingNarrowingDependency and NonFloatingNonNarrowingDependency ?
What do you think @eme64 ?
There was a problem hiding this comment.
Either of these sound great :)
src/hotspot/share/opto/castnode.hpp
Outdated
| bool depends_only_on_test() const { | ||
| return _depends_only_on_test; | ||
| } |
There was a problem hiding this comment.
Is this synonimous to non_pinning? Might that be more descriptive?
src/hotspot/share/opto/castnode.hpp
Outdated
| const bool _depends_only_on_test; // Does this Cast depends on its control input or is it pinned? | ||
| const bool _narrows_type; // Does this Cast narrows the type i.e. if input type is narrower can it be removed? |
There was a problem hiding this comment.
I think it would be good to have a really strong definition of these two, because everything else depends on it.
I would recommend to either use depends_only_on_test as the "primary" word here, or else pinned. But then try to consistently use the chosen one everywhere. Just to avoid confusion with these near synonymes.
It may also be helpful to have an example for each of the 4 combinations, just as an illustration of your definitions.
The current patch constant folds the |
|
@emea thanks for the comments. As mentioned in another comment, I'm in the process of reworking the patch.
|
|
Just wondering, since we are getting closer to RDP 1 for JDK 25 (June 05, 2025), should we defer this to JDK 26? |
Deferring makes sense. This is a corner case anyway. I've been reworking the patch and it's getting more complicated so it will likely need more time for reviews. |
|
Sounds good, I'll defer it to JDK 26 then. Thanks for the quick reply! |
|
@rwestrel this pull request can not be integrated into git checkout JDK-8354282
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 |
|
@rwestrel This pull request has been inactive for more than 4 weeks and will be automatically closed if another 4 weeks passes without any activity. To avoid this, simply issue a |
|
@rwestrel This pull request has been inactive for more than 8 weeks and will now be automatically closed. If you would like to continue working on this pull request in the future, feel free to reopen it! This can be done using the |
|
/keepalive |
|
@rwestrel This command can only be used in open pull requests. |
|
/open |
|
@rwestrel This pull request is now open |
|
@rwestrel This pull request has been inactive for more than 4 weeks and will be automatically closed if another 4 weeks passes without any activity. To avoid this, simply issue a |
|
@rwestrel This pull request has been inactive for more than 8 weeks and will now be automatically closed. If you would like to continue working on this pull request in the future, feel free to reopen it! This can be done using the |
chhagedorn
left a comment
There was a problem hiding this comment.
Thanks for the update, it looks good to me! If @eme64 also agrees with the latest patch, we can submit some testing and then hopefully get it in right before the fork.
| const DependencyType& with_pinned_dependency() const { | ||
| if (_narrows_type) { | ||
| return NonFloatingNarrowing; | ||
| } | ||
| return NonFloatingNonNarrowing; | ||
| } |
There was a problem hiding this comment.
Yes, that's true. I was also unsure about whether we should stick with one or just allow both interchangeably. I guess since there are so many uses, we can just move forward with what you have now and still come back to clean it up if necessary - we can always do that.
| // used when a floating node is sunk out of loop: we don't want the cast that forces the node to be out of loop to | ||
| // be removed in any case otherwise the sunk node floats back into the loop. | ||
| static const DependencyType NonFloatingNonNarrowing; | ||
|
|
There was a problem hiding this comment.
Thanks for taking it over :-)
|
|
||
| // All the possible combinations of floating/narrowing with example use cases: | ||
|
|
||
| // Use case example: Range Check CastII |
There was a problem hiding this comment.
I believe this is incorrect, a range check should be floating non-narrowing. It is only narrowing if the length of the array is a constant. It is because this cast encodes the dependency on the condition index u< length. This condition cannot be expressed in terms of Type unless length is a constant.
There was a problem hiding this comment.
Range check CastII were added to protect the ConvI2L in the address expression on 64 bits. The problem there was, in some cases, that the ConvI2L would float above the range check (because ConvI2L has no control input) and could end up with an out of range input (which in turn would cause the ConvI2L to become top in places where it wasn't expected).
So CastII doesn't carry the control dependency of an array access on its range check. That dependency is carried by the MemNode which has its control input set to the range check.
What you're saying, if I understand it correctly, would be true if the CastII was required to prevent an array Load from floating. But that's not the case.
There was a problem hiding this comment.
Got it, sorry I misunderstood!
Co-authored-by: Emanuel Peter <emanuel.peter@oracle.com>
|
@merykitty @eme64 @chhagedorn thanks for the reviews |
|
@rwestrel I'll run some testing now ... |
|
@chhagedorn I see that an internal IR test is failing - one that you added a while back. Could you have a look what may have gone wrong? |
|
I had a look and it seems that the internal test is relying on a I therefore propose to fix the internal test before integrating this PR and then follow up with an RFE to fix the ideal optimization. I can take care of this and let you know once this is done. |
That sounds good to me. Should I take care of the ideal transformation? Let me know when the internal test is so I can proceed with the integration. |
|
Thanks Roland! I'll let you know and file a follow-up RFE and assign it to you. I will dump all the relevant information in there with a test case. |
|
The internal test is fixed and sanity testing passed - you can move forward with integrating this PR :-) |
|
@chhagedorn @eme64 @merykitty thanks for the reviews and testing |
|
/integrate |
|
@rwestrel This pull request has not yet been marked as ready for integration. |
|
/integrate |
|
Going to push as commit 00068a8.
Your commit was automatically rebased without conflicts. |
|
/backport :jdk26 |
|
@rwestrel the backport was successfully created on the branch backport-rwestrel-00068a80-jdk26 in my personal fork of openjdk/jdk. To create a pull request with this backport targeting openjdk/jdk:jdk26, just click the following link: The title of the pull request is automatically filled in correctly and below you find a suggestion for the pull request body:
If you need to update the source branch of the pull then run the following commands in a local clone of your personal fork of openjdk/jdk: |
This is a variant of 8332827. In 8332827, an array access becomes
dependent on a range check
CastIIfor another array access. When,after loop opts are over, that RC
CastIIwas removed, the arrayaccess could float and an out of bound access happened. With the fix
for 8332827, RC
CastIIs are no longer removed.With this one what happens is that some transformations applied after
loop opts are over widen the type of the RC
CastII. As a result, thetype of the RC
CastIIis no longer narrower than that of its input,the
CastIIis removed and the dependency is lost.There are 2 transformations that cause this to happen:
after loop opts are over, the type of the
CastIInodes are widenso nodes that have the same inputs but a slightly different type can
common.
When pushing a
CastIIthrough anAdd, if of the type both inputsof the
Adds are non constant, then we end up widening the type(the resulting
Addhas a type that's wider than that of theinitial
CastII).There are already 3 types of
Castnodes depending on theoptimizations that are allowed. Either the
Castis floating(
depends_only_test()returnstrue) or pinned. Either theCastcan be removed if it no longer narrows the type of its input or
not. We already have variants of the
CastII:if the Cast can float and be removed when it doesn't narrow the type
of its input.
if the Cast is pinned and be removed when it doesn't narrow the type
of its input.
if the Cast is pinned and can't be removed when it doesn't narrow
the type of its input.
What we need here, I think, is the 4th combination:
the type of its input.
Anyway, things are becoming confusing with all these different
variants named in ways that don't always help figure out what
constraints one of them operate under. So I refactored this and that's
the biggest part of this change. The fix consists in marking
Castnodes when their type is widen in a way that prevents them from being
optimized out.
Tobias ran performance testing with a slightly different version of
this change and there was no regression.
Progress
Issue
Reviewers
Reviewing
Using
gitCheckout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/24575/head:pull/24575$ git checkout pull/24575Update a local copy of the PR:
$ git checkout pull/24575$ git pull https://git.openjdk.org/jdk.git pull/24575/headUsing Skara CLI tools
Checkout this PR locally:
$ git pr checkout 24575View PR using the GUI difftool:
$ git pr show -t 24575Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/24575.diff
Using Webrev
Link to Webrev Comment