summaryrefslogtreecommitdiffstats
path: root/mysys/crc32/clang_workaround.h
diff options
context:
space:
mode:
Diffstat (limited to 'mysys/crc32/clang_workaround.h')
-rw-r--r--mysys/crc32/clang_workaround.h87
1 files changed, 87 insertions, 0 deletions
diff --git a/mysys/crc32/clang_workaround.h b/mysys/crc32/clang_workaround.h
new file mode 100644
index 00000000..915f7e52
--- /dev/null
+++ b/mysys/crc32/clang_workaround.h
@@ -0,0 +1,87 @@
+#ifndef CLANG_WORKAROUNDS_H
+#define CLANG_WORKAROUNDS_H
+
+/*
+ * These stubs fix clang incompatibilities with GCC builtins.
+ */
+
+#ifndef __builtin_crypto_vpmsumw
+#define __builtin_crypto_vpmsumw __builtin_crypto_vpmsumb
+#endif
+#ifndef __builtin_crypto_vpmsumd
+#define __builtin_crypto_vpmsumd __builtin_crypto_vpmsumb
+#endif
+
+static inline
+__vector unsigned long long __attribute__((overloadable))
+vec_ld(int __a, const __vector unsigned long long* __b)
+{
+ return (__vector unsigned long long)__builtin_altivec_lvx(__a, __b);
+}
+
+/*
+ * GCC __builtin_pack_vector_int128 returns a vector __int128_t but Clang
+ * does not recognize this type. On GCC this builtin is translated to a
+ * xxpermdi instruction that only moves the registers __a, __b instead generates
+ * a load.
+ *
+ * Clang has vec_xxpermdi intrinsics. It was implemented in 4.0.0.
+ */
+static inline
+__vector unsigned long long __builtin_pack_vector (unsigned long __a,
+ unsigned long __b)
+{
+ #if defined(__BIG_ENDIAN__)
+ __vector unsigned long long __v = {__a, __b};
+ #else
+ __vector unsigned long long __v = {__b, __a};
+ #endif
+ return __v;
+}
+
+/*
+ * Clang 7 changed the behavior of vec_xxpermdi in order to provide the same
+ * behavior of GCC. That means code adapted to Clang >= 7 does not work on
+ * Clang <= 6. So, fallback to __builtin_unpack_vector() on Clang <= 6.
+ */
+#if !defined vec_xxpermdi || __clang_major__ <= 6
+
+static inline
+unsigned long __builtin_unpack_vector (__vector unsigned long long __v,
+ int __o)
+{
+ return __v[__o];
+}
+
+#if defined(__BIG_ENDIAN__)
+#define __builtin_unpack_vector_0(a) __builtin_unpack_vector ((a), 0)
+#define __builtin_unpack_vector_1(a) __builtin_unpack_vector ((a), 1)
+#else
+#define __builtin_unpack_vector_0(a) __builtin_unpack_vector ((a), 1)
+#define __builtin_unpack_vector_1(a) __builtin_unpack_vector ((a), 0)
+#endif
+
+#else
+
+static inline
+unsigned long __builtin_unpack_vector_0 (__vector unsigned long long __v)
+{
+ #if defined(__BIG_ENDIAN__)
+ return vec_xxpermdi(__v, __v, 0x0)[0];
+ #else
+ return vec_xxpermdi(__v, __v, 0x3)[0];
+ #endif
+}
+
+static inline
+unsigned long __builtin_unpack_vector_1 (__vector unsigned long long __v)
+{
+ #if defined(__BIG_ENDIAN__)
+ return vec_xxpermdi(__v, __v, 0x3)[0];
+ #else
+ return vec_xxpermdi(__v, __v, 0x0)[0];
+ #endif
+}
+#endif /* vec_xxpermdi */
+
+#endif