Overte C++ Documentation
CPUDetect.h
1 //
2 // CPUDetect.h
3 // libraries/shared/src
4 //
5 // Created by Ken Cooke on 6/16/17.
6 // Copyright 2017 High Fidelity, Inc.
7 //
8 // Distributed under the Apache License, Version 2.0.
9 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10 //
11 
12 #ifndef hifi_CPUDetect_h
13 #define hifi_CPUDetect_h
14 
15 //
16 // Lightweight functions to detect SSE/AVX/AVX2/AVX512 support
17 //
18 
19 #define MASK_SSE3 (1 << 0) // SSE3
20 #define MASK_SSSE3 (1 << 9) // SSSE3
21 #define MASK_SSE41 (1 << 19) // SSE4.1
22 #define MASK_SSE42 ((1 << 20) | (1 << 23)) // SSE4.2 and POPCNT
23 #define MASK_OSXSAVE (1 << 27) // OSXSAVE
24 #define MASK_AVX ((1 << 27) | (1 << 28)) // OSXSAVE and AVX
25 #define MASK_AVX2 (1 << 5) // AVX2
26 
27 #define MASK_AVX512 ((1 << 16) | (1 << 17) | (1 << 28) | (1 << 30) | (1 << 31)) // AVX512 F,DQ,CD,BW,VL (SKX)
28 
29 #define MASK_XCR0_YMM ((1 << 1) | (1 << 2)) // XMM,YMM
30 #define MASK_XCR0_ZMM ((1 << 1) | (1 << 2) | (7 << 5)) // XMM,YMM,ZMM
31 
32 #if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__)
33 #define ARCH_X86
34 #endif
35 
36 #if defined(ARCH_X86) && defined(_MSC_VER)
37 
38 #include <intrin.h>
39 
40 // use MSVC intrinsics
41 #define cpuidex(info, eax, ecx) __cpuidex(info, eax, ecx)
42 #define xgetbv(ecx) _xgetbv(ecx)
43 
44 #elif defined(ARCH_X86) && defined(__GNUC__)
45 
46 #include <cpuid.h>
47 
48 // use GCC intrinics/asm
49 static inline void cpuidex(int info[4], int eax, int ecx) {
50  __cpuid_count(eax, ecx, info[0], info[1], info[2], info[3]);
51 }
52 
53 static inline unsigned long long xgetbv(unsigned int ecx){
54  unsigned int eax, edx;
55  __asm__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(ecx));
56  return ((unsigned long long)edx << 32) | eax;
57 }
58 
59 #else
60 
61 static inline void cpuidex(int info[4], int eax, int ecx) {
62  info[0] = 0;
63  info[1] = 0;
64  info[2] = 0;
65  info[3] = 0;
66 }
67 
68 static inline unsigned long long xgetbv(unsigned int ecx){
69  return 0ULL;
70 }
71 
72 #endif
73 
74 static inline bool cpuSupportsSSE3() {
75  int info[4];
76 
77  cpuidex(info, 0x1, 0);
78 
79  return ((info[2] & MASK_SSE3) == MASK_SSE3);
80 }
81 
82 static inline bool cpuSupportsSSSE3() {
83  int info[4];
84 
85  cpuidex(info, 0x1, 0);
86 
87  return ((info[2] & MASK_SSSE3) == MASK_SSSE3);
88 }
89 
90 static inline bool cpuSupportsSSE41() {
91  int info[4];
92 
93  cpuidex(info, 0x1, 0);
94 
95  return ((info[2] & MASK_SSE41) == MASK_SSE41);
96 }
97 
98 static inline bool cpuSupportsSSE42() {
99  int info[4];
100 
101  cpuidex(info, 0x1, 0);
102 
103  return ((info[2] & MASK_SSE42) == MASK_SSE42);
104 }
105 
106 static inline bool cpuSupportsAVX() {
107  int info[4];
108 
109  cpuidex(info, 0x1, 0);
110 
111  bool result = false;
112  if ((info[2] & MASK_AVX) == MASK_AVX) {
113 
114  // verify OS support for YMM state
115  if ((xgetbv(0) & MASK_XCR0_YMM) == MASK_XCR0_YMM) {
116  result = true;
117  }
118  }
119  return result;
120 }
121 
122 static inline bool cpuSupportsAVX2() {
123  int info[4];
124 
125  bool result = false;
126  if (cpuSupportsAVX()) {
127 
128  cpuidex(info, 0x7, 0);
129 
130  if ((info[1] & MASK_AVX2) == MASK_AVX2) {
131  result = true;
132  }
133  }
134  return result;
135 }
136 
137 static inline bool cpuSupportsAVX512() {
138  int info[4];
139 
140  cpuidex(info, 0x1, 0);
141 
142  bool result = false;
143  if ((info[2] & MASK_OSXSAVE) == MASK_OSXSAVE) {
144 
145  // verify OS support for ZMM state
146  if ((xgetbv(0) & MASK_XCR0_ZMM) == MASK_XCR0_ZMM) {
147 
148  cpuidex(info, 0x7, 0);
149 
150  if ((info[1] & MASK_AVX512) == MASK_AVX512) {
151  result = true;
152  }
153  }
154  }
155  return result;
156 }
157 
158 #endif // hifi_CPUDetect_h