Version 7.3.5.2, tag libreoffice-7.3.5.2
[LibreOffice.git] / tools / source / misc / cpuid.cxx
blob855b87e6da630fc4fc5b2c985ea8e12005cb325a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 */
11 #include <tools/cpuid.hxx>
12 #include <cstdint>
14 namespace cpuid
16 namespace
18 #if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64))
19 #include <intrin.h>
20 void getCpuId(uint32_t array[4], uint32_t nInfoType)
22 __cpuid(reinterpret_cast<int*>(array), nInfoType);
24 #elif (defined(__i386__) || defined(__x86_64__))
25 #include <cpuid.h>
26 void getCpuId(uint32_t array[4], uint32_t nInfoType)
28 __cpuid_count(nInfoType, 0, *(array + 0), *(array + 1), *(array + 2), *(array + 3));
30 #else
31 void getCpuId(uint32_t array[4], uint32_t /*nInfoType*/)
33 array[0] = array[1] = array[2] = array[3] = 0;
35 #endif
37 // For AVX we need to check if OS has support for ymm registers
38 bool checkAVXSupportInOS()
40 uint32_t xcr0 = 0;
41 #if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64))
42 xcr0 = uint32_t(_xgetbv(0));
43 #elif (defined(__i386__) || defined(__x86_64__))
44 __asm__("xgetbv" : "=a"(xcr0) : "c"(0) : "%edx");
45 #endif
46 return ((xcr0 & 6) == 6); /* checking if xmm and ymm state are enabled in XCR0 */
49 } // end anonymous namespace
51 #define HYPER_bit (1 << 28)
52 #define SSE2_bit (1 << 26)
53 #define SSSE3_bit (1 << 9)
54 #define SSE41_bit (1 << 19)
55 #define SSE42_bit (1 << 20)
56 #define XSAVE_bit (1 << 27)
57 #define AVX_bit (1 << 28)
58 #define AVX2_bit (1 << 5)
59 #define AVX512F_bit (1 << 16)
61 InstructionSetFlags getCpuInstructionSetFlags()
63 InstructionSetFlags eInstructions = InstructionSetFlags::NONE;
65 uint32_t info[] = { 0, 0, 0, 0 };
66 getCpuId(info, 0);
67 int nLevel = info[0];
69 if (nLevel >= 1)
71 uint32_t aCpuInfoArray[] = { 0, 0, 0, 0 };
72 getCpuId(aCpuInfoArray, 1);
74 if ((aCpuInfoArray[3] & HYPER_bit) != 0)
75 eInstructions |= InstructionSetFlags::HYPER;
77 if ((aCpuInfoArray[3] & SSE2_bit) != 0)
78 eInstructions |= InstructionSetFlags::SSE2;
80 if ((aCpuInfoArray[2] & SSSE3_bit) != 0)
81 eInstructions |= InstructionSetFlags::SSSE3;
83 if ((aCpuInfoArray[2] & SSE41_bit) != 0)
84 eInstructions |= InstructionSetFlags::SSE41;
86 if ((aCpuInfoArray[2] & SSE42_bit) != 0)
87 eInstructions |= InstructionSetFlags::SSE42;
89 if (((aCpuInfoArray[2] & AVX_bit) != 0) && ((aCpuInfoArray[2] & XSAVE_bit) != 0))
91 if (checkAVXSupportInOS())
93 eInstructions |= InstructionSetFlags::AVX;
95 if (nLevel >= 7)
97 uint32_t aExtendedInfo[] = { 0, 0, 0, 0 };
98 getCpuId(aExtendedInfo, 7);
100 if ((aExtendedInfo[1] & AVX2_bit) != 0)
101 eInstructions |= InstructionSetFlags::AVX2;
102 if ((aExtendedInfo[1] & AVX512F_bit) != 0)
103 eInstructions |= InstructionSetFlags::AVX512F;
109 return eInstructions;
112 bool isCpuInstructionSetSupported(InstructionSetFlags eInstructions)
114 static InstructionSetFlags eCPUFlags = getCpuInstructionSetFlags();
115 return (eCPUFlags & eInstructions) == eInstructions;
118 OUString instructionSetSupportedString()
120 OUString aString;
121 if (isCpuInstructionSetSupported(InstructionSetFlags::SSE2))
122 aString += "SSE2 ";
123 if (isCpuInstructionSetSupported(InstructionSetFlags::SSSE3))
124 aString += "SSSE3 ";
125 if (isCpuInstructionSetSupported(InstructionSetFlags::SSE41))
126 aString += "SSE4.1 ";
127 if (isCpuInstructionSetSupported(InstructionSetFlags::SSE42))
128 aString += "SSE4.2 ";
129 if (isCpuInstructionSetSupported(InstructionSetFlags::AVX))
130 aString += "AVX ";
131 if (isCpuInstructionSetSupported(InstructionSetFlags::AVX2))
132 aString += "AVX2 ";
133 if (isCpuInstructionSetSupported(InstructionSetFlags::AVX512F))
134 aString += "AVX512F ";
135 return aString;
138 } // end cpuid
140 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */