RFR: 8350896: Integer/Long.compress gets wrong type from CompressBitsNode::Value [v9]

Emanuel Peter epeter at openjdk.org
Tue Jun 3 14:21:02 UTC 2025


On Mon, 2 Jun 2025 17:58:09 GMT, Jatin Bhateja <jbhateja at openjdk.org> wrote:

>> Hi All,
>> 
>> This bugfix patch fixes incorrect value computation for Integer/Long. compress APIs.
>> 
>> Problems occur with a constant input and variable mask where the input's value is equal to the lower bound of the mask value., In this case, an erroneous value range estimation results in a constant value. Existing value routine first attempts to constant fold the compression operation if both input and compression mask are constant values; otherwise, it attempts to constrain the value range of result based on the upper and lower bounds of mask type.
>> 
>> New IR test covers the issue reported in the bug report along with a case for value range based logic pruning.
>> 
>> Kindly review and share your feedback.
>> 
>> Best Regards,
>> Jatin
>
> Jatin Bhateja has updated the pull request incrementally with one additional commit since the last revision:
> 
>   Fix aarch64 failure

src/hotspot/share/opto/intrinsicnode.cpp line 314:

> 312:         // mask value for which iff all corresponding input bits are set then bit compression
> 313:         // will result in a -ve value, therefore this case negates the possibility of
> 314:         // strictly non-negative bit compression result.

Grammar was a little off. I think we can say it in fewer words.
Suggestion:

        // Case B.1 The mask value range includes -1, hence we may use all bits,
        //          the result has the whole value range.

src/hotspot/share/opto/intrinsicnode.cpp line 328:

> 326:         // optimistic upper bound of result i.e. all the bits other than leading zero bits
> 327:         // can be assumed holding 1 value.
> 328:         assert(mask_type->lo_as_long() >= 0, "");

Suggestion:

        assert(mask_type->lo_as_long() >= 0, "");
        // Case B.3 Mask value range only includes non-negative values. Since all integral
        // types honours an invariant that TypeInteger._lo <= TypeInteger._hi, thus computing
        // leading zero bits of upper bound of mask value will allow us to ascertain
        // optimistic upper bound of result i.e. all the bits other than leading zero bits
        // can be assumed holding 1 value.

Have the assert first, like a condition. Then the comments follow from it and make sense immediately.

src/hotspot/share/opto/intrinsicnode.cpp line 339:

> 337:       // compression result will never be a -ve value and we can safely set the
> 338:       // lower bound of bit compression to zero.
> 339:       lo = result_bit_width == mask_bit_width ? lo : 0L;

Fixed grammar a little.
Suggestion:

      // If the number of bits required to for the mask value range is less than the
      // full bit width of the integral type, then the MSB bit is guaranteed to be zero,
      // thus the compression result will never be a -ve value and we can safely set the
      // lower bound of the bit compression to zero.
      lo = result_bit_width == mask_bit_width ? lo : 0L;

src/hotspot/share/opto/intrinsicnode.cpp line 369:

> 367:       hi = src_type->hi_as_long() >= 0 ? src_type->hi_as_long() : hi;
> 368:       // Tightening upper bound of bit compression as per Rule 3.
> 369:       hi = result_bit_width < mask_bit_width ? MIN2((jlong)((1UL << result_bit_width) - 1L), hi) : hi;

// As per Rule 1, bit compression packs the source bits corresponding to
      // set mask bits

This says something, but does not really explain the rest of the sentence:

      // set mask bits, hence for a non-negative input, result of compression will
      // always be less that equal to input.

Plus: input could be both `mask` or `src`. I would be specific, and just talk about `src`.

Also: I don't really see how the conclusion in this sentence follows from its assumption.
How exactly does some bits not participating really ensure that the value is not greater?

        // set. If a mask bit corresponding to set input bit is zero then that input bit will
        // not take part in bit compression, which means that maximum possible result value
        // can never be greater than non-negative input.


I think I know what you are trying to say, it just sounds a little vague.

It also smells like this `Lemma 1` might be easier proved by a proof of contradiction.
I need to take a break now, but I'll see if I can come up with something a bit clearer later.

Here my suggestion:
Suggestion:

      if (src_type->hi_as_long() >= 0) {
        // Lemma 1: For strictly non-negative src, the result of the compression will never be
        // greater than src.
        // Proof: Since src is a non-negative value, its most significant bit is always 0.
        // Thus even if the corresponding MSB of the mask is one, the result will be a +ve
        // value. <the actual proof>
        hi = src_type->hi_as_long();
      }

      if (result_bit_width < mask_bit_width) {
        // Rule 3:
        // We can further constrain the upper bound of bit compression if the number of bits
        // which can be set to 1 is less than the maximum number of bits of integral type.
        hi = MIN2((jlong)((1UL << result_bit_width) - 1L), hi);
      }

test/hotspot/jtreg/compiler/c2/gvn/TestBitCompressValueTransform.java line 307:

> 305:         }
> 306:         Asserts.assertEQ(0, res);
> 307:     }

Like I mentioned in the email. I contributed this test, it would be nice if you could give me credits by making me a contributor to this issue.

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

PR Review Comment: https://git.openjdk.org/jdk/pull/23947#discussion_r2123857262
PR Review Comment: https://git.openjdk.org/jdk/pull/23947#discussion_r2123864703
PR Review Comment: https://git.openjdk.org/jdk/pull/23947#discussion_r2123881395
PR Review Comment: https://git.openjdk.org/jdk/pull/23947#discussion_r2123983125
PR Review Comment: https://git.openjdk.org/jdk/pull/23947#discussion_r2123992004


More information about the hotspot-compiler-dev mailing list