I have the following function:
struct sbi_i128_t {
union {
unsigned long long r[2];
unsigned __int128 i;
};
};
/// Unsigned 128-bit integers addition with overflow indication.
static inline sbi_i128_t sbi_addo_i128(sbi_i128_t a, sbi_i128_t b, unsigned char *o) {
sbi_i128_t r;
*o = _addcarry_u64(0, a.r[0], b.r[0], &r.r[0]);
*o = _addcarry_u64(*o, a.r[1], b.r[1], &r.r[1]);
return r;
}
To modify it for signed integers I need to return overflow flag (OF) instead of carry one (CF) from the last call. What is best way you may suggest, taking into account that the function must keep inlining, and inline assembly is avoided? Compiler - GCC v11+, but using other compilers is also an option.
-edit-:
With __builtin_add_overflow() the best implementation I see is:
/// Unsigned 128-bit integers addition with overflow indication.
static inline sbi_i128_t sbi_addo_i128(sbi_i128_t a, sbi_i128_t b, unsigned char *o) {
sbi_i128_t r;
*o = _addcarry_u64(0, a.r[0], b.r[0], &r.r[0]);
uint64_t ov = *o ? -1 : 0;
bool o1 = __builtin_add_overflow(a.r[1], b.r[1], &r.r[1]);
bool o2 = __builtin_sub_overflow(r.r[1], ov, &r.r[1]);
*o = o1 | o2;
return r;
}
-edit-: But with __int128 directly (thx Peter Cordes):
__int128 foo(__int128 a, __int128 b, unsigned char *signed_OF){
__int128 retval;
*signed_OF = __builtin_add_overflow(a,b, &retval);
return retval;
}