1 /****************************************************************************/
2 #if( defined __GNUC__ )
3 // TRD : makes checking GCC versions much tidier
4 #define LFDS710_PAL_GCC_VERSION ( __GNUC__ * 100 + __GNUC_MINOR__ * 10 + __GNUC_PATCHLEVEL__ )
11 /****************************************************************************/
12 #if( defined _MSC_VER && _MSC_VER >= 1400 )
14 #ifdef LFDS710_PAL_COMPILER
15 #error More than one porting abstraction layer matches the current platform in lfds710_porting_abstraction_layer_compiler.h
18 #define LFDS710_PAL_COMPILER
20 #define LFDS710_PAL_COMPILER_STRING "MSVC"
22 #define LFDS710_PAL_ALIGN(alignment) __declspec( align(alignment) )
23 #define LFDS710_PAL_INLINE __forceinline
25 #define LFDS710_PAL_BARRIER_COMPILER_LOAD _ReadBarrier()
26 #define LFDS710_PAL_BARRIER_COMPILER_STORE _WriteBarrier()
27 #define LFDS710_PAL_BARRIER_COMPILER_FULL _ReadWriteBarrier()
29 /* TRD : there are four processors to consider;
31 . ARM32 (32 bit, ADD, CAS, DWCAS, EXCHANGE, SET) (defined _M_ARM)
32 . Itanium (64 bit, ADD, CAS, EXCHANGE, SET) (defined _M_IA64)
33 . x64 (64 bit, ADD, CAS, DWCAS, EXCHANGE, SET) (defined _M_X64 || defined _M_AMD64)
34 . x86 (32 bit, ADD, CAS, DWCAS, EXCHANGE, SET) (defined _M_IX86)
36 can't find any indications of 64-bit ARM support yet
38 ARM has better intrinsics than the others, as there are no-fence variants
40 in theory we also have to deal with 32-bit Windows on a 64-bit platform,
41 and I presume we'd see the compiler properly indicate this in its macros,
42 but this would require that we use 32-bit atomics on the 64-bit platforms,
43 while keeping 64-bit cache line lengths and so on, and this is just so
44 wierd a thing to do these days that it's not supported
48 #define LFDS710_PAL_BARRIER_PROCESSOR_LOAD __dmb( _ARM_BARRIER_ISH )
49 #define LFDS710_PAL_BARRIER_PROCESSOR_STORE __dmb( _ARM_BARRIER_ISHST )
50 #define LFDS710_PAL_BARRIER_PROCESSOR_FULL __dmb( _ARM_BARRIER_ISH )
52 #define LFDS710_PAL_ATOMIC_ADD( pointer_to_target, value, result, result_type ) \
54 LFDS710_PAL_BARRIER_COMPILER_FULL; \
55 (result) = (result_type) _InterlockedAdd_nf( (int long volatile *) (pointer_to_target), (int long) (value) ); \
56 LFDS710_PAL_BARRIER_COMPILER_FULL; \
59 #define LFDS710_PAL_ATOMIC_CAS( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, result ) \
64 original_compare = (lfds710_pal_uint_t) *(pointer_to_compare); \
66 LFDS710_PAL_BARRIER_COMPILER_FULL; \
67 *(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) ); \
68 LFDS710_PAL_BARRIER_COMPILER_FULL; \
70 result = (char unsigned) ( original_compare == (lfds710_pal_uint_t) *(pointer_to_compare) ); \
73 #define LFDS710_PAL_ATOMIC_DWCAS( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result ) \
78 original_compare = *(__int64 *) (pointer_to_compare); \
80 LFDS710_PAL_BARRIER_COMPILER_FULL; \
81 *(__int64 *) (pointer_to_compare) = _InterlockedCompareExchange64_nf( (__int64 volatile *) (pointer_to_destination), *(__int64 *) (pointer_to_new_destination), *(__int64 *) (pointer_to_compare) ); \
82 LFDS710_PAL_BARRIER_COMPILER_FULL; \
84 (result) = (char unsigned) ( *(__int64 *) (pointer_to_compare) == original_compare ); \
87 #define LFDS710_PAL_ATOMIC_EXCHANGE( pointer_to_destination, exchange, exchange_type ) \
89 LFDS710_PAL_BARRIER_COMPILER_FULL; \
90 (exchange) = (exchange_type) _InterlockedExchange_nf( (int long volatile *) (pointer_to_destination), (int long) (exchange) ); \
91 LFDS710_PAL_BARRIER_COMPILER_FULL; \
94 #define LFDS710_PAL_ATOMIC_SET( pointer_to_destination, new_value ) \
96 LFDS710_PAL_BARRIER_COMPILER_FULL; \
97 (void) _InterlockedExchange_nf( (int long volatile *) (pointer_to_destination), (int long) (new_value) ); \
98 LFDS710_PAL_BARRIER_COMPILER_FULL; \
102 #if( defined _M_IA64 )
103 #define LFDS710_PAL_BARRIER_PROCESSOR_LOAD __mf()
104 #define LFDS710_PAL_BARRIER_PROCESSOR_STORE __mf()
105 #define LFDS710_PAL_BARRIER_PROCESSOR_FULL __mf()
107 #define LFDS710_PAL_ATOMIC_ADD( pointer_to_target, value, result, result_type ) \
109 LFDS710_PAL_BARRIER_COMPILER_FULL; \
110 (result) = (result_type) _InterlockedAdd64_acq( (__int64 volatile *) (pointer_to_target), (__int64) (value) ); \
111 LFDS710_PAL_BARRIER_COMPILER_FULL; \
114 #define LFDS710_PAL_ATOMIC_CAS( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, result ) \
119 original_compare = (lfds710_pal_uint_t) *(pointer_to_compare); \
121 LFDS710_PAL_BARRIER_COMPILER_FULL; \
122 *(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) ); \
123 LFDS710_PAL_BARRIER_COMPILER_FULL; \
125 result = (char unsigned) ( original_compare == (lfds710_pal_uint_t) *(pointer_to_compare) ); \
128 #define LFDS710_PAL_ATOMIC_EXCHANGE( pointer_to_destination, exchange, exchange_type ) \
130 LFDS710_PAL_BARRIER_COMPILER_FULL; \
131 (exchange) = (exchange_type) _InterlockedExchange64_acq( (__int64 volatile *) (pointer_to_destination), (__int64) (exchange) ); \
132 LFDS710_PAL_BARRIER_COMPILER_FULL; \
135 #define LFDS710_PAL_ATOMIC_SET( pointer_to_destination, new_value ) \
137 LFDS710_PAL_BARRIER_COMPILER_FULL; \
138 (void) _InterlockedExchange64_acq( (__int64 volatile *) (pointer_to_destination), (__int64) (new_value) ); \
139 LFDS710_PAL_BARRIER_COMPILER_FULL; \
143 #if( defined _M_X64 || defined _M_AMD64 )
144 #define LFDS710_PAL_BARRIER_PROCESSOR_LOAD _mm_lfence()
145 #define LFDS710_PAL_BARRIER_PROCESSOR_STORE _mm_sfence()
146 #define LFDS710_PAL_BARRIER_PROCESSOR_FULL _mm_mfence()
148 // 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)
149 #define LFDS710_PAL_ATOMIC_ADD( pointer_to_target, value, result, result_type ) \
151 LFDS710_PAL_BARRIER_COMPILER_FULL; \
152 (result) = (result_type) _InterlockedExchangeAdd64( (__int64 volatile *) (pointer_to_target), (__int64) (value) ); \
153 LFDS710_PAL_BARRIER_COMPILER_FULL; \
157 #define LFDS710_PAL_ATOMIC_CAS( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, result ) \
162 original_compare = (lfds710_pal_uint_t) *(pointer_to_compare); \
164 LFDS710_PAL_BARRIER_COMPILER_FULL; \
165 *(lfds710_pal_uint_t *) (pointer_to_compare) = (lfds710_pal_uint_t) _InterlockedCompareExchange64( (__int64 volatile *) (pointer_to_destination), (__int64) (new_destination), (__int64) *(pointer_to_compare) ); \
166 LFDS710_PAL_BARRIER_COMPILER_FULL; \
168 result = (char unsigned) ( original_compare == (lfds710_pal_uint_t) *(pointer_to_compare) ); \
171 #if( _MSC_VER >= 1500 )
172 #define LFDS710_PAL_ATOMIC_DWCAS( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result ) \
174 LFDS710_PAL_BARRIER_COMPILER_FULL; \
175 (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) ); \
176 LFDS710_PAL_BARRIER_COMPILER_FULL; \
180 #define LFDS710_PAL_ATOMIC_EXCHANGE( pointer_to_destination, exchange, exchange_type ) \
182 LFDS710_PAL_BARRIER_COMPILER_FULL; \
183 (exchange) = (exchange_type) _InterlockedExchange64( (__int64 volatile *) (pointer_to_destination), (__int64) (exchange) ); \
184 LFDS710_PAL_BARRIER_COMPILER_FULL; \
187 #define LFDS710_PAL_ATOMIC_SET( pointer_to_destination, new_value ) \
189 LFDS710_PAL_BARRIER_COMPILER_FULL; \
190 (void) _InterlockedExchange64( (__int64 volatile *) (pointer_to_destination), (__int64) (new_value) ); \
191 LFDS710_PAL_BARRIER_COMPILER_FULL; \
195 #if( defined _M_IX86 )
196 #define LFDS710_PAL_BARRIER_PROCESSOR_LOAD lfds710_misc_force_store()
197 #define LFDS710_PAL_BARRIER_PROCESSOR_STORE lfds710_misc_force_store()
198 #define LFDS710_PAL_BARRIER_PROCESSOR_FULL lfds710_misc_force_store()
200 // 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)
201 #define LFDS710_PAL_ATOMIC_ADD( pointer_to_target, value, result, result_type ) \
203 LFDS710_PAL_BARRIER_COMPILER_FULL; \
204 (result) = (result_type) _InterlockedExchangeAdd( (__int64 volatile *) (pointer_to_target), (__int64) (value) ); \
205 LFDS710_PAL_BARRIER_COMPILER_FULL; \
209 #define LFDS710_PAL_ATOMIC_CAS( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, result ) \
214 /* LFDS710_PAL_ASSERT( (pointer_to_destination) != NULL ); */ \
215 /* LFDS710_PAL_ASSERT( (pointer_to_compare) != NULL ); */ \
216 /* TRD : new_destination can be any value in its range */ \
217 /* TRD : cas_strength can be any value in its range */ \
218 /* TRD : result can be any value in its range */ \
220 original_compare = (lfds710_pal_uint_t) *(pointer_to_compare); \
222 LFDS710_PAL_BARRIER_COMPILER_FULL; \
223 *(lfds710_pal_uint_t *) (pointer_to_compare) = (lfds710_pal_uint_t) _InterlockedCompareExchange( (long volatile *) (pointer_to_destination), (long) (new_destination), (long) *(pointer_to_compare) ); \
224 LFDS710_PAL_BARRIER_COMPILER_FULL; \
226 result = (char unsigned) ( original_compare == (lfds710_pal_uint_t) *(pointer_to_compare) ); \
229 #define LFDS710_PAL_ATOMIC_DWCAS( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result ) \
234 original_compare = *(__int64 *) (pointer_to_compare); \
236 LFDS710_PAL_BARRIER_COMPILER_FULL; \
237 *(__int64 *) (pointer_to_compare) = _InterlockedCompareExchange64( (__int64 volatile *) (pointer_to_destination), *(__int64 *) (pointer_to_new_destination), *(__int64 *) (pointer_to_compare) ); \
238 LFDS710_PAL_BARRIER_COMPILER_FULL; \
240 (result) = (char unsigned) ( *(__int64 *) (pointer_to_compare) == original_compare ); \
243 #define LFDS710_PAL_ATOMIC_EXCHANGE( pointer_to_destination, exchange, exchange_type ) \
245 /* LFDS710_PAL_ASSERT( (pointer_to_destination) != NULL ); */ \
246 /* LFDS710_PAL_ASSERT( (pointer_to_exchange) != NULL ); */ \
248 LFDS710_PAL_BARRIER_COMPILER_FULL; \
249 (exchange) = (exchange_type) _InterlockedExchange( (int long volatile *) (pointer_to_destination), (int long) (exchange) ); \
250 LFDS710_PAL_BARRIER_COMPILER_FULL; \
253 #define LFDS710_PAL_ATOMIC_SET( pointer_to_destination, new_value ) \
255 LFDS710_PAL_BARRIER_COMPILER_FULL; \
256 (void) _InterlockedExchange( (int long volatile *) (pointer_to_destination), (int long) (new_value) ); \
257 LFDS710_PAL_BARRIER_COMPILER_FULL; \
267 /****************************************************************************/
268 #if( defined __GNUC__ && LFDS710_PAL_GCC_VERSION >= 412 && LFDS710_PAL_GCC_VERSION < 473 )
270 #ifdef LFDS710_PAL_COMPILER
271 #error More than one porting abstraction layer matches the current platform in lfds710_porting_abstraction_layer_compiler.h
274 #define LFDS710_PAL_COMPILER
276 #define LFDS710_PAL_COMPILER_STRING "GCC < 4.7.3"
278 #define LFDS710_PAL_ALIGN(alignment) __attribute__( (aligned(alignment)) )
279 #define LFDS710_PAL_INLINE inline
281 static LFDS710_PAL_INLINE void lfds710_pal_barrier_compiler( void )
283 __asm__ __volatile__ ( "" : : : "memory" );
286 #define LFDS710_PAL_BARRIER_COMPILER_LOAD lfds710_pal_barrier_compiler()
287 #define LFDS710_PAL_BARRIER_COMPILER_STORE lfds710_pal_barrier_compiler()
288 #define LFDS710_PAL_BARRIER_COMPILER_FULL lfds710_pal_barrier_compiler()
290 #define LFDS710_PAL_BARRIER_PROCESSOR_LOAD __sync_synchronize()
291 #define LFDS710_PAL_BARRIER_PROCESSOR_STORE __sync_synchronize()
292 #define LFDS710_PAL_BARRIER_PROCESSOR_FULL __sync_synchronize()
294 #define LFDS710_PAL_ATOMIC_ADD( pointer_to_target, value, result, result_type ) \
296 LFDS710_PAL_BARRIER_COMPILER_FULL; \
297 (result) = (result_type) __sync_add_and_fetch( (lfds710_pal_uint_t *) (pointer_to_target), (lfds710_pal_uint_t) (value) ); \
298 LFDS710_PAL_BARRIER_COMPILER_FULL; \
301 #define LFDS710_PAL_ATOMIC_CAS( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, result ) \
306 original_compare = (lfds710_pal_uint_t) *(pointer_to_compare); \
308 LFDS710_PAL_BARRIER_COMPILER_FULL; \
309 *(pointer_to_compare) = __sync_val_compare_and_swap( pointer_to_destination, *(pointer_to_compare), new_destination ); \
310 LFDS710_PAL_BARRIER_COMPILER_FULL; \
312 result = (unsigned char) ( original_compare == (lfds710_pal_uint_t) *(pointer_to_compare) ); \
315 // TRD : ARM and x86 have DWCAS which we can get via GCC intrinsics
316 #if( defined __arm__ || defined __i686__ || defined __i586__ || defined __i486__ )
317 #define LFDS710_PAL_ATOMIC_DWCAS( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result ) \
319 int long long unsigned \
320 original_destination; \
322 LFDS710_PAL_BARRIER_COMPILER_FULL; \
323 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) ); \
324 LFDS710_PAL_BARRIER_COMPILER_FULL; \
326 (result) = (char unsigned) ( original_destination == *(int long long unsigned *) (pointer_to_compare) ); \
328 *(int long long unsigned *) (pointer_to_compare) = original_destination; \
332 #define LFDS710_PAL_ATOMIC_EXCHANGE( pointer_to_destination, exchange, exchange_type ) \
334 /* LFDS710_PAL_ASSERT( (pointer_to_destination) != NULL ); */ \
335 /* TRD : exchange can be any value in its range */ \
336 /* TRD : exchange_type can be any value in its range */ \
338 LFDS710_PAL_BARRIER_COMPILER_FULL; \
339 (exchange) = (exchange_type) __sync_lock_test_and_set( pointer_to_destination, (exchange) ); \
340 LFDS710_PAL_BARRIER_COMPILER_FULL; \
343 #define LFDS710_PAL_ATOMIC_SET( pointer_to_destination, new_value ) \
345 LFDS710_PAL_BARRIER_COMPILER_FULL; \
346 (void) __sync_lock_test_and_set( pointer_to_destination, (new_value) ); \
347 LFDS710_PAL_BARRIER_COMPILER_FULL; \
356 /****************************************************************************/
357 #if( defined __GNUC__ && LFDS710_PAL_GCC_VERSION >= 473 )
359 #ifdef LFDS710_PAL_COMPILER
360 #error More than one porting abstraction layer matches the current platform in lfds710_porting_abstraction_layer_compiler.h
363 #define LFDS710_PAL_COMPILER
365 #define LFDS710_PAL_COMPILER_STRING "GCC >= 4.7.3"
367 #define LFDS710_PAL_ALIGN(alignment) __attribute__( (aligned(alignment)) )
368 #define LFDS710_PAL_INLINE inline
370 // TRD : GCC >= 4.7.3 compiler barriers are built into the intrinsics
371 #define LFDS710_PAL_COMPILER_BARRIERS_MISSING_PRESUMED_HAVING_A_GOOD_TIME
373 #define LFDS710_PAL_BARRIER_PROCESSOR_LOAD __atomic_thread_fence( __ATOMIC_ACQUIRE )
374 #define LFDS710_PAL_BARRIER_PROCESSOR_STORE __atomic_thread_fence( __ATOMIC_RELEASE )
375 #define LFDS710_PAL_BARRIER_PROCESSOR_FULL __atomic_thread_fence( __ATOMIC_ACQ_REL )
377 #define LFDS710_PAL_ATOMIC_ADD( pointer_to_target, value, result, result_type ) \
379 (result) = (result_type) __atomic_add_fetch( (pointer_to_target), (value), __ATOMIC_RELAXED ); \
382 #define LFDS710_PAL_ATOMIC_CAS( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, result ) \
384 result = (char unsigned) __atomic_compare_exchange_n( pointer_to_destination, pointer_to_compare, new_destination, cas_strength, __ATOMIC_RELAXED, __ATOMIC_RELAXED ); \
387 // TRD : ARM and x86 have DWCAS which we can get via GCC intrinsics
388 #if( defined __arm__ || defined __i686__ || defined __i586__ || defined __i486__ )
389 #define LFDS710_PAL_ATOMIC_DWCAS( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result ) \
391 (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 ); \
395 #if( defined __x86_64__ )
396 /* TRD : On 64 bit platforms, unsigned long long int is 64 bit, so we must manually use cmpxchg16b,
397 as __sync_val_compare_and_swap() will only emit cmpxchg8b
400 // 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
402 #define LFDS710_PAL_ATOMIC_DWCAS( pointer_to_destination, pointer_to_compare, pointer_to_new_destination, cas_strength, result ) \
406 __asm__ __volatile__ \
408 "lock;" /* make cmpxchg16b atomic */ \
409 "cmpxchg16b %0;" /* cmpxchg16b sets ZF on success */ \
410 "setz %4;" /* if ZF set, set result to 1 */ \
413 : "+m" ((pointer_to_destination)[0]), "+m" ((pointer_to_destination)[1]), "+a" ((pointer_to_compare)[0]), "+d" ((pointer_to_compare)[1]), "=q" (result) \
416 : "b" ((pointer_to_new_destination)[0]), "c" ((pointer_to_new_destination)[1]) \
424 #define LFDS710_PAL_ATOMIC_EXCHANGE( pointer_to_destination, exchange, exchange_type ) \
426 (exchange) = (exchange_type) __atomic_exchange_n( (pointer_to_destination), (exchange), __ATOMIC_RELAXED ); \
429 #define LFDS710_PAL_ATOMIC_SET( pointer_to_destination, new_value ) \
431 (void) __atomic_exchange_n( (pointer_to_destination), (new_value), __ATOMIC_RELAXED ); \
440 /****************************************************************************/
441 #if( !defined LFDS710_PAL_COMPILER )
443 #error No matching porting abstraction layer in lfds710_porting_abstraction_layer_compiler.h