/src/libreoffice/tools/source/misc/cpuid.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
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/. |
8 | | * |
9 | | */ |
10 | | |
11 | | #include <tools/cpuid.hxx> |
12 | | #include <cstdint> |
13 | | |
14 | | namespace cpuid |
15 | | { |
16 | | namespace |
17 | | { |
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) |
21 | | { |
22 | | __cpuid(reinterpret_cast<int*>(array), nInfoType); |
23 | | } |
24 | | #elif (defined(__i386__) || defined(__x86_64__)) |
25 | | #include <cpuid.h> |
26 | | void getCpuId(uint32_t array[4], uint32_t nInfoType) |
27 | 66 | { |
28 | 66 | __cpuid_count(nInfoType, 0, *(array + 0), *(array + 1), *(array + 2), *(array + 3)); |
29 | 66 | } |
30 | | #else |
31 | | void getCpuId(uint32_t array[4], uint32_t /*nInfoType*/) |
32 | | { |
33 | | array[0] = array[1] = array[2] = array[3] = 0; |
34 | | } |
35 | | #endif |
36 | | |
37 | | // For AVX we need to check if OS has support for ymm registers |
38 | | bool checkAVXSupportInOS() |
39 | 22 | { |
40 | 22 | 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 | 22 | #endif |
46 | 22 | return ((xcr0 & 6) == 6); /* checking if xmm and ymm state are enabled in XCR0 */ |
47 | 22 | } |
48 | | |
49 | | } // end anonymous namespace |
50 | | |
51 | 22 | #define HYPER_bit (1 << 28) |
52 | 22 | #define SSE2_bit (1 << 26) |
53 | 22 | #define SSSE3_bit (1 << 9) |
54 | 22 | #define SSE41_bit (1 << 19) |
55 | 22 | #define SSE42_bit (1 << 20) |
56 | 22 | #define XSAVE_bit (1 << 27) |
57 | 22 | #define AVX_bit (1 << 28) |
58 | 22 | #define AVX2_bit (1 << 5) |
59 | 22 | #define AVX512F_bit (1 << 16) |
60 | | |
61 | | InstructionSetFlags getCpuInstructionSetFlags() |
62 | 22 | { |
63 | 22 | InstructionSetFlags eInstructions = InstructionSetFlags::NONE; |
64 | | |
65 | 22 | uint32_t info[] = { 0, 0, 0, 0 }; |
66 | 22 | getCpuId(info, 0); |
67 | 22 | int nLevel = info[0]; |
68 | | |
69 | 22 | if (nLevel >= 1) |
70 | 22 | { |
71 | 22 | uint32_t aCpuInfoArray[] = { 0, 0, 0, 0 }; |
72 | 22 | getCpuId(aCpuInfoArray, 1); |
73 | | |
74 | 22 | if ((aCpuInfoArray[3] & HYPER_bit) != 0) |
75 | 22 | eInstructions |= InstructionSetFlags::HYPER; |
76 | | |
77 | 22 | if ((aCpuInfoArray[3] & SSE2_bit) != 0) |
78 | 22 | eInstructions |= InstructionSetFlags::SSE2; |
79 | | |
80 | 22 | if ((aCpuInfoArray[2] & SSSE3_bit) != 0) |
81 | 22 | eInstructions |= InstructionSetFlags::SSSE3; |
82 | | |
83 | 22 | if ((aCpuInfoArray[2] & SSE41_bit) != 0) |
84 | 22 | eInstructions |= InstructionSetFlags::SSE41; |
85 | | |
86 | 22 | if ((aCpuInfoArray[2] & SSE42_bit) != 0) |
87 | 22 | eInstructions |= InstructionSetFlags::SSE42; |
88 | | |
89 | 22 | if (((aCpuInfoArray[2] & AVX_bit) != 0) && ((aCpuInfoArray[2] & XSAVE_bit) != 0)) |
90 | 22 | { |
91 | 22 | if (checkAVXSupportInOS()) |
92 | 22 | { |
93 | 22 | eInstructions |= InstructionSetFlags::AVX; |
94 | | |
95 | 22 | if (nLevel >= 7) |
96 | 22 | { |
97 | 22 | uint32_t aExtendedInfo[] = { 0, 0, 0, 0 }; |
98 | 22 | getCpuId(aExtendedInfo, 7); |
99 | | |
100 | 22 | if ((aExtendedInfo[1] & AVX2_bit) != 0) |
101 | 22 | eInstructions |= InstructionSetFlags::AVX2; |
102 | 22 | if ((aExtendedInfo[1] & AVX512F_bit) != 0) |
103 | 0 | eInstructions |= InstructionSetFlags::AVX512F; |
104 | 22 | } |
105 | 22 | } |
106 | 22 | } |
107 | 22 | } |
108 | | |
109 | 22 | return eInstructions; |
110 | 22 | } |
111 | | |
112 | | bool isCpuInstructionSetSupported(InstructionSetFlags eInstructions) |
113 | 22 | { |
114 | 22 | static InstructionSetFlags eCPUFlags = getCpuInstructionSetFlags(); |
115 | 22 | return (eCPUFlags & eInstructions) == eInstructions; |
116 | 22 | } |
117 | | |
118 | | OUString instructionSetSupportedString() |
119 | 0 | { |
120 | 0 | OUString aString; |
121 | 0 | if (isCpuInstructionSetSupported(InstructionSetFlags::SSE2)) |
122 | 0 | aString += "SSE2 "; |
123 | 0 | if (isCpuInstructionSetSupported(InstructionSetFlags::SSSE3)) |
124 | 0 | aString += "SSSE3 "; |
125 | 0 | if (isCpuInstructionSetSupported(InstructionSetFlags::SSE41)) |
126 | 0 | aString += "SSE4.1 "; |
127 | 0 | if (isCpuInstructionSetSupported(InstructionSetFlags::SSE42)) |
128 | 0 | aString += "SSE4.2 "; |
129 | 0 | if (isCpuInstructionSetSupported(InstructionSetFlags::AVX)) |
130 | 0 | aString += "AVX "; |
131 | 0 | if (isCpuInstructionSetSupported(InstructionSetFlags::AVX2)) |
132 | 0 | aString += "AVX2 "; |
133 | 0 | if (isCpuInstructionSetSupported(InstructionSetFlags::AVX512F)) |
134 | 0 | aString += "AVX512F "; |
135 | 0 | return aString; |
136 | 0 | } |
137 | | |
138 | | } // end cpuid |
139 | | |
140 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |