1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Copyright (C) 2012 Intel Corporation.
5 ** Contact: http://www.qt-project.org/
7 ** This file is part of the QtCore module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
41 ****************************************************************************/
48 # if defined(Q_OS_WINCE)
49 # include <qt_windows.h>
50 # include <cmnintrin.h>
52 # if !defined(Q_CC_GNU)
57 #elif defined(Q_OS_LINUX) && defined(__arm__)
58 #include "private/qcore_unix_p.h"
60 // the kernel header definitions for HWCAP_*
61 // (the ones we need/may need anyway)
63 // copied from <asm/hwcap.h> (ARM)
64 #define HWCAP_IWMMXT 512
65 #define HWCAP_CRUNCH 1024
66 #define HWCAP_THUMBEE 2048
67 #define HWCAP_NEON 4096
68 #define HWCAP_VFPv3 8192
69 #define HWCAP_VFPv3D16 16384
71 // copied from <linux/auxvec.h>
72 #define AT_HWCAP 16 /* arch dependent hints at CPU capabilities */
78 #if defined (Q_OS_NACL)
79 static inline uint detectProcessorFeatures()
83 #elif defined (Q_OS_WINCE)
84 static inline uint detectProcessorFeatures()
89 if (IsProcessorFeaturePresent(PF_ARM_INTEL_WMMX)) {
95 if (IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE))
97 if (IsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE))
105 #elif defined(Q_PROCESSOR_ARM) || defined(QT_HAVE_IWMMXT) || defined(QT_HAVE_NEON)
106 static inline uint detectProcessorFeatures()
110 #if defined(Q_OS_LINUX)
111 int auxv = qt_safe_open("/proc/self/auxv", O_RDONLY);
113 unsigned long vector[64];
115 while (features == 0) {
116 nread = qt_safe_read(auxv, (char *)vector, sizeof vector);
122 int max = nread / (sizeof vector[0]);
123 for (int i = 0; i < max; i += 2)
124 if (vector[i] == AT_HWCAP) {
125 if (vector[i+1] & HWCAP_IWMMXT)
127 if (vector[i+1] & HWCAP_NEON)
136 // fall back if /proc/self/auxv wasn't found
139 #if defined(QT_HAVE_IWMMXT)
140 // runtime detection only available when running as a previlegied process
142 #elif defined(QT_ALWAYS_HAVE_NEON)
149 #elif defined(Q_PROCESSOR_X86)
151 #ifdef Q_PROCESSOR_X86_32
152 # define PICreg "%%ebx"
154 # define PICreg "%%rbx"
157 static int maxBasicCpuidSupported()
159 #if defined(Q_CC_GNU)
162 # ifdef Q_PROCESSOR_X86_32
163 // check if the CPUID instruction is supported
164 long cpuid_supported;
168 "xor $0x00200000, %0\n"
173 "xor %1, %0\n" // %eax is now 0 if CPUID is not supported
174 : "=a" (cpuid_supported), "=r" (tmp1)
176 if (!cpuid_supported)
181 asm ("xchg " PICreg", %1\n"
183 "xchg " PICreg", %1\n"
184 : "=&a" (result), "=&r" (tmp1)
188 #elif defined(Q_OS_WIN)
189 // Use the __cpuid function; if the CPUID instruction isn't supported, it will return 0
198 static void cpuidFeatures01(uint &ecx, uint &edx)
200 #if defined(Q_CC_GNU)
202 asm ("xchg " PICreg", %2\n"
204 "xchg " PICreg", %2\n"
205 : "=&c" (ecx), "=&d" (edx), "=&r" (tmp1)
207 #elif defined(Q_OS_WIN)
216 inline void __cpuidex(int info[4], int, __int64) { memset(info, 0, 4*sizeof(int));}
219 static void cpuidFeatures07_00(uint &ebx)
221 #if defined(Q_CC_GNU)
222 quintptr rbx; // in case it's 64-bit
223 asm ("xchg " PICreg", %0\n"
225 "xchg " PICreg", %0\n"
230 #elif defined(Q_OS_WIN)
232 __cpuidex(info, 7, 0);
238 // fallback overload in case this intrinsic does not exist: unsigned __int64 _xgetbv(unsigned int);
239 inline quint64 _xgetbv(__int64) { return 0; }
241 static void xgetbv(uint in, uint &eax, uint &edx)
244 quint64 result = _xgetbv(in);
247 #elif defined(Q_CC_GNU)
248 asm (".byte 0x0F, 0x01, 0xD0" // xgetbv instruction
249 : "=a" (eax), "=d" (edx)
254 static inline uint detectProcessorFeatures()
257 int cpuidLevel = maxBasicCpuidSupported();
261 uint cpuid01ECX = 0, cpuid01EDX = 0;
262 cpuidFeatures01(cpuid01ECX, cpuid01EDX);
263 #if defined(Q_PROCESSOR_X86_32)
264 // x86 might not have SSE2 support
265 if (cpuid01EDX & (1u << 26))
272 // common part between 32- and 64-bit
273 if (cpuid01ECX & (1u))
275 if (cpuid01ECX & (1u << 9))
277 if (cpuid01ECX & (1u << 19))
279 if (cpuid01ECX & (1u << 20))
281 if (cpuid01ECX & (1u << 25))
282 features |= 0; // AES, enable if needed
284 uint xgetbvA = 0, xgetbvD = 0;
285 if (cpuid01ECX & (1u << 27)) {
287 xgetbv(0, xgetbvA, xgetbvD);
290 uint cpuid0700EBX = 0;
292 cpuidFeatures07_00(cpuid0700EBX);
294 if ((xgetbvA & 6) == 6) {
295 // support for YMM and XMM registers is enabled
296 if (cpuid01ECX & (1u << 28))
299 if (cpuid0700EBX & (1u << 5))
303 if (cpuid0700EBX & (1u << 4))
304 features |= HLE; // Hardware Lock Ellision
305 if (cpuid0700EBX & (1u << 11))
306 features |= RTM; // Restricted Transactional Memory
313 static inline uint detectProcessorFeatures()
320 * Use kdesdk/scripts/generate_string_table.pl to update the table below.
321 * Here's the data (don't forget the ONE leading space):
336 static const char features_string[] =
350 static const int features_indices[] = {
351 0, 8, 14, 20, 26, 33, 41, 49,
356 static const int features_count = (sizeof features_indices - 1) / (sizeof features_indices[0]);
358 static const uint minFeature = None
362 // don't define for HLE, since the HLE prefix can be run on older CPUs
369 #if defined __SSE4_2__
372 #if defined __SSE4_1__
375 #if defined __SSSE3__
384 #if defined __ARM_NEON__
387 #if defined __IWMMXT__
393 #if defined(Q_CC_GNU)
394 # define ffs __builtin_ffs
399 unsigned long result;
400 return _BitScanForward(&result, i) ? result : 0;
408 uint qDetectCPUFeatures()
410 static QBasicAtomicInt features = Q_BASIC_ATOMIC_INITIALIZER(-1);
411 if (features.load() != -1)
412 return features.load();
414 uint f = detectProcessorFeatures();
415 QByteArray disable = qgetenv("QT_NO_CPU_FEATURE");
416 if (!disable.isEmpty()) {
417 disable.prepend(' ');
418 for (int i = 0; i < features_count; ++i) {
419 if (disable.contains(features_string + features_indices[i]))
424 if (minFeature != 0 && (f & minFeature) != minFeature) {
425 uint missing = minFeature & ~f;
426 fprintf(stderr, "Incompatible processor. This Qt build requires the following features:\n ");
427 for (int i = 0; i < features_count; ++i) {
428 if (missing & (1 << i))
429 fprintf(stderr, "%s", features_string + features_indices[i]);
431 fprintf(stderr, "\n");
433 qFatal("Aborted. Incompatible processor: missing feature 0x%x -%s.", missing,
434 features_string + features_indices[ffs(missing) - 1]);
441 void qDumpCPUFeatures()
443 uint features = qDetectCPUFeatures();
444 printf("Processor features: ");
445 for (int i = 0; i < features_count; ++i) {
446 if (features & (1 << i))
447 printf("%s%s", features_string + features_indices[i],
448 minFeature & (1 << i) ? "[required]" : "");