21 ms·
An ex-ARM engineer critiques RISC-V
- bonzini 6y agoThe worst issue, at least for the versions of the ISA that will run a "real" OS, are the lack of conditional move instructions and lack of bitwise rotation instructions. Lack of shift-and-sum instructions or equivalently addresses with shifted indexes is usually mitigated by optimization of induction variables in the compiler. They are nice to have (I have written code where I took advantage of x86's ability to compute a+b*9 with a single instruction) but not particularly common with the massive inlining that is common in C++ or Rust. The ugly parts are indeed all ugly, though they have now added hint instructions.
- saagarjha 6y agoYeah, IDK about the RISC ISAs–they seem to be designed around being architecturally simple (and I guess easy to teach?) but they really don't seem to map back to actual code at all, nor do they seem particularly grounded in hardware design either. (Or sometimes they're too close to the hardware and burn themselves…)
- d33 6y agoCould it be because of some patents that made it impossible to do it properly?
- nickik 6y agoNo. The just don't share the opinions. RISC-V is designed to go from the smallest possible core to high performance compute. Bit instructions will be in the 'B' extension.
- bumblebritches5 6y agoUmm, Unicode decoding/encoding REQUIRES bitwise operators to work... Not including that in the core ISA is a monumental mistake.
- ThrowawayR2 6y agoBitwise rotation instructions date back to at least the PDP-8. Even if they were patentable, the patents would have expired long ago.
- varispeed 6y agoCan you not add these instructions? At least when you use FPGA IP, it can be done. But you would have to update the toolchain etc to support these new instructions.
- Veedrac 6y agoThey have added them, it's just they're in bitmanip, which isn't finalized, nor is the extension mandatory.
- fulafel 6y agoHave decent speedups been gotten by previous CPUs by the addition of conditional moves? IIRC for some the SPECcpu impact was negligible, amd many RISCs don't have it. RISC is about quantifying this kind of thing and skipping marginal additions after all.
- PeCaN 6y agoI'm not sure about this "RISC way" stuff. From a uarch standpoint the RISC vs CISC distinction is moot and from an ISA standpoint the only real quantifiable difference seems to be being a load-store architecture. ISAs without conditional moves tend to have predicated instructions which are functionally the same thing. I'm not actually aware of any traditionally RISC architectures that have neither conditional moves or predicated instructions. While ARMv7 removed predicated instructions as a general feature ARMv8 gained a few "conditional data processing" instructions (e.g. CSEL is basically cmov), so clearly at least ARM thinks there's a benefit even with modern branch predictors. Conditional instructions are really, really handy when you need them. It's an escape hatch for when you have an unbiased branch and need to turn control flow into data flow.
- fulafel 6y agoWe were talking ISAs so let's focus on that. The quantifiability comes from measuring results when you give compilers new instructions, vs paying implementation complexity (time, money and future baggage to support the insn forever). The upsides and downsides here come in different units so it's still tricky. Lots of instructions can be proposed with impressive qualitative speeches convincing you how dandy they are, but in the end it's down to the real world speedup yield vs the price you pay in complexity and resulting second order effects. (In rarer cases the instructions might be added not for performance reasons but to ease complexity and cost, that's where qualitative arguments still have a place when arguing for adding instructions). It's fine if we don't have the evidence in this thread - I was just asking on the off chance that someone can point to a reference.
- PeCaN 6y ago
- tralarpa 6y agoI thought the scale factor is either 1,2,4 or 8?
- saagarjha 6y agoYou can combine them. For example, [rax+rax*8+1] (base register, register shifted by 8, constant).
- tralarpa 6y agoIsn't the scale factor encoded in just two bits? (i.e. 00=1, 01=2, 10=4, 11=8)
- saagarjha 6y agoJust edited with an example; I’m on my iPhone so assembling via nasm takes an extra minute ;)
- tralarpa 6y agoThanks for the example. I was assuming that a and b are variables in OPs posting.
- bonzini 6y agoTrue that. In my case it was 12+x*9, which is log2 of the page sizes on x86 (4K, 2M, 1G).
- vardump 6y ago> I have written code where I took advantage of x86's ability to compute a+b*9 with a single instruction... Didn't check, but I suspect that decodes at least into two microinstructions.
- pizlonator 6y agoI’m assuming a is a constant in your example and that you’re doing a(b, b, 8). That’s one cycle on modern intels I believe (I think the manual promised this for Nehalam). OP also alludes right this fact when talking about fusion.
- pbsd 6y agoNot only is it a single uop for the last 10 years of Intel chips, you can also run 2 of them per cycle.
- bumblebritches5 6y agoNope. It's a pretty famous instruction, FMA Fused Multiply-Add
- saagarjha 6y agoSome discussion back when it was written in 2019: https://news.ycombinator.com/item?id=20541144 https://news.ycombinator.com/item?id=20541144
- deleted 6y ago[deleted]
- souprock 6y agoThe use of LL/SC for atomics is a common mistake. It makes replay debuggers like rr impossible to implement.
- saagarjha 6y agoLast I heard, adding a hardware counter for failed SCs may help work around this on ARM–presumably RISC-V could do the same thing here?
- garaetjjte 6y agoNot necessarily, it needs to allow trap on failures.
- EE84M3i 6y agoFor anyone confused like me, see https://en.wikipedia.org/wiki/Load-link/store-conditional https://en.wikipedia.org/wiki/Load-link/store-conditional
- londons_explore 6y agoWhen designing an ISA, I assume a basic step is figuring out which instructions to include. For each instruction, I would guess that a 'draft' compiler is produced that can use that instruction in its code generation steps, and a few 'draft' CPU designs are made which include support for that instruction. Then cycle accurate simulations can be done on a set of test benches to see how the addition of that instruction affects performance, power, and code size across a wide array of different usecases. In the case of RISC-V, where some CPU extensions might be emulated, I would expect the test to also cover the performance hit of emulation of the extension for those machines without native support. If all of that was done, and still it made sense to add the instruction, then most of these critiques aren't valid - since there will be hard data that the approach taken was the best one. Perhaps when RISCV was a young project, too many design decisions were made without the massive compute farm to do all these simulations, or before more complex multi-issue CPU designs were added to it, and therefore some decisions aren't optimal?
- baybal2 6y agoAcademia pulled in too much. Small ISA != Small transistor count. People will inevitably try to throw more transistors on the ISA limitations.
- rwmj 6y agoThis isn't true. Berkeley produced several real RISC-V ASICs and adjusted the encoding according to their findings before RISC-V got any wider attention. Also the team had a long history making real chips before RISC-V, dating back to the early 80s.
- usr1106 6y agoEvery design has its flaws. Intel's instruction set is probably closer to the lower end of the spectrum than the opposite. Still there are very performant implementations (probably at the price of increased power consumption). Any educated opinions how bad the RISC-V problems are compared to others when looking at the big picture?
- orbifold 6y agoPersonally I think the POWER instruction set is better in many ways. It has a proven track record of high performance and embedded implementations. A lot of ISA design is about avoiding patents and other traps. Ultimately it doesn’t really matter because most of the value is in the implementation and the software is the commoditized complement. Truly innovative designs don’t actually use RISC encoding and hide the details of instruction encoding. See for example NVIDIAs PTX , which gets mapped to hardware specific instruction streams, which are nothing like a traditional RISC architecture. To me RISC-V is another example of how open source often produces lowest common denominator copy cat versions of ideas that are 30+ years old. Just like Linux. The sad thing is that this often kills innovation and locks in suboptimal designs for a long time, because it is hard to compete against something that is free.
- taffer 6y ago> A lot of ISA design is about avoiding patents and other traps. Aren't patents limited to 20 years? Can't you just ignore all inventions that are < 20 years old to be safe from patents? Then you'd still be 10 years ahead of POWER.
- Someone 6y agoI think anybody wanting to implement POWER nowadays means the PowerPC ISA, as implemented in modern POWER CPUs, not the original POWER ISA from 1990.
- deleted 6y ago[deleted]
- outsomnia 6y ago> This pursuit of minimalism has resulted in false orthogonalities (such as reusing the same instruction for branches, calls and returns) They are all kinds of changes in flow, it's not crazy to have an instruction for that primitive. He complains Risc-V need 4 instructions to do what x86_64 and arm does in two, but... it says Risc-V. And x86_64 CISC instructions devolve to a pile of microcode anyway. Guy invested in powerful incumbant using a completely different and even more established enumbant to bash the challenger over the head with doesn't feel like I am learning anything useful when I read it.
- nojs 6y agoThe author is a woman fyi :)
- K2L8M11N2 6y agoAccording to their Twitter, the author uses they/them pronouns. https://twitter.com/erincandescent https://twitter.com/erincandescent
- Taniwha 6y agoThey got the riscv code slightly wrong (but the instruction count correct). (puts on chip designer's hat) Essentially the ARM/x64 case turns the load memory address calculation into a 4-input adder (so 2 layers of adders) and maybe a couple of extra gates because there are multiple addressing modes. Riscv's equivalent is a 2-input adder. Those get into a critical cache (and TLB) access path and that limits how fast your CPU's core clock can be (or forces you to split that path into 2 clocks). Essentially that's part of the whole RISC idea - simple means faster - you can run your core clocks faster if the decode (and address calculations etc etc) are simpler - getting rid of lots of addressing modes was a big part of the original RISC movement. I think all 4 of those riscv instructions are 16-bit ones so they may even fit into the same space as the 2 ARM ones (haven't hacked on ARM for a while) BTW chances are that that x86_64 mov instruction is not being devolved into more than one internal uOp (might be two if they separate off the address calculation into it's own uOp)
- 6y ago
- unnouinceput 6y agoConsidering none of major players in CPU world are implementing RISC-V (nor will in near future) this rant is same as ranting "what if Hitler developed atomic bomb before US" that History channel likes to throw sometime. An exercise in imagination.
- mcv 6y agoAre you saying that RISC-V was never meant to be implemented? Or is nobody implementing it because this guy is correct and RISC-V is bad? I mean, whatever the exact goal of RISC-V, I don't see any reason why an analysis and critique would not be relevant. Nobody invests resources into this with the intention that it gets ignored. Also, Wikipedia has a list of RISC-V implementations.
- Symmetry 6y agoThere are a number of serious companies using RISC-V in embedded contexts where a number of the author's criticisms don't apply.
- rwmj 6y agoYou are so completely wrong.
- simias 6y agoI enjoyed reading this a lot, I keep seeing RISC-V being touted as a potential replacement for ARM but I had yet to read a good critique of the ISA by people who know what they're talking about. This point I didn't quite understand: >Highly unconstrained extensibility. While this is a goal of RISC-V, it is also a recipe for a fragmented, incompatible ecosystem and will have to be managed with extreme care. Most successful ISAs (including ARM) have their share of extensions, coprocessors, optional opcodes etc... ARM has the various Thumb encodings, Jazelle, VFP, NEON and more. Toolchains and embedded developers are used to dealing with optional features of computers, I'm not sure why RISC-V would fare worse here. Beyond that I notice that many of the ascribed weaknesses are shared with other RISC ISAs like MIPS (but not ARM): - No condition codes - Less powerful, simpler instructions that require more opcodes to do the same thing but can potentially run faster. - No MOV instruction - The "unconstrained extensibility" is arguably a thing on MIPS too, with the four coprocessors that can be used to implement all sorts of custom logic. Of course ARM has been more successful than MIPS, so maybe it's a sign that those things are indeed bad idea but given that this comes from an ARM dev I wonder if part of it is not just "that's now how ARM does it". On the other hand I must say that I was surprised that RISC-V made multiplication optional, in this day and age it seems like such a useful instructions that it's well worth the die area. Optional DIV I can understand, but an ISA without MUL? That's rough, even for small microcontroller-type scenarios.
- tom_mellior 6y ago> ARM has the various Thumb encodings, Jazelle, VFP, NEON and more. Having done just a tiny bit of compiler development for ARM, I can assure you that having all of these variants is a pain. Making compiler writers' lives harder means you're less likely to get optimal performance. At least on the more exotic variants, but possibly even on the most common ones.
- blueflow 6y ago> I believe the author doesn't identify as a "guy". I don't think this was meant as assumption about the authors gender. The same way i wouldn't assume that there is physical, actual pain involved when you said "having all of these variants is a pain" even when you literally wrote it.
- Symmetry 6y agoThese are all good points but fixing many would interfere with the ability of students to create a basic RISC-V processor in a single semester. The simplest possible in order RISC-V and the simplest possible out of order RISC-V designs are a lot easier to do than the equivalents in more common ISAs and that makes it really useful as a teaching tool. EDIT: Also, when the B extension becomes standard that should fix some of the issues.
- socialdemocrat 6y agoGood point. I think the author forgot that RISC-V was motivate as a ISA for both teaching and being giving decent performance in the real world. Seems like some things have to give in the name of simplicity.
- TazeTSchnitzel 6y agoForgot? I think that's a fairly well-known fact about RISC-V, but a good ISA for teaching and a good ISA for the real world are not necessarily the same.
- Veedrac 6y agoI've never really been a fan of this take. It seems to rest a lot on the ideas that: 1) Fusion is hard. While it can be hard (fusing x86 will be), I do not see why it would be meaningfully difficult for RISC-V hardware (except on devices so small it's better to have the simpler base ISA anyway), or compilers, who can in the worst case just treat fused pairs as their own instructions. 2) There's anything wrong with just most software assuming a fairly fixed set of extensions, as seems to have happened. If microcontrollers want to use a subset without multipliers, that doesn't mean anyone else has to care. If bitmanip is stabilized before RISC-V breaks into more common consumer use, why not assume it when writing code? It's only a problem if people make it one. Most of the rest don't matter much in a global sense. The arguments about which operations go in which extensions might have meaningful merit, but it seems not very important to me.
- Jasper_ 6y agoFusion is hard. At least, unconstrained fusion is hard. If you have a couple instructions pairs to fuse together, that's fine, but fusing any possible compiler output together is going to make decode even more complicated in practice. This is why Intel publishes software optimization guides that go over what their fusions are, but it doesn't seem like the RISV-C spec is going to do that yet for many cases. And compiler authors need to know which instruction stream to generate to ensure fused execution.
- Veedrac 6y agoMostly the concern around the lack of instructions in RISC-V revolves around a few well-known cases (eg. indexed loads) where the instructions to fuse are pretty canonical. There is always room for creativity, but that would be the same with or without indexed loads in the base instruction set. Any non-monopolistic hardware ecosystem has this problem; we've been able to ignore it largely on x86 since Intel had had a performance monopoly for so long, but once you have multiple competing core implementations compilers will have to worry about the edge-case performance differences. What I'm talking about is more specific to groups of instructions that are safe to treat as fused by default. Note that even if the compiler outputs a pair of instructions but the hardware running the code doesn't fuse it, out-of-order execution means the penalty will generally be extremely small versus the best unfused instruction schedule. RISC-V does give guidelines on which instructions are good fusion candidates. See for example section 2.13 in the bitmanip extension document. Hardware, naturally, just has a fixed set of fusions it does.
- legulere 6y agoHow often do you read a single array element that is not the first element? Usually you iterate over it
- TazeTSchnitzel 6y ago> How often do you read a single array element that is not the first element Quite often in some applications, for example hash tables (a very popular data structure).
- ncmncm 6y ago[Citation needed] :-)
- pizlonator 6y agoThe lack of condition codes is a big deal for anyone relying on overflow checked arithmetic, like modern safe languages that do this for all integer math by default, or dynamic languages where it’s necessary for the JIT to speculate that the dynamic “number” type (which in those languages is either like a double or like a bigint semantically) is being used as an integer. RISC-V means three instructions instead of two in the best case. It requires five or more instead of two in bad cases. That’s extremely annoying since these code sequences will be emitted frequently if that’s how all math in the language works. Also worth noting, since this always comes up, that these things are super hard for a compiler to optimize away. JSC tries very aggressively but only succeeds a minority of the time (we have a backwards abstract interpreter based on how values are used, a forward interpreter that uses a simplified octagon domain to prove integer ranges, and a bunch of other things - and it’s not enough). So, even with very aggressive compilers you will often emit sequences to check overflow. It’s ideal if this is just a branch on a flag because this maximizes density. Density is especially important in JITs; more density means not just better perf but better memory usage since JITed instructions use dirty memory.
- jhallenworld 6y agoMaybe overflow checking could included as an ISA extension. If it is included, what is the least impactful design? Overflow is part of the result, so maybe include extra bits to each register that can be arithmetic destination. These bits are not included in moves, but could be tested with new instructions. Another way that avoids flags is new arithmetic instructions: add but jump on overflow. Maybe this is reduced to add and skip next instruction except for overflow, but maybe things are simplified if the only allowed next instruction is a jump, so the result is a single longer instruction.
- pizlonator 6y agoThe best design is control bits which RISC-V doesn’t have but x86 and ARM do have. The best design is part of the core ISA and not and extension since overflow checking is fundamental to modern languages.
- mark_l_watson 6y agoSorry in advance, this is going to be a little off topic: while I agree with the technical points in the article and the comments here about RISC-V deficiencies, I hope for a world where Free Software licenses and open hardware rule. (And I admit to some hypocrisy since my daily drivers are the Apple closed ecosystem and Google Workplace.) What gives me some hope is that an open hardware and Free Software world would help so many people, businesses, and governments. I think it would be a rising tide that lifted all boats except for specific tech industries. That said, good article.
- nsajko 6y agoThe misconception you present here seems to be widely held, so I'm actually going to upvote you; RISC-V being an open ISA just means that the standards describing the ISA are open, there is no relation with open source hardware. I.e., proprietary RISC-V cores exist, as do open source ARM cores.
- shahid273y34 6y agoHello
- shahid273y34 6y agoI don't know
- jeff-davis 6y agoIt would be nice to have some context around why these decisions were made. Are they outright mistakes? Trade-offs about the goals of thr ISA? Or trade-offs that the author thinks are bad ones?
- dathinab 6y agoHaving taken a look at the RISC-V ISA spec I'm wondering if they did cripple LL/SC (LR/SC in RISC-V). Basically: - LL/SC can prevent ABA if the ABA-prone part is in-between a LL and SC instruction - To have a ABA prone problem you need some state implicitly dependent on the atomic state but not encoded in it. Normally (always?) the atomic state is a pointer and we depend on some state behind the pointer not changing in a context of a ABA situation (roughly ~ switch out ptr, change ptr target, switch back in ptr, through often more complex to prevent race conditions). This means in all situations I'm aware of LL/SC only prevents the ABA problem if you at least can do one atomic (relaxed ordering) load "somehow" depending on the LL load. (LL load pointer, offset or similar). But the RISC-V spec doesn't only not guarantee forward process in this cases (which I guess is fine) but goes as far as explicitly stating that guaranteed not having forward provess is ok, e.g. doing any load between the load reserved and store conditional is allowed to make the store conditional fail> Doesn't that mean that if you target RISC-V you will not benefit from LL/SC based ABA workaround and instead it's just a slightly more flexible and potential faster compare exchange which can spuriously fail? The spec says you are supposed to detect if it work and potentially switch implementations. But how can you do that reasonable if it means that you have to switch to fundamentally different data structures, which isn't something easily and reasonably done at runtime. Or do I miss something fundamental?
- ChuckMcM 6y agoI saw this when it was a twitter thread[1] and noted then, some good points and some not so good points. One of the things that comes up with Risc-V a lot is code density, and it is a sore spot for many CPU designers because it is shamelessly abused by marketing departments as a measure of 'goodness'. This has sort of trained these engineers to flinch when something doesn't exhibit good code density, and the author is no exception. However, FLASH/RAM volume has gone up hugely. This is in part because once you run out of logic to lay down in a chip you flood fill the rest with RAM and/or FLASH because hey the chip has to be big enough to hold pad landings for all of its pins. This has taken a lot of pressure off the code density thing and now it seems appropriate to look at algorithmic capacity. I agree with the author that it is a much better use of resources to put a hard multiplier on a chip than it is to have more space in flash so that you can do that with instructions. But from a algorithmic capacity question? It is all Turing complete so really what is the practical difference? Now I started life programming on PDP-11's that had a "native" instruction set that was not unlike RISC-V in being maximally simple. We called it "microcode" :-) And the "real" instructions were actually sequences of microcode in a microcode ROM. That was pretty cool because you could swap out floating point instructions for vector instructions or string handling instructions if you wanted. I will not be surprised in the least if people design "custom instruction sets" that layer on top of a RISC-V core, just like layering a front end stack on web assembly. And the available resources to do that are pretty plentiful. One of the coolest architectures I got to play with was the Xerox "D" machines. They took this to an extreme and some amazing software was written for them. You could get really close to maximizing utilization. It was very interesting to load a new instruction set, recompile your Mesa code, and have it run faster with no changes to the hardware at all. Of course DEC and Xerox didn't invent this, the IBM 360 had a big button on the front "IMPL" which was "Initial Micro Program Load" which prepped the instruction set for what ever OS you were about to start up. And now you can build systems like this with open source tools and off the shelf FPGA dev boards. Such a great time to be interested in systems architecture. [1] https://twitter.com/erincandescent/status/1154535799423229952 https://twitter.com/erincandescent/status/115453579942322995...
- audunw 6y ago> However, FLASH/RAM volume has gone up hugely. This is in part because once you run out of logic to lay down in a chip you flood fill the rest with RAM and/or FLASH because hey the chip has to be big enough to hold pad landings for all of its pins. This has taken a lot of pressure off the code density thing and now it seems appropriate to look at algorithmic capacity. I don’t agree. I’m working on a chip right now where NVM and RAM is extremely constrained. There will probably be many millions made, so it’s still relevant. On the last chip I worked on, it was perhaps true to some degree. But that chip, even though it was a microcontroller, had a decent cache. Access to NVM is slow. And code density can have a significant impact on cache performance.
- avianes 6y ago> Same instruction (JALR) used for both calls, returns and register-indirect branches (requires extra decode for branch prediction) JALR for call and return used the same opcode but are two different instructions, there is no need for "extra logic" for the decode or for branch prediction. The lack of "register + shifted" could easily be circumvented by adding an extension for "complex arithmetic instructions". And macro op fusion is a common solution that already exists in modern CPUs to increase the number of stages in the pipeline. > Multiply and divide are part of the same extension An extension can easily be partially supported in hardware (e.g. multiplication) and leave the other instructions emulated in software (e.g. divisions) > No atomic instructions in the base ISA. Multi-core microcontrollers are increasingly common But some microcontrollers do not need atomics. And if you are designing a microcontroller that does, just include the atomic extension. Many of the criticisms made here are incorrect and are due more to a misunderstanding of RISC-V than to RISC-V design flaws
- ncmncm 6y agoSo many flaws, and without even mentioning the missing POPCOUNT. (No, the M extension does not help.)