Addressing Criticism of RISC-V Microprocessors
erik-engheim.medium.com
erik-engheim.medium.com
Even if by <insert objective measurement> RISC-V is 10% worse then ARM, it wouldn't actually matter that much for adoption.
Adoption happens for business reasons and what is differentiating RISC-V far more then anything else is the chance in license, governance and ecosystem.
RISC-V being better at hitting different verticals optimally because of the molecularity is likely another thing that matters more overall then how perfectly it fits for each vertical.
One of the most important goals of RISC-V is to make an architecture which can stand the test of time. In this space adding the wrong kind of instructions is a bigger problem than not adding particular instructions.
Whether you look at x86, HTML or just about anything the problem is nearly always about having to support old junk which no longer makes sense to support, or lacking the ability to grow. Remember 640K is enough for everyone? RISC-V has a lot of room to grow.
If you want an architecture for the future you would want a minimalist one with room to grow a lot. By keeping the instruction count very low and building in a system for extensions they have made a future proof ISA. Okay we cannot know the future, but it is more likely to survive for decades than something like x86 or maybe even ARM.
The question is does it make sense to add these to the ISA long term? In the short term, given die density and how memory works today, it has advantages. But die density increases, making OoO cores cheaper, and memory technology changes. It’s not obvious that these are long term improvements.
Everything being an extension (and thus removable) is a strength in some specific circumstances, but is a weakness in most.
General-purpose CPUs for desktop computers and such will not be willy nilly adding extensions. They will standardize on something like RV64GC. However for specialized hardware which you only ever deal with through drivers, nobody will care whether extensions come and go. Are you worried that the processor in your keyboard or mouse isn't backwards compatible with the processor you used in your previous mouse or keyboard?
Anyway code today can already check what extensions you have and generate different code paths. You can ship operating systems which have fallback code for most extensions so they can be be removed in the future. You also got traps so RISC-V can jump to a software implementation of unsupported instructions.
No, but the keyboard manufacturer might be, as might the people who are writing and optimising compilers targetting that CPU.
If <insert objective measurement> = binary size, and I'm buying ROM in volume to hold that binary, +10% ROM address space can easily cost more than the ARM license.
That can matter quite a lot for adoption. Especially in the short term.
Obviously, priorities differ and change as a function of time but as the saying goes, the only thing worse than making a decision with benchmarks is making a decision without benchmarks.
Some data from Ubuntu 21.10 for amd64, arm64, and riscv64:
https://www.reddit.com/r/RISCV/comments/tik718/addressing_cr...
My high level point is: changes in "objective measurement" have costs in the same way that license, governance and ecosystem have costs. And "objective measurement" can easily overwhelm the others, especially at scale, and therefore they should not be dismissed as unimportant.
However, I do want to point out that a real issue (especially with legacy code) is the scaled address calculation with 32-bit unsigned values. Thankfully the Zba extension adds a number of instructions that help a lot, but still would require fusion to get complete parity with Arm64
For
int update(int *base, unsigned index) { return base[index]++; }
We get update:
sh2add.uw a1,a1,a0
lw a0,0(a1)
addiw a5,a0,1
sw a5,0(a1)
ret
Zba is included in the next Unix profile and will _likely_ be adopted eventually by all serious implementations.EDIT: grammar and spacing
Compiling your function with Godbolt, I get:
RISC-V (no Zba) Clang - 7 instructions - https://godbolt.org/z/7znnrzxKq
Arm64 Clang - 7 instructions - https://godbolt.org/z/Trv8scxad
Annoyingly I can't see the code size for the Arm64 case because no output is generated if I tick the "Compile to binary" option in "Output". I have to use GCC instead: RISC-V (no Zba) Clang - 20 bytes - https://godbolt.org/z/eWfPaorcj
Arm64 GCC - 24 bytes - https://godbolt.org/z/bzsPzov5h int get(int *base, unsigned index) {return base[index];}
Arm64: update:
ldr w0, [x0, w1, uxtw 2]
ret
RV64GC (vanilla): update:
slli a5,a1,32
srli a1,a5,30
add a0,a0,a1
lw a0,0(a0)
ret
RV64GC+Zba: update:
sh2add.uw a0,a1,a0
lw a0,0(a0)
ret
Arm64 is able to do some indexed loads in a single instruction that might take two in RISC-V w/Zba (and up to 4+ in regular RISC-V). However, calling that a win for Arm64 is not so clear as the more complicated addressing modes could become a critical timing path and/or require an extra pipeline stage. However, as a first approximation, for a superscalar dynamically scheduled implementation, fewer ops is better so I would say it's a slight win.I don't understand the obsession with bytes. 25% fewer bytes has only very marginally impact on a high-performance implementation and the variable length encoding has some horrendous complications (which is probably why Arm64 _dropped_ variable length instructions). Including compressed instruction in the Unix profile was the biggest mistake RISC-V did and I'll die on that hill.
ADD: Don't forget that every 32-bit instruction is currently wasting the lower two bits to allow for compressed, thus any gain from compress must be offset by the 6.25% tax that is forced upon it.
Instruction cache doesn't come for free, and is usually pretty small on most shipping processors. It's not a big deal for smaller benchmarks, but in real-world programs this can become a problem.
ADD: had RISC-V just disallowed instructions from spanning cache lines and disallowing jumping into the middle of instructions then almost all of the issues would have gone away. Sigh.
(I should also note that I am pretty on board with you with regards to variable-length instructions, this is just independent of that.)
https://m.soundcloud.com/university-of-cambridge/a-history-o...
His own opinion appears to be that the worst thing ARM ever did was T2EE, designed for JIT compilers and compilers for dynamic languages. He says that by the time the chips came out compiler technology had advanced to the point that it was no longer useful and no one else used it.
A couple of other points picked up in the talk:
- He reverses Hennessy and Patterson wrt SPARC and MIPS.
- A64 effort started in 2007. So it took 5 years to freeze/publishing, the same as RISC-V.
- A64 architects thought code density is no longer important. Some people definitely disagree with that. At the time they probably thought amd64 was the only competition and matching/beating that was good enough.
- he seems to be regretting the 2nd operand shift because it fell naturally out of the 1985 micro-architecture, but it's a burden now. And yet it was included in A64 -- presumably because the initial processor pipelines had it anyway, because they supported A32. But now we have A64-only CPUs.
- LL/SC was the wrong thing to do.
It also means you cannot tell instruction boundaries until you directly fetch instructions, so you cannot do any predecode in the cache that would help you figure out dependencies, branch targets, etc. These things matter when you are trying to fetch 8+ instructions per cycle.
Even with fixed (32 bit) instruction lengths aligned on 32 bit, when we have to decode a group of 8 instructions you are facing this kind of issue.
So you either have to cut the instruction group (and thus not take full advantage of the 8 way decoder) or you have to implement a more complex prefetch with a longer pipeline. And these special cases can be handled in these pipeline stages.
> It also means you cannot tell instruction boundaries until you directly fetch instructions
I mean, AMD does that on x86, with 14 instruction lengths.
It can be done for RISC-V, it's much cheaper than x86, and it takes significantly less surface area than a bigger cache to compensate.
Wait (he says to himself, realising he's an idiot immediately -before- posting the comment for once). You said upthread the C extension is specified as part of the standard UNIX profile, so I guess people are effectively required to implement it currently?
If that was changed, would that be sufficient to dissolve the issues for people wanting to design high performance implementations, or are there other problems inherent to the extension having been specified at all? (apologies for the 101 level questions, the only processor I really understood was the ARM2 so my curiosity vastly exceeds my knowledge here)
(Of course, you can add unnecessary dependency with a badly designer ISA. But it's not a necessary condition.)
If you use a simple int for index:
slli a1,a1,2
add a0,a0,a1
lw a0,0(a0)
And isolating this code in a small function puts constraints on register allocation, but if we remove this constraint then we can write: slli a1,a1,2
add a1,a1,a0
lw a1,0(a1)
Which is very suitable for macro-op fusion and C extension> Including compressed instruction in the Unix profile was the biggest mistake RISC-V did and I'll die on that hill.
This is so wrong. The C extension is one of the great strengths of RISC-V, it is easy to decode, very suitable for macro-op fusion, and it gives a huge boost in code density
I don't think RISC-V is perfect or universal, but on this point they do a pretty good job compared to other ISAs
If the compressed extension is great in practice it might be a win. If the early criticism of overfit to gcc -O0 proves sound and in practice compilers don't emit it then it was an expensive experiment.
As an example, in an ISA with 8-bits fixed instruction length and 8 registers (reg index encoded on 3 bit):
If the last 2 bits are the opcode and we define 2 instructions (eg. AND, XOR) that manipulate 2 registers (3 bits + 3 bits), then instruction word values 0b00_000_000 to 0b01_111_111 might encode these two instructions (ignore "_" they are separators).
Therefore, instruction word values from 0b10_000_000 to 0b11_111_111 remain free, which represents half of the encoding space. So half of the encoding space remains free.
This means we still have room to put new instructions.
Similarly, RISC-V valid instructions use almost all the available bits, but there is still room in the encoding space because some opcodes remain free.
From a performance perspective what is the evidence that this actually provides an advantage?
If there is lots of evidence for the performance benefits of improved density vs the alternative of fixed instruction width in real world CPUs then I’m sure you’ll be able to cite it.
ARMv8 and ARMv9 have poor code density. These cache are large as a workaround to that.
This isn't free, as besides making the die larger (and thus lower yields), the L1's clock speed is limited due to its size.
You are right, code density is perhaps not that critical today.
And it is difficult to quantify its relevance as code density is always related to other variables such as instruction expressiveness, numbers of uop emitted, etc.
But I still think that code density is important for RISC-V. Because RISC-V philosophy to reach high performance is to use very simple instructions that can be combined together and take advantage of macro-op fusion. I think RISC-V without macro-op fusion can't reach the performance of other ISA.
But RISC-V with all these simple and not very expressive instructions and without C extension has a pretty bad code density which could cost a lot because it is not at the competitors' level.
So if we think of RISC-V as a macro-op fusion oriented ISA, then the C extension becomes important to be competitive.
I don't know what is better between a "macro-fusion" oriented arch or a "complex-instruction" oriented arch, future will tell us.
The sins of the original RISC-V was spending too much time looking at RV32 and not realizing how big a problem this is in practice. Zba (slipped in as it’s not really “bit manipulation”) fixes the worst of this.
ADD: The problem in this HN thread is the same reason we got compressed it in the first place. The vast majority of people aren’t doing high performance wide implementation so the true cost isn’t widely appreciated. The people holding the decision power certainly didn’t understand it. I really think you have to live it to understand it.
This does not really justify isolating that snippet if you admit yourself it's a bad one.
> The sins of the original RISC-V was spending too much time looking at RV32 and not realizing how big a problem this is in practice.
But indeed, my previous message shows that even without Zba the problem is erased by a good register allocation and macro-op fusion.
I think you are trying too hard to find special cases that "trick" RISC-V, you didn't even pay attention to the use of unsigned which is non-optimal (unsigned has an undesirable overflow semantic here).
On the one hand we have byte count, with its obvious effect on cache space used. But to those of us who don't know, why is instruction count so important?
There's macro-op fusion, which admittedly would burn transistors that could be used for other things. Could you elaborate why it's not sufficient?
And then the fact that modern x86 does the opposite to macro-op fusion, by actually splitting up CISC instructions into micro-ops. Why is it so bad if they were more micro-ops to start with, if Intel chooses to do this?
So the four input operands and one output operand are not a problem because that's just what two pipelines do all the time anyway.
Imaging someone uses quantum gravity to explain why Australians stand upside down on a globe.
The author starts with a apparently meaningless `int x = a[i];`, but did not ask an obvious question before digging in: what usually goes before and after this statement and together what will they produce? A formal RISC-V code analysis usually does not go like this.
`int x = a[i];` is the kind of expression that strikes you as useful at the first glance, but then nothing. If you visit an array, then on x64/ARM/RISC-V, they are all compiled down to 2 instructions per iteration. Not 1 vs 2 vs 3 as suggested by the article. RISV-V may have one or two more instructions outside the loop but that's it.
I'm sure there are some bad decisions in RISC-V, but I've yet to see one that isn't in the process of being remedied. There was a good argument for a lack of POPCOUNT instruction being bad, but I think that's being added soon
OTOH if one is designing an ISA that will have a bunch of different implementations - and this includes later implementations wanting to be ASM compatible with earlier ones - they tend to eventually become a footgun for the processor designers. (if I remember correctly and didn't completely misunderstand, MIPS' branch delay slots were absolutely a neat optimisation for the early models, but when they went to a deeper pipeline for later chips required a bunch of extra design effort to maintain compatibility with, without being helpful anymore)
(explicit disclaimer that I'm an armchair amateur here, so if you're a fellow non-expert reading this comment before it attracts better informed replies please default to joining me in the assumption that I've made at least one massive error in what I'm saying here)
The fact is that integer operations and floating point are two completely different beasts, so much so that we have different benchmark suites for each.
Integer operations are critically latency sensitive and bagging on extra semantics doesn't come for free and for most code this would be a tax. The "overflow bit" represents an implicit result that would have to be threaded around (I'm assuming that you aren't asking for exceptions which literally nobody wants). For FP we do that, but the cost and latency of FP ops is already high so it doesn't hurt quite as much.
The RISC-V spec [1] (which I assume you have seen) already discusses all these trade offs:
"We did not include special instruction-set support for overflow checks on integer arithmetic operations in the base instruction set, as many overflow checks can be cheaply implemented using RISC-V branches. Overflow checking for unsigned addition requires only a single additional branch instruction after the addition:
add t0, t1, t2
bltu t0, t1, overflow
For signed addition, if one operand’s sign is known, overflow checking requires only a single branch after the addition: addi t0, t1, +imm
blt t0, t1, overflow
This covers the common case of addition with an immediate operand.
For general signed addition, three additional instructions after the addition are required, leveraging the observation that the sum should be less than one of the operands if and only if the other operand is negative. add t0, t1, t2
slti t3, t2, 0
slt t4, t0, t1
bne t3, t4, overflow
In RV64I, checks of 32-bit signed additions can be optimized further by comparing the results of ADD and ADDW on the operands."I do think that it might have been worth adding an single instruction version for the last one (excluding the branch), but I'm not aware of it getting accepted.
Most real cases of overflow checking are of the last type. Tripling the number of instructions over a bad ISA that lacks overflow exceptions, like unfortunately almost all currently popular ISAs are, or quadrupling the number of instructions over a traditional ISA with overflow exceptions is a totally unacceptable cost.
The claim that providing overflow exceptions for integer addition might be too expensive can be easily countered by the fact that generating exceptions on each instruction is not the only way to guarantee that overflows do not happen.
It is enough to store 2 overflow flags, 1 flag with the result of the last operation and 1 sticky flag that is set by any overflow and is reset only by a special instruction. Having the sticky flag allows zero-overhead overflow checking for most arithmetic instructions, because it can be tested only once after many operations, e.g. at a function exit.
The cost of implementing the 2 overflow bits is absolutely negligible, 2 gates and 2 flip-flops. Much more extra hardware is needed for decoding a few additional instructions for flag testing and clearing, but even that is a negligible cost compared with a typical complete RISC-V implementation.
Not providing such a means of reliable and cheap overflow detection is just stupid and it is an example of hardware design disconnected from the software design for the same device.
The early RISC theory was to select the features that need to be implemented in hardware by carefully examining the code generated by compilers for representative useful programs.
The choices made for the RISC-V ISA, e.g. the omission of both the most frequently required addressing modes and of the overflow checking. proves that the ISA designers either have never applied the RISC methodology, or they have studied only examples of toy programs, which are allowed to provide erroneous results.
On a simple processor like a microcontroller this doesn't cost much, but it's severely hampers a superscalar or out of order processor, as it can't work out very easily which instructions can be run in parallel or out of order.
The clean solution from a micro architectural point of view would be to have an overflow bit (or whatever flags you wanted) in every integer register. But that's an expense most don't want to pay.
In every 4-5 instructions, one is a load or store, which may generate a multitude of exceptions.
Allowing exceptions does not slow down a CPU. However they create the problem that a CPU must be able to restore the state previous to the exception, so the instruction results must not be committed to permanent storage before it becomes certain that they could not have generated an exception.
Allowing overflow exceptions on all integer arithmetic instructions, would increase the number of instructions that cannot be committed yet at any given time.
This would increase the size of various internal queues, so it would increase indeed the cost of a CPU.
That is why I have explained that overflow exceptions can be avoided while still having zero-overhead overflow checking, by using sticky overflow flags.
On a microcontroller with a target price under 50 cents, which may lack a floating-point unit, the infrastructure to support a flags register may be missing, so it may be argued that it is an additional cost, even if the truth is that the cost is negligible. Such an infrastructure existed in 8-bit CPUs with much less than 10 thousand transistors, so arguing that it is too expensive in 32-bit or 64-bit CPUs is BS.
On the other hand, any CPU that includes the floating-point unit must have a status register for the FPU and means of testing and setting its flags, so that infrastructure already exists.
It is enough to allocate some of the unused bits of the FPU status register to the integer overflow flags.
So, no, there are absolutely no valid arguments that may justify the failure to provide means for overflow checking.
I have no idea why they happened to make this choice, but the reasons are not those stated publicly. All this talk about "costs" is BS made up to justify an already taken decision.
For a didactic CPU, as RISC-V was actually designed, lacking support for overflow checking or for indexed addressing is completely irrelevant. RISC-V is a perfect target for student implementation projects.
The problem appears only when an ISA like RISC-V is taken outside its right domain of application and forced into industrial or general-purpose applications by managers who have no idea about its real advantages and disadvantages. After that, the design engineers must spend extra efforts into workarounds for the ISA shortcomings.
Moreover, the claim that overflow checking may have any influence upon the parallel execution of instructions is incorrect.
For a sticky overflow bit, the order in which it is updated by instructions does not matter. For an overflow bit that shows the last operation, the bit updates must be reordered, but that is also true for absolutely all the registers in a CPU. Even if 4 previous instructions that were executed in parallel had the same destination register, you must ensure that the result stored in the register is the result corresponding to the last instruction in program order. One more bit along hundreds of other bits does not matter.
That is too optimistic. Programs will keep running unchecked and we'll keep getting CVE's from overflow bugs.
That's what the Mill CPU does. Each "register" also had the other usual flags, and even some new ones like Not a Result, which helps with vector operations and access protection.
This is an old myth, endlessly parroted. On current x86, the status register is renamed just like other registers, as could easily have been done in a better RISC-V design. Lack of status flags will be RISC-V's equivalent of delay slots, that once felt like an optimization but has already aged badly.
The unreliable presence of POPCNT and ROT instructions was a worse failing, apparently mitigated lately.
That's understating things considerably.
ARMv8-A has PSTATE, which includes the overflow bit. This explicit state must be saved / restored upon any context switch.
And there isn't just a single PSTATE for an OOO SuperScalar, there are several.
Everything has a cost.
How does this work? Isn't `bltu` simply a branch that is taken if `t0 < t1`? How does that detect addition overflow?
EDIT: Ah, because the operands are `t1` and `t2`. `t0` is the result. Quack.
I want exceptions. Why would they be a bad idea? Besides the fact that software doesn't utilize them today (because they're not implemented, chicken and egg problem)? IMO they would be as big a security win as many other complex features CPU designers are adding in the name of security, e.g. pointer authentication.
This is not really accurate AIUI, since the RISC-V C extension allows 32-bit insns to be 16-bit aligned. (This would also happen if 48-bit insns were enabled by some other future extension). It's nonetheless a lot simpler than whatever x86 has to do, since insn length is given by a few well-defined bits in the insn word.
No thanks, Medium. These dark patterns crop up everywhere lately...
As a Medium writer, I’m annoyed now! They already stopped paying me my ~0-10$ per month because I refused to beg everyone to get to their new minimum 100 followers requirement for getting paid.
Medium is a like a magazine with a very large number of journalists which it pays to write for it. Naturally it needs to charge subscribers to make an income.
- Even with instruction compression the type of code they present will take more space than, say, Aarch64. - The entire section on conditional execution doesn't make any sense. Conditional execution is bad, we know it, that's why modern ARM does not have conditional execution. Overall, author's insistence to compare RISC-V to practically obsolete ARMv7 when ARMv8 has been available for over a decade is... odd. - Regarding SIMD... it's a very complex topic, but personally, I don't see any fundamental problem with vector-style ISA. I think it's a great way of allowing scalable software. But vector ISA does not replace basic SIMD as they solve different problems. Vector stuff is great for throughput, SIMD is great for latency. There are many tasks such as geometry processing, modern data structures etc. where fixed-size 128-bit SIMD is an excellent building block. That's why ARM has both NEON and SVE2, the latter does not make obsolete the former. And that bit about GPUs and how they are not good for vector processing... not even sure how to comment on it. Also, at the end of the day, specialised devices will vastly outperform any general-purpose CPU solution. That's why we see, say, Apple M1 matrix accelerators delivering matmul performance on par with workstation CPU solutions, despite using a fraction of power.
Overall, my impression is that the article is grasping at straws, ignores modern technology and ultimately fails to deliver. I aolso remain unconvinced by the initial premise that RISC-V follows the principle "not painting yourself into a corner due to choices which have short term benefit". I do think that choices like keeping instructions as simple as possible (even though it makes expression of common patterns verbose), avoiding flags registers, disregarding SIMD etc. could be characterised as "painting oneself into a corner".
A usual disclaimer: I do think that RISC-V is a great architecture for many domains. Simple low-power/low-cost controllers, specialised hardware, maybe even GPUs (with extensions) — the simplicity and openness of RISC-V makes it a great point of entry for basically anyone and invites experimentation. I just don't see much merit of RISC-V in the general-purpose high-performance consumer computing (laptop/desktop). In this space RISC-V does not have any notable advantages, it does have potential disadvantages (e.g. code density and lack of standard SIMD — yet). Most importantly, the CPU microarchitecture becomes the decisive factor, and designing a fast general-purpose CPU requires a lot of expertise and resources. It's not something that a small group of motivated folk can realistically pull off. So all the great things about RISC-V simply do not apply here.
So anyone that isn't deep into ARM architecture will indeed buy into the arguments being made, as they can't assert otherwise.
The article touched on this briefly so it's odd that you would claim this without a source for the claim. I know there's some outdated benchmarks where it's slightly worse than Thumb for instance. But then Thumb isn't relevant for desktop CPUs.
The downside for RISC-V for high end desktop/laptop is lack of a large commercial backer (someone like Apple could pull it off, but clearly they've bet on ARM,which was clearly the right choice since RISC-V was far from ready). Lack of the huge legacy of tool chains and software built around x86 and ARM is also obviously a huge disadvantage.
But you could have said the same about ARM back in the day. The thing is I'm not sure if the advantages for RISC-V is big enough to take over all of ARMs markets the way ARM has the potential for with x86.
HOWEVER, an argument in the ARM camp is that they are very useful when dealing with smaller chips. Remember ARM and RISC-V compete in the low range as well as higher range. AArch32 is not obsolete. It still has uses. There has been ARM fans claiming that conditional instructions make ARM superior for simple chips. The argument here was that RISC-V has way of dealing with simple In-Order chips as well.
For those following this only from the sidelines, it would help strengthen the article if the article has links to such claims. I couldn’t easily find them, and would be curious as to their age, given that, reading https://en.wikipedia.org/wiki/Predication_(computer_architec..., ARM has made substantial changes to conditional execution a few times since 1994 (over 25 years ago); Thumb (1994) dropped them, Thumb-2 (2003) replaced them by, if I understand it correctly, an instruction “skip the next 4 instructions depending on flags”, and ARMv8 replaced them by conditional select.
(In general, providing links to articles claiming each proclaimed myth to be true would strengthen this article. I think I’ve only ever read about #1, and not with as strong a wording as “bloats”)
It should be possible to discuss these opinions without singling out anyone.
I am however talking about claims put forth after ARMv8. The argument here has basically been this: Both ARM and RISC-V aims to cover both the low end and high end. Some ARM fans think that by not including conditional instructions RISC-V really only works for high-end CPUs. The idea here is that AArch32 would be better than RV32 for lower-end chips.
This is also a place where RISC-V displays an ABI choice that is nonsensical: a bit of historical awareness would have made the boolean "true" value ~0, or -1, as indeed it effectively is in AVX2 and GPUs.
Of course CPUs are good for vector processing compared to a general-purpose CPU. That was not the point at all. The point is that unlike older architectures such as Cray, they were not designed specifically for general-purpose vector processing but for graphics processing. That is why solutions such as SOC-1 built specifically for genera-purpose vector processing can compete with graphics cards made by giants like Nvidia.
The article is talking about adding vector processing both to RISC-V chips aimed at general purpose processing as well as to specialized RISC-V cores which are primarily designed for vector-processing. SOC-1 is an example of this. It has 4 general purpose RISC-V cores called ET-Maxion, while also having 1088 small ET-Minion cores made for vector processing. However these are still RISC-V cores, rather than some graphics card SM core.
I don't get your argument about SIMD being great for latency. RISC-V requires that vector registers are at minimum 128-bit you you can use RVV as a SIMD instruction-set with 128-bit registers if you want.
Regarding SIMD: maybe you are right. I don’t know. Performance of RISC-V vectors here is an unknown factor. If VSETVL is zero-cost and the CPU can rename vector partitions without added latency, sure. But I remain skeptical until proven otherwise. The very design of RISC-V vector stuff screams amortized processing of large data blocks, not flexible low-latency operations on small data blocks. And notably, I could not find basic SIMD shuffle/interleave operations in the spec. That’s perfectly fine for large data vectors where you can work with multiple instruction, data-parallel vector registers and blends, but it would kill performance for many algorithms that work on limited number of lanes.
I'm surprised that it wasn't pointed out that this should probably be eliminated by a compiler transformation. Rather than loading from r0+r1<<2 and incrementing r1 by one every loop iteration, surely it might be possible to load from just r0 and increment it by 4 every loop iteration?
One simple example: when you do loop unrolling, you must access elements n+4, n+8 and n+12 etc.
As for unrolling, isn't this a job for RV64V?
However, trade offs matter. Compressing instructions may improve density, but it makes them variable length. This is a big barrier to decoding in parallel, which is very important to high performance cores.
Unlike x86 where instructions can range from 1 up to 15 byte, current RISC-V ISA only has 2 instruction sizes.
Today x86 decoding is limiting because we want to decode more than ~4 instructions each cycle, for RISC-V to cause same decoding difficulty it would probably be required to decode more than ~20 instructions each cycle
What I've been wondering is how difficult it is to fuse instructions when the compressed instructions you're trying to fuse isn't aligned to a 32-bit word.
Uh? In RISC-V with the C extension, 32bit instructions are 16-bits aligned, so no you don't.
If decoding 32 bytes of code (256 bits, somewhere between 8 and 16 instructions) You can figure out where all the actual instructions start (yes, even the 16th instruction) with 2 layers of LUT6.
You can then use those outputs to mux two possible starting positions for 8 decoders that do 16 or 32 bit instructions, plus 8 decoders what will only ever do 16 bit instructions from fixed start positions (and might output a NOP or in some other way indicate they don't have an input).
OR you can use those outputs to mux the outputs of a 8 decoders that only do 32 bit instructions and 8 decoders that do 16 or 32 (all with fixed starting positions), plus again 8 decoders that only do 16 bit instructions from fixed start positions (possibly not used / NOP).
The first option uses less hardware but has higher latency.
That, again, is for decoding between 8 and 16 instructions per cycle, with an average on real code of close to 12.
That is more than is actually useful on normally branchy code.
In short: not a problem. Unlike x86 decoding.
I’m assuming the decode window is aligned, but that may be a bad assumption.
A function that does nothing but return an array element from an array base address and index passed to it? Really? Do you actually write junk like that? And if you write it does your compiler really not inline it? Why? Do you like big slow code? Once it's inlined, it's probably in a loop, and strength-reduced.
It's very easy to verify that in the real-world RISC-V code is more compact than amd64 and arm64. Just download the same version of Ubuntu or Fedora (etc) for each one and run the "size" command on the binaries. The RISC-V ones are consistently significantly smaller.
You can also, with quite a bit more work, count the number of µops each ISA executes. RISC-V executes slightly more instructions, but they are each simple and don't need expanding. Lots of x86 instructions get expanded into multiple µops and many 64 bit ARM instructions do too. In the end the number of µops executed by each is very similar.
Trying to judge the goodness of a modern ISA by looking at two or three instruction snippets is as silly as using Dhrystone as your only benchmark program.
This makes it very inefficient to compile languages that would like overflow checks on all arithmetic.
> No data [that I can see at least]
https://www.reddit.com/r/RISCV/comments/tik718/addressing_cr...
From what I read in the comments, I don't expect compressed instructions on future high performance desktop/servers RISC-V CPU cores to be there.
One thing ARM and x86 got right that SPARC and POWER got wrong is widely-available machines available at reasonable prices. All the 'being right' in the world won't help if developers need a five-figure hardware budget to port to your platform. VMs don't cut it for bringup.
$29 64 bit RISC-V in the same form factor as an RPi CM3 https://www.clockworkpi.com/product-page/copy-of-clockworkpi...
If you never look for it, you will believe it doesn’t exist.
I was very skeptical of ARM back in the day thinking that it was great for crappy little iTrinkets and Androids but not for “real computing”. I was clearly wrong. I was very skeptical of RISC-V until I recently heard Jim Keller explain why RISC-V has a bright future. He was rather convincing. This is especially true given his track record of straight-up magical results. Looking at different RISC-V machines, I think that the greatest advantage is that it is simple and can therefore be optimized more easily than complex designs, and due to being open, it has very low cost which will encourage more eyes trying more and different optimizations.
EDIT: Link to Jim Keller interview https://www.anandtech.com/show/16762/an-anandtech-interview-...
Would like to hear it too. Can you share a link?
It’s actually important (if you’re not an engineer) to listen to the whole thing, because he drops knowledge all over the place.
I watched at 1.5x speed.
Where is a RISC-V doing “real computing” on a Acorn Archimedes like personal computer?
The x86 tool chains are amazing. They're practically black magic in the kinds of optimizations they can do. Honestly, I think they're a lot of what is keeping Intel competitive in performance. ARM tool chains are also very good. I think they're a lot of the reason behind why ARM can beat RISCV in code space and performance on equivalent class hardware because honestly, like Keller says, they're not all that different for common case software. But frankly x86 and ARM toolchains should dominate RISCV when we just consider the amount of person-hours that have been devoted to these tools.
So for me the real question is, where are the resources that make RISCV toolchains competitive going to come from (and keep in mind x86 and ARM have open source toolchains too)? And, will these optimizations be made available to the public?
If we see significant investment in the toolchains from the likes of Google, Apple and nVidia, or even Intel. ARM needs to be really worried.
If you look at generated code, it seems fairly straightforward. There aren't a lot of tricks or anything.
The compiler has just tons of internal heuristics on when and when not to apply various code transformations. Those heuristics, first off may not even be applicable for your platform of choice, and even if they are, their magic numbers aren't necessarily tuned well to the platform and application at hand.
Here is a well written and concise case study, albeit somewhat old (2010), that illustrates what I am talking about. The results of variations measurements will have changed since then but the overall high level situation hasn't. If you read the paper, in your mind, just replace every instance of x86 with ARM and every instance of ARM with RISCV and you'll get the idea.
Also no mention of the binary compatibility issues - which `-march` do you compile your code for? On x86 you have a choice of 3. For RISC-V as far as I can tell there are 96 valid targets.
Secondly, AVX-512 alone has a handful of different extensions. There are a bunch of different SSE variants, and similarly instructions are still being added to the VEX prefix (normal AVX).
There is more potentially for getting it wrong with riscv but 64 bit implies a number of extensions too so it's too far off what amd64 originally meant for X86 (e.g. implies SSE2)
> Firstly -march (or similar, e.g. -mcpu in LLVM land) should target a chip not individual instruction sets.
LLVM still uses -march. And no you shouldn't target a specific chip unless you know your code will only run on that chip. That's the whole point I'm making. Sometimes you do know that (in embedded situations) but often you don't. Desktop apps aren't compiled for specific chips.
> Secondly, AVX-512 alone has a handful of different extensions.
Yes but these are generally linear - if an x86 chip supports extension N it will support extension N-1 too. Not true for RISC-V.
As for linearity, the "generally" bit will apply to RISC-V by the time we have real desktop class chips using the ISA. We still can't assume AVX support for most programs, I don't view this as any different to RISC-V extensions. Just this ~year Intel added VEX-coded AI NN acceleration instructions, I assume RISC-V has similar plans.
Time will tell if there's a de facto minimum set of extensions for desktop RISC-V. Let's hope so, but it isn't guaranteed.
Not if you include AMD and Intel cores in that.
There's plenty of cores that don't follow that versioning scheme, and it's not an Intel or AMD construct.
Not to mention that by sticking with simple single purpose instructions you make the CPU easier to teach to students. That is after all one of the goals of RISC-V in addition to creating a good ISA for industry.
Have we learned nothing about why we abandoned CISC in the first place? Those CPUs got riddled with instructions that never got used much.
Yes... if you willing to tolerate ever more complex and slow instruction decoding. This is a very bad tradeoff.
The point isn't just saving gates because it's cheaper. Less gates means less critical path length, meaning less power consumption, and/or higher overall performance when compared apples to apples.
RISC-V gives people a way to learn and understand what a modern CPU is like. Remember Donald Knuth's books. He teaches algorithms on an imaginary CPU. As CISC architecture got superseded by RISC, he started using an imaginary RISC CPU in teaching.
His point is that people implementing stuff need to have some sense of how the hardware works to understand tradeoffs. RISC-V is in my view a great CPU arch to give that kind of understanding for somebody who is not necessarily interested in writing assemblers, compilers or what not.
Beyond that RISC-V really fits well with the heterogenous computing trend we are moving towards where specialized hardware is increasingly doing more and more of our tasks. I would say it is and advantage that these different specialized chips have some commonality between them. RISC-V is giving people a way of creating a whole ecosystem of chips for a variety of purpose which share a lot of instructions, debuggers, profilers, compilers and other tools.
There is no way x86 could be part of that revolution. x86 is stuck as a general purpose CPU. RISC-V on the other hand will power desktop computers, smart phones, micro-controllers, AI accelerator cards, super-computers and just about anything.
What matters is not 'RISC philosophy' but that it is an Open Standard that allows for Open implementation.