RFR: 8351889: C2 crash: assertion failed: Base pointers must match (addp 344)
Roland Westrelin
roland at openjdk.org
Thu May 22 08:40:08 UTC 2025
The test case has an out of loop `Store` with an `AddP` address
expression that has other uses and is in the loop body. Schematically,
only showing the address subgraph and the bases for the `AddP`s:
Store#195 -> AddP#133 -> AddP#134 -> CastPP#110
-> CastPP#110
Both `AddP`s have the same base, a `CastPP` that's also in the loop
body.
That loop is a counted loop and only has 3 iterations so is fully
unrolled. First, one iteration is peeled:
/-> CastPP#110
Store#195 -> Phi#360 -> AddP#133 -> AddP#134 -> CastPP#110
-> AddP#277 -> AddP#278 -> CastPP#283
-> CastPP#283
The `AddP`s and `CastPP` are cloned (because in the loop body). As
part of peeling, `PhaseIdealLoop::peeled_dom_test_elim()` is
called. It finds the test that guards `CastPP#283` in the peeled
iteration dominates and replaces the test that guards `CastPP#110`
(the test in the peeled iteration is the clone of the test in the
loop). That causes `CastPP#110`'s control to be updated to that of the
test in the peeled iteration and to be yanked from the loop. So now
`CastPP#283` and `CastPP#110` have the same inputs.
Next unrolling happens:
/-> CastPP#110
/-> AddP#400 -> AddP#401 -> CastPP#110
Store#195 -> Phi#360 -> Phi#477 -> AddP#133 -> AddP#134 -> CastPP#110
\ -> CastPP#110
-> AddP#277 -> AddP#278 -> CastPP#283
-> CastPP#283
`AddP`s are cloned once more but not the `CastPP`s because they are
both in the peeled iteration now. A new `Phi` is added.
Next igvn runs. It's going to push the `AddP`s through the `Phi`s.
Through `Phi#477`:
/-> CastPP#110
Store#195 -> Phi#360 -> AddP#510 -> Phi#509 -> AddP#401 -> CastPP#110
\ -> AddP#134 -> CastPP#110
-> AddP#277 -> AddP#278 -> CastPP#283
-> CastPP#283
Through `Phi#360`:
/-> AddP#134 -> CastPP#110
/-> Phi#509 -> AddP#401 -> CastPP#110
Store#195 -> AddP#516 -> Phi#515 -> AddP#278 -> CastPP#283
-> Phi#514 -> CastPP#283
-> CastP#110
Then `Phi#514` which has 2 `CastPP`s as input with identical inputs is
transformed into another `CastPP` at the `Phi` constrol with the data
control of the `CastPP` as input. `PhiNode::unique_input()` with
`uncast = true` is where that happens. That's where things go wrong I
think.
/-> AddP#134 -> CastPP#110
/-> Phi#509 -> AddP#401 -> CastPP#110
Store#195 -> AddP#516 -> Phi#515 -> AddP#278 -> CastPP#283
-> CastPP#529
Next `AddP`s pushed through `Phi#509`:
/-> AddP#536 -> CastPP#110
Store#195 -> AddP#516 -> Phi#515 -> AddP#278 -> CastPP#283
-> CastPP#529
`CastPP#110` and `CastPP#283` commoned (they have the same inputs):
/-> AddP#536 -> CastPP#110
Store#195 -> AddP#516 -> Phi#515 -> AddP#278 -> CastPP#110
-> CastPP#529
Finally, AddPs pushed through `Phi#515`:
Store#195 -> AddP#516 -> AddP#544 -> CastPP#110
-> CastPP#529
And we end up with 2 `AddP`s with different bases. The 2 `CastPP`s
have the same data input but not same control and igvn can't common
them.
The fix I propose is to delay the call to `PhiNode::unique_input()`
with `uncast = true` if the `Phi`'s inputs are cast nodes and have yet
to be processed by igvn. This causes identical `CastPP`s to common and
then only the `Phi` has 2 identical inputs is transformed to that
input (rather than have a new `CastPP`s be created at a different
control).
-------------
Commit messages:
- more
- test
- fix
Changes: https://git.openjdk.org/jdk/pull/25386/files
Webrev: https://webrevs.openjdk.org/?repo=jdk&pr=25386&range=00
Issue: https://bugs.openjdk.org/browse/JDK-8351889
Stats: 99 lines in 3 files changed: 99 ins; 0 del; 0 mod
Patch: https://git.openjdk.org/jdk/pull/25386.diff
Fetch: git fetch https://git.openjdk.org/jdk.git pull/25386/head:pull/25386
PR: https://git.openjdk.org/jdk/pull/25386
More information about the hotspot-compiler-dev
mailing list