RFR: 8300258: C2: vectorization fails on simple ByteBuffer loop [v2]

Emanuel Peter epeter at openjdk.org
Thu Mar 2 09:08:17 UTC 2023


On Thu, 2 Mar 2023 08:29:47 GMT, Emanuel Peter <epeter at openjdk.org> wrote:

>> Maybe we should first collect all legal packs and then try to find the best alignment, dropping packs that are unaligned on those platforms that support it.
>
> Hi @rwestrel @vnkozlov .
> 
> I have another general question. Should this really vectorize?
> 
>     @Test
>     @IR(counts = { IRNode.LOAD_VECTOR, ">=1", IRNode.STORE_VECTOR, ">=1" })
>     public static void testOffHeapLong1(long dest, long[] src) {
>         for (int i = 0; i < src.length; i++) {
>             UNSAFE.putLongUnaligned(null, dest + 8 * i, src[i]);
>         }
>     }
> 
> 
> I talked with @TobiHartmann about this. It is apparently possible to get the address of an array, and store in a `long`. In that case, we could play with that rawptr a bit, and create a cyclic dependency.
> 
> Pseudocode:
> 
> long[] arr = new long[1000];
> long ptr = unsafe.getTheArrayAddress(arr); // does not exist directly, but it is possible
> ptr += 8; // shift it one long forward
> testOffHeapLong1(ptr, arr);
> 
> 
> This should have different behavior if it is vectorized or not.
> 
> But maybe this is expected, and just a bad use of `Unsafe`. Probably we want this to vectorize, for the extra performance, and people who use `Unsafe` just have to be careful not to do such strange things.

> Thanks for the comments @eme64 @vnkozlov Looking at the code again, if `vectors_should_be_aligned()` is true, if `create_pack` is false, the current code removes every memops and already created packset with `same_velt_type()` true: That can't be motivated by a correctness issue. So I suppose we want to preserve that behavior. Wouldn't we need the change of the last commit I pushed then?

I think the reason we used `same_velt_type` was that we were confused. Or maybe we did that before we had memory slices, and using `same_velt_type` was at least already an improvemnt? At any rate: it was confused and leads to Bugs in conjunction with `Unsafe`, as my example showed.

Keeping `same_velt_type` will probably not harm much, but be more restrictive than neccessary.
It will not harm much because `velt_type == memory_slice` as long as we are not using `Unsafe`.
And when we do use `Unsafe`, we probably do not use it in very wild ways.

One "wild" use might be something like this:

void test(int[] iarr, float[] farr) {
    // cyclic dependency -> not vectorized
    in v1 = (int)Unsafe.LoadF(iarr, i);  // assume this to be best
    Unsafe.StoreI(iarr, i + 1);
    // separate slice -> could be vectorized
    Unsafe.StoreI(farr, i) = Unsafe.LoadI(farr, i);   // on different slice as best, but have same velt_type -> rejected
    // We end up vectorizing nothing, even though we could vectorize the farr
}

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

PR: https://git.openjdk.org/jdk/pull/12440


More information about the hotspot-compiler-dev mailing list