Do there exist intrinsics for ARM C compilers to do add-with-carry operations, or is it necessary to use assembly language?
On x86, there is _addcarry_u64
for add-with-carry. (There's also the newer _addcarryx_u64
for special purposes.)
From old documentation (as old as gcc 5 !!!!)
https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html https://gcc.gnu.org/onlinedocs/gcc-5.3.0/gcc/Integer-Overflow-Builtins.html
Both clang and GCC do implement these builtins, and I verified the generated code is optimal on both x86_64 and aarch64 targets
#include <stdint.h>
typedef unsigned __int128 uint128_t;
// carry_out = a + b + carry_in
uint8_t my_addcarry_u64(uint8_t carry_in, uint64_t a, uint64_t b, uint64_t * sum)
{
bool c;
uint64_t res;
c = __builtin_uaddll_overflow (a, b, (long long unsigned *)&res);
c |= __builtin_uaddll_overflow (res, carry_in, (long long unsigned *)&res);
*sum = res;
return c;
}
// carry_out = a + b + carry_in
uint8_t my_addcarry_u128(uint8_t carry_in, uint128_t a, uint128_t b, uint128_t * sum)
{
bool c;
uint64_t res_lo, res_hi;
c = __builtin_uaddll_overflow (a, b, (long long unsigned *)&res_lo);
c |= __builtin_uaddll_overflow (carry_in, res_lo, (long long unsigned *)&res_lo);
c = __builtin_uaddll_overflow (a >> 64, c, (long long unsigned *)&res_hi);
c |= __builtin_uaddll_overflow (b >> 64, res_hi, (long long unsigned *)&res_hi);
*sum = ((uint128_t)res_hi << 64) + res_lo;
return c;
}
Even if the original post is old, I provide a solution to the original question, in case someone reads this thread again