Skip to content

Commit 232d7a5

Browse files
committed
MDEV-34565: SIGILL due to OS not supporting AVX512
It is not sufficient to check that the CPU supports the necessary instructions. Also the operating system (or virtual machine hypervisor) must enable all the AVX registers to be saved and restored on a context switch. Because clang 8 does not support the compiler intrinsic _xgetbv() we will require clang 9 or later for enabling the use of VPCLMULQDQ and the related AVX512 features.
1 parent 0939bfc commit 232d7a5

File tree

1 file changed

+22
-7
lines changed

1 file changed

+22
-7
lines changed

mysys/crc32/crc32c_x86.cc

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@
2828
# elif __GNUC__ >= 14 || (defined __clang_major__ && __clang_major__ >= 18)
2929
# define TARGET "pclmul,evex512,avx512f,avx512dq,avx512bw,avx512vl,vpclmulqdq"
3030
# define USE_VPCLMULQDQ __attribute__((target(TARGET)))
31-
# elif __GNUC__ >= 11 || (defined __clang_major__ && __clang_major__ >= 8)
31+
# elif __GNUC__ >= 11 || (defined __clang_major__ && __clang_major__ >= 9)
32+
/* clang 8 does not support _xgetbv(), which we also need */
3233
# define TARGET "pclmul,avx512f,avx512dq,avx512bw,avx512vl,vpclmulqdq"
3334
# define USE_VPCLMULQDQ __attribute__((target(TARGET)))
3435
# endif
@@ -38,6 +39,7 @@ extern "C" unsigned crc32c_sse42(unsigned crc, const void* buf, size_t size);
3839

3940
constexpr uint32_t cpuid_ecx_SSE42= 1U << 20;
4041
constexpr uint32_t cpuid_ecx_SSE42_AND_PCLMUL= cpuid_ecx_SSE42 | 1U << 1;
42+
constexpr uint32_t cpuid_ecx_XSAVE= 1U << 26;
4143

4244
static uint32_t cpuid_ecx()
4345
{
@@ -382,8 +384,19 @@ static unsigned crc32_avx512(unsigned crc, const char *buf, size_t size,
382384
}
383385
}
384386

385-
static ATTRIBUTE_NOINLINE int have_vpclmulqdq()
387+
#ifdef __GNUC__
388+
__attribute__((target("xsave")))
389+
#endif
390+
static bool os_have_avx512()
391+
{
392+
// The following flags must be set: SSE, AVX, OPMASK, ZMM_HI256, HI16_ZMM
393+
return !(~_xgetbv(0 /*_XCR_XFEATURE_ENABLED_MASK*/) & 0xe6);
394+
}
395+
396+
static ATTRIBUTE_NOINLINE bool have_vpclmulqdq(uint32_t cpuid_ecx)
386397
{
398+
if (!(cpuid_ecx & cpuid_ecx_XSAVE) || !os_have_avx512())
399+
return false;
387400
# ifdef _MSC_VER
388401
int regs[4];
389402
__cpuidex(regs, 7, 0);
@@ -410,30 +423,32 @@ static unsigned crc32c_vpclmulqdq(unsigned crc, const void *buf, size_t size)
410423

411424
extern "C" my_crc32_t crc32_pclmul_enabled(void)
412425
{
413-
if (~cpuid_ecx() & cpuid_ecx_SSE42_AND_PCLMUL)
426+
const uint32_t ecx= cpuid_ecx();
427+
if (~ecx & cpuid_ecx_SSE42_AND_PCLMUL)
414428
return nullptr;
415429
#ifdef USE_VPCLMULQDQ
416-
if (have_vpclmulqdq())
430+
if (have_vpclmulqdq(ecx))
417431
return crc32_vpclmulqdq;
418432
#endif
419433
return crc32_pclmul;
420434
}
421435

422436
extern "C" my_crc32_t crc32c_x86_available(void)
423437
{
438+
const uint32_t ecx= cpuid_ecx();
424439
#ifdef USE_VPCLMULQDQ
425-
if (have_vpclmulqdq())
440+
if (have_vpclmulqdq(ecx))
426441
return crc32c_vpclmulqdq;
427442
#endif
428443
#if SIZEOF_SIZE_T == 8
429-
switch (cpuid_ecx() & cpuid_ecx_SSE42_AND_PCLMUL) {
444+
switch (ecx & cpuid_ecx_SSE42_AND_PCLMUL) {
430445
case cpuid_ecx_SSE42_AND_PCLMUL:
431446
return crc32c_3way;
432447
case cpuid_ecx_SSE42:
433448
return crc32c_sse42;
434449
}
435450
#else
436-
if (cpuid_ecx() & cpuid_ecx_SSE42)
451+
if (ecx & cpuid_ecx_SSE42)
437452
return crc32c_sse42;
438453
#endif
439454
return nullptr;

0 commit comments

Comments
 (0)