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

Emanuel Peter epeter at openjdk.org
Mon Jan 27 14:49:03 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

A few more for today. More tomorrow or later.

src/hotspot/share/opto/rangeinference.hpp line 145:

> 143:     // srange intersects with urange in 2 intervals [srange._lo, urange._hi]
> 144:     // and [urange._lo, srange._hi]
> 145:     return (urange._hi - U(srange._lo)) + (U(srange._hi) - urange._lo) + 1;

Ah, you are adding +1 here, but not above. I think that is because above it is one range, but here 2, right? Would be nice if you made a comment about that too.

src/hotspot/share/opto/rangeinference.hpp line 149:

> 147: 
> 148:   template <class CT, class S, class U>
> 149:   static const Type* int_type_xmeet(const CT* i1, const Type* t2, const Type* (*make)(const TypeIntPrototype<S, U>&, int, bool), bool dual);

I would create a typedef for the function pointer. Otherwise my brain only sees a salad of  asterisks, brackets, keywords etc 😅

src/hotspot/share/opto/rangeinference.hpp line 162:

> 160:     return super->_lo <= sub->_lo && super->_hi >= sub->_hi &&
> 161:            super->_ulo <= sub->_ulo && super->_uhi >= sub->_uhi &&
> 162:            (super->_bits._zeros &~ sub->_bits._zeros) == 0 && (super->_bits._ones &~ sub->_bits._ones) == 0;

Can you add a comment here what this does? Because it looks like a `&~` operator :)

I also wonder if it would make sense to delegate the `_bits` checks to its own class, for `equal` and `subset`.

src/hotspot/share/opto/type.cpp line 510:

> 508:   TypeLong::ZERO     = TypeLong::make( 0);   //  0
> 509:   TypeLong::ONE      = TypeLong::make( 1);   //  1
> 510:   TypeLong::NON_ZERO = TypeLong::try_make(TypeIntPrototype<jlong, julong>{{min_jlong, max_jlong}, {1, max_julong}, {0, 0}}, WidenMin)->is_long();

Here we really expect the `try` not to fail, right? Maybe we could have some `make` method, that calls `try_make` and asserts that we succeed?

src/hotspot/share/opto/type.cpp line 1610:

> 1608: const Type* TypeInt::try_make(const TypeIntPrototype<jint, juint>& t, int w, bool dual) {
> 1609:   auto new_t = t.canonicalize_constraints();
> 1610:   if (!new_t._present) {

Here `empty` would read a little more naturally, just an idea.
Ah, and I would rename `new_t` -> `canonical_t` or `canonicalized_t`.

src/hotspot/share/opto/type.cpp line 1620:

> 1618:   return (new TypeInt(TypeIntPrototype<jint, juint>{{lo, lo}, {ulo, ulo}, {~ulo, ulo}},
> 1619:                       WidenMin, false))->hashcons()->is_int();
> 1620: }

We are talking about a constant here, right? In that case, I would rename `lo` -> `con` or `val`.

src/hotspot/share/opto/type.cpp line 1629:

> 1627: const Type* TypeInt::try_make(const TypeIntPrototype<jint, juint>& t, int w) {
> 1628:   return try_make(t, w, false);
> 1629: }

While we are already here: can we use the full name of `w`? Is it `widen`?

src/hotspot/share/opto/type.cpp line 1667:

> 1665:   assert(!_is_dual, "dual types should only be used for join calculation");
> 1666:   const TypeInt* ft = join_helper(kills, include_speculative)->isa_int();
> 1667:   if (ft == nullptr) {

Why can this now not be empty any more?

src/hotspot/share/opto/type.cpp line 1708:

> 1706: 
> 1707: bool TypeInt::empty(void) const {
> 1708:   return false;

Oh, so it can now never be empty, why?

src/hotspot/share/opto/type.cpp line 1726:

> 1724: const TypeLong* TypeLong::TYPE_DOMAIN; // alias for TypeLong::LONG
> 1725: 
> 1726: TypeLong::TypeLong(const TypeIntPrototype<jlong, julong>& t, int w, bool dual)

Rename `w` -> `widen`

src/hotspot/share/opto/type.cpp line 1740:

> 1738: }
> 1739: 
> 1740: const TypeLong* TypeLong::make(jlong lo) {

Rename `lo` -> `con`.

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

PR Review: https://git.openjdk.org/jdk/pull/17508#pullrequestreview-2575570593
PR Review Comment: https://git.openjdk.org/jdk/pull/17508#discussion_r1930607348
PR Review Comment: https://git.openjdk.org/jdk/pull/17508#discussion_r1930608024
PR Review Comment: https://git.openjdk.org/jdk/pull/17508#discussion_r1930614382
PR Review Comment: https://git.openjdk.org/jdk/pull/17508#discussion_r1930617991
PR Review Comment: https://git.openjdk.org/jdk/pull/17508#discussion_r1930622146
PR Review Comment: https://git.openjdk.org/jdk/pull/17508#discussion_r1930626921
PR Review Comment: https://git.openjdk.org/jdk/pull/17508#discussion_r1930630031
PR Review Comment: https://git.openjdk.org/jdk/pull/17508#discussion_r1930633898
PR Review Comment: https://git.openjdk.org/jdk/pull/17508#discussion_r1930642138
PR Review Comment: https://git.openjdk.org/jdk/pull/17508#discussion_r1930643070
PR Review Comment: https://git.openjdk.org/jdk/pull/17508#discussion_r1930643521


More information about the hotspot-compiler-dev mailing list