3 ms·
> An algorithm which works well for hardware implementing 128-bit vectors might be quite bad for one implementing 2048-bit vectors Yeah, that's definitely a co
by dzaima 3y ago
> An algorithm which works well for hardware implementing 128-bit vectors might be quite bad for one implementing 2048-bit vectors
Yeah, that's definitely a concern. I do wish that RVV had some built-in way to cap the width in a request (of course emulatable by doing a min() manually), but beyond that it's up to the hardware I guess.
> but they are likely to also have many loops which cannot be vectorised performance-portably
Such would also likely not be autovectorizable either, making whether it can be done performance-portably much less significant due to the much lower frequency of manually-vectorized things. In most situations, if you're at the point of manually vectorizing some piece of code, it's enough of a bottleneck that you can tune it for whatever (set of) hardware you're targeting.
I, as someone who enjoys writing manually vectorized stuff, don't particularly like that added burden, but it's a pretty reasonable decision.
> I have some half-written code to use vector shuffles in place of loads for indexing small arrays in the j interpreter
Marshall has written that for CBQN[0] for AVX2, primarily tuned for Intel[1], but yeah the boundary is pretty sketchy to have to hard-code and RVV could definitely make it worse. But base 128-bit RVV, with LMUL=8 provides 1024-bit lookup tables in a single instruction, which should at least mostly negate the desire of manually blending multiple, which is where you'd start desiring tuning. Though, I wouldn't be surprised if an LMUL=8 in-register shuffle on some hardware would be slower than a memory gather for some element widths, which'd suck.
> but n/4 starts to cause problems
The existence of LMUL=8 means that hardware will necessarily have to figure out some way to split single instructions across many cycles. Arguably that's by itself pretty bad, but at least I'd imagine that further splitting up should be largely free, though the register file size problem of course persists.
> sve would effectively standardise on 256 bits
Yeah, I feel like 256 is a pretty nice sweet spot too.
In regards to higher-level hardware interfacing, I'd worry that what it'd do would be making everything uniformly slow, instead of making everything uniformly fast, thus potentially not actually being any better than status quo. And such would be at a very significantly worse spot in terms of performance-portable tuning than RVV. Not to mention that nicer array operation behavior wouldn't help the vast majority of code which is very scalar & dispatchy. And an equivalent of this would be to just share programs in IR and not machine code form, which we can already do, but don't really for whatever reason (if requiring near-native speed; otherwise there's JS/WASM/JVM. Then there's LLVM IR/MLIR but I haven't heard of it being used as a shared binary format. Maybe Julia would count with it compiling LLVM IR at runtime, and it having high-level array ops?)
[0]: https://github.com/dzaima/CBQN/blob/a67a19dd0bf6be5eb765cac87eb03d16286c11e0/src/singeli/src/select.singeli#L108-L115 https://github.com/dzaima/CBQN/blob/a67a19dd0bf6be5eb765cac8... - wd is bit width of the table elements, xl - number of such elements in the table. Beyond that, it just does the expected thing of blending permutes & shuffles via some Singeli that not even I have bothered to particularly understand
[1]: "Select" section at https://mlochbaum.github.io/bencharray/pages/summary.html https://mlochbaum.github.io/bencharray/pages/summary.html on Tiger Lake i5-1135G7, with similarly scaling results on haswell & skylake
- dzaima 3y agoAs an extra note on big/little cores - instead of having the small core break up ops, you could possibly instead have the big core handle higher LMUL natively. Requires code to use said higher LMUL (currently, clang defaults to LMUL 2, gcc to LMUL 1[0], but that's of course up for change), but would mean that you'd have higher potential throughput for big cores while leaving the register size tractible for the small cores. Also has some fun possibilities of, say, having native LMUL=2 add/sub, but only LMUL=1 multiplications or something. [0]: https://godbolt.org/z/YqjWhT8Y8 https://godbolt.org/z/YqjWhT8Y8 - "m1" vs "m2" in "vsetvli"