RFR: 8342692: C2: long counted loop/long range checks: don't create loop-nest for short running loops [v25]
Christian Hagedorn
chagedorn at openjdk.org
Wed May 21 10:26:01 UTC 2025
On Wed, 21 May 2025 09:35:20 GMT, Roland Westrelin <roland at openjdk.org> wrote:
>> To optimize a long counted loop and long range checks in a long or int
>> counted loop, the loop is turned into a loop nest. When the loop has
>> few iterations, the overhead of having an outer loop whose backedge is
>> never taken, has a measurable cost. Furthermore, creating the loop
>> nest usually causes one iteration of the loop to be peeled so
>> predicates can be set up. If the loop is short running, then it's an
>> extra iteration that's run with range checks (compared to an int
>> counted loop with int range checks).
>>
>> This change doesn't create a loop nest when:
>>
>> 1- it can be determined statically at loop nest creation time that the
>> loop runs for a short enough number of iterations
>>
>> 2- profiling reports that the loop runs for no more than ShortLoopIter
>> iterations (1000 by default).
>>
>> For 2-, a guard is added which is implemented as yet another predicate.
>>
>> While this change is in principle simple, I ran into a few
>> implementation issues:
>>
>> - while c2 has a way to compute the number of iterations of an int
>> counted loop, it doesn't have that for long counted loop. The
>> existing logic for int counted loops promotes values to long to
>> avoid overflows. I reworked it so it now works for both long and int
>> counted loops.
>>
>> - I added a new deoptimization reason (Reason_short_running_loop) for
>> the new predicate. Given the number of iterations is narrowed down
>> by the predicate, the limit of the loop after transformation is a
>> cast node that's control dependent on the short running loop
>> predicate. Because once the counted loop is transformed, it is
>> likely that range check predicates will be inserted and they will
>> depend on the limit, the short running loop predicate has to be the
>> one that's further away from the loop entry. Now it is also possible
>> that the limit before transformation depends on a predicate
>> (TestShortRunningLongCountedLoopPredicatesClone is an example), we
>> can have: new predicates inserted after the transformation that
>> depend on the casted limit that itself depend on old predicates
>> added before the transformation. To solve this cicular dependency,
>> parse and assert predicates are cloned between the old predicates
>> and the loop head. The cloned short running loop parse predicate is
>> the one that's used to insert the short running loop predicate.
>>
>> - In the case of a long counted loop, the loop is transformed into a
>> regular loop with a ...
>
> Roland Westrelin has updated the pull request incrementally with one additional commit since the last revision:
>
> review
Thanks for all the updates! I like the new documentation. Some final comments, then I think it's good to go from my side.
> JDK 26 sounds ok to me.
Sounds good. We might want to run some more testing after the fork when it's fully reviewed.
src/hotspot/share/opto/predicates.hpp line 83:
> 81: * int counted loops with long range checks for which a loop nest also needs to be created
> 82: * in the general case (so the transformation of long range checks to int range checks is
> 83: * legal).
Nice, thanks for adding it!
test/hotspot/jtreg/compiler/c2/irTests/TestLongRangeChecks.java line 41:
> 39: public class TestLongRangeChecks {
> 40: public static void main(String[] args) {
> 41: TestFramework.runWithFlags("-XX:-ShortRunningLongLoop", "-XX:+TieredCompilation", "-XX:-UseCountedLoopSafepoints", "-XX:LoopUnrollLimit=0");
You can probably update the copyright year to 2025.
test/hotspot/jtreg/compiler/longcountedloops/TestShortLoopLostLimit.java line 2:
> 1: /*
> 2: * Copyright (c) 2024, Red Hat, Inc. All rights reserved.
You can either update it to 2025 or just add 2025 additionally since you already proposed the initial PR in 2024. Same for the other files below.
test/hotspot/jtreg/compiler/longcountedloops/TestShortRunningIntLoopWithLongChecksPredicates.java line 36:
> 34:
> 35: // int RC is first eliminated by predication which causes assert
> 36: // predicate to be added. Then the loop is transformed to make it
Suggestion:
// int RC is first eliminated by predication which causes Assertion
// Predicates to be added. Then the loop is transformed to make it
test/hotspot/jtreg/compiler/longcountedloops/TestShortRunningIntLoopWithLongChecksPredicates.java line 38:
> 36: // predicate to be added. Then the loop is transformed to make it
> 37: // possible to optimize long RC. Finally unrolling happen which
> 38: // require the assert predicate to have been properly copied when the
Suggestion:
// require the Assert Predicates to have been properly copied when the
-------------
PR Review: https://git.openjdk.org/jdk/pull/21630#pullrequestreview-2856875349
PR Review Comment: https://git.openjdk.org/jdk/pull/21630#discussion_r2099906356
PR Review Comment: https://git.openjdk.org/jdk/pull/21630#discussion_r2099907906
PR Review Comment: https://git.openjdk.org/jdk/pull/21630#discussion_r2099908542
PR Review Comment: https://git.openjdk.org/jdk/pull/21630#discussion_r2099911193
PR Review Comment: https://git.openjdk.org/jdk/pull/21630#discussion_r2099912075
More information about the hotspot-compiler-dev
mailing list