This is an archive of the discontinued LLVM Phabricator instance.

[RISCV] Add support for the vscale_range attribute

Authored by frasercrmck on Aug 2 2021, 9:52 AM.



This patch begins the process of supporting the vscale_range attribute
for RVV.

Most notably, this patch implements the attribute according to the
minimum and maximum values of VLEN according to specific V extensions
being compiled for. The minimum is taken using the minimum-known VLEN
(i.e., specified through the V or zvl*b extensions) and the maximum is
unconditionally taken as 65536. Both values are then divided by our
"bits per block" value, hardcoded to 64.

The backend can still be given more information about VLEN using the
-riscv-v-vector-bits-min and -riscv-v-vector-bits-max flags. This
means that the API it aims to replace,
TargetTransformInfo::getMaxVScale, may still generate better code with
its better knowledge. Those options override the values found in the
vscale_range attribute.

It is unclear whether we want to move those backend options up into the
frontend, whether we are able to allow the backend to infer all
information from the IR attribute, or whether we even want to do that;
that's a wider discussion.

Diff Detail

Event Timeline

frasercrmck created this revision.Aug 2 2021, 9:52 AM
frasercrmck requested review of this revision.Aug 2 2021, 9:52 AM
Herald added a project: Restricted Project. · View Herald TranscriptAug 2 2021, 9:52 AM

update usage in vein of AArch64:

  • use vscale_range attribute to determine RVV vector bits min/max values
  • if no attribute is present, use existing backend flags
  • sanitize and pass RVV vector bits from RISCVTargetMachine through to RISCVSubtarget
  • RISCVSubtarget just stores and reports
Herald added a project: Restricted Project. · View Herald TranscriptAug 18 2021, 9:20 AM
Matt added a subscriber: Matt.Aug 18 2021, 1:59 PM

This may be as far as we can take this patch without exposing RVV vectors bit control to the user/driver and having to worry about the concerns that spring from that: linking objects compiled with different RVV vector bits options, LTO, etc.

I believe that with the current state of the patch, the default, hard-coded vscale_range with values mandated by the spec, combined with the existing backend options for overrides, mean we're not losing any functionality.

Ah no, my mistake. This would be a drop in functionality if getMaxVScale is removed, since its replacement only checks the IR attribute and will not be affected by our backend flags.

craig.topper added inline comments.Aug 20 2021, 11:57 AM

Should we move RVVBitsPerBlock to RISCVTargetParser.def? Or some other place that can be shared between lllvm/lib/Target/RISCV/ and here?

kito-cheng added inline comments.Aug 25 2021, 7:02 PM

RISC-V require VLEN in power of 2, multiples of 128 is constraint for SVE :p

frasercrmck marked 2 inline comments as done.
  • rebase
  • move V VLEN bits-per-block (64), min (128), max (65536) defines into TargetParser.h
  • clean up assertions
frasercrmck added inline comments.Aug 30 2021, 4:57 AM

Good idea. I also added the "StdV" min/max values of 128/65536 in there. However, I just put them in TargetParser.h as putting them in the .def file felt a bit odd and you had to account for preprocessor logic. It still feels a little odd but I agree that sharing these values is important. Other targets have specific values in there so it's not unprecedented. It is target-adjacent data, even if it's not (currently) dependent on triples or cpus.


Yeah to be honest I was just being cheeky/lazy here :) Since our current implementation requires VLEN >= 128 we know that VLEN must always be a multiple of 128. But yes this isn't really the right way of coding it, even if it does the right thing. I've fixed that up now.

craig.topper added inline comments.Aug 30 2021, 6:16 PM

If clang always emits the attribute, are these options effectively dead for clang codegen?

frasercrmck added inline comments.Aug 31 2021, 7:15 AM

Yes, that's a good point - I'd missed that. I'm not sure the best way of keeping that ability apart from moving the options up to clang and dealing with the fallout from that. Which I'm not even sure we can deal with yet?

Unless we make the options override the attribute, though that might be its own can of worms.

frasercrmck added inline comments.Jan 21 2022, 8:50 AM

Well we now have zvl which kinda solve the "min" problem at the frontend level.

Thinking about it again, though, maybe it's not such a bad thing to have clang emit min=<zvl>, max=2^16/RVVBitsPerBlock and then allow backend codegen flags to override that. Then the onus is clearly on the user not to do anything wrong. We could assert if the user-provided values are clearly at odds with the attribute?

craig.topper added inline comments.Jan 21 2022, 10:07 AM

I'm fine with that. I think we should consider dropping the riscv-v-vector-bits-min flag and just have a -riscv-v-fixed-width-vectorization-flag until we can prove that vectorization is robust. Bugs like D117663 make me nervous about blindly vectorizing code right now.

take minimum from zvl extensions
allow backend options to override attribute values
add extra testing

