diff --git a/cmdline/speed.c b/cmdline/speed.c index e2fe8a1d..02e4c566 100644 --- a/cmdline/speed.c +++ b/cmdline/speed.c @@ -122,11 +122,10 @@ void speed(int period) raid_cpu_info(vendor, &family, &model); - printf("CPU %s, family %u, model %u, flags%s%s%s%s%s%s%s%s\n", vendor, family, model, - raid_cpu_has_mmx() ? " mmx" : "", + printf("CPU %s, family %u, model %u, flags%s%s%s%s%s%s%s\n", vendor, family, model, raid_cpu_has_sse2() ? " sse2" : "", raid_cpu_has_ssse3() ? " ssse3" : "", - raid_cpu_has_sse42() ? " sse42" : "", + raid_cpu_has_crc32() ? " crc32" : "", raid_cpu_has_avx2() ? " avx2" : "", raid_cpu_has_slowmult() ? " slowmult" : "", raid_cpu_has_slowpshufb() ? " slowpshufb" : "", @@ -191,7 +190,7 @@ void speed(int period) fflush(stdout); #if HAVE_SSE42 - if (raid_cpu_has_sse42()) { + if (raid_cpu_has_crc32()) { SPEED_START { for (j = 0; j < nd; ++j) crc32c_x86(0, v[j], size); diff --git a/cmdline/util.c b/cmdline/util.c index 98158797..67fe8f86 100644 --- a/cmdline/util.c +++ b/cmdline/util.c @@ -419,7 +419,7 @@ void crc32c_init(void) { crc32c = crc32c_gen; #if HAVE_SSE42 - if (raid_cpu_has_sse42()) { + if (raid_cpu_has_crc32()) { crc_x86 = 1; crc32c = crc32c_x86; } diff --git a/raid/cpu.h b/raid/cpu.h index 65b5084a..3296ffc6 100644 --- a/raid/cpu.h +++ b/raid/cpu.h @@ -35,6 +35,19 @@ static inline void raid_cpuid(uint32_t func_eax, uint32_t sub_ecx, uint32_t *reg ); } +static inline void raid_xgetbv(uint32_t* reg) +{ + /* get the value of the Extended Control Register ecx=0 */ + asm volatile ( + /* uses a direct encoding of the XGETBV instruction as only recent */ + /* assemblers support it. */ + /* the next line is equivalent at: "xgetbv\n" */ + ".byte 0x0f, 0x01, 0xd0\n" + : "=a" (reg[0]), "=d" (reg[3]) + : "c" (0) + ); +} + #define CPU_VENDOR_MAX 13 static inline void raid_cpu_info(char *vendor, unsigned *family, unsigned *model) @@ -70,85 +83,124 @@ static inline void raid_cpu_info(char *vendor, unsigned *family, unsigned *model } } -static inline int raid_cpu_has_mmx(void) +static inline int raid_cpu_match_sse(uint32_t cpuid_1_ecx, uint32_t cpuid_1_edx) { uint32_t reg[4]; raid_cpuid(1, 0, reg); + if ((reg[2] & cpuid_1_ecx) != cpuid_1_ecx) + return 0; + if ((reg[3] & cpuid_1_edx) != cpuid_1_edx) + return 0; - return (reg[3] >> 23) & 1; + return 1; +} + +static inline int raid_cpu_match_avx(uint32_t cpuid_1_ecx, uint32_t cpuid_7_ebx, uint32_t xcr0) +{ + uint32_t reg[4]; + + raid_cpuid(1, 0, reg); + if ((reg[2] & cpuid_1_ecx) != cpuid_1_ecx) + return 0; + + raid_xgetbv(reg); + if ((reg[0] & xcr0) != xcr0) + return 0; + + raid_cpuid(7, 0, reg); + if ((reg[1] & cpuid_7_ebx) != cpuid_7_ebx) + return 0; + + return 1; } static inline int raid_cpu_has_sse2(void) { - uint32_t reg[4]; - - raid_cpuid(1, 0, reg); - - return (reg[3] >> 26) & 1; + /* + * Intel® 64 and IA-32 Architectures Software Developer's Manual + * 325462-048US September 2013 + * + * 11.6.2 Checking for SSE/SSE2 Support + * Before an application attempts to use the SSE and/or SSE2 extensions, it should check + * that they are present on the processor: + * 1. Check that the processor supports the CPUID instruction. Bit 21 of the EFLAGS + * register can be used to check processor's support the CPUID instruction. + * 2. Check that the processor supports the SSE and/or SSE2 extensions (true if + * CPUID.01H:EDX.SSE[bit 25] = 1 and/or CPUID.01H:EDX.SSE2[bit 26] = 1). + */ + return raid_cpu_match_sse( + 0, + 1 << 26); /* SSE2 */ } static inline int raid_cpu_has_ssse3(void) { - uint32_t reg[4]; - - raid_cpuid(1, 0, reg); - - return (reg[2] >> 9) & 1; + /* + * Intel® 64 and IA-32 Architectures Software Developer's Manual + * 325462-048US September 2013 + * + * 12.7.2 Checking for SSSE3 Support + * Before an application attempts to use the SSSE3 extensions, the application should + * follow the steps illustrated in Section 11.6.2, "Checking for SSE/SSE2 Support." + * Next, use the additional step provided below: + * Check that the processor supports SSSE3 (if CPUID.01H:ECX.SSSE3[bit 9] = 1). + */ + return raid_cpu_match_sse( + 1 << 9, /* SSSE3 */ + 1 << 26); /* SSE2 */ } -static inline int raid_cpu_has_sse42(void) +static inline int raid_cpu_has_crc32(void) { - uint32_t reg[4]; - - raid_cpuid(1, 0, reg); - - return (reg[2] >> 20) & 1; -} - -static inline int raid_cpu_has_xsavexrstor(void) -{ - uint32_t reg[4]; - - raid_cpuid(1, 0, reg); - - return (reg[2] >> 27) & 1; -} - -static inline int raid_os_support_256bit_regs(void) -{ - uint32_t reg[4]; - - /* get the value of the Extended Control Register ecx=0 */ - asm volatile ( - /* uses a direct encoding of the XGETBV instruction as only recent */ - /* assemblers support it. */ - /* the next line is equivalent at: "xgetbv\n" */ - ".byte 0x0f, 0x01, 0xd0\n" - : "=a" (reg[0]), "=d" (reg[3]) - : "c" (0) - ); - - /* check if the OS saves the 256 bits registers in task switch */ - return (reg[0] & 0x6) == 0x6; + /* + * Intel® 64 and IA-32 Architectures Software Developer's Manual + * 325462-048US September 2013 + * + * 12.12.3 Checking for SSE4.2 Support + * ... + * Before an application attempts to use the CRC32 instruction, it must check + * that the processor supports SSE4.2 (if CPUID.01H:ECX.SSE4_2[bit 20] = 1). + */ + return raid_cpu_match_sse( + 1 << 20, /* CRC32 */ + 0); /* SSE2 */ } static inline int raid_cpu_has_avx2(void) { - uint32_t reg[4]; + /* + * Intel Architecture Instruction Set Extensions Programming Reference + * 319433-022 October 2014 + * + * 14.7.1 Detection of AVX2 + * Hardware support for AVX2 is indicated by CPUID.(EAX=07H, ECX=0H):EBX.AVX2[bit 5]=1. + * Application Software must identify that hardware supports AVX, after that it must + * also detect support for AVX2 by checking CPUID.(EAX=07H, ECX=0H):EBX.AVX2[bit 5]. + */ + return raid_cpu_match_avx( + (1 << 27) | (1 << 5), /* OSXSAVE and AVX */ + 1 << 5, /* AVX2 */ + 3 << 1); /* OS saves XMM and YMM registers */ +} - /* check if the CPU supports XSAVE and XRSTOR, and XGETBV */ - if (!raid_cpu_has_xsavexrstor()) - return 0; - - /* check if the OS supports AVX2 registers */ - if (!raid_os_support_256bit_regs()) - return 0; - - /* now check for AVX2 support */ - raid_cpuid(7, 0, reg); - - return (reg[1] >> 5) & 1; +static inline int raid_cpu_has_avx512bw(void) +{ + /* + * Intel Architecture Instruction Set Extensions Programming Reference + * 319433-022 October 2014 + * + * 2.2 Detection of 512-bit Instruction Groups of Intel AVX-512 Family + * 1) Detect CPUID.1:ECX.OSXSAVE[bit 27] = 1 (XGETBV enabled for application use) + * 2) Execute XGETBV and verify that XCR0[7:5] = `111b' (OPMASK state, upper 256-bit of + * ZMM0-ZMM15 and ZMM16-ZMM31 state are enabled by OS) and that XCR0[2:1] = `11b' + * (XMM state and YMM state are enabled by OS). + * 3) Verify both CPUID.0x7.0:EBX.AVX512F[bit 16] = 1, CPUID.0x7.0:EBX.AVX512BW[bit 30] = 1. + */ + return raid_cpu_match_avx( + (1 << 27) | (1 << 28), /* XSAVE/XGETBV and AVX */ + (1 << 16) | (1 << 30), /* AVX512F and AVX512BW */ + (3 << 1) | (7 << 5)); /* OS saves XMM, YMM and ZMM registers */ } /**