mariadb/mysys/crc32/clang_workaround.h
mysqlonarm dec3f8ca69
MDEV-22641: Provide SIMD optimized wrapper for zlib crc32() (#1558)
Existing implementation used my_checksum (from mysys)
for calculating table checksum and binlog checksum.

This implementation was optimized for powerpc only and lacked
SIMD implementation for x86 (using clmul) and ARM
(using ACLE) instead used zlib-crc32.

mariabackup had its own copy of the crc32 implementation
using hardware optimized implementation only for x86 and lagged
hardware based implementation for powerpc and ARM.

Patch helps unifies all such calls and help aggregate all of them
using an unified interface my_checksum().

Said unification also enables hardware optimized calls for all
architecture viz. x86, ARM, POWERPC.
Default always fallback to zlib crc32.

Thanks to Daniel Black for reviewing, fixing and testing
PowerPC changes. Thanks to Marko and Daniel for early code feedback.
2020-06-01 11:34:06 +03:00

87 lines
2.3 KiB
C

#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