/****************************************************************************/ #if( defined __GNUC__ ) // TRD : makes checking GCC versions much tidier #define LFDS710_PAL_GCC_VERSION ( __GNUC__ * 100 + __GNUC_MINOR__ * 10 + __GNUC_PATCHLEVEL__ ) #endif /****************************************************************************/ #if( defined _MSC_VER && _MSC_VER >= 1400 ) #ifdef LFDS710_PAL_COMPILER #error More than one porting abstraction layer matches the current platform in lfds710_porting_abstraction_layer_compiler.h #endif #define LFDS710_PAL_COMPILER #define LFDS710_PAL_COMPILER_STRING "MSVC" #define LFDS710_PAL_ALIGN(alignment) __declspec( align(alignment) ) #define LFDS710_PAL_INLINE __forceinline #define LFDS710_PAL_BARRIER_COMPILER_LOAD _ReadBarrier() #define LFDS710_PAL_BARRIER_COMPILER_STORE _WriteBarrier() #define LFDS710_PAL_BARRIER_COMPILER_FULL _ReadWriteBarrier() /* TRD : there are four processors to consider; . ARM32 (32 bit, ADD, CAS, DWCAS, EXCHANGE, SET) (defined _M_ARM) . Itanium (64 bit, ADD, CAS, EXCHANGE, SET) (defined _M_IA64) . x64 (64 bit, ADD, CAS, DWCAS, EXCHANGE, SET) (defined _M_X64 || defined _M_AMD64) . x86 (32 bit, ADD, CAS, DWCAS, EXCHANGE, SET) (defined _M_IX86) can't find any indications of 64-bit ARM support yet ARM has better intrinsics than the others, as there are no-fence variants in theory we also have to deal with 32-bit Windows on a 64-bit platform, and I presume we'd see the compiler properly indicate this in its macros, but this would require that we use 32-bit atomics on the 64-bit platforms, while keeping 64-bit cache line lengths and so on, and this is just so wierd a thing to do these days that it's not supported */ #if( defined _M_ARM ) #define LFDS710_PAL_BARRIER_PROCESSOR_LOAD __dmb( _ARM_BARRIER_ISH ) #define LFDS710_PAL_BARRIER_PROCESSOR_STORE __dmb( _ARM_BARRIER_ISHST ) #define LFDS710_PAL_BARRIER_PROCESSOR_FULL __dmb( _ARM_BARRIER_ISH ) #define LFDS710_PAL_ATOMIC_ADD( pointer_to_target, value, result, result_type ) \ { \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ (result) = (result_type) _InterlockedAdd_nf( (int long volatile *) (pointer_to_target), (int long) (value) ); \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ } #define LFDS710_PAL_ATOMIC_CAS( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, result ) \ { \ lfds710_pal_uint_t \ original_compare; \ \ original_compare = (lfds710_pal_uint_t) *(pointer_to_compare); \ \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ *(lfds710_pal_uint_t *) (pointer_to_compare) = (lfds710_pal_uint_t) _InterlockedCompareExchange_nf( (long volatile *) (pointer_to_destination), (long) (new_destination), (long) *(pointer_to_compare) ); \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ \ result = (char unsigned) ( original_compare == (lfds710_pal_uint_t) *(pointer_to_compare) ); \ } #define LFDS710_PAL_ATOMIC_DWCAS( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result ) \ { \ __int64 \ original_compare; \ \ original_compare = *(__int64 *) (pointer_to_compare); \ \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ *(__int64 *) (pointer_to_compare) = _InterlockedCompareExchange64_nf( (__int64 volatile *) (pointer_to_destination), *(__int64 *) (pointer_to_new_destination), *(__int64 *) (pointer_to_compare) ); \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ \ (result) = (char unsigned) ( *(__int64 *) (pointer_to_compare) == original_compare ); \ } #define LFDS710_PAL_ATOMIC_EXCHANGE( pointer_to_destination, exchange, exchange_type ) \ { \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ (exchange) = (exchange_type) _InterlockedExchange_nf( (int long volatile *) (pointer_to_destination), (int long) (exchange) ); \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ } #define LFDS710_PAL_ATOMIC_SET( pointer_to_destination, new_value ) \ { \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ (void) _InterlockedExchange_nf( (int long volatile *) (pointer_to_destination), (int long) (new_value) ); \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ } #endif #if( defined _M_IA64 ) #define LFDS710_PAL_BARRIER_PROCESSOR_LOAD __mf() #define LFDS710_PAL_BARRIER_PROCESSOR_STORE __mf() #define LFDS710_PAL_BARRIER_PROCESSOR_FULL __mf() #define LFDS710_PAL_ATOMIC_ADD( pointer_to_target, value, result, result_type ) \ { \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ (result) = (result_type) _InterlockedAdd64_acq( (__int64 volatile *) (pointer_to_target), (__int64) (value) ); \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ } #define LFDS710_PAL_ATOMIC_CAS( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, result ) \ { \ lfds710_pal_uint_t \ original_compare; \ \ original_compare = (lfds710_pal_uint_t) *(pointer_to_compare); \ \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ *(lfds710_pal_uint_t *) (pointer_to_compare) = (lfds710_pal_uint_t) _InterlockedCompareExchange64_acq( (__int64 volatile *) (pointer_to_destination), (__int64) (new_destination), (__int64) *(pointer_to_compare) ); \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ \ result = (char unsigned) ( original_compare == (lfds710_pal_uint_t) *(pointer_to_compare) ); \ } #define LFDS710_PAL_ATOMIC_EXCHANGE( pointer_to_destination, exchange, exchange_type ) \ { \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ (exchange) = (exchange_type) _InterlockedExchange64_acq( (__int64 volatile *) (pointer_to_destination), (__int64) (exchange) ); \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ } #define LFDS710_PAL_ATOMIC_SET( pointer_to_destination, new_value ) \ { \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ (void) _InterlockedExchange64_acq( (__int64 volatile *) (pointer_to_destination), (__int64) (new_value) ); \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ } #endif #if( defined _M_X64 || defined _M_AMD64 ) #define LFDS710_PAL_BARRIER_PROCESSOR_LOAD _mm_lfence() #define LFDS710_PAL_BARRIER_PROCESSOR_STORE _mm_sfence() #define LFDS710_PAL_BARRIER_PROCESSOR_FULL _mm_mfence() // TRD : no _InterlockedAdd64 for x64 - only the badly named _InterlockedExchangeAdd64, which is the same as _InterlockedAdd64 but returns the *original* value (which we must then add to before we return) #define LFDS710_PAL_ATOMIC_ADD( pointer_to_target, value, result, result_type ) \ { \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ (result) = (result_type) _InterlockedExchangeAdd64( (__int64 volatile *) (pointer_to_target), (__int64) (value) ); \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ result += value; \ } #define LFDS710_PAL_ATOMIC_CAS( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, result ) \ { \ lfds710_pal_uint_t \ original_compare; \ \ original_compare = (lfds710_pal_uint_t) *(pointer_to_compare); \ \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ *(lfds710_pal_uint_t *) (pointer_to_compare) = (lfds710_pal_uint_t) _InterlockedCompareExchange64( (__int64 volatile *) (pointer_to_destination), (__int64) (new_destination), (__int64) *(pointer_to_compare) ); \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ \ result = (char unsigned) ( original_compare == (lfds710_pal_uint_t) *(pointer_to_compare) ); \ } #if( _MSC_VER >= 1500 ) #define LFDS710_PAL_ATOMIC_DWCAS( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result ) \ { \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ (result) = (char unsigned) _InterlockedCompareExchange128( (__int64 volatile *) (pointer_to_destination), (__int64) (pointer_to_new_destination[1]), (__int64) (pointer_to_new_destination[0]), (__int64 *) (pointer_to_compare) ); \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ } #endif #define LFDS710_PAL_ATOMIC_EXCHANGE( pointer_to_destination, exchange, exchange_type ) \ { \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ (exchange) = (exchange_type) _InterlockedExchange64( (__int64 volatile *) (pointer_to_destination), (__int64) (exchange) ); \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ } #define LFDS710_PAL_ATOMIC_SET( pointer_to_destination, new_value ) \ { \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ (void) _InterlockedExchange64( (__int64 volatile *) (pointer_to_destination), (__int64) (new_value) ); \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ } #endif #if( defined _M_IX86 ) #define LFDS710_PAL_BARRIER_PROCESSOR_LOAD lfds710_misc_force_store() #define LFDS710_PAL_BARRIER_PROCESSOR_STORE lfds710_misc_force_store() #define LFDS710_PAL_BARRIER_PROCESSOR_FULL lfds710_misc_force_store() // TRD : no _InterlockedAdd for x86 - only the badly named _InterlockedExchangeAdd, which is the same as _InterlockedAdd but returns the *original* value (which we must then add to before we return) #define LFDS710_PAL_ATOMIC_ADD( pointer_to_target, value, result, result_type ) \ { \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ (result) = (result_type) _InterlockedExchangeAdd( (__int64 volatile *) (pointer_to_target), (__int64) (value) ); \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ result += value; \ } #define LFDS710_PAL_ATOMIC_CAS( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, result ) \ { \ lfds710_pal_uint_t \ original_compare; \ \ /* LFDS710_PAL_ASSERT( (pointer_to_destination) != NULL ); */ \ /* LFDS710_PAL_ASSERT( (pointer_to_compare) != NULL ); */ \ /* TRD : new_destination can be any value in its range */ \ /* TRD : cas_strength can be any value in its range */ \ /* TRD : result can be any value in its range */ \ \ original_compare = (lfds710_pal_uint_t) *(pointer_to_compare); \ \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ *(lfds710_pal_uint_t *) (pointer_to_compare) = (lfds710_pal_uint_t) _InterlockedCompareExchange( (long volatile *) (pointer_to_destination), (long) (new_destination), (long) *(pointer_to_compare) ); \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ \ result = (char unsigned) ( original_compare == (lfds710_pal_uint_t) *(pointer_to_compare) ); \ } #define LFDS710_PAL_ATOMIC_DWCAS( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result ) \ { \ __int64 \ original_compare; \ \ original_compare = *(__int64 *) (pointer_to_compare); \ \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ *(__int64 *) (pointer_to_compare) = _InterlockedCompareExchange64( (__int64 volatile *) (pointer_to_destination), *(__int64 *) (pointer_to_new_destination), *(__int64 *) (pointer_to_compare) ); \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ \ (result) = (char unsigned) ( *(__int64 *) (pointer_to_compare) == original_compare ); \ } #define LFDS710_PAL_ATOMIC_EXCHANGE( pointer_to_destination, exchange, exchange_type ) \ { \ /* LFDS710_PAL_ASSERT( (pointer_to_destination) != NULL ); */ \ /* LFDS710_PAL_ASSERT( (pointer_to_exchange) != NULL ); */ \ \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ (exchange) = (exchange_type) _InterlockedExchange( (int long volatile *) (pointer_to_destination), (int long) (exchange) ); \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ } #define LFDS710_PAL_ATOMIC_SET( pointer_to_destination, new_value ) \ { \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ (void) _InterlockedExchange( (int long volatile *) (pointer_to_destination), (int long) (new_value) ); \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ } #endif #endif /****************************************************************************/ #if( defined __GNUC__ && LFDS710_PAL_GCC_VERSION >= 412 && LFDS710_PAL_GCC_VERSION < 473 ) #ifdef LFDS710_PAL_COMPILER #error More than one porting abstraction layer matches the current platform in lfds710_porting_abstraction_layer_compiler.h #endif #define LFDS710_PAL_COMPILER #define LFDS710_PAL_COMPILER_STRING "GCC < 4.7.3" #define LFDS710_PAL_ALIGN(alignment) __attribute__( (aligned(alignment)) ) #define LFDS710_PAL_INLINE inline static LFDS710_PAL_INLINE void lfds710_pal_barrier_compiler( void ) { __asm__ __volatile__ ( "" : : : "memory" ); } #define LFDS710_PAL_BARRIER_COMPILER_LOAD lfds710_pal_barrier_compiler() #define LFDS710_PAL_BARRIER_COMPILER_STORE lfds710_pal_barrier_compiler() #define LFDS710_PAL_BARRIER_COMPILER_FULL lfds710_pal_barrier_compiler() #define LFDS710_PAL_BARRIER_PROCESSOR_LOAD __sync_synchronize() #define LFDS710_PAL_BARRIER_PROCESSOR_STORE __sync_synchronize() #define LFDS710_PAL_BARRIER_PROCESSOR_FULL __sync_synchronize() #define LFDS710_PAL_ATOMIC_ADD( pointer_to_target, value, result, result_type ) \ { \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ (result) = (result_type) __sync_add_and_fetch( (lfds710_pal_uint_t *) (pointer_to_target), (lfds710_pal_uint_t) (value) ); \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ } #define LFDS710_PAL_ATOMIC_CAS( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, result ) \ { \ lfds710_pal_uint_t \ original_compare; \ \ original_compare = (lfds710_pal_uint_t) *(pointer_to_compare); \ \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ *(pointer_to_compare) = __sync_val_compare_and_swap( pointer_to_destination, *(pointer_to_compare), new_destination ); \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ \ result = (unsigned char) ( original_compare == (lfds710_pal_uint_t) *(pointer_to_compare) ); \ } // TRD : ARM and x86 have DWCAS which we can get via GCC intrinsics #if( defined __arm__ || defined __i686__ || defined __i586__ || defined __i486__ ) #define LFDS710_PAL_ATOMIC_DWCAS( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result ) \ { \ int long long unsigned \ original_destination; \ \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ original_destination = __sync_val_compare_and_swap( (int long long unsigned volatile *) (pointer_to_destination), *(int long long unsigned *) (pointer_to_compare), *(int long long unsigned *) (pointer_to_new_destination) ); \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ \ (result) = (char unsigned) ( original_destination == *(int long long unsigned *) (pointer_to_compare) ); \ \ *(int long long unsigned *) (pointer_to_compare) = original_destination; \ } #endif #define LFDS710_PAL_ATOMIC_EXCHANGE( pointer_to_destination, exchange, exchange_type ) \ { \ /* LFDS710_PAL_ASSERT( (pointer_to_destination) != NULL ); */ \ /* TRD : exchange can be any value in its range */ \ /* TRD : exchange_type can be any value in its range */ \ \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ (exchange) = (exchange_type) __sync_lock_test_and_set( pointer_to_destination, (exchange) ); \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ } #define LFDS710_PAL_ATOMIC_SET( pointer_to_destination, new_value ) \ { \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ (void) __sync_lock_test_and_set( pointer_to_destination, (new_value) ); \ LFDS710_PAL_BARRIER_COMPILER_FULL; \ } #endif /****************************************************************************/ #if( defined __GNUC__ && LFDS710_PAL_GCC_VERSION >= 473 ) #ifdef LFDS710_PAL_COMPILER #error More than one porting abstraction layer matches the current platform in lfds710_porting_abstraction_layer_compiler.h #endif #define LFDS710_PAL_COMPILER #define LFDS710_PAL_COMPILER_STRING "GCC >= 4.7.3" #define LFDS710_PAL_ALIGN(alignment) __attribute__( (aligned(alignment)) ) #define LFDS710_PAL_INLINE inline // TRD : GCC >= 4.7.3 compiler barriers are built into the intrinsics #define LFDS710_PAL_COMPILER_BARRIERS_MISSING_PRESUMED_HAVING_A_GOOD_TIME #define LFDS710_PAL_BARRIER_PROCESSOR_LOAD __atomic_thread_fence( __ATOMIC_ACQUIRE ) #define LFDS710_PAL_BARRIER_PROCESSOR_STORE __atomic_thread_fence( __ATOMIC_RELEASE ) #define LFDS710_PAL_BARRIER_PROCESSOR_FULL __atomic_thread_fence( __ATOMIC_ACQ_REL ) #define LFDS710_PAL_ATOMIC_ADD( pointer_to_target, value, result, result_type ) \ { \ (result) = (result_type) __atomic_add_fetch( (pointer_to_target), (value), __ATOMIC_RELAXED ); \ } #define LFDS710_PAL_ATOMIC_CAS( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, result ) \ { \ result = (char unsigned) __atomic_compare_exchange_n( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, __ATOMIC_RELAXED, __ATOMIC_RELAXED ); \ } // TRD : ARM and x86 have DWCAS which we can get via GCC intrinsics #if( defined __arm__ || defined __i686__ || defined __i586__ || defined __i486__ ) #define LFDS710_PAL_ATOMIC_DWCAS( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result ) \ { \ (result) = (char unsigned) __atomic_compare_exchange_n( (int long long unsigned volatile *) (pointer_to_destination), (int long long unsigned *) (pointer_to_compare), *(int long long unsigned *) (pointer_to_new_destination), (cas_strength), __ATOMIC_RELAXED, __ATOMIC_RELAXED ); \ } #endif #if( defined __x86_64__ ) /* TRD : On 64 bit platforms, unsigned long long int is 64 bit, so we must manually use cmpxchg16b, as __sync_val_compare_and_swap() will only emit cmpxchg8b */ // TRD : lfds710_pal_uint_t volatile (*destination)[2], lfds710_pal_uint_t (*compare)[2], lfds710_pal_uint_t (*new_destination)[2], enum lfds710_misc_cas_strength cas_strength, char unsigned result #define LFDS710_PAL_ATOMIC_DWCAS( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result ) \ { \ (result) = 0; \ \ __asm__ __volatile__ \ ( \ "lock;" /* make cmpxchg16b atomic */ \ "cmpxchg16b %0;" /* cmpxchg16b sets ZF on success */ \ "setz %4;" /* if ZF set, set result to 1 */ \ \ /* output */ \ : "+m" ((pointer_to_destination)[0]), "+m" ((pointer_to_destination)[1]), "+a" ((pointer_to_compare)[0]), "+d" ((pointer_to_compare)[1]), "=q" (result) \ \ /* input */ \ : "b" ((pointer_to_new_destination)[0]), "c" ((pointer_to_new_destination)[1]) \ \ /* clobbered */ \ : \ ); \ } #endif #define LFDS710_PAL_ATOMIC_EXCHANGE( pointer_to_destination, exchange, exchange_type ) \ { \ (exchange) = (exchange_type) __atomic_exchange_n( (pointer_to_destination), (exchange), __ATOMIC_RELAXED ); \ } #define LFDS710_PAL_ATOMIC_SET( pointer_to_destination, new_value ) \ { \ (void) __atomic_exchange_n( (pointer_to_destination), (new_value), __ATOMIC_RELAXED ); \ } #endif /****************************************************************************/ #if( !defined LFDS710_PAL_COMPILER ) #error No matching porting abstraction layer in lfds710_porting_abstraction_layer_compiler.h #endif