Only use intrinsics when the compiler supports them. https://github.com/cisco/ChezScheme/issues/845 https://github.com/cisco/ChezScheme/commit/f1ad314a3809074c6f2b986a5db6a84ad88700c1 --- c/atomic.h.orig 2024-02-05 16:52:07.000000000 -0600 +++ c/atomic.h 2024-06-27 00:56:20.000000000 -0500 @@ -114,7 +114,7 @@ } # define CAS_LOAD_ACQUIRE(a, old, new) S_cas_any_fence(1, a, old, new) # define CAS_STORE_RELEASE(a, old, new) S_cas_any_fence(0, a, old, new) -#elif (__GNUC__ >= 5) || defined(__clang__) +#elif (__GNUC__ >= 5) || C_COMPILER_HAS_BUILTIN(__sync_bool_compare_and_swap) # define CAS_ANY_FENCE(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 --- c/pb.h.orig +++ 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. */ --- c/version.h.orig +++ 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 */