[vector] RFC: Add scalable shapes for Arm Scalable Vector Extension

Vladimir Ivanov vladimir.x.ivanov at oracle.com
Wed Oct 10 23:01:31 UTC 2018


Ningsheng,

>>>> The name (*ScalableVector) is slightly misleading to me, but I'm fine
>>>> with it.  I interpret new shapes as representing vectors of maximally
>>>> supported size at runtime without specifying the actual size.
>>>>
>>>
>>> I am happy to change the name if you have some suggestion. The new shapes
>> are representing current (SVE) hardware supported (max) vector register size,
>> and the actual size is known at runtime.
>>
>> Yes, I'd like the names to clearly manifest it's the vector of maximum size
>> available at runtime. Maybe *MaxVector, but I'm not too happy with it as well.
>>
> 
> OK, but I think Max could not imply the point of one shape to fit multiple sizes. I was thinking about VL (variable length), but finally used current name to align with SVE (Scalable Vector Extension).

My understanding from the patch you shared is that vector size is fixed 
across the run and is set to maximally supported [1]

IMO "variable length" is misleading in a sense it may be erroneously 
interpreted as "vectors of that shape may be of different size at 
runtime", so user have to check for that. In that respect, "*Max*" 
clearly refers to *some* size (fixed across the run) without specifying 
what the actual size is, but user can query it at runtime.

...
>> So, my question boils down to: how vector shape checks are expected to
>> work on *ScalableVectors in presence of operations which change vector size.
>>
>> For example, IntScalableVector.rebracket() => LongScalableVector which
>> is fine, but ISV.resize() => ISV is what I'm concerned about and
>> existing checks aren't enough for *ScalableVectors unless you check
>> their length at runtime.
>>
> 
> Thanks for the detailed explanation. So, which checks do you mean here? Do you mean this [1]? I find that current Java implementations already has some runtime length checks. One thing we need to consider is the ambiguity between existing sizes and scalable size. Current VectorIntrinsics.reinterpret() just tries to get the shape from size (library_call.cpp:get_exact_klass_for_vector_box) instead of getting the real class from input argument, which will lead to ClassCastException. Maybe that can be fixed by adding real klass type to the reinterpret function.

The checks I referred to are the casts on vector shapes which are part 
of every vector operation (e.g., [2]), but they don't immediately relate 
to shape-changing operations.

It seems I had some wrong assumptions when coming up with the examples. 
Sorry for the confusion. Taking those into account, here's my take on 
current state of vector shape changing operations w.r.t. SV shapes.

There'll be 30 vector shapes in total (5 sizes x 6 element types):
   * Byte64V, Byte128V, Byte256V, Byte512V, ByteSV
   * Short64V, ..., ShortSV
   ...
   * Double64V, Double128V, ... Double512V, DoubleSV

Depending on hardware, SVs may alias with "explicitly sized" shapes 
(e.g., IntSV is equivalent to Int512V on AVX512 capable H/W).

(1) Vector.rebracket(): works fine for SVs since vector size (in bits) 
stays the same: IntSV <-> LongSV <-> ... <-> DoubleSV.

(2) Vector.resize(): SV->SV doesn't make sense and the operation should 
involve both SV and existing vector shapes: IntSV <-> 
Int64V/Int128V/.../Int512V. The ambiguity you mention can cause problems 
and needs to be carefully handled to avoid 2 equivalent shapes to meet 
at runtime. Otherwise, vector shape checks I mentioned earlier should be 
changed.

(3) Vector.cast(): SV->SV, SV<->64V/.../512V
     * size-preserving transformations (int <-> float):
       SV->SV work fine: IntSV <-> FloatSV, LongSV <-> DoubleSV;

     * widening casts (e.g., int->long)
       SV->SV/64V/...:  truncate upper part of the vector, since SVs 
already represent widest vector shapes;
       64V/...->SV: either truncated or filled with defaults depending 
on actual size

     * narrowing casts (e.g., long->int)
       SV->SV/64V/...: fill upper part of SV with defaults;
       64V/...->SV: either truncated or filled with defaults depending 
on actual size

Best regards,
Vladimir Ivanov

[1]

final class IntScalableVector extends IntVector<Shapes.SScalableBit> {
     static final IntScalableSpecies SPECIES = new IntScalableSpecies();

     static final IntScalableVector ZERO = new IntScalableVector();

     static final int LENGTH = SPECIES.length();

...

     static final class IntScalableSpecies extends 
IntSpecies<Shapes.SScalableBit> {
         static final int BIT_SIZE = Shapes.S_Scalable_BIT.bitSize();

         static final int LENGTH = BIT_SIZE / Integer.SIZE;

...

     public static final SScalableBit S_Scalable_BIT = new SScalableBit();
     public static final class SScalableBit extends Vector.Shape {
         @Override
         public int bitSize() {
             Unsafe u = Unsafe.getUnsafe();
             return u.getMaxVectorSize(byte.class) * 8;
         }
     }

[2] 
http://hg.openjdk.java.net/panama/dev/file/e8f06cc3fe82/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int128Vector.java#l327


More information about the panama-dev mailing list