5 ms·
> I noted the other day that zig has @addWithOverflow which is a step in the right direction. This seems reasonably easy to implement in C: #include <stdi
by haberman 6y ago
> I noted the other day that zig has @addWithOverflow which is a step in the right direction.
This seems reasonably easy to implement in C:
#include <stdint.h>
typedef struct {
uint64_t val;
uint64_t carry;
} Result;
Result addWithOverflow(uint64_t x, uint64_t y) {
Result res = {x + y, x + y < x};
return res;
}
On GCC and Clang this does the right thing (grabs the carry flag): https://godbolt.org/z/dzP3TPGTW https://godbolt.org/z/dzP3TPGTW
I agree a dedicated intrinsic like in Zig is even better, but it is nice that modern compilers make it reasonably straightforward to get the desired code even without dedicated intrinsics.
- nickcw 6y ago@addWithOverflow is easy to implement in C, but you still need to look at the assembler code to see if the compiler did the right thing. I don't like that tension between C code you've arranged in just the right way and hoping that it continues to generate the assembler output it did once. I guess a portable set of compiler intrinsics it what is really needed to solve this problem. There is an x86 intrinsic for 32 x 32 -> 64 bit multiply now-a-days https://docs.microsoft.com/en-us/cpp/intrinsics/emul-emulu?view=msvc-160 https://docs.microsoft.com/en-us/cpp/intrinsics/emul-emulu?v... And one for 32 + 32 -> 32 + carry also. Though I don't know how portable __emulu is.. does it work on ARM for instance?
- bombcar 6y agoToo bad you can’t put some sort of assert saying “this code should generate this assembly assuming x86-64” or something - at least get a warning if the compiler upgrade changes it.
- Karliss 6y agoIf the performance is important you can have performance regression tests. If not, then it probably doesn't matter too much if it always generates optimal assembly for this specific line of code.
- globular-toast 6y agoWhat about "addWithCarry", ie. ADC? Getting the carry bit seems only half the battle. I'd not seen this compiler tool before so had a quick play around with it. It's very cool! But I couldn't get a compiler to recognise it could use ADC.
- haberman 6y agoThis seems to work. The compiler has to see the previous add to know what is in the carry flag. #include <stdint.h> uint64_t addWithCarry(uint64_t x, uint64_t y, uint64_t z) { return x + y + (y + z < y); } Output here: https://godbolt.org/z/zfP7PnGcs https://godbolt.org/z/zfP7PnGcs