--- libecb/ecb.h 2014/06/09 17:31:57 1.134 +++ libecb/ecb.h 2014/10/17 11:02:20 1.144 @@ -42,7 +42,7 @@ #define ECB_H /* 16 bits major, 16 bits minor */ -#define ECB_VERSION 0x00010003 +#define ECB_VERSION 0x00010004 #ifdef _WIN32 typedef signed char int8_t; @@ -92,12 +92,24 @@ * we try to detect these and simply assume they are not gcc - if they have * an issue with that they should have done it right in the first place. */ -#ifndef ECB_GCC_VERSION - #if !defined __GNUC_MINOR__ || defined __INTEL_COMPILER || defined __SUNPRO_C || defined __SUNPRO_CC || defined __llvm__ || defined __clang__ - #define ECB_GCC_VERSION(major,minor) 0 - #else - #define ECB_GCC_VERSION(major,minor) (__GNUC__ > (major) || (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor))) - #endif +#if !defined __GNUC_MINOR__ || defined __INTEL_COMPILER || defined __SUNPRO_C || defined __SUNPRO_CC || defined __llvm__ || defined __clang__ + #define ECB_GCC_VERSION(major,minor) 0 +#else + #define ECB_GCC_VERSION(major,minor) (__GNUC__ > (major) || (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor))) +#endif + +#define ECB_CLANG_VERSION(major,minor) (__clang_major__ > (major) || (__clang_major__ == (major) && __clang_minor__ >= (minor))) + +#if __clang__ && defined(__has_builtin) + #define ECB_CLANG_BUILTIN(x) __has_builtin(x) +#else + #define ECB_CLANG_BUILTIN(x) 0 +#endif + +#if __clang__ && defined(__has_extension) + #define ECB_CLANG_EXTENSION(x) __has_extension(x) +#else + #define ECB_CLANG_EXTENSION(x) 0 #endif #define ECB_CPP (__cplusplus+0) @@ -191,16 +203,11 @@ #define ECB_MEMORY_FENCE_ACQUIRE __atomic_thread_fence (__ATOMIC_ACQUIRE) #define ECB_MEMORY_FENCE_RELEASE __atomic_thread_fence (__ATOMIC_RELEASE) - /* The __has_feature syntax from clang is so misdesigned that we cannot use it - * without risking compile time errors with other compilers. We *could* - * define our own ecb_clang_has_feature, but I just can't be bothered to work - * around this shit time and again. - * #elif defined __clang && __has_feature (cxx_atomic) - * // see comment below (stdatomic.h) about the C11 memory model. - * #define ECB_MEMORY_FENCE __c11_atomic_thread_fence (__ATOMIC_SEQ_CST) - * #define ECB_MEMORY_FENCE_ACQUIRE __c11_atomic_thread_fence (__ATOMIC_ACQUIRE) - * #define ECB_MEMORY_FENCE_RELEASE __c11_atomic_thread_fence (__ATOMIC_RELEASE) - */ + #elif ECB_CLANG_EXTENSION(c_atomic) + /* see comment below (stdatomic.h) about the C11 memory model. */ + #define ECB_MEMORY_FENCE __c11_atomic_thread_fence (__ATOMIC_SEQ_CST) + #define ECB_MEMORY_FENCE_ACQUIRE __c11_atomic_thread_fence (__ATOMIC_ACQUIRE) + #define ECB_MEMORY_FENCE_RELEASE __c11_atomic_thread_fence (__ATOMIC_RELEASE) #elif ECB_GCC_VERSION(4,4) || defined __INTEL_COMPILER || defined __clang__ #define ECB_MEMORY_FENCE __sync_synchronize () @@ -300,36 +307,55 @@ #define ecb_function_ ecb_inline -#if ECB_GCC_VERSION(3,1) - #define ecb_attribute(attrlist) __attribute__(attrlist) - #define ecb_is_constant(expr) __builtin_constant_p (expr) - #define ecb_expect(expr,value) __builtin_expect ((expr),(value)) - #define ecb_prefetch(addr,rw,locality) __builtin_prefetch (addr, rw, locality) +#if ECB_GCC_VERSION(3,1) || ECB_CLANG_VERSION(2,8) + #define ecb_attribute(attrlist) __attribute__ (attrlist) #else #define ecb_attribute(attrlist) +#endif +#if ECB_GCC_VERSION(3,1) || ECB_CLANG_BUILTIN(__builtin_constant_p) + #define ecb_is_constant(expr) __builtin_constant_p (expr) +#else /* possible C11 impl for integral types typedef struct ecb_is_constant_struct ecb_is_constant_struct; #define ecb_is_constant(expr) _Generic ((1 ? (struct ecb_is_constant_struct *)0 : (void *)((expr) - (expr)), ecb_is_constant_struct *: 0, default: 1)) */ #define ecb_is_constant(expr) 0 +#endif + +#if ECB_GCC_VERSION(3,1) || ECB_CLANG_BUILTIN(__builtin_expect) + #define ecb_expect(expr,value) __builtin_expect ((expr),(value)) +#else #define ecb_expect(expr,value) (expr) +#endif + +#if ECB_GCC_VERSION(3,1) || ECB_CLANG_BUILTIN(__builtin_prefetch) + #define ecb_prefetch(addr,rw,locality) __builtin_prefetch (addr, rw, locality) +#else #define ecb_prefetch(addr,rw,locality) #endif /* no emulation for ecb_decltype */ -#if ECB_GCC_VERSION(4,5) - #define ecb_decltype(x) __decltype(x) -#elif ECB_GCC_VERSION(3,0) - #define ecb_decltype(x) __typeof(x) +#if ECB_CPP11 + // older implementations might have problems with decltype(x)::type, work around it + struct ecb_decltype_t { typedef T type; }; + #define ecb_decltype(x) ecb_decltype_t::type +#elif ECB_GCC_VERSION(3,0) || ECB_CLANG_VERSION(2,8) + #define ecb_decltype(x) __typeof__ (x) +#endif + +#if _MSC_VER >= 1300 + #define ecb_deprecated __declspec(deprecated) +#else + #define ecb_deprecated ecb_attribute ((__deprecated__)) #endif -#define ecb_deprecated ecb_attribute ((__deprecated__)) #define ecb_noinline ecb_attribute ((__noinline__)) #define ecb_unused ecb_attribute ((__unused__)) #define ecb_const ecb_attribute ((__const__)) #define ecb_pure ecb_attribute ((__pure__)) +/* http://msdn.microsoft.com/en-us/library/k6ktzx3s.aspx __declspec(noreturn) */ #if ECB_C11 #define ecb_noreturn _Noreturn #else @@ -356,7 +382,10 @@ #define ecb_unlikely(expr) ecb_expect_false (expr) /* count trailing zero bits and count # of one bits */ -#if ECB_GCC_VERSION(3,4) +#if ECB_GCC_VERSION(3,4) \ + || (ECB_CLANG_BUILTIN(__builtin_clz) && ECB_CLANG_BUILTIN(__builtin_clzll) \ + && ECB_CLANG_BUILTIN(__builtin_ctz) && ECB_CLANG_BUILTIN(__builtin_ctzll) \ + && ECB_CLANG_BUILTIN(__builtin_popcount)) /* we assume int == 32 bit, long == 32 or 64 bit and long long == 64 bit */ #define ecb_ld32(x) (__builtin_clz (x) ^ 31) #define ecb_ld64(x) (__builtin_clzll (x) ^ 63) @@ -497,7 +526,7 @@ ecb_inline uint64_t ecb_rotl64 (uint64_t x, unsigned int count) { return (x >> (64 - count)) | (x << count); } ecb_inline uint64_t ecb_rotr64 (uint64_t x, unsigned int count) { return (x << (64 - count)) | (x >> count); } -#if ECB_GCC_VERSION(4,3) +#if ECB_GCC_VERSION(4,3) || (ECB_CLANG_BUILTIN(__builtin_bswap32) && ECB_CLANG_BUILTIN(__builtin_bswap64)) #define ecb_bswap16(x) (__builtin_bswap32 (x) >> 16) #define ecb_bswap32(x) __builtin_bswap32 (x) #define ecb_bswap64(x) __builtin_bswap64 (x) @@ -524,7 +553,7 @@ } #endif -#if ECB_GCC_VERSION(4,5) +#if ECB_GCC_VERSION(4,5) || ECB_CLANG_BUILTIN(__builtin_unreachable) #define ecb_unreachable() __builtin_unreachable () #else /* this seems to work fine, but gcc always emits a warning for it :/ */