--- libecb/ecb.h 2014/03/25 19:26:31 1.132 +++ libecb/ecb.h 2014/10/24 04:54:11 1.149 @@ -25,13 +25,24 @@ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, the contents of this file may be used under the terms of + * the GNU General Public License ("GPL") version 2 or any later version, + * in which case the provisions of the GPL are applicable instead of + * the above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use your + * version of this file under the BSD license, indicate your decision + * by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file under + * either the BSD or the GPL. */ #ifndef ECB_H #define ECB_H /* 16 bits major, 16 bits minor */ -#define ECB_VERSION 0x00010003 +#define ECB_VERSION 0x00010004 #ifdef _WIN32 typedef signed char int8_t; @@ -81,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) @@ -180,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 () @@ -262,7 +280,7 @@ /*****************************************************************************/ -#if __cplusplus +#if ECB_CPP #define ecb_inline static inline #elif ECB_GCC_VERSION(2,5) #define ecb_inline static __inline__ @@ -289,28 +307,47 @@ #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 + template 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_noinline ecb_attribute ((__noinline__)) @@ -318,7 +355,9 @@ #define ecb_const ecb_attribute ((__const__)) #define ecb_pure ecb_attribute ((__pure__)) -#if ECB_C11 +/* TODO http://msdn.microsoft.com/en-us/library/k6ktzx3s.aspx __declspec(noreturn) */ +#if ECB_C11 || __IBMC_NORETURN + /* http://pic.dhe.ibm.com/infocenter/compbg/v121v141/topic/com.ibm.xlcpp121.bg.doc/language_ref/noreturn.html */ #define ecb_noreturn _Noreturn #else #define ecb_noreturn ecb_attribute ((__noreturn__)) @@ -344,7 +383,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) @@ -485,7 +527,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) @@ -512,7 +554,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 :/ */ @@ -560,7 +602,7 @@ #define ecb_mod(m,n) ((m) < 0 ? ((n) - 1 - ((-1 - (m)) % (n))) : ((m) % (n))) #endif -#if __cplusplus +#if ECB_CPP template static inline T ecb_div_rd (T val, T div) { @@ -630,6 +672,12 @@ #define ECB_NAN ECB_INFINITY #endif + #if ECB_C99 || _XOPEN_VERSION >= 600 || _POSIX_VERSION >= 200112L + #define ecb_ldexpf(x,e) ldexpf (x, e) + #else + #define ecb_ldexpf(x,e) (float) ldexp ((double)(x), e) + #endif + /* converts an ieee half/binary16 to a float */ ecb_function_ float ecb_binary16_to_float (uint16_t x) ecb_const; ecb_function_ float @@ -639,8 +687,8 @@ int m = x & 0x3ff; float r; - if (!e ) r = ldexpf (m , -24); - else if (e != 31) r = ldexpf (m + 0x400, e - 25); + if (!e ) r = ecb_ldexpf (m , -24); + else if (e != 31) r = ecb_ldexpf (m + 0x400, e - 25); else if (m ) r = ECB_NAN; else r = ECB_INFINITY; @@ -709,7 +757,7 @@ e = 1; /* we distrust ldexpf a bit and do the 2**-24 scaling by an extra multiply */ - r = ldexpf (x * (0.5f / 0x800000U), e - 126); + r = ecb_ldexpf (x * (0.5f / 0x800000U), e - 126); r = neg ? -r : r; #endif