Live data from Hacker News

“Risc V greatly underperforms”

gmplib.org

351–360 of 365 posts

Re: “Risc V greatly underperforms”

#351

Earlier quoted context omitted.

> Except for this good feature, the rest of the ISA is full of bad features What are your thoughts on the way RISC V handled the compressed instructions subset?

The compressed instruction encoding is very good and it is mandatory for any use of RISC-V in embedded computers. With this extension, RISC-V can be competitive with ARM Cortex-M. On the other hand, the compressed instruction encoding is useless for general-purpose computers intended as personal computers or as servers, because it limits the achievable performance to much lower levels than for ARMv8-A or Intel/AMD.

This is wrong. RISC-V's instruction length encoding is designed in such a way that compressed instructions can be decoded very quickly. It doesn't pose the same kind of performance problem amd64's variable instruction length encoding does. Even if it did, it would be obvious nonsense to claim that this made it impossible for a RISC-V implementation to achieve amd64-like performance; if it were true, it would also make it impossible for amd64 implementations to achieve amd64-like performance, which is clearly a contradiction. And ILP and instruction decode speed are also improved by other aspects of the RISC-V ISA: the fused test-and-branch instructions you mentioned, but also the MIPS-like absence of status flags.

Re: “Risc V greatly underperforms”

#352
post #133

Earlier quoted context omitted.

> I am sorry but saying that RISC-V is a winner in code density is beyond ridiculous. You have no idea what you're talking about. I've worked on designs with both ARM and RISC-V cores. The RISC-V code outperforms the ARM core, with smaller gate count, and has similar or higher code density in real world code, depending on the extensions supported. The only way you get much lower code density is without the C extensio…

Memory-safe programming does not need any special ISA extension compared to traditional, C-like unsafe code. Even the practical overhead of bounds- and overflow checking is all about how it impedes the applicability of optimizations, not about the checks themselves.

It doesn't need them, but having hardware checks is generally more performant than having software ones.

Re: “Risc V greatly underperforms”

#353
post #90

Earlier quoted context omitted.

The argument for RISC instructions (in high performance architectures) is that the faster decode makes up for the increase in instruction count. The problem is that a faster decode has a practical ceiling on how much faster it's going to make your processor, and it's much lower than 3x. If your workload is bottlenecked on an inner loop that got 3x larger in instruction count, no 15% improvement in decode performance…

Amount of instructions matters much less if they can be fused into more complex instructions before execution. RISC-V was designed with hindsight on fusion, thus it has more opportunities for doing it, and doing it at a lower cost. And, due to the very high code density RISC-V has, the decoder can do its job while not having to look at a huge window.

Ok, but where it the chip that can fuse these?

Re: “Risc V greatly underperforms”

#354
post #91
post #6

Earlier quoted context omitted.

RISC-V designers optimized for C and found overflow flag isn't used much and got rid of it. It was the wrong choice: overflow flag is used a lot for JavaScript and any language with arbitrary precision integer (including GMP, the topic of OP).

Also Rust applications are increasingly going to be built with integer overflow checking enabled, e.g. Android's Rust components are going to ship with integer overflow checking. And unlike say GMP, that poses a potential code density problem because we're not talking about inner loops that can be effectively cached, it's code bloat smeared across the entire binary.

> it's code bloat smeared across the entire binary.

That's probably not true in the usual case. Most arch's are 64 bit nowadays. If you are working on something that isn't 64 it you are doing embedded stuff, and different rules and coding standards apply (like using embedded assembler rather than pure C or Rust). In 64 bit environments only pointers are 64 bits by default, almost all integers remain 32 bit. Checking for a 32 bit overflow on a 64 bit RISC-V machine takes the same amount of instructions as everywhere else. Also, in C integers are very common because they are used as iterators (ie, stepping along things in for loops). But in Rust, iterators replace integers for this sort thing. There still is an integer under the hood of course, and perhaps it will be bounds checked. But that is bounds checked - not overflow checked. 2^32 is far larger than most data structures in use. Which means while there may be some code bloat, the lack full 64 integers in your average Rust problem means it's going to be pretty rare.

