There is a new presentation about the improvements to the XiangShan Kunminghu V3 RISC-V Vector implementation.
Previously the RVV implementation was suvierly bottlenecked to the point of unusability.
Now it looks like we'll have a good open-source out-of-order RVV implementation soon.
Apparently the implementation was completed in September, but they are now successively releasing the changes over the next few months.
(the slides I post here were translated by google translate)
First thing, they fixed the decoder to maintain full 8 uop/cycle throughout reguardless of LMUL.
vtype gets propagated in IBuffer.
I personally prefer the idea of handling RVV after scalar/fp rename, so you can propagate vtype in rename and handle RVV renaming/cracking in a slightly decoupled and narrower stage, but apparently they were happy with this solution.
They improved the memory uop generation improvements for strided/indexed load/store:
They are now not only treating v0 as a mask register, but make it dependent on the instruction semantics. Previously they already had seperate mask and vector files.
gains in libc str* look nice (this is probably mostly the fault-onlt-first load improvements)
Permutations have also been improved. I am a bit worried if permutation unit blocks the other execution units, that wasn't apparent from the slides.
still, these LMUL>1 latency/throughput numbers look great.
16 cycle latency, 12 cycle throughout LMUL=8 vrgather.vv is really good.
It's also nice to see that the rules of thumb: prefer vslideup over down and .vi over .vx hold here as well
Finally some other improvements:
* RVV move elimination support
* strides/indexed load/store can generate 3 ld or 2 st per cycle, so the complex memory operations should basically always match or exceed the equivalent scalar code
* segmented load/store in `2*nf` cycles, makes sense. Presumably nf memory accesses followed by nf register writebacks
@palmer From my perspective the "higher-latency" design, is higher latency for RVV but lower for scalar, which generally aligns with what you want in software.
Consider scalar1, m8rvv, scalar2. In a 4-wide design, the "latency" focuses RVV implementation would decode scalar2 after 3 cycles, but the "throughput" one on the first.
I envision a design that puts a small vector buffer after scalar rename, from which it cracks/renames at a smaller bandwidth corresponding to the vector backend. The buffer would increase the reorder window substantially, because it store LMUL bundles. I think this would add 1-2 cycle latency for RVV.
But that additional latency is not for RVV -> RVV dependencies, it's only for RVV -> scalar or branch recovery. And then again, branch recovery for scalar instructions would be faster.
With this design Ovlt is also much more feasable. You "just" use vl when cracking from the vector buffer, if vl is already know (scalar runs ahead), otherwise fall back to LMUL.
@palmer I suppose if you mostly run LMUL=1 code, then it's worse.
But I'd imagine the reduced complexity would still make it attractive.
@palmer There is nothing it can do if it's actually vlmax LMUL=8, the renamer is only so wide (here 4).
Edit: Well I said nothing. I suppose somebody could figure out LMUL wide renaming, but that seems very hard and not possible without defragmentation.
@palmer With scalar RISC-V you don't have to crack anything before rename, so putting LMUL support into that pipeline directly seems very messy. (well that one 2W atomic, but that doesn't have to be high frequency)
If you separate it, you can scale it down to fit your backend size reducing the complexity further.
And because implementors can choose their VLEN, the backens size is bounded.
I doubt anybody would close to build a 6x128 (like X925) design over a 3x256 design, if software support for both is the same.