RFR: 8315066: Add unsigned bounds and known bits to TypeInt/Long [v32]

Emanuel Peter epeter at openjdk.org
Mon Jan 27 14:19:12 UTC 2025


On Wed, 22 Jan 2025 15:43:03 GMT, Quan Anh Mai <qamai at openjdk.org> wrote:

>> Hi,
>> 
>> This patch adds unsigned bounds and known bits constraints to TypeInt and TypeLong. This opens more transformation opportunities in an elegant manner as well as helps avoid some ad-hoc rules in Hotspot.
>> 
>> In general, a `TypeInt/Long` represents a set of values `x` that satisfies: `x s>= lo && x s<= hi && x u>= ulo && x u<= uhi && (x & zeros) == 0 && (x & ones) == ones`. These constraints are not independent, e.g. an int that lies in [0, 3] in signed domain must also lie in [0, 3] in unsigned domain and have all bits but the last 2 being unset. As a result, we must canonicalize the constraints (tighten the constraints so that they are optimal) before constructing a `TypeInt/Long` instance.
>> 
>> This is extracted from #15440 , node value transformations are left for later PRs. I have also added unit tests to verify the soundness of constraint normalization.
>> 
>> Please kindly review, thanks a lot.
>> 
>> Testing
>> 
>> - [x] GHA
>> - [x] Linux x64, tier 1-4
>
> Quan Anh Mai has updated the pull request with a new target base due to a merge or a rebase. The pull request now contains 44 commits:
> 
>  - remove precompiled.hpp
>  - Merge branch 'master' into unsignedbounds
>  - copyright
>  - Merge branch 'master' into unsignedbounds
>  - Merge branch 'master' into unsignedbounds
>  - move try_cast to Type
>  - Merge branch 'master' into unsignedbounds
>  - build failure
>  - build failures
>  - whitespace
>  - ... and 34 more: https://git.openjdk.org/jdk/compare/893d00ac...c4d46c87

@merykitty I've always had this on the list. I'm a little tired today, so won't tough the math heavy stuff, but I have some other suggestions. I'll try to put in a bit of time multiple time a week to get through this eventually.

src/hotspot/share/opto/rangeinference.cpp line 42:

> 40: 
> 41:   static AdjustResult<T> make_empty() {
> 42:     return {true, false, {}};

I'd say you should choose between `empty` and `consistent` and `contradiction`. Three synonyms is a little much 😅

src/hotspot/share/opto/rangeinference.cpp line 47:

> 45: 
> 46: // In the canonical form, [lo, hi] intersects with [ulo, uhi] can result in 2
> 47: // cases:

Fix grammar. Would this be correct?
Suggestion:

// In the canonical form, intersection of [lo, hi] with [ulo, uhi] can result in 2
// cases:

src/hotspot/share/opto/rangeinference.cpp line 52:

> 50: // being [lo, uhi] and [ulo, hi], lo and uhi are < 0 while ulo and hi are >= 0.
> 51: // This class deals with each interval with both bounds being >= 0 or < 0 in
> 52: // the signed domain.

I would indent to the bullet points consistently.

src/hotspot/share/opto/rangeinference.cpp line 342:

> 340: }
> 341: 
> 342: // Try to tighten both the bounds and the bits at the same time

Suggestion:

// Try to tighten both the bounds and the bits at the same time.

src/hotspot/share/opto/rangeinference.cpp line 343:

> 341: 
> 342: // Try to tighten both the bounds and the bits at the same time
> 343: // Iteratively tighten 1 using the other until no progress is made.

Suggestion:

// Iteratively tighten one using the other until no progress is made.

Or are you talking about the number `1`?

src/hotspot/share/opto/rangeinference.cpp line 345:

> 343: // Iteratively tighten 1 using the other until no progress is made.
> 344: // This function converges because at each iteration, some bits that are
> 345: // unknown is made known. As there are at most 64 bits, the number of

Suggestion:

// unknown are made known. As there are at most 64 bits, the number of

src/hotspot/share/opto/rangeinference.cpp line 346:

> 344: // This function converges because at each iteration, some bits that are
> 345: // unknown is made known. As there are at most 64 bits, the number of
> 346: // iterations should not be larger than 64

Suggestion:

// iterations should not be larger than 64.

src/hotspot/share/opto/rangeinference.cpp line 349:

> 347: template <class U>
> 348: static SimpleCanonicalResult<U>
> 349: canonicalize_constraints_simple(const RangeInt<U>& bounds, const KnownBits<U>& bits) {

What does the "simple" mean here? To me, what is happening here is not really "simple" if that is what you were trying to say 😆

src/hotspot/share/opto/rangeinference.cpp line 352:

> 350:   AdjustResult<KnownBits<U>> nbits = adjust_bits_from_bounds(bits, bounds);
> 351:   if (!nbits._is_result_consistent) {
> 352:     return SimpleCanonicalResult<U>::make_empty();

Suggestion:

  if (nbits._is_result_empty) {
    return SimpleCanonicalResult<U>::make_empty();

That would read much more easily ;)

src/hotspot/share/opto/rangeinference.cpp line 354:

> 352:     return SimpleCanonicalResult<U>::make_empty();
> 353:   }
> 354:   AdjustResult<RangeInt<U>> nbounds{true, true, bounds};

`nbounds`: what is the `n` here?

Since you are doing this iteratively, I think `nbits` -> `current_bits`, and `nbounds` -> `current_bounds` would be more explicit.

Alternatively, you rename the inputs to `old_...`, and just call the ones you keep updating `bits` and `bounds`. Up to you.

src/hotspot/share/opto/rangeinference.cpp line 361:

> 359:     nbounds = adjust_bounds_from_bits(nbounds._result, nbits._result);
> 360:     if (!nbounds._progress || !nbounds._is_result_consistent) {
> 361:       return {nbounds._is_result_consistent, nbounds._result, nbits._result};

That sounds a little scary to me:
It sounds like we could have inconsistent results: `!nbounds._is_result_consistent` and then simply return the `nbounds._result`. Is that ok, or just confusing wording?
I think again here `empty` would be our friend: returning an empty result is more sane than returning an inconsistent one 😅

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

PR Review: https://git.openjdk.org/jdk/pull/17508#pullrequestreview-2575032986
PR Review Comment: https://git.openjdk.org/jdk/pull/17508#discussion_r1930286401
PR Review Comment: https://git.openjdk.org/jdk/pull/17508#discussion_r1930289367
PR Review Comment: https://git.openjdk.org/jdk/pull/17508#discussion_r1930569492
PR Review Comment: https://git.openjdk.org/jdk/pull/17508#discussion_r1930576397
PR Review Comment: https://git.openjdk.org/jdk/pull/17508#discussion_r1930576938
PR Review Comment: https://git.openjdk.org/jdk/pull/17508#discussion_r1930577571
PR Review Comment: https://git.openjdk.org/jdk/pull/17508#discussion_r1930577850
PR Review Comment: https://git.openjdk.org/jdk/pull/17508#discussion_r1930580768
PR Review Comment: https://git.openjdk.org/jdk/pull/17508#discussion_r1930583715
PR Review Comment: https://git.openjdk.org/jdk/pull/17508#discussion_r1930586968
PR Review Comment: https://git.openjdk.org/jdk/pull/17508#discussion_r1930593064


More information about the hotspot-compiler-dev mailing list