From 3a3d2da7c2331d33de23cf7d866f9d8a80233370 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Fri, 4 Nov 2016 20:38:09 -0700 Subject: [PATCH] Fix compilation with clang 3.7 --- common/common_defs.h | 13 ++++----- common/compiler_gcc.h | 66 +++++++++++++++++++++++++------------------ lib/adler32.c | 3 +- lib/crc32.c | 3 +- 4 files changed, 49 insertions(+), 36 deletions(-) diff --git a/common/common_defs.h b/common/common_defs.h index 2b7e3ea..677f97e 100644 --- a/common/common_defs.h +++ b/common/common_defs.h @@ -121,22 +121,21 @@ typedef size_t machine_word_t; # define COMPILER_SUPPORTS_TARGET_FUNCTION_ATTRIBUTE 0 #endif -/* Does the compiler support __attribute__((target("pclmul")))? */ +/* Are target-specific intrinsics supported in 'target' attribute functions? */ +#ifndef COMPILER_SUPPORTS_TARGET_INTRINSICS +# define COMPILER_SUPPORTS_TARGET_INTRINSICS 0 +#endif + +/* Which targets are supported with the 'target' function attribute? */ #ifndef COMPILER_SUPPORTS_PCLMUL_TARGET # define COMPILER_SUPPORTS_PCLMUL_TARGET 0 #endif - -/* Does the compiler support __attribute__((target("bmi2")))? */ #ifndef COMPILER_SUPPORTS_BMI2_TARGET # define COMPILER_SUPPORTS_BMI2_TARGET 0 #endif - -/* Does the compiler support __attribute__((target("avx")))? */ #ifndef COMPILER_SUPPORTS_AVX_TARGET # define COMPILER_SUPPORTS_AVX_TARGET 0 #endif - -/* Does the compiler support __attribute__((target("avx2")))? */ #ifndef COMPILER_SUPPORTS_AVX2_TARGET # define COMPILER_SUPPORTS_AVX2_TARGET 0 #endif diff --git a/common/compiler_gcc.h b/common/compiler_gcc.h index 6b17dda..3e2d7f5 100644 --- a/common/compiler_gcc.h +++ b/common/compiler_gcc.h @@ -7,6 +7,21 @@ (__GNUC__ > (major) || \ (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor))) +/* Note: only check the clang version when absolutely necessary! + * "Vendors" such as Apple can use different version numbers. */ +#ifdef __clang__ +# ifdef __apple_build_version__ +# define CLANG_PREREQ(major, minor, apple_version) \ + (__apple_build_version__ >= (apple_version)) +# else +# define CLANG_PREREQ(major, minor, apple_version) \ + (__clang_major__ > (major) || \ + (__clang_major__ == (major) && __clang_minor__ >= (minor))) +# endif +#else +# define CLANG_PREREQ(major, minor, apple_version) 0 +#endif + #ifndef __has_attribute # define __has_attribute(attribute) 0 #endif @@ -32,42 +47,39 @@ #define prefetchw(addr) __builtin_prefetch((addr), 1) #define _aligned_attribute(n) __attribute__((aligned(n))) -#define COMPILER_SUPPORTS_TARGET_FUNCTION_ATTRIBUTE \ - (GCC_PREREQ(4, 4) || __has_attribute(target)) - /* - * Support for the following instruction set extensions was introduced by the - * following gcc versions: + * Support for the following x86 instruction set extensions was introduced by + * the following gcc versions: * * PCLMUL 4.4 * AVX 4.6 * BMI2 4.7 * AVX2 4.7 * - * However, target-specific intrinsics don't work in __attribute__((target(..))) - * functions until gcc 4.9. Currently we need this for PCLMUL and AVX2 but not - * AVX and BMI2. Hence the particular version checks below. + * With clang, __has_builtin() can be used to detect the presence of one of the + * associated builtins. * - * Note: clang does not have this problem and also supports __has_builtin() for - * testing for whether an intrinsic is available without having to check the - * compiler version. + * Additionally, gcc 4.4 introduced the 'target' function attribute. With + * clang, support for this can be detected with with __has_attribute(target). + * + * However, prior to gcc 4.9 and clang 3.8, x86 intrinsics not available in the + * main target could not be used in 'target' attribute functions. Unfortunately + * clang has no feature test macro for this so we have to check its version. */ - -#define COMPILER_SUPPORTS_PCLMUL_TARGET \ - (COMPILER_SUPPORTS_TARGET_FUNCTION_ATTRIBUTE && \ - (GCC_PREREQ(4, 9) || __has_builtin(__builtin_ia32_pclmulqdq128))) - -#define COMPILER_SUPPORTS_AVX_TARGET \ - (COMPILER_SUPPORTS_TARGET_FUNCTION_ATTRIBUTE && \ - (GCC_PREREQ(4, 6) || __has_builtin(__builtin_ia32_maxps256))) - -#define COMPILER_SUPPORTS_BMI2_TARGET \ - (COMPILER_SUPPORTS_TARGET_FUNCTION_ATTRIBUTE && \ - (GCC_PREREQ(4, 7) || __has_builtin(__builtin_ia32_pdep_di))) - -#define COMPILER_SUPPORTS_AVX2_TARGET \ - (COMPILER_SUPPORTS_TARGET_FUNCTION_ATTRIBUTE && \ - (GCC_PREREQ(4, 9) || __has_builtin(__builtin_ia32_pmaddwd256))) +#define COMPILER_SUPPORTS_TARGET_FUNCTION_ATTRIBUTE \ + (GCC_PREREQ(4, 4) || __has_attribute(target)) +#if COMPILER_SUPPORTS_TARGET_FUNCTION_ATTRIBUTE +# define COMPILER_SUPPORTS_TARGET_INTRINSICS \ + (GCC_PREREQ(4, 9) || CLANG_PREREQ(3, 8, 7030000)) +# define COMPILER_SUPPORTS_PCLMUL_TARGET \ + (GCC_PREREQ(4, 4) || __has_builtin(__builtin_ia32_pclmulqdq128)) +# define COMPILER_SUPPORTS_AVX_TARGET \ + (GCC_PREREQ(4, 6) || __has_builtin(__builtin_ia32_maxps256)) +# define COMPILER_SUPPORTS_BMI2_TARGET \ + (GCC_PREREQ(4, 7) || __has_builtin(__builtin_ia32_pdep_di)) +# define COMPILER_SUPPORTS_AVX2_TARGET \ + (GCC_PREREQ(4, 7) || __has_builtin(__builtin_ia32_pmaddwd256)) +#endif /* Newer gcc supports __BYTE_ORDER__. Older gcc doesn't. */ #ifdef __BYTE_ORDER__ diff --git a/lib/adler32.c b/lib/adler32.c index 1133cdb..2148802 100644 --- a/lib/adler32.c +++ b/lib/adler32.c @@ -74,7 +74,8 @@ /* Include the AVX2 implementation? */ #define NEED_AVX2_IMPL 0 #if defined(__AVX2__) || \ - (X86_CPU_FEATURES_ENABLED && COMPILER_SUPPORTS_AVX2_TARGET) + (X86_CPU_FEATURES_ENABLED && COMPILER_SUPPORTS_AVX2_TARGET && \ + COMPILER_SUPPORTS_TARGET_INTRINSICS) # include # undef NEED_AVX2_IMPL # define NEED_AVX2_IMPL 1 diff --git a/lib/crc32.c b/lib/crc32.c index 060b12a..5c3f8ba 100644 --- a/lib/crc32.c +++ b/lib/crc32.c @@ -183,7 +183,8 @@ /* Include the PCLMUL implementation? */ #define NEED_PCLMUL_IMPL 0 #if defined(__PCLMUL__) || \ - (X86_CPU_FEATURES_ENABLED && COMPILER_SUPPORTS_PCLMUL_TARGET) + (X86_CPU_FEATURES_ENABLED && COMPILER_SUPPORTS_PCLMUL_TARGET && \ + COMPILER_SUPPORTS_TARGET_INTRINSICS) # include # undef NEED_PCLMUL_IMPL # define NEED_PCLMUL_IMPL 1