RFR: 8371674: C2 fails with Missed optimization opportunity in PhaseIterGVN for MoveL2D [v2]
Christian Hagedorn
chagedorn at openjdk.org
Wed Nov 19 13:04:22 UTC 2025
On Wed, 19 Nov 2025 08:31:05 GMT, Benoît Maillard <bmaillard at openjdk.org> wrote:
>> This PR addresses yet another missed optimization in `PhaseIterGVN`. The way this optimization is triggered is a bit different this time though, and the notification is missing in `Node::has_special_unique_user`.
>>
>> ## Analysis
>>
>> The affected optimization is the transformation of `MoveX2Y (LoadX mem)` into `LoadY mem`. This is implemented in `MoveNode::Ideal`. The optimization is as follows:
>>
>> ```c++
>> // Fold reinterpret cast into memory operation:
>> // MoveX2Y (LoadX mem) => LoadY mem
>> LoadNode* ld = in(1)->isa_Load();
>> if (ld != nullptr && (ld->outcnt() == 1)) { // replace only
>> const Type* rt = bottom_type();
>> if (ld->has_reinterpret_variant(rt)) {
>> if (phase->C->post_loop_opts_phase()) {
>> return ld->convert_to_reinterpret_load(*phase, rt);
>> } else {
>> // attempt the transformation once loop opts are over
>> phase->C->record_for_post_loop_opts_igvn(this);
>> }
>> }
>> }
>>
>>
>> The optimization is triggered only if the input is a `LoadNode` and the `MoveNode` is its only user. This is a relatively unusual pattern.
>>
>> The bug was found by the fuzzer. At some point during IGVN, we have the following subgraph:
>>
>>
>> CountedLoop LoadL
>> \ / \
>> Phi MoveL2D
>>
>> In `RegionNode::Ideal`, we end up calling `set_req_X` on the `Phi` node to delete the edge from the `Phi` node to `LoadL`. As a result, the `LoadL` node only has one user left, and the `MoveNode::Ideal` gets triggered at the next verification pass.
>>
>> ## Proposed Solution
>>
>> Add this particular case to `Node::has_special_unique_user`, which gets called by `Node::set_req_X`.
>>
>> ## Summary of changes
>>
>> This PR brings the following changes:
>> - Detect the optimization pattern in `Node::has_special_unique_user`.
>> - Add new test `TestMissingOptMoveX2YLoadX.java`, initially obtained from the fuzzer and then heavily reduced, both with the usual tools and manually. I tried to get a reproducer for each of the `Move` nodes, but I was only able to get one for `MoveL2D`.
>>
>> ### Testing
>>
>> - [x] https://github.com/benoitmaillard/jdk/actions?query=branch%3AJDK-8371674
>> - [x] tier1-4, plus some internal testing
>>
>> Thank you for reviewing!
>
> Benoît Maillard has updated the pull request incrementally with one additional commit since the last revision:
>
> Rename test and add comment
Looks good to me, too!
-------------
Marked as reviewed by chagedorn (Reviewer).
PR Review: https://git.openjdk.org/jdk/pull/28290#pullrequestreview-3482586988
More information about the hotspot-compiler-dev
mailing list