summaryrefslogtreecommitdiff
path: root/tools/source
diff options
context:
space:
mode:
Diffstat (limited to 'tools/source')
-rw-r--r--tools/source/misc/cpuid.cxx119
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: */