RFR: 8360510: C2: Template Assertion Predicates are not cloned to the inner counted loop with -XX:+StressDuplicateBackedge
Emanuel Peter
epeter at openjdk.org
Tue Nov 25 10:50:29 UTC 2025
On Tue, 25 Nov 2025 10:21:26 GMT, Emanuel Peter <epeter at openjdk.org> wrote:
>> ### Strong Connection between Template Assertion Predicate and Counted Loop
>> In [JDK-8350579](https://bugs.openjdk.org/browse/JDK-8350579), we fixed the issue that a Template Assertion Predicate for a folded loop A could end up at another loop B. We then created an Initialized Assertion Predicate at loop B from the template of loop A and used the values from the already folded, completely unrelated loop A . As a result, we crashed with a halt because loop B violated the predicate with the wrong values. As a fix, we established a strong connection between Template Assertion Predicates and their associated loop node by adding a direct link from `OpaqueTemplateAssertionPredicate` -> `CountedLoop`.
>>
>> #### Maintaining this Property
>> In `PhaseIdealLoop::eliminate_useless_predicates()`, we walk through all counted loops and only keep those `OpaqueTemplateAssertionPredicate` nodes that can be found from the loop heads and are actually meant for this loop (using the strong connection):
>> https://github.com/openjdk/jdk/blob/d2926dfd9a242928877d0b1e40eac498073975bd/src/hotspot/share/opto/predicates.cpp#L1245-L1249
>>
>> All other opaque nodes are removed.
>>
>> ### Additional Verification for Useless `OpaqueTemplateAssertionPredicate` Nodes
>> As an additional verification for `OpaqueTemplateAssertionPredicate` nodes that are found to be useless in `eliminate_useless_predicates()`, we check that in this case the `CountedLoop` is really dead (otherwise, we should have found the `OpaqueTemplateAssertionPredicate` in our walks through all loop):
>> https://github.com/openjdk/jdk/blob/d2926dfd9a242928877d0b1e40eac498073975bd/src/hotspot/share/opto/predicates.cpp#L1294-L1301
>>
>> ### Violating the Additional Verification with `-XX:+StressLoopBackedge`
>> In `PhaseIdealLoop::duplicate_loop_backedge()`, we convert a loop with a merge point into two loops which should enable us to transform the new inner loop into a counted loop. This only makes sense for a `Loop` that is not a counted loop, yet. However, to stress the transformation, we can also run with `-XX:+StressDuplicateBackedge` that also transforms a counted loop into an inner and an outer loop. This is a problem when we have Template Assertion Predicates above a counted loop to be stressed:
>>
>> <img width="581" height="556" alt="image" src="https://github.com/user-attachments/assets/e7948804-e74d-4dd0-a0f8-64eedaa259ba" />
>>
>> After duplicate backedge, the Template Assertion Predicates are now at the outer non-...
>
> test/hotspot/jtreg/compiler/predicates/assertion/TestStressDuplicateBackedgeWithAssertionPredicate.java line 62:
>
>> 60: // The Template Assertion Predicates are still at the outer loop. As a result, we find them to
>> 61: // be useless in the next predicate elimination call with EliminateUselessPredicates because
>> 62: // they cannot be found from the inner counted loop. However, we have verification code in place
>
> First: cudos on the annotations in this test! Really much appreciated :)
>
> I'm a bit confused here. Are you talking about the Template Assertion Predicates of the outer or inner loop here? Because you say both:
> - `Template Assertion Predicates are still at the outer loop`
> - `they cannot be found from the inner counted loop`
> Can you clarify?
Ah, maybe the confusion comes from this:
- We have an "inner" loop: the one that becomes empty and is removed.
- And an "inner" loop from the duplicate backedge optimization.
Is this correct? If yes, name them a bit more precisely ;)
Also: are the new inner/outer loops nested? The ascii art suggests that they are in sequence. Maybe drawing some backedges could help?
-------------
PR Review Comment: https://git.openjdk.org/jdk/pull/28389#discussion_r2559459326
More information about the hotspot-compiler-dev
mailing list