frasercrmck retitled this revision from [PoC][RISCV] Add support for the vscale_range attribute to [RISCV] Add support for the vscale_range attribute.Jan 24 2022, 9:43 AM
frasercrmck edited the summary of this revision. (Show Details)
khchen added inline comments.Jan 24 2022, 6:53 PM

I'm thinking do we need to test zvl and vscale_range in the same attribute?
ex. attributes #0 = { vscale_range(2,1024) "target-features"="+zvl512b" }

frasercrmck added inline comments.Jan 25 2022, 2:31 AM

Perhaps yeah. Just to check - what exactly for? Because we need zvl in the attributes for correctness, or in order to test the combination of zvl architecture and vscale_range to test what happens when they disagree?

Does this mean RISCVTTIImpl::getMaxVScale() can be removed?

khchen added inline comments.Jan 25 2022, 6:40 AM

Just test for they disagree.
Do you know what's expected value for different vscale_range value in two function after function inlining? If they are always have the same minimum value for VLEN, I think we don't need a check.

Does this mean RISCVTTIImpl::getMaxVScale() can be removed?

Good question. I'm unsure at this stage. At hinted at in the description, getMaxVScale can make use of backend-specific flags to hone the maximum down a bit, whereas relying on the attribute basically reduces us to the one value which the frontend will ever likely produce. So as it stands, the vscale_range attribute is not at feature parity with this TTI method. I think we'd have to come to a decision that this outcome is okay.


Good idea.

As for inlining, I can't see anything that would prevent inlining of functions with different vscale_range attributes, per se. However, I was looking at TTI::areInlineCompatible and the default implementation checks whether CPU/Feature Strings are equivalent. The frontend should ensure that vscale_range attributes match up 1:1 with our +zvl feature strings so I think in practice we won't inline functions with different zvl values in clang-generated C/C++ code. But users could write IR with different vscale_range attributes and we'd happily inline them, which sounds fishy. What do you think?

khchen added inline comments.Jan 27 2022, 10:05 AM

Could we have an assertion to prevent RVVBitsMin and Zvl are different?


For forward compatibility, if there is no VScaleRangeAttr, maybe we could initialize the RVVBitsMin as zvl*b if it is present?
I guess maybe some exist IRs have zvl with no VScaleRangeAttr?


Thanks for investigation!!!
I think we can postpone this inline issue until we really need to fix it.
at least the function would keep the feature string, which may include zvl*b, right?

BTW, could you please try the C code in to see what's vscale_range value for function vadd256 and vadd512? Are they expected value?

check for zvl feature strings alongside vscale_range


Yeah... I just realised that by taking vscale_range to mean -riscv-v-vector-bits-min, and us now using zvl to dictate vscale_range, we're effectively enabling fixed-length support by default now. I don't really want to introduce such a change in behaviour in this patch.

Maybe we should delay this patch until we have a -riscv-v-fixed-width-vector-support flag, or something, as you suggest. That or we emit vscale_range now but ignore it in the backend until such a change has been made.


It's complicated due to us using RVVBitsMin != 0 to also enable fixed-length vectorization. Defaulting that to our zvl*b extension is a change in behaviour. See the discussion with Craig above this one.


Yeah the feature string looks to contain zvl*b as we expect -- in simple cases (see below). I've updated this test to check for them too.

Thanks for the example! I tried it. We have a couple of issues.

Firstly, the vscale_range is not correctly set for the functions. It is taken from whichever zvl*b we set on the command line. If I do -target-feature +zvl128b all functions have vscale_range(2,1024), if I do -target-feature +zvl256b all functions have (4,1024), etc. So something's not being communicated properly.

The second issue is that, because of this (I think) when using the non-CC1 driver, the subtarget initialization crashes if I compile with -march=rv64gcv or any zvl*b up to -march=rv64gcv_zvl512b1p0 because the -march we specify there determines the vscale_range which in turn determines RVVBitsMin, but that's "lower than the Zvl*b limitation" so an assert triggers.

khchen added inline comments.Jan 29 2022, 7:45 AM

Sorry, I have no idea about what's good way to fix them, or maybe RISC-V has not already supported ifunc then we could ignore this example, I'm not sure.

BTW, I'm wondering why we want to support vscale_range attribute in RISC-V V.
Could we get any benefit after supporting it?
It seems like SVE does not have a way to encode vector length information, so it must introduce a new function attribute vscale_range in IR.
But in RISC-V V, we already have zvl*b target-feature to get the minimum vlen information, and the maximum vlen is always 65536. In addition, we also have default implication rule for zvl*b depend on V/Zve*.

It seem like we are trying to support users's manually IRs which have vscale_range without zvl*b target-feature, is it?
Or am I misunderstanding the intention?

reames added a subscriber: reames.Oct 13 2022, 10:53 AM

Not knowing about this patch, I posted D135894 which addresses a small sub-set of this. If that goes in, I plan to iterative split off some other parts of this into stand alone changes.

frasercrmck abandoned this revision.Feb 6 2023, 1:42 AM

Superseded by D139873 amongst others