← Back to context

Comment by adgjlsfhk1

2 months ago

dammmit I meant <=2. https://godbolt.org/z/4WxeW58Pc sltu or snez for add/multiply respectively.

This result is misleading.

First, the code claims to be returning "unsigned long" from each of these functions, but the value will only ever be 0 or 1 (see [1]). The code is actually throwing away the result and just returning whether overflow occurred. If we take unsigned long *c as another argument to the function, so that we actually keep the result, we end up having to issue an extra instruction for multiplication (see [2]; I'm ignoring the sd instruction since it is simply there to dereference the *c pointer and wouldn't exist if the function got inlined).

Second, this is just unsigned overflow detection. If we do signed overflow detection, now we're up to 5 instructions for add and mul (see [3]). Considering that this is the bigger challenge, it compares quite unfavorably to architectures where this is just 2 instructions: the operation itself and a branch against a condition flag.

[1]: https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins...

[2]: https://godbolt.org/z/7rWWv57nx

[3]: https://godbolt.org/z/PnzKaz4x5

  • That's fair. The good news is that for signed overflow, you can claw back to the cost of unsigned overflow if you know the sign of either argument (which is fairly common).

    • Yeah, it's not the end of the world, and as others mentioned, a good implementation can recognize the instruction pattern and optimize for it.

      It's just a bizarre design choice. I understand wanting to get rid of condition flags, but not replacing them with nothing at all.

      EDIT: It seems the same choice was made by MIPS, which is a clear inspiration for RISC-V.

      2 replies →