Confusion regarding vscale in LLVM-IR

In LLVM Language Reference Manual, Vector type has following example:

<vscale x 4 x i32>	Vector with a multiple of 4 32-bit integer values.

Documentation also states that value of vscale can only be determined at runtime. Can someone please further elaborate what is vscale and how is it calculated at runtime? Can vscale take fractional values? If yes, what possible fractional values can it take? Is there any upper limit on the vscale value?
If vscale is calculated as 2, does that mean that the vector will have 8 32-bit integers?

The vector in your example is a scalable vector. Intel e.g. has fixed length vectors with 128, 256, and 512 bits. The scalable vector extension (SVE) from Arm supports scalable vectors. At compile time the vector length is unknown. At runtime the vector length is dictated by hardware. There are SVE cores with 256 and 512 bits in the wild. Even if your hardware supports 512 bits. You could change the vector length down to 256 or 128. The vector length is always a multiple of 128 up to 2048.

There could be custom cores that support odd values for vscale.

The original design and implementation did not account for non natural (positive integers) values for vscale. If customs cores want to implement it that way, there will probably have to be some changes to the current implementation (checks, constructors, etc).

The restrictions on 128 and 2048 are an SVE thing. In theory, it could be any (natural) number.

The nature of scalable vector hardware implementation make the question “what is the vscale” irrelevant to the compiler. It’s not just that you don’t want to know, is that knowing may lead you to generate less efficient/generic code.

So if you’re thinking about fractional numbers, perhaps you should just use a lower minimum length, so that whatever value you want can be a multiple of that. You could probably even use 1, if you have a quirky FPGA implementation where the vectors aren’t the same length even in the same basic block.

1 Like

Till today vscale is an unknown value at compile time and is constant during the execution of the program. Otherwise you could get miscompiles. Arm is working on SME, the scalable matrix extension. They are planning to weaken that invariant.

Neither Arm nor RISCV discard the possibility of changed of vscale at run time. If the implementation doesn’t support it’s because neither decided to actually do anything about it (because it’s a bit mad to do it), but the concept of vscale in LLVM IR does not mandate a constant value throughout the program.

Miscompilation for non-constant vscale is a matter of implementation, fractional vscale values are a matter of design. In that sense, it would be possible (though hard) to introduce different vscales for different functions/loops, but it would not make sense have a fractional value.

vscale is a positive value that is constant throughout program execution, but is unknown at compile time. If the result value does not fit in the result type, then the result is a poison value.

from LLVM Langref. Violating Langref is up to you. For Arm there is register that you can change at runtime.

1 Like

I stand corrected. This was a discussion when we were introducing vscale, I thought we didn’t make that strict. Probably added by request to make it easier to codegen initially, but Paul’s proposal is what we had in mind initially.

What I had to have said was that the original design didn’t intend to make it a constant, but how it ended up in IR was another story.

I don’t understand this comment, though. Paul’s proposal does exactly what I was talking about. The LangRef isn’t immutable, as the introduction of vscale to vector is proof enough. Anyone can come up with changes to it and propose, and it’s up to the community to accept or not.

Pardon my English. But function boundaries are an interesting concept with the new ML Inliner, IR and Machine Outliner, ThinLTO, and PGO.