Since I'm here, I'll comment on the article. It's true the lack of carry will make adds a little more difficult for multi precision libraries. But - I've written a multi precision library, and the adds are the least of your problems. Adds just generate 1 bit of carry. Multiplies generate an entire word of carry, and they almost a common as adds. Divides are no so common fortunately, but the execution time of just one divide will make all the overhead caused by a lack of carry look like insignificant noise.

I'm no CPU architect, but I gather the lack of carry and overflow bits makes life a little easier for just about every instruction other than adc and jo. If that's true, I'd be very surprised if the cumulative effect of those little gains didn't completely overwhelm the wins adc and jo gets from having them. Have a look at the code generated by a compiler some time. You will have a hard time spotting the adc's and jo's because there are bugger all of them.

Re: “Risc V greatly underperforms”

#355

Earlier quoted context omitted.

Not having the definition being controlled by a company, being and open specification and the whole ecosystem and tooling from the ground up being designed around a fully modular instruction set with use-case specific profiles that can evolve independently is very different then what we have now. > Finally, "the goal" is really "a goal or vision" as expressed by proponents. It's not really one in the objective sense.…

I agree with the latter portion, and that's the part I like about RISC-V the most. Just wish some of the choices were made differently. Open could be open and amazing. We are likely to get open with a bit of hobbling built in early on, and that makes me wonder. This discussion is much improved over the initial, "unified, but..." one we started with.

I think overall it is amazing. I think considering everything they had to do and everything they wanted to achieve, I think they made really, really good overall choices.

There are some things here and there one can argue, depending on what one considers the main usecase. Overall I think starting with a very small base makes a lot of sense.

In fact they actually went to large in some places and that's why they have been working on a profile that is considerably smaller, less registers and floats in int register standards.

Given that this was made by a small group of students and one professor I think its remarkable and innovative.

Re: “Risc V greatly underperforms”

#356

Earlier quoted context omitted.

I agree with the latter portion, and that's the part I like about RISC-V the most. Just wish some of the choices were made differently. Open could be open and amazing. We are likely to get open with a bit of hobbling built in early on, and that makes me wonder. This discussion is much improved over the initial, "unified, but..." one we started with.

I think overall it is amazing. I think considering everything they had to do and everything they wanted to achieve, I think they made really, really good overall choices. There are some things here and there one can argue, depending on what one considers the main usecase. Overall I think starting with a very small base makes a lot of sense. In fact they actually went to large in some places and that's why they have b…

I do not think much of the choice on how to do math and not have flags.

We will see over time.

My preference is a hybrid. There are ops we know will repeat a lot. Targeting those with efficient, small instructions will be a win over this every time.

I expect to see that done.

Sing the tool chains all come up as a good thing though. We're heading into interesting times.

Re: “Risc V greatly underperforms”

#357
post #3

So this is one tiny corner of the ISA, not something that makes ALL instruction sequences longer - essentially RISCV has no condition codes (they're a bit of an architectural nightmare for everyone doing any more than the simplest CPUs, they make every instruction potentially have dependencies or anti-dependencies with every other). It's a trade off - and the one that's been made is one that makes it possible to make…

This isn't an isolated case. RISC-V makes the same basic tradeoff (simplicity above all else) across the board. You can see this in the (lack of) addressing modes, compare-and-branch, etc. Where this really bites you is in workloads dominated by tight loops (image processing, cryptography, HPC, etc). While a microarchitecture may be more efficient thanks to simpler instructions (ignoring the added complexity of compr…

> it's not going to be 2-3x faster, so it's never going to compensate for a 2-3x larger inner loop.

As someone else who replied said, I'm not a CPU architect, just software that works close to the metal. That means I pay attention to compiler output.

What you say is true in the very early says: compilers did indeed use the x86's addressing modes in all sorts of odd ways to squeeze as many calculations as possible into as few bytes as possible. Then it went in the reverse direction. You started seeing compilers emitting long series of simple instructions instead, seemingly deliberately avoiding those complex addressing modes. And now it's swung back again - I'm the complier using addressing modes to shift plus a couple of adds in one instruction is common again. I presume all these shifts were driven by speed of the resulting code.

I have no idea why one method was faster than the other - but clearly there is no hard and fast rule operating here. For some internal x86's implementations using complex addressing modes was a win. On some, for exactly the same instruction set, it wasn't. There is no cut and dried "best" way of doing it, rather it varies as the transistor and power budget changes.

One thing we do know about RISC-V is it is intended to cover a _lot_ transistor and power budgets. Where it's used now (low power / low transistor) is turned out their design decisions have turned out _very_ well, far better than x86.

More fascinatingly to me, today the biggest speed ups compilers get for super scalar arch's has nothing to do with the addressing modes so much attention is being focused on here. It comes from avoiding conditional jumps. The compilers will often emit code that evaluates both paths of the computation (thus burning 50% more ALU time on a calculating a result that will never be used), then choose the result they want with a cmov. In extreme cases, I've seen doing that sort of thing gain them a factor of 10, which is far more than playing tiddly winks with addressing modes will get you.

I have no idea how that will pan out for RISC-V. I don't think any one has done a super scalar implementation of it yet(?) But in the non-super scalar implementations the RISC-V instruction set choices have worked out very well so far. And when someone does do a super scalar implementation (and I'm sure there will be a lot of different implementations over time), it seems very possible x86's learnings on addressing mode use will be yesterdays news.

Re: “Risc V greatly underperforms”

#358
post #91

Earlier quoted context omitted.

Also Rust applications are increasingly going to be built with integer overflow checking enabled, e.g. Android's Rust components are going to ship with integer overflow checking. And unlike say GMP, that poses a potential code density problem because we're not talking about inner loops that can be effectively cached, it's code bloat smeared across the entire binary.

> it's code bloat smeared across the entire binary. That's probably not true in the usual case. Most arch's are 64 bit nowadays. If you are working on something that isn't 64 it you are doing embedded stuff, and different rules and coding standards apply (like using embedded assembler rather than pure C or Rust). In 64 bit environments only pointers are 64 bits by default, almost all integers remain 32 bit. Checking…

It's a good observation that checking for 32-bit overflow is not too bad, but...

> In 64 bit ... almost all integers remain 32 bit.

I don't believe this is true for Rust, even if we exclude index integers in iterators because we think those overflow checks can be optimized out. Certainly in my Rust project (Pernosco) there is a lot of manipulation of 64-bit integer data.

Re: “Risc V greatly underperforms”

#359

Earlier quoted context omitted.

Can you treat the whole vector register as a single bignum on x86? If so, I totally missed that.

No. Which is why I'm sure add / adc will still win at 128-bits, or 256-bits. The main issue is that the vector-add instructions are missing carry-out entirely, so recreating the carry will be expensive. But with a big enough number, that carry propagation is parallelizable in log2(n), so a big enough bignum (like maybe 1024-bits) will probably be more efficient for SIMD.

even AVX512 dies

Re: “Risc V greatly underperforms”

#360
post #296

Earlier quoted context omitted.

Return values are pushed onto the Wasm operand stack in left-to-right order. Engines use registers for params/returns up to a point in optimized code and then spill to the stack. So at the call site you can just drop the return values you don't want and should end up with machine code that does exactly what you want.

wasm functions must have a fixed number of results[1]. Lisp functions may have variadic results. A wasm function call must explicitly pop every result off of the stack[2]. These rules add significant overhead to implementing: (foo (bar)) Which calls foo with just the first result of bar, and the number of results yielded by bar is possibly unknown. In psuedo-assembly for a register machine, implementing this is rough…

Ok, I see. Yes, there is some overhead if you want not just multiple returns, but variadic returns. Most virtual machines and programming languages make this fairly inefficient because of fixed arity of returns. AFAICT, targeting anything other than machine code is going to cost you in this case.
Post reply on HN