8376587: Fatal "dead path discovered by TypeNode during igvn" after C2 compilation#30339
8376587: Fatal "dead path discovered by TypeNode during igvn" after C2 compilation#30339rwestrel wants to merge 6 commits intoopenjdk:masterfrom
Conversation
|
👋 Welcome back roland! A progress list of the required criteria for merging this PR into |
|
❗ This change is not yet ready to be integrated. |
merykitty
left a comment
There was a problem hiding this comment.
For the
DecodeNabove, there's no type narrowing at theDecodeNso when theDecodeNbecomestop, it shouldn't causemake_paths_from_here_dead()from being called. I think It was error prone to haveTypeNode::Idealrunmake_paths_from_here_dead()for all nodes that becometopso I refactored that code.
I think this is not quite right, if a node becomes top, it propagates that top downwards, no matter the reason it becomes top. As a result, making uses of the top dead seems correct even if there is no type narrowing happening.
I noticed that the igvn split thru phi logic, when it checks whether inputs dominate the current region, bails out if a dead subgraph is encountered but the shape above is missed. I fixed that as well.
I think this is the main culprit. Suppose before the pointer input becomes dead, it is below the Phi, so we should not be able to split the load through that Phi. However, after the pointer input becomes top, it is suddenly dominated by only root, making all_paths_dominate incorrectly declare that we can incorrectly split the load through the Phi.
| return dom_result; | ||
| } | ||
| } else { | ||
| if (phase != nullptr && n->Value(phase) == Type::TOP) { |
There was a problem hiding this comment.
I think phase should be a mandatory input of this function, unless we can be sure that we are looking at a canonical graph. There are other uses (such as in MemNode::detect_ptr_independence) that suffer the same issue.
There was a problem hiding this comment.
Would you say the risk is that MemNode::detect_ptr_independence() returns an incorrect result or a too conservative one?
I initially added the phase input everywhere:
de785ee
but it turned out to be a big change and my understanding was that was only needed for correctness for the split thru phi of a load.
There was a problem hiding this comment.
It looks like a lot of changes... could a "warning" comment before the method be enough?
I think you're right. But would you agree that if the |
The result of the
Yes, I think for the current implementation of |
| } | ||
| virtual const Type* Value(PhaseGVN* phase) const; | ||
| virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); | ||
| virtual Node* make_paths_from_here_dead_if_needed(PhaseGVN* phase, bool can_reshape); |
There was a problem hiding this comment.
Does it still need to be virtual?
A subgraph:
where
Loopis reachable but theLoadBis dead (DecodeN's inputis
topand theLoadBhas no use in a live CFG path), is split thruphi during IGVN and transformed into:
DecodeNnodes becometopnext because of it'stopinput.
TypeNode::Idealruns (There's noDecodeNNode::Ideal()) andcalls
make_paths_from_here_dead()which causes the path on loopentry to be made dead even though it's reachable.
The
make_paths_from_here_dead()was added for cast nodes. The logicin
ConstraintCastNode::Ideal()shows how this is expected to work:TypeNode::Ideal()is only called if the cast becomestopand itsinput is not
top, that is, it's the type narrowing that the castperforms that causes the cast to become
topnot that it's in a deadsubgraph.
For the
DecodeNabove, there's no type narrowing at theDecodeNsowhen the
DecodeNbecomes top, it shouldn't causemake_paths_from_here_dead()from being called. I think It was errorprone to have
TypeNode::Idealrunmake_paths_from_here_dead()forall nodes that become
topso I refactored that code.I noticed that the igvn split thru phi logic, when it checks whether
inputs dominate the current region, bails out if a dead subgraph is
encountered but the shape above is missed. I fixed that as well.
Progress
Issue
Reviewing
Using
gitCheckout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/30339/head:pull/30339$ git checkout pull/30339Update a local copy of the PR:
$ git checkout pull/30339$ git pull https://git.openjdk.org/jdk.git pull/30339/headUsing Skara CLI tools
Checkout this PR locally:
$ git pr checkout 30339View PR using the GUI difftool:
$ git pr show -t 30339Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/30339.diff
Using Webrev
Link to Webrev Comment