[llvm-dev] [RFC][SVE] Supporting SIMD instruction sets with variable vector lengths
David Greene via llvm-dev
llvm-dev at lists.llvm.org
Tue Jun 5 12:08:49 PDT 2018
Graham Hunter <Graham.Hunter at arm.com> writes:
>> Can you explain a bit about what the two integers represent? What's the
>> "unscaled" part for?
>
> 'Unscaled' just means 'exactly this many bits', whereas 'scaled' is 'this many bits
> multiplied by vscale'.
Right, but what do they represent? If I have <scalable 4 x i32> is "32"
"unscaled" and "4" "scaled?" Or is "128" "scaled?" Or something else?
I see you answered this below.
>> The name "getSizeExpressionInBits" makes me think that a Value
>> expression will be returned (something like a ConstantExpr that uses
>> vscale). I would be surprised to get a pair of integers back. Do
>> clients actually need constant integer values or would a ConstantExpr
>> sufffice? We could add a ConstantVScale or something to make it work.
>
> I agree the name is not ideal and I'm open to suggestions -- I was thinking of the two
> integers representing the known-at-compile-time terms in an expression:
> '(scaled_bits * vscale) + unscaled_bits'.
>
> Assuming the pair is of the form (unscaled, scaled), then for a type with a size known at
> compile time like <4 x i32> the size would be (128, 0).
>
> For a scalable type like <scalable 4 x i32> the size would be (0, 128).
>
> For a struct with, say, a <scalable 32 x i8> and an i64, it would be (64, 256).
>
> When calculating the offset for memory addresses, you just need to multiply the scaled
> part by vscale and add the unscaled as is.
Ok, now I understand what you're getting at. A ConstantExpr would
encapsulate this computation. We alreay have "non-static-constant"
values for ConstantExpr like sizeof and offsetof. I would see
VScaleConstant in that same tradition. In your struct example,
getSizeExpressionInBits would return:
add(mul(256, vscale), 64)
Does that satisfy your needs?
Is there anything about vscale or a scalable vector that requires a
minimum bit width? For example, is this legal?
<scalable 1 x double>
I know it won't map to an SVE type. I'm simply curious because
traditionally Cray machines defined vectors in terms of
machine-dependent "maxvl" with an element type, so with the above vscale
would == maxvl. Not that we make any such things anymore. But maybe
someone else does?
>> If we went the ConstantExpr route and added ConstantExpr support to
>> ScalarEvolution, then SCEVs could be compared to do this size
>> comparison. We have code here that adds ConstantExpr support to
>> ScalarEvolution. We just didn't know if anyone else would be interested
>> in it since we added it solely for our Fortran frontend.
>
> We added a dedicated SCEV expression class for vscale instead; I suspect it works
> either way.
Yes, that's probably true. A vscale SCEV is less invasive.
> We've tried it as both an instruction and as a 'Constant', and both work fine with
> ScalarEvolution. I have not yet tried it with the intrinsic.
vscale as a Constant is interesting. It's a target-dependent Constant
like sizeof and offsetof. It doesn't have a statically known value and
maybe isn't "constant" across functions. So it's a strange kind of
constant.
Ultimately whatever is easier for LLVM to analyze in the long run is
best. Intrinsics often block optimization. I don't know whether vscale
would be "eaiser" as a Constant or an Instruction.
>> As above, we could add ConstantVScale and also ConstantStepVector (or
>> ConstantIota). They won't fold to compile-time values but the
>> expressions could be simplified. I haven't really thought through the
>> implications of this, just brainstorming ideas. What does your
>> downstream compiler require in terms of constant support. What kinds of
>> queries does it need to do?
>
> It makes things a little easier to pattern match (just looking for a constant to start
> instead of having to match multiple different forms of vscale or stepvector multiplied
> and/or added in each place you're looking for them).
Ok. Normalization could help with this but I certainly understand the
issue.
> The bigger reason we currently depend on them being constant is that code generation
> generally looks at a single block at a time, and there are several expressions using
> vscale that we don't want to be generated in one block and passed around in a register,
> since many of the load/store addressing forms for instructions will already scale properly.
This is kind of like X86 memop folding. If a load has multiple uses, it
won't be folded, on the theory that one load is better than many folded
loads. If a load has exactly one use, it will fold. There's explicit
predicate code in the X86 backend to enforce this requirement. I
suspect if the X86 backend tried to fold a single load into multiple
places, Bad Things would happen (needed SDNodes might disappear, etc.).
Codegen probably doesn't understand non-statically-constant
ConstantExprs, since sizeof of offsetof can be resolved by the target
before instruction selection.
> We've done this downstream by having them be Constants, but if there's a good way
> of doing them with intrinsics we'd be fine with that too.
If vscale/stepvector as Constants works, it seems fine to me.
-David
More information about the llvm-dev
mailing list