RFR: 8349637: Integer.numberOfLeadingZeros outputs incorrectly in certain cases [v3]

Emanuel Peter epeter at openjdk.org
Fri Feb 14 13:47:11 UTC 2025


On Fri, 14 Feb 2025 13:44:40 GMT, Tobias Hartmann <thartmann at openjdk.org> wrote:

>> Jasmine Karthikeyan has updated the pull request incrementally with one additional commit since the last revision:
>> 
>>   Improve explanation of logic
>
> Ah, right, makes sense. Thanks for checking, Emanuel. And nice to see that limitation being addressed.

I looked at @TobiHartmann Examples. I rewrote them a little, to make things more apparent.


public class TestByte {

    static byte[] vals = new byte[1024];
    static byte[] results = new byte[1024];

    public static void test() {
        for (int i = 0; i < 1024; ++i) {
            results[i] = (byte)Integer.numberOfLeadingZeros(vals[i]);
        }
   }

    public static void main(String[] args) {
        for (int j = 0; j < 10_000; ++j) {
            test();
            for (int i = 0; i < 1024; ++i) {
                if (results[i] != 32) throw new RuntimeException("Wrong result: " + results[i] + " at " + i);
            }
        }
    }
}

Running it like this:

java -Xbatch -XX:-TieredCompilation -XX:UseAVX=2 -XX:CompileCommand=compileonly,TestByte::test -XX:+TraceNewVectors TestByte.java 
CompileCommand: compileonly TestByte.test bool compileonly = true
TraceNewVectors [AutoVectorization]:  1190  LoadVector  === 943 1080 1055  [[ ]]  @byte[int:>=0] (java/lang/Cloneable,java/io/Serializable):NotNull:exact+any *, idx=7; mismatched #vectory<B,32> (does not depend only on test, unknown control)
TraceNewVectors [AutoVectorization]:  1191  CountLeadingZerosV  === _ 1190  [[ ]]  #vectory<B,32>
TraceNewVectors [AutoVectorization]:  1192  StoreVector  === 1079 1080 1021 1191  [[ ]]  @byte[int:>=0] (java/lang/Cloneable,java/io/Serializable):NotNull:exact+any *, idx=7; mismatched  Memory: @byte[int:>=0] (java/lang/Cloneable,java/io/Serializable):NotNull:exact+any *, idx=7;
Exception in thread "main" java.lang.RuntimeException: Wrong result: 8 at 24
	at TestByte.main(TestByte.java:18)

See the error message: `Wrong result: 8 at 24`, we get `8` instead of the expected `32`.

We see that we have a `LoadVector` of `bytes` going directly into `CountLeadingZerosV` for `bytes`, and the result is stored as `bytes` with `StoreVector`.

But this is not ok, because `CountLeadingZerosV` for `bytes` will have a different result, it only operates on `8 bytes`, and so if it sees a `zero = 0`, it sees only `8` leading zeros. But we called `Integer.numberOfLeadingZeros`, which expects to operate on `32 bit` integers, where a zero has `32` leading zeros.

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

Let's do the same with `shorts`:

public class TestShort {

    static short[] vals = new short[1024];
    static short[] results = new short[1024];

    public static void test() {
        for (int i = 0; i < 1024; ++i) {
            results[i] = (short)Integer.numberOfLeadingZeros(vals[i]);
        }
   }

    public static void main(String[] args) {
        for (int j = 0; j < 10_000; ++j) {
            test();
            for (int i = 0; i < 1024; ++i) {
                if (results[i] != 32) throw new RuntimeException("Wrong result " + results[i] + " at " + i);
            }
        }
    }
}

And we get:

java -Xbatch -XX:-TieredCompilation -XX:UseAVX=2 -XX:CompileCommand=compileonly,TestShort::test -XX:+TraceNewVectors TestShort.java 
CompileCommand: compileonly TestShort.test bool compileonly = true
TraceNewVectors [AutoVectorization]:  980  LoadVector  === 813 885 864  [[ ]]  @short[int:>=0] (java/lang/Cloneable,java/io/Serializable):NotNull:exact+any *, idx=7; mismatched #vectory<S,16> (does not depend only on test, unknown control)
TraceNewVectors [AutoVectorization]:  981  CountLeadingZerosV  === _ 980  [[ ]]  #vectory<S,16>
TraceNewVectors [AutoVectorization]:  982  StoreVector  === 882 885 866 981  [[ ]]  @short[int:>=0] (java/lang/Cloneable,java/io/Serializable):NotNull:exact+any *, idx=7; mismatched  Memory: @short[int:>=0] (java/lang/Cloneable,java/io/Serializable):NotNull:exact+any *, idx=7;
Exception in thread "main" java.lang.RuntimeException: Wrong result 16 at 12
	at TestShort.main(TestShort.java:41)

Here we get `16` leading zeros because a `short` has `16` bits, rather than the expected `32` from `Integer.numberOfLeadingZeros`. Again, because `CountLeadingZerosV` for `short` operates on `shorts` and not `ints`.

How did we not catch this with testing. I mean this is so trivial to catch with any vectorizing example 🙈

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

PR Comment: https://git.openjdk.org/jdk/pull/23579#issuecomment-2659378298


More information about the hotspot-compiler-dev mailing list