diff --git a/c/atomic.h b/c/atomic.h index 9ceb2c153..2660d7484 100644 --- a/c/atomic.h +++ b/c/atomic.h @@ -52,7 +52,7 @@ # define STORE_FENCE() __asm__ __volatile__ ("dbar 0" : : : "memory") # define ACQUIRE_FENCE() STORE_FENCE() # define RELEASE_FENCE() STORE_FENCE() -#elif (__GNUC__ >= 5) || defined(__clang__) +#elif (__GNUC__ >= 5) || C_COMPILER_HAS_BUILTIN(__sync_synchronize) # define STORE_FENCE() __sync_synchronize() # define ACQUIRE_FENCE() STORE_FENCE() # define RELEASE_FENCE() STORE_FENCE() @@ -112,7 +112,7 @@ FORCEINLINE int COMPARE_AND_SWAP_PTR(volatile void *addr, void *old_val, void *n : "cc", "memory", "r12", "r7"); return ret; } -#elif (__GNUC__ >= 5) || defined(__clang__) +#elif (__GNUC__ >= 5) || C_COMPILER_HAS_BUILTIN(__sync_bool_compare_and_swap) # define COMPARE_AND_SWAP_PTR(a, old, new) __sync_bool_compare_and_swap((ptr *)(a), TO_PTR(old), TO_PTR(new)) #elif defined(__i386__) || defined(__x86_64__) # if ptr_bits == 64 diff --git a/c/pb.h b/c/pb.h index ddbaea03a..eb6806f86 100644 --- a/c/pb.h +++ b/c/pb.h @@ -71,12 +71,25 @@ enum { #define SIGN_FLIP(r, a, b) ((~((a ^ b) | (r ^ ~b))) >> (ptr_bits-1)) -#if (__GNUC__ >= 5) || defined(__clang__) +#if C_COMPILER_HAS_BUILTIN(__builtin_add_overflow) \ + && C_COMPILER_HAS_BUILTIN(__builtin_sub_overflow) \ + && C_COMPILER_HAS_BUILTIN(__builtin_mul_overflow) +# define USE_OVERFLOW_INTRINSICS 1 +#elif (__GNUC__ >= 5) # define USE_OVERFLOW_INTRINSICS 1 #else # define USE_OVERFLOW_INTRINSICS 0 #endif +#if C_COMPILER_HAS_BUILTIN(__builtin_bswap16) \ + && C_COMPILER_HAS_BUILTIN(__builtin_bswap32) +# define USE_BSWAP_INTRINSICS 1 +#elif (__GNUC__ >= 5) +# define USE_BSWAP_INTRINSICS 1 +#else +# define USE_BSWAP_INTRINSICS 0 +#endif + /* Use `machine_state * RESTRICT_PTR`, because machine registers won't be modified in any way other than through the machine-state pointer */ @@ -714,7 +727,7 @@ enum { #if ptr_bits == 64 #define doi_pb_rev_op_pb_int16_pb_register(instr) \ do_pb_rev_op_pb_int16_pb_register(INSTR_dr_dest(instr), INSTR_dr_reg(instr)) -# if USE_OVERFLOW_INTRINSICS +# if USE_BSWAP_INTRINSICS /* See note below on unsigned swap. */ # define do_pb_rev_op_pb_int16_pb_register(dest, reg) \ regs[dest] = ((uptr)(((iptr)((uptr)__builtin_bswap16(regs[reg]) << 48)) >> 48)) @@ -740,7 +753,7 @@ enum { #if ptr_bits == 64 # define doi_pb_rev_op_pb_int32_pb_register(instr) \ do_pb_rev_op_pb_int32_pb_register(INSTR_dr_dest(instr), INSTR_dr_reg(instr)) -# if USE_OVERFLOW_INTRINSICS +# if USE_BSWAP_INTRINSICS /* x86_64 GCC before 12.2 incorrectly compiles the code below to an unsigned swap. Defeat that by using the unsigned-swap intrinsic (which is good, anyway), then shift up and back. */ diff --git a/c/version.h b/c/version.h index bb8be394c..95f297b87 100644 --- a/c/version.h +++ b/c/version.h @@ -33,6 +33,14 @@ #define FORCEINLINE static inline #endif +/* GCC 10 and later and all versions of Clang provide `__has_builtin` for + checking for builtins. */ +#ifdef __has_builtin +# define C_COMPILER_HAS_BUILTIN(x) __has_builtin(x) +#else +# define C_COMPILER_HAS_BUILTIN(x) 0 +#endif + /*****************************************/ /* Architectures */