Live data from Hacker News

RISC-V formal spec public review

github.com

11–20 of 38 posts

Re: RISC-V formal spec public review

#11
post #8

Earlier quoted context omitted.

Connecting from one word to the next. Do you have to do 32-bit multiplications so as to retain the high half of the result, or does a 64-bit multiply deliver the high 64 bits of the result somewhere? Also there is stuff about the carry from 64-bit addition. (Substitute 16 and 32, for 32-bit units.)

There are instructions to get the top half of a multiply, and a suggested ordering so that the chip can deliver both halves with only one calculation. There's no carry flag but I'd say it's still easy to work around that.

[deleted]

Re: RISC-V formal spec public review

#12

How easy is it to do bigint arithmetic in RISC-V?

It has perfectly good add and multiply instructions, so uh easy? What at an ISA level would make it hard?

On x86 you'd do a bigint add with an ADC chain. In RISC-V I think it would be a lot more branchy.

Re: RISC-V formal spec public review

#13
post #5
post #4

Earlier quoted context omitted.

What's wrong with conditional moves? They're good for mispredictable branches, although I liked them better on PPC which had 8 condition/flags registers instead of just 1.

Conditional moves depend on state left over from the last instruction. But when you want to re-order your instructions to keep all your functional units busy, keeping the conditional moves right makes a big mess. They're fine as micro-ops after you've scheduled them all, but are lousy at the ISA level. Intel and AMD make it work by throwing another 10,000 or 100,000 transistors at it. It is better to let macro-op fus…

> Cmov is one of the methods to mitigate Spectre because Intel refuses to speculate loads in them.

Sure, this is what makes it good for mispredictable branches - data decompression for instance. If you can't speculate ahead, it's a waste of space in the branch prediction buffer to do it.

But I definitely wish it was a builtin function instead of the compiler generating it, because none of them can guess when to use it.

Re: RISC-V formal spec public review

#14
post #8

Earlier quoted context omitted.

Connecting from one word to the next. Do you have to do 32-bit multiplications so as to retain the high half of the result, or does a 64-bit multiply deliver the high 64 bits of the result somewhere? Also there is stuff about the carry from 64-bit addition. (Substitute 16 and 32, for 32-bit units.)

There are instructions to get the top half of a multiply, and a suggested ordering so that the chip can deliver both halves with only one calculation. There's no carry flag but I'd say it's still easy to work around that.

Specifically, I think the "sltu" (set if less than, unsigned) instruction is useful for carries. When you add two unsigned integers, the result is smaller than the inputs if and only if an overflow occurred.

  ; a1:a0 * a2 --> a5:a4:a3
  ; using t0 as temp reg
  mulhu a5, a1, a2
  mulu  a4, a1, a2
  mulhu t0, a0, a2
  mulu  a3, a0, a2
  add   a4, a4, t0
  ; carry a 1 or a 0, overwriting t0
  sltu  t0, a4, t0
  add   a5, a5, t0
(edit: switched a1 and a0 for consistency)

Re: RISC-V formal spec public review

#15
post #5
post #4

Earlier quoted context omitted.

What's wrong with conditional moves? They're good for mispredictable branches, although I liked them better on PPC which had 8 condition/flags registers instead of just 1.

Conditional moves depend on state left over from the last instruction. But when you want to re-order your instructions to keep all your functional units busy, keeping the conditional moves right makes a big mess. They're fine as micro-ops after you've scheduled them all, but are lousy at the ISA level. Intel and AMD make it work by throwing another 10,000 or 100,000 transistors at it. It is better to let macro-op fus…

> Conditional moves depend on state left over from the last instruction.

So, literally exactly the same state that conditional branch instructions depend on? Aside from implementation details (like >Intel refuses to speculate loads in them<, which, to be fair, might be its own problem), "cmovz D S" is just "jnz skip ; mov D S ; skip:" without the useless branch overhead.

Re: RISC-V formal spec public review

#16

Earlier quoted context omitted.

It has perfectly good add and multiply instructions, so uh easy? What at an ISA level would make it hard?

On x86 you'd do a bigint add with an ADC chain. In RISC-V I think it would be a lot more branchy.

I know nothing about RISC-V, but my usual way of finding out how to do something standard with a given instruction set is to ask a compiler. There are online compilers, such as this one: https://cx.rv8.io/ Just type in "__int128 add(__int128 a, __int128 b) { return a + b; }" on the left, stick "-O2" into the "Compiler options", and see what you get! I don't know whether that particular compiler is doing the right thing, of course, but it gives you an idea and it's definitely less work than reading the spec.

Re: RISC-V formal spec public review

#17

Earlier quoted context omitted.

It has perfectly good add and multiply instructions, so uh easy? What at an ISA level would make it hard?

On x86 you'd do a bigint add with an ADC chain. In RISC-V I think it would be a lot more branchy.

No need for branches, see comment above demonstrating sltu.

For a long carry chain, I guess it might look like this:

  ; Inputs: x = 4-word number, in a3:a2:a1:a0,
  ;         y = 1-word number, in a4.
  ; Output: x+y, 5-word number, in a4:a3:a2:a1:a0.
  add  a0, a0, a4
  sltu a4, a0, a4 ; a4 = carry bit
  add a1, a1, a4
  sltu a4, a1, a4 ; a4 = carry bit again
  add a2, a2, a4
  sltu a4, a2, a4
  add a3, a3, a4
  sltu a4, a3, a4

Re: RISC-V formal spec public review

#18

Earlier quoted context omitted.

On x86 you'd do a bigint add with an ADC chain. In RISC-V I think it would be a lot more branchy.

No need for branches, see comment above demonstrating sltu. For a long carry chain, I guess it might look like this: ; Inputs: x = 4-word number, in a3:a2:a1:a0, ; y = 1-word number, in a4. ; Output: x+y, 5-word number, in a4:a3:a2:a1:a0. add a0, a0, a4 sltu a4, a0, a4 ; a4 = carry bit add a1, a1, a4 sltu a4, a1, a4 ; a4 = carry bit again add a2, a2, a4 sltu a4, a2, a4 add a3, a3, a4 sltu a4, a3, a4

Ah, nice, thank you! I must have missed sltu.

Re: RISC-V formal spec public review

#19
post #5

Earlier quoted context omitted.

Conditional moves depend on state left over from the last instruction. But when you want to re-order your instructions to keep all your functional units busy, keeping the conditional moves right makes a big mess. They're fine as micro-ops after you've scheduled them all, but are lousy at the ISA level. Intel and AMD make it work by throwing another 10,000 or 100,000 transistors at it. It is better to let macro-op fus…

> Cmov is one of the methods to mitigate Spectre because Intel refuses to speculate loads in them. Sure, this is what makes it good for mispredictable branches - data decompression for instance. If you can't speculate ahead, it's a waste of space in the branch prediction buffer to do it. But I definitely wish it was a builtin function instead of the compiler generating it, because none of them can guess when to use i…

They can't guess, which is why they all offer `__builtin_expect` to control them (which people often wrap in LIKELY/UNLIKELY macros).

Re: RISC-V formal spec public review

#20
post #5
post #4

Earlier quoted context omitted.

What's wrong with conditional moves? They're good for mispredictable branches, although I liked them better on PPC which had 8 condition/flags registers instead of just 1.

Conditional moves depend on state left over from the last instruction. But when you want to re-order your instructions to keep all your functional units busy, keeping the conditional moves right makes a big mess. They're fine as micro-ops after you've scheduled them all, but are lousy at the ISA level. Intel and AMD make it work by throwing another 10,000 or 100,000 transistors at it. It is better to let macro-op fus…

Isn't cmov just a normal instruction with 3 source operands?

Or do you mean that the problem is having 3 instead of 2 source operands?

Or that one of the operands is the flag register on x86-like architecture? (but you can just use a normal register being nonzero)

Post reply on HN