Hacker News new | ask | show | jobs
by Joker_vD 18 days ago
> RISC-V supports variable length instructions, even much longer than 32 bits, and you've just got to deal with it.

...no, not really? There is nothing like 9 byte-long MOVABS instruction of x64 that exists on RISC-V.

The main difficulty in decoding is that 32-bit instructions are not required to be 4-byte aligned, this means that naïve decoders will spend 2 cycles fetching such split instructions. It's possible to add a 4-byte ring buffer but all in all, efficiently supporting the C extension is non-trivial.

2 comments

There are two options when designing an ISA to achieve competitive code size, add variable length instructions or add more complex fixed-length instructions which require cracking (2W instructions). The other option is: maybe codesize don't matter?

For high performance implementations both decoding variable length instructions and decoding/cracking fixed-length instructions into uops, are rather analogous in terms of the work hardware needs to do.

However, I think the advantage of fixed-length instructions, is that you can do further tricks, like pre-decoding in Icache. With RVC, you can also do pre-decoding, but now you need twice the amount of pre-decoding data, unless you find other tricks.

Still, in a reasonable variable-length ISA and fixed-length ISA, the variable-length one will get better code size. There are also a lot of other things to consider, RVC is self synchronizing, cracking is challenging for decode, but also keeps the backend better fed, how more instruction starts impact branch predictors, instructions crossing cache-lines...

I benchmark compiling programs with a rva23 clang build and clang compiled for rva23-without-C and got a 10% performance improvement from RVC on the SpacemiT X100. The X100 is a 4-wide out-of-order core and afaik doesn't do anything special for RVC, except for expanding the 16-bit to 32-bit instructions.

It's hard to quantify the real impact on a CPU design, but going the fixed-width route seems to enable more optimizations (not so much the decoding it self).

> maybe codesize don't matter?

Well, instruction cache still has limited size, and you still need to get your code into it. Paging in 512 KiB from the disk is faster than paging in 1 MiB from the disk.

> like pre-decoding in Icache.

I'm fairly certain x64 also does that?

> RVC is self synchronizing,

No, not really. You can still jump into the middle a 32-bit instruction, and it's possible it can be reinterpreted as a valid 32/16-bit instruction. Remember when people complained about how "overlapped instructions"/"hidden instruction streams" on x64 enable even more ROPs/gadgets than meets the eye? Don't worry, RISC-V has those too!

> No, not really. You can still jump into the middle a 32-bit instruction, and it's possible it can be reinterpreted as a valid 32/16-bit instruction. Remember when people complained about how "overlapped instructions"/"hidden instruction streams" on x64 enable even more ROPs/gadgets than meets the eye? Don't worry, RISC-V has those too!

Sure, it's a probabilistic thing. Whenever you see a 2-byte block starting with 0b11, you know there is an instruction start after those 2 bytes.

When I last looked at it, I got synchronize 99% of the time, when looking at a 8-byte block. In one qemu trace I empirically got that only 626 out of 70479 8-byte blocks don't contain synchronizations.

This certainly seems like something you could exploit quite well, if you are doing things like 8+ wide decoding. (maybe have a fast path that safes one cycle of latency)

RISC-V definitely does support instructions longer than 32 bits, starting at 48 bits (ie. 32 + 16), and going much longer. They are much easier to decode than x86 because the length is evident from the first byte. No ratified extension uses them now, but you're going to need to deal with them as the extension space gets more crowded. Including dealing with instructions split across cache lines and pages, and instructions aligned to 16 bits.

I'm not sure what point you're making TBH.

My point is that fixed-length instructions are supposed to be easier to decode than variable-length ones, right?

If not, then why even bother with fitting immediates and inventing LUI/AUIPC, just have a 48-bit long LI instruction. The same goes for 64-bit, an 80-bit LI.W is still shorter than the piecemeal construction with several instructions.

If yes, then the small cores are arbitrarily given a burden of supporting variable-length instructions, supposedly efficiently: if your instruction fetch is 16-bit wide, you need two fetches to fetch a single 32-bit instruction, which sucks; if it's 32-bit wide, you need to conditionally stash the upper half for the next fetch cycle, and still prefetch yet more 32-bits because that upper half may contain only a half of a full 32-bit instruction; alternatively, you can fetch 32-bits at alternated aligned/misaligned addresses and ignore the inefficiency of throwing away re-fetched bits — again, all of this sucks.

Yes, fixed-length instructions are easier to decode, but that also means a hard upper limit on the number of instructions that could ever be supported. Which is obviously a problem for a future-proof architecture.

The rationale for this and also for confining the base set to 32 bit is explained here: https://docs.riscv.org/reference/isa/v20250508/unpriv/extend...

I've read that rationale, and it's, well, I'm not going to say it's lying, but it's insincere. By the time it was written, they already settled on 16-bit alignment, and fetching (and then decoding) 16-bit aligned 32-bit instructions is either inefficient, or hard, or requires extra circuitry (or an instruction cache).
High performance RISC-V chips exist from Rivos, Ventana and others, and high performance variable length chips also exist in general (AMD, Intel). So in actual reality it increases complexity somewhat, but is not a problem.
sighs This kind of discussion is so annoying... I start with "RISC-V's decision to make 32-bit instructions only 16-bit aligned complicates instruction fetch and decoding", and the response is "For high performance RISC-V implementations, it's a trivial matter" (which is true), I response with "But then why even bother with mostly-fixed-but-not-quite instruction length, just make a properly variable length ISA, it'd even simplify the instructions", and the reply is "the low-end implementations would struggle with decoding that efficiently" — but they already struggle with instruction fetch when they implement C extension! Nah, it's fine, the high-end chips can cope with that.

And round and around this discussion goes... Apparently, RISC-V has no downsides at any end of the price spectrum, what a marvelous ISA.

> small cores are arbitrarily given a burden of supporting variable-length instructions

Even the smallest commercial microcontroller cores e.g. the CH32V003, support the C extension. They strip out other things, such as half the integer registers, but they keep C.

And that's in a market where you can use literally any combination of extensions you want, because the customers compile all their own code, and you just tell them what ISA string to use.