diff options
author | Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk> | 2017-05-08 10:47:04 +0200 |
---|---|---|
committer | Tomaž Vajngerl <quikee@gmail.com> | 2019-07-09 02:46:43 +0200 |
commit | f43f9b99603736a4d54f550052509eb5f4d04b45 (patch) | |
tree | 96f8e17bc271471d54571d6ffce7146b6bcdb626 /tools/source | |
parent | f65905dd0ff464774f338db44d69925f98e1766c (diff) |
CPU intrinsics detection (SSE, AVX)
Adds CPU intrinsics detection in configure pass for compile time
detection and "cpuid" runtime detection of which CPU instruction
sets are available on the user device.
Change-Id: I0ee4d0b22a7c51f72796d43e7383a31d03b437ad
Reviewed-on: https://gerrit.libreoffice.org/75175
Tested-by: Jenkins
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
Diffstat (limited to 'tools/source')
-rw-r--r-- | tools/source/misc/cpuid.cxx | 119 |
1 files changed, 93 insertions, 26 deletions
diff --git a/tools/source/misc/cpuid.cxx b/tools/source/misc/cpuid.cxx index ee5093ce1892..e8699cbdf51c 100644 --- a/tools/source/misc/cpuid.cxx +++ b/tools/source/misc/cpuid.cxx @@ -11,25 +11,21 @@ #include <tools/cpuid.hxx> #include <cstdint> -namespace tools -{ -namespace cpuid -{ +namespace cpuid { + +namespace { -namespace -{ #if defined(_MSC_VER) #include <intrin.h> -void getCpuId(uint32_t array[4]) +void getCpuId(uint32_t array[4], uint32_t nInfoType) { - __cpuid(reinterpret_cast<int*>(array), 1); + __cpuid(reinterpret_cast<int*>(array), nInfoType); } -#else -#if (defined(__i386__) || defined(__x86_64__)) +#elif (defined(__i386__) || defined(__x86_64__)) #include <cpuid.h> -void getCpuId(uint32_t array[4]) +void getCpuId(uint32_t array[4], uint32_t nInfoType) { - __get_cpuid(1, array + 0, array + 1, array + 2, array + 3); + __cpuid_count(nInfoType, 0, *(array + 0), *(array + 1), *(array + 2), *(array + 3)); } #else void getCpuId(uint32_t array[4]) @@ -37,33 +33,104 @@ void getCpuId(uint32_t array[4]) array[0] = array[1] = array[2] = array[3] = 0; } #endif + +// For AVX we need to check if OS has support for ymm registers +bool checkAVXSupportInOS() +{ + uint32_t xcr0 = 0; +#if defined(_MSC_VER) + xcr0 = uint32_t(_xgetbv(0)); +#elif (defined(__i386__) || defined(__x86_64__)) + __asm__("xgetbv" : "=a" (xcr0) : "c" (0) : "%edx"); #endif + return ((xcr0 & 6) == 6); /* checking if xmm and ymm state are enabled in XCR0 */ } -#if defined(LO_SSE2_AVAILABLE) +} // end anonymous namespace -bool hasSSE2() +#define HYPER_bit (1 << 28) +#define SSE2_bit (1 << 26) +#define SSSE3_bit (1 << 9) +#define SSE41_bit (1 << 19) +#define SSE42_bit (1 << 20) +#define XSAVE_bit (1 << 27) +#define AVX_bit (1 << 28) +#define AVX2_bit (1 << 5) + +InstructionSetFlags getCpuInstructionSetFlags() { - uint32_t cpuInfoArray[] = {0, 0, 0, 0}; - getCpuId(cpuInfoArray); - return (cpuInfoArray[3] & (1 << 26)) != 0; -} + InstructionSetFlags eInstructions = InstructionSetFlags::NONE; -#else + uint32_t info[] = {0, 0, 0, 0}; + getCpuId(info, 0); + int nLevel = info[0]; -bool hasSSE2() { return false; } + if (nLevel >= 1) + { + uint32_t aCpuInfoArray[] = {0, 0, 0, 0}; + getCpuId(aCpuInfoArray, 1); -#endif + if ((aCpuInfoArray[3] & HYPER_bit) != 0) + eInstructions |= InstructionSetFlags::HYPER; -bool hasHyperThreading() -{ - uint32_t cpuInfoArray[] = {0, 0, 0, 0}; - getCpuId(cpuInfoArray); - return (cpuInfoArray[3] & (1 << 28)) != 0; + if ((aCpuInfoArray[3] & SSE2_bit) != 0) + eInstructions |= InstructionSetFlags::SSE2; + + if ((aCpuInfoArray[2] & SSSE3_bit) != 0) + eInstructions |= InstructionSetFlags::SSSE3; + + if ((aCpuInfoArray[2] & SSE41_bit ) != 0) + eInstructions |= InstructionSetFlags::SSE41; + + if ((aCpuInfoArray[2] & SSE42_bit) != 0) + eInstructions |= InstructionSetFlags::SSE42; + + if (((aCpuInfoArray[2] & AVX_bit) != 0) && + ((aCpuInfoArray[2] & XSAVE_bit) != 0)) + { + if (checkAVXSupportInOS()) + { + eInstructions |= InstructionSetFlags::AVX; + + if (nLevel >= 7) + { + uint32_t aExtendedInfo[] = {0, 0, 0, 0}; + getCpuId(aExtendedInfo, 7); + + if ((aExtendedInfo[1] & AVX2_bit) != 0) + eInstructions |= InstructionSetFlags::AVX2; + } + } + } + } + + return eInstructions; } +bool isCpuInstructionSetSupported(InstructionSetFlags eInstructions) +{ + static InstructionSetFlags eCPUFlags = getCpuInstructionSetFlags(); + return (eCPUFlags & eInstructions) == eInstructions; } + +OUString instructionSetSupportedString() +{ + OUString aString; + if (isCpuInstructionSetSupported(InstructionSetFlags::SSE2)) + aString += "SSE2 "; + if (isCpuInstructionSetSupported(InstructionSetFlags::SSSE3)) + aString += "SSSE3 "; + if (isCpuInstructionSetSupported(InstructionSetFlags::SSE41)) + aString += "SSE4.1 "; + if (isCpuInstructionSetSupported(InstructionSetFlags::SSE42)) + aString += "SSE4.2 "; + if (isCpuInstructionSetSupported(InstructionSetFlags::AVX)) + aString += "AVX "; + if (isCpuInstructionSetSupported(InstructionSetFlags::AVX2)) + aString += "AVX2 "; + return aString; } +} // end cpuid /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |