+/* ==================================================================== */
+/*
+ * Special "activate intrinsics" code, needed for some compiler versions.
+ * This is defined at the end of this file, so that it won't impact any
+ * of the inline functions defined previously; and it is controlled by
+ * a specific macro defined in the caller code.
+ *
+ * Calling code conventions:
+ *
+ * - Caller must define BR_ENABLE_INTRINSICS before including "inner.h".
+ * - Functions that use intrinsics must be enclosed in an "enabled"
+ * region (between BR_TARGETS_X86_UP and BR_TARGETS_X86_DOWN).
+ * - Functions that use intrinsics must be tagged with the appropriate
+ * BR_TARGET().
+ */
+
+#if BR_ENABLE_INTRINSICS && (BR_GCC_4_4 || BR_CLANG_3_7 || BR_MSC_2005)
+
+/*
+ * x86 intrinsics (both 32-bit and 64-bit).
+ */
+#if BR_i386 || BR_amd64
+
+/*
+ * On GCC before version 5.0, we need to use the pragma to enable the
+ * target options globally, because the 'target' function attribute
+ * appears to be unreliable. Before 4.6 we must also avoid the
+ * push_options / pop_options mechanism, because it tends to trigger
+ * some internal compiler errors.
+ */
+#if BR_GCC && !BR_GCC_5_0
+#if BR_GCC_4_6
+#define BR_TARGETS_X86_UP \
+ _Pragma("GCC push_options") \
+ _Pragma("GCC target(\"sse2,ssse3,sse4.1,aes,pclmul,rdrnd\")")
+#define BR_TARGETS_X86_DOWN \
+ _Pragma("GCC pop_options")
+#else
+#define BR_TARGETS_X86_UP \
+ _Pragma("GCC target(\"sse2,ssse3,sse4.1,aes,pclmul\")")
+#endif
+#define BR_TARGETS_X86_DOWN
+#pragma GCC diagnostic ignored "-Wpsabi"
+#endif
+
+#if BR_CLANG && !BR_CLANG_3_8
+#undef __SSE2__
+#undef __SSE3__
+#undef __SSSE3__
+#undef __SSE4_1__
+#undef __AES__
+#undef __PCLMUL__
+#undef __RDRND__
+#define __SSE2__ 1
+#define __SSE3__ 1
+#define __SSSE3__ 1
+#define __SSE4_1__ 1
+#define __AES__ 1
+#define __PCLMUL__ 1
+#define __RDRND__ 1
+#endif
+
+#ifndef BR_TARGETS_X86_UP
+#define BR_TARGETS_X86_UP
+#endif
+#ifndef BR_TARGETS_X86_DOWN
+#define BR_TARGETS_X86_DOWN
+#endif
+
+#if BR_GCC || BR_CLANG
+BR_TARGETS_X86_UP
+#include <x86intrin.h>
+#include <cpuid.h>
+#define br_bswap32 __builtin_bswap32
+BR_TARGETS_X86_DOWN
+#endif
+
+#if BR_MSC
+#include <stdlib.h>
+#include <intrin.h>
+#include <immintrin.h>
+#define br_bswap32 _byteswap_ulong
+#endif
+
+static inline int
+br_cpuid(uint32_t mask_eax, uint32_t mask_ebx,
+ uint32_t mask_ecx, uint32_t mask_edx)
+{
+#if BR_GCC || BR_CLANG
+ unsigned eax, ebx, ecx, edx;
+
+ if (__get_cpuid(1, &eax, &ebx, &ecx, &edx)) {
+ if ((eax & mask_eax) == mask_eax
+ && (ebx & mask_ebx) == mask_ebx
+ && (ecx & mask_ecx) == mask_ecx
+ && (edx & mask_edx) == mask_edx)
+ {
+ return 1;
+ }
+ }
+#elif BR_MSC
+ int info[4];
+
+ __cpuid(info, 1);
+ if (((uint32_t)info[0] & mask_eax) == mask_eax
+ && ((uint32_t)info[1] & mask_ebx) == mask_ebx
+ && ((uint32_t)info[2] & mask_ecx) == mask_ecx
+ && ((uint32_t)info[3] & mask_edx) == mask_edx)
+ {
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+#endif
+
+#endif
+