rcx

miscellaneous C library
git clone git://git.rr3.xyz/rcx
Log | Files | Refs | README | LICENSE

commit 403d9be45e3ad1bf18f116b767d7404461b2d811
parent 8458a01b297853e80ec071bae61cc34efebf57a4
Author: Robert Russell <robert@rr3.xyz>
Date:   Sun, 12 Jan 2025 01:12:58 -0800

Add add/sub with carry/borrow

Diffstat:
Minc/bits.h | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 94 insertions(+), 0 deletions(-)

diff --git a/inc/bits.h b/inc/bits.h @@ -205,6 +205,100 @@ r_rzb64(u64 n) { } +/* ----- Add/subtract with carry/borrow ----- */ + +/* TODO: Use addc/subc intrinsics for non-64 bit adds/subs as well? */ +#if __GNUC__ >= 14 + #define HAVE_ADDC_SUBC 1 + /* TODO: I think this is technically not a portable way to figure out which + * integer type to use, but it should be ok. */ + #if UINT_BITS >= 64 + #define ADDC __builtin_addc + #define SUBC __builtin_subc + #elif ULONG_BITS >= 64 + #define ADDC __builtin_addcl + #define SUBC __builtin_subcl + #else /* ULLONG_BITS >= 64 always */ + #define ADDC __builtin_addcll + #define SUBC __builtin_subcll + #endif +#endif + +static inline void +r_add8(u8 *co, u8 *z, u8 x, u8 y, u8 ci) { + u16 s = (u16)x + (u16)y + (u16)ci; + *z = s; + *co = s >> 8; +} + +static inline void +r_add16(u16 *co, u16 *z, u16 x, u16 y, u16 ci) { + u32 s = (u32)x + (u32)y + (u32)ci; + *z = s; + *co = s >> 16; +} + +static inline void +r_add32(u32 *co, u32 *z, u32 x, u32 y, u32 ci) { + u64 s = (u64)x + (u64)y + (u64)ci; + *z = s; + *co = s >> 32; +} + +static inline void +r_add64(u64 *co, u64 *z, u64 x, u64 y, u64 ci) { +#ifdef HAVE_ADDC_SUBC + *z = ADDC(x, y, ci, co); +#else + u64 s = x + y; + u64 co0 = s < x; + u64 t = s + ci; + u64 co1 = t < s; + *z = t; + *co = co0 | co1; +#endif +} + +static inline void +r_sub8(u8 *bo, u8 *z, u8 x, u8 y, u8 bi) { + u16 d = (u16)x - (u16)y - (u16)bi; + *z = d; + *bo = -(d >> 8); +} + +static inline void +r_sub16(u16 *bo, u16 *z, u16 x, u16 y, u16 bi) { + u32 d = (u32)x + (u32)y + (u32)bi; + *z = d; + *bo = -(d >> 16); +} + +static inline void +r_sub32(u32 *bo, u32 *z, u32 x, u32 y, u32 bi) { + u64 d = (u64)x + (u64)y + (u64)bi; + *z = d; + *bo = -(d >> 32); +} + +static inline void +r_sub64(u64 *bo, u64 *z, u64 x, u64 y, u64 bi) { +#ifdef HAVE_ADDC_SUBC + *z = SUBC(x, y, bi, bo); +#else + u64 s = x - y; + u64 bo0 = s > x; + u64 t = s - bi; + u64 bo1 = t > s; + *z = t; + *bo = bo0 | bo1; +#endif +} + +#undef GNU_SUBC +#undef GNU_ADDC +#undef HAVE_ADDC_SUBC + + /* ----- Full width multiply ----- */ static inline void