RFR: 8315066: Add unsigned bounds and known bits to TypeInt/Long [v55]
Emanuel Peter
epeter at openjdk.org
Thu May 1 16:01:20 UTC 2025
On Thu, 1 May 2025 10:48:42 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 incrementally with one additional commit since the last revision:
>
> Emanuel's reviews
Made it down through `type.cpp`.
Will have to do a pass through the rest later. And then go through the whole thing again.
I feel like we are making good progress on this now :)
src/hotspot/share/opto/rangeinference.cpp line 694:
> 692: return i1;
> 693: }
> 694: const CT* i2 = t2->try_cast<CT>();
And what is the significance of the `dual` state of i1 and `i2`? Should their `dual` state be the same?
Can we add some assert here?
src/hotspot/share/opto/rangeinference.hpp line 185:
> 183:
> 184: template <class CT>
> 185: static const Type* int_type_narrow(const CT* nt, const CT* ot);
Suggestion:
static const Type* int_type_widen(const CT* new_type, const CT* old_type, const CT* limit_type);
template <class CT>
static const Type* int_type_narrow(const CT* new_type, const CT* old_type, const CT* limit_type);
For consistency with its definition.
src/hotspot/share/opto/type.cpp line 1806:
> 1804: bool TypeInt::contains(jint i) const {
> 1805: juint u = i;
> 1806: return i >= _lo && i <= _hi && u >= _ulo && u <= _uhi && _bits.is_satisfied_by(u);
Suggestion:
return _lo <= i && i <= _hi &&
_ulo <= u && u <= _uhi &&
_bits.is_satisfied_by(u);
Optional, for readability.
src/hotspot/share/opto/type.cpp line 1809:
> 1807: }
> 1808:
> 1809: bool TypeInt::contains(const TypeInt* t) const {
Is dual allowed here, or could we assert?
src/hotspot/share/opto/type.cpp line 1848:
> 1846: // The widen bits must be allowed to run freely through the graph.
> 1847: return (new TypeInt(TypeIntPrototype<jint, juint>{{ft->_lo, ft->_hi}, {ft->_ulo, ft->_uhi}, ft->_bits},
> 1848: this->_widen, false))->hashcons();
Why not use `TypeInt::make`?
src/hotspot/share/opto/type.cpp line 1930:
> 1928: bool TypeLong::contains(jlong i) const {
> 1929: julong u = i;
> 1930: return i >= _lo && i <= _hi && u >= _ulo && u <= _uhi && _bits.is_satisfied_by(u);
Suggestion:
return _lo <= i && i <= _hi &&
_ulo <= u && u <= _uhi &&
_bits.is_satisfied_by(u);
For readability.
-------------
PR Review: https://git.openjdk.org/jdk/pull/17508#pullrequestreview-2810044167
PR Review Comment: https://git.openjdk.org/jdk/pull/17508#discussion_r2070423848
PR Review Comment: https://git.openjdk.org/jdk/pull/17508#discussion_r2070413425
PR Review Comment: https://git.openjdk.org/jdk/pull/17508#discussion_r2070420492
PR Review Comment: https://git.openjdk.org/jdk/pull/17508#discussion_r2070430474
PR Review Comment: https://git.openjdk.org/jdk/pull/17508#discussion_r2070432896
PR Review Comment: https://git.openjdk.org/jdk/pull/17508#discussion_r2070437258
More information about the hotspot-compiler-dev
mailing list