Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: CPL - Common Portability Library
4 : * Purpose: CPU features detection
5 : * Author: Even Rouault, <even dot rouault at spatialys dot com>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2016, Even Rouault <even dot rouault at spatialys dot com>
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "cpl_port.h"
14 : #include "cpl_string.h"
15 : #include "cpl_cpu_features.h"
16 :
17 : //! @cond Doxygen_Suppress
18 :
19 : #define CPUID_SSSE3_ECX_BIT 9
20 : #define CPUID_OSXSAVE_ECX_BIT 27
21 : #define CPUID_AVX_ECX_BIT 28
22 :
23 : #define CPUID_SSE_EDX_BIT 25
24 :
25 : #define BIT_XMM_STATE (1 << 1)
26 : #define BIT_YMM_STATE (2 << 1)
27 :
28 : #define REG_EAX 0
29 : #define REG_EBX 1
30 : #define REG_ECX 2
31 : #define REG_EDX 3
32 :
33 : #if defined(__GNUC__)
34 : #if defined(__x86_64)
35 : #define GCC_CPUID(level, a, b, c, d) \
36 : __asm__("xchgq %%rbx, %q1\n" \
37 : "cpuid\n" \
38 : "xchgq %%rbx, %q1" \
39 : : "=a"(a), "=r"(b), "=c"(c), "=d"(d) \
40 : : "0"(level))
41 : #else
42 : #define GCC_CPUID(level, a, b, c, d) \
43 : __asm__("xchgl %%ebx, %1\n" \
44 : "cpuid\n" \
45 : "xchgl %%ebx, %1" \
46 : : "=a"(a), "=r"(b), "=c"(c), "=d"(d) \
47 : : "0"(level))
48 : #endif
49 :
50 : #define CPL_CPUID(level, array) \
51 : GCC_CPUID(level, array[0], array[1], array[2], array[3])
52 :
53 : #elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
54 :
55 : #include <intrin.h>
56 : #define CPL_CPUID(level, array) __cpuid(array, level)
57 :
58 : #endif
59 :
60 : #if defined(HAVE_SSE_AT_COMPILE_TIME) && !defined(HAVE_INLINE_SSE)
61 :
62 : /************************************************************************/
63 : /* CPLHaveRuntimeSSE() */
64 : /************************************************************************/
65 :
66 : bool CPLHaveRuntimeSSE()
67 : {
68 : int cpuinfo[4] = {0, 0, 0, 0};
69 : CPL_CPUID(1, cpuinfo);
70 : return (cpuinfo[REG_EDX] & (1 << CPUID_SSE_EDX_BIT)) != 0;
71 : }
72 :
73 : #endif
74 :
75 : #if defined(HAVE_SSSE3_AT_COMPILE_TIME) && !defined(HAVE_INLINE_SSSE3)
76 :
77 : /************************************************************************/
78 : /* CPLHaveRuntimeSSSE3() */
79 : /************************************************************************/
80 :
81 249930 : static inline bool CPLDetectSSSE3()
82 : {
83 249930 : int cpuinfo[4] = {0, 0, 0, 0};
84 249930 : CPL_CPUID(1, cpuinfo);
85 249930 : return (cpuinfo[REG_ECX] & (1 << CPUID_SSSE3_ECX_BIT)) != 0;
86 : }
87 :
88 : #if defined(__GNUC__) && !defined(DEBUG)
89 : bool bCPLHasSSSE3 = false;
90 : static void CPLHaveRuntimeSSSE3Initialize() __attribute__((constructor));
91 :
92 : static void CPLHaveRuntimeSSSE3Initialize()
93 : {
94 : bCPLHasSSSE3 = CPLDetectSSSE3();
95 : }
96 : #else
97 249924 : bool CPLHaveRuntimeSSSE3()
98 : {
99 : #ifdef DEBUG
100 249924 : if (!CPLTestBool(CPLGetConfigOption("GDAL_USE_SSSE3", "YES")))
101 3 : return false;
102 : #endif
103 249930 : return CPLDetectSSSE3();
104 : }
105 : #endif
106 :
107 : #endif // defined(HAVE_SSSE3_AT_COMPILE_TIME) && !defined(HAVE_INLINE_SSSE3)
108 :
109 : #if defined(HAVE_AVX_AT_COMPILE_TIME) && !defined(HAVE_INLINE_AVX)
110 :
111 : /************************************************************************/
112 : /* CPLHaveRuntimeAVX() */
113 : /************************************************************************/
114 :
115 : #if defined(__GNUC__)
116 :
117 1315 : static bool CPLDetectRuntimeAVX()
118 : {
119 1315 : int cpuinfo[4] = {0, 0, 0, 0};
120 1315 : CPL_CPUID(1, cpuinfo);
121 :
122 : // Check OSXSAVE feature.
123 1315 : if ((cpuinfo[REG_ECX] & (1 << CPUID_OSXSAVE_ECX_BIT)) == 0)
124 : {
125 0 : return false;
126 : }
127 :
128 : // Check AVX feature.
129 1315 : if ((cpuinfo[REG_ECX] & (1 << CPUID_AVX_ECX_BIT)) == 0)
130 : {
131 0 : return false;
132 : }
133 :
134 : // Issue XGETBV and check the XMM and YMM state bit.
135 : unsigned int nXCRLow;
136 : unsigned int nXCRHigh;
137 1315 : __asm__("xgetbv" : "=a"(nXCRLow), "=d"(nXCRHigh) : "c"(0));
138 1315 : if ((nXCRLow & (BIT_XMM_STATE | BIT_YMM_STATE)) !=
139 : (BIT_XMM_STATE | BIT_YMM_STATE))
140 : {
141 0 : return false;
142 : }
143 1315 : CPL_IGNORE_RET_VAL(nXCRHigh); // unused
144 :
145 1315 : return true;
146 : }
147 :
148 : bool bCPLHasAVX = false;
149 : static void CPLHaveRuntimeAVXInitialize() __attribute__((constructor));
150 :
151 1315 : static void CPLHaveRuntimeAVXInitialize()
152 : {
153 1315 : bCPLHasAVX = CPLDetectRuntimeAVX();
154 1315 : }
155 :
156 : #elif defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 160040219) && \
157 : (defined(_M_IX86) || defined(_M_X64))
158 : // _xgetbv available only in Visual Studio 2010 SP1 or later
159 :
160 : bool CPLHaveRuntimeAVX()
161 : {
162 : int cpuinfo[4] = {0, 0, 0, 0};
163 : CPL_CPUID(1, cpuinfo);
164 :
165 : // Check OSXSAVE feature.
166 : if ((cpuinfo[REG_ECX] & (1 << CPUID_OSXSAVE_ECX_BIT)) == 0)
167 : {
168 : return false;
169 : }
170 :
171 : // Check AVX feature.
172 : if ((cpuinfo[REG_ECX] & (1 << CPUID_AVX_ECX_BIT)) == 0)
173 : {
174 : return false;
175 : }
176 :
177 : // Issue XGETBV and check the XMM and YMM state bit.
178 : unsigned __int64 xcrFeatureMask = _xgetbv(_XCR_XFEATURE_ENABLED_MASK);
179 : if ((xcrFeatureMask & (BIT_XMM_STATE | BIT_YMM_STATE)) !=
180 : (BIT_XMM_STATE | BIT_YMM_STATE))
181 : {
182 : return false;
183 : }
184 :
185 : return true;
186 : }
187 :
188 : #else
189 :
190 : bool CPLHaveRuntimeAVX()
191 : {
192 : return false;
193 : }
194 :
195 : #endif
196 :
197 : #endif // defined(HAVE_AVX_AT_COMPILE_TIME) && !defined(CPLHaveRuntimeAVX)
198 :
199 : //! @endcond
|