RFR: 8349139: C2: Div looses dependency on condition that guarantees divisor not null in counted loop [v6]

Christian Hagedorn chagedorn at openjdk.org
Tue Apr 22 08:30:54 UTC 2025


On Fri, 18 Apr 2025 14:08:11 GMT, Roland Westrelin <roland at openjdk.org> wrote:

>> The test crashes because of a division by zero. The `Div` node for
>> that one is initially part of a counted loop. The control input of the
>> node is cleared because the divisor is non zero. This is because the
>> divisor depends on the loop phi and the type of the loop phi is
>> narrowed down when the counted loop is created. pre/main/post loops
>> are created, unrolling happens, the main loop looses its backedge. The
>> `Div` node can then float above the zero trip guard for the main
>> loop. When the zero trip guard is not taken, there's no guarantee the
>> divisor is non zero so the `Div` node should be pinned below it.
>> 
>> I propose we revert the change I made with 8334724 which removed
>> `PhaseIdealLoop::cast_incr_before_loop()`. The `CastII` that this
>> method inserted was there to handle exactly this problem. It was added
>> initially for a similar issue but with array loads. That problem with
>> loads is handled some other way now and that's why I thought it was
>> safe to proceed with the removal.
>> 
>> The code in this patch is somewhat different from the one we had
>> before for a couple reasons:
>> 
>> 1- assert predicate code evolved and so previous logic can't be
>>   resurrected as it was.
>>   
>> 2- the previous logic has a bug.
>> 
>> Regarding 1-: during pre/main/post loop creation, we used to add the
>> `CastII` and then to add assertion predicates (so assertion predicates
>> depended on the `CastII`). Then when unrolling, when assertion
>> predicates are updated, we would skip over the `CastII`. What I
>> propose here is to add the `CastII` after assertion predicates are
>> added. As a result, they don't depend on the `CastII` and there's no
>> need for any extra logic when unrolling happens. This, however,
>> doesn't work when the assertion predicates are added by RCE. In that
>> case, I had to add logic to skip over the `CastII` (similar to what
>> existed before I removed it).
>> 
>> Regarding 2-: previous implementation for
>> `PhaseIdealLoop::cast_incr_before_loop()` would add the `CastII` at
>> the first loop `Phi` it encounters that's a use of the loop increment:
>> it's usually the iv but not always. I tweaked the test case to show,
>> this bug can actually cause a crash and changed the logic for
>> `PhaseIdealLoop::cast_incr_before_loop()` accordingly.
>
> Roland Westrelin has updated the pull request incrementally with one additional commit since the last revision:
> 
>   whitespace

Looks good to me, too.

Nit: You should probably update the title: "divisor not null" -> "divisor not zero".

src/hotspot/share/opto/loopnode.cpp line 6072:

> 6070:     // which is be transformed to (3):
> 6071:     // (AddI pre_loop_iv -1)
> 6072:     // The compiler may be able to constant fold the assert predicate condition for (3) but not (1)

Suggestion:

    // skip over the cast added by PhaseIdealLoop::cast_incr_before_loop() when pre/post/main loops are created because
    // it can get in the way of type propagation. For instance, the index tested by an Assertion Predicate, if the cast is
    // not skipped over, could be (1):
    // (AddI (CastII (AddI pre_loop_iv -2) int) 1)
    // while without the cast, it is (2):
    // (AddI (AddI pre_loop_iv -2) 1)
    // which is be transformed to (3):
    // (AddI pre_loop_iv -1)
    // The compiler may be able to constant fold the Assertion Predicate condition for (3) but not (1)

-------------

Marked as reviewed by chagedorn (Reviewer).

PR Review: https://git.openjdk.org/jdk/pull/23617#pullrequestreview-2783275896
PR Review Comment: https://git.openjdk.org/jdk/pull/23617#discussion_r2053606293


More information about the hotspot-compiler-dev mailing list