-
Notifications
You must be signed in to change notification settings - Fork 6.1k
8274074: SIGFPE with C2 compiled code with -XX:+StressGCM #5651
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
👋 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
|
src/hotspot/share/opto/loopopts.cpp
Outdated
@@ -1558,6 +1558,11 @@ void PhaseIdealLoop::try_sink_out_of_loop(Node* n) { | |||
_igvn.remove_dead_node(n); | |||
} | |||
_dom_lca_tags_round = 0; | |||
} else if (n_loop == _ltree_root && n->in(0) != NULL && get_loop(n->in(0)) != _ltree_root) { |
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.
Couldn't the node be out of this loop but not necessarily out of all loops?
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, that's an unnecessary limitation. I've tried to find an example where this happens but could not come up with one. But I'm sure that situation will occur at some point. I pushed an update.
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.
// Zero check Z2 with UCT | ||
// DivI node D is only used on IfFalse path of zero check Z2 into UCT (on IfTrue path, the result is not used anywhere | ||
// because we directly overwrite it again with "y = (5 / iFld)). The IfFalse path of the zero check, however, is never | ||
// taken because iFld = 1. But before applying the sinking algorithm, the DivI node D could be be executed during 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.
"could be be" -> "could be"
// and optimizing it accordingly (iFld is found to be zero because the zero check Z2 failed, i.e. iFld is zero which is | ||
// propagated into the CastII node whose type is improved to [0,0] and the node is replaced by constant zero), the | ||
// DivI node must NOT be executed inside the loop anymore. But the DivI node is executed in the loop because of losing | ||
// the CastII pin. The fix is to updated the control input of the DivI node to the get_ctrl() input outside the 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.
"to updated" -> "to update"
Thanks Tobias 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.
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 138 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 |
Thanks Roland for your review! |
/integrate |
Going to push as commit b0983df.
Your commit was automatically rebased without conflicts. |
@chhagedorn Pushed as commit b0983df. 💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored. |
In the testcase, the divisor input node of a
DivI
node is sunk out of a loop to a div by zero UCT and is pinned with aCastII
node to ensure it's not floating back into the loop. The divisor is optimized by taking into account that it's only executed on the uncommon path. TheCastII
, however, is removed later and the division floats back into the loop which results in a SIGFPE crash.The relevent lines in the testcase are the following two divisions:
After sinking the
divisor
ofdivision 1
in the testcase to the div by zero UCT ofdivision 2
, the graph looks like this:201 If
is the zero check ofdivision 2
(will always succeed becauseiFld = 1
, i.e. UCT is never taken).193 DivI
(division 1
) is not sunk because itsget_ctrl()
is203 IfFalse
(outside the loop already because there is no use inside the loop since the localy
is directly overwritten again).275 SubI
(divisor
) was sunk out of the loop and is pinned by276 CastII
(unconditional dependency).In IGVN,
CastII::Value()
is called for276 CastII
. It sees anIf/Cmp
(zero check ofdivision 2
) with the same137 LoadI
input as for the276 CastII
. Therefore, we set its type to [0,0] here:jdk/src/hotspot/share/opto/castnode.cpp
Lines 248 to 252 in d098751
As a result, we replace
276 CastII
with a constant zero in IGVN. But now we lost the pin to the uncommon path of the zero check ofdivision 2
for275 SubI
and193 DivI
.193 DivI
is only used on the uncommon path but can now float around again, also inside the loop itself, which happens in the testcase. Inside the loop, we execute the division with the now optimized divisor0 - q = 0
which is a division by zero and we crash.In summary, it's not a problem that a
Div
node floats above its zero check here but rather that we optimize an input node used as divisor by assuming that we only execute the division on the uncommon path when the zero check ofdivision 2
failed (which never happens). This divisor optimization would be wrong when the division is executed inside the loop. But due to losing the pin, we end up doing exactly that which results in a SIGFPE crash.The suggested fix is to extend the sinking algorithm to rewire data nodes with a control input inside a loop whose
get_ctrl()
is actually completely outside loops on uncommon paths. The control input is set toget_ctrl()
to force the nodes out of loops. In the example above, the control input of193 DivI
is set to203 IfFalse
, ensuring that it is still pinned to the uncommon path after276 CastII
is removed. This fix is also beneficial if we do not sink any nodes at all later.Thanks,
Christian
Progress
Issue
Reviewers
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.java.net/jdk pull/5651/head:pull/5651
$ git checkout pull/5651
Update a local copy of the PR:
$ git checkout pull/5651
$ git pull https://git.openjdk.java.net/jdk pull/5651/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 5651
View PR using the GUI difftool:
$ git pr show -t 5651
Using diff file
Download this PR as a diff file:
https://git.openjdk.java.net/jdk/pull/5651.diff