RFR: 8278857: C2: optimize (x << 2) & -4 to x (and similar patterns) -> KnownBits for LShift

Quan Anh Mai qamai at openjdk.org
Thu Feb 26 17:26:50 UTC 2026


On Tue, 24 Feb 2026 17:00:42 GMT, Ashay Rane <duke at openjdk.org> wrote:

> This PR contains the first of the two changes necessary to resolve
> JDK-8278857.
> 
> The commit message, pasted below, has additional details.
> 
>> Augment `RangeInference` with information about left shifts
>> 
>> Add `RangeInference::infer_lshift()` to compute type information for
>> left shift operations.  This method tracks known zero bits in the low
>> positions (the bottom `shift` bits are always zero after a left shift)
>> and computes signed and unsigned range bounds when the shift does not
>> cause overflow.
>> 
>> This is the first of the two changes necessary to resolve JDK-8278857.
>> The second change will build on top of these changes to enable AND nodes
>> to be optimized away when the bits that would have been cleared by the
>> AND operation were already known to be zero.

Thanks for extracting this into a separate PR, it will be much clearer for us to review and much less overwhelming for you to address all of the comments :)

src/hotspot/share/opto/mulnode.cpp line 1137:

> 1135:   }
> 1136: 
> 1137:   // Left input is ZERO ==> the result is ZERO.

When neither input is `Type::TOP`, `t1` must be `TypeInt`/`TypeLong` and `t2` must be `TypeInt`. So you don't need to check for `Type::BOTTOM` below.

src/hotspot/share/opto/mulnode.cpp line 1148:

> 1146:   // If the left input is BOTTOM or if nothing is known about the shift amount,
> 1147:   // then the result is BOTTOM
> 1148:   if (t2 == TypeInt::INT || t1 == Type::BOTTOM || t2 == Type::BOTTOM) {

In general, `x << y` is defined to be `x << (y & 31)`. Can you tighten the type of the second operand using `normalized_t2 = RangeInference::infer_and(t2, TypeInt::make(31))`. It may allow you to have a complete picture of the operand here. For example, if `t2` has the lowest 5 bits known, then normalising it results in a constant, or if `normalized_t2->_lo == 10`, then you can infer that the result will have the lowest 10 bits being 0, which is not the case for the non-normalised `t2`.

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

> 415:   static CTP infer_lshift(CTP t1, int shift) {
> 416:     constexpr int type_bits = sizeof(U<CTP>) * 8;
> 417:     int masked_shift = shift & (type_bits - 1);

Sadly, `sizeof` does not work for `intn_t`, you may need to count the set bits of the maximum unsigned value.

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

> 428:     S<CTP> shi = s_overflow ? std::numeric_limits<S<CTP>>::max() : shifted_shi;
> 429: 
> 430:     U<CTP> shifted_ulo = t1->_ulo << masked_shift;

I believe unsigned bounds still hold when overflowing, so you don't need to check for the overflow of unsigned bounds.

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

PR Review: https://git.openjdk.org/jdk/pull/29898#pullrequestreview-3862432820
PR Review Comment: https://git.openjdk.org/jdk/pull/29898#discussion_r2860307294
PR Review Comment: https://git.openjdk.org/jdk/pull/29898#discussion_r2860302390
PR Review Comment: https://git.openjdk.org/jdk/pull/29898#discussion_r2860332006
PR Review Comment: https://git.openjdk.org/jdk/pull/29898#discussion_r2860323932


More information about the hotspot-dev mailing list