7#define __INTEL_COMPILER_USE_INTRINSIC_PROTOTYPES
16#if defined(QT_NO_DEBUG) && !defined(NDEBUG)
22# include "../testlib/3rdparty/valgrind/valgrind_p.h"
25#define QT_FUNCTION_TARGET_BASELINE
28# if !defined(Q_CC_GNU)
31# if defined(Q_PROCESSOR_ARM_64)
32# include <qt_windows.h>
33# include <processthreadsapi.h>
35#elif defined(Q_OS_LINUX) && defined(Q_PROCESSOR_MIPS_32)
36# include "private/qcore_unix_p.h"
37#elif QT_CONFIG(getauxval) && (defined(Q_PROCESSOR_ARM) || defined(Q_PROCESSOR_LOONGARCH))
44#define HWCAP_NEON 4096
47#define HWCAP2_AES (1
<< 0
)
48#define HWCAP2_CRC32 (1
<< 4
)
51#define HWCAP_AES (1
<< 3
)
52#define HWCAP_CRC32 (1
<< 7
)
53#define HWCAP_SVE (1
<< 22
)
59#elif defined(Q_CC_GHS)
60# include <INTEGRITY_types.h>
61#elif defined(Q_OS_DARWIN) && defined(Q_PROCESSOR_ARM)
62# include <sys/sysctl.h>
68uint arraysize(T (&)[N])
75#if defined(Q_PROCESSOR_ARM)
77
78
79
80
81
82static const char features_string[] =
88static const int features_indices[] = { 0, 1, 7, 14, 19 };
89#elif defined(Q_PROCESSOR_MIPS)
91
92
93
94static const char features_string[] =
99static const int features_indices[] = {
102#elif defined(Q_PROCESSOR_LOONGARCH)
104
105
106
107static const char features_string[] =
112static const int features_indices[] = {
115#elif defined(Q_PROCESSOR_X86)
116# include "qsimd_x86.cpp"
123#if defined(Q_PROCESSOR_ARM)
124static inline quint64 detectProcessorFeatures()
126 quint64 features = 0;
128#if QT_CONFIG(getauxval)
129 unsigned long auxvHwCap = getauxval(AT_HWCAP);
130 if (auxvHwCap != 0) {
131# if defined(Q_PROCESSOR_ARM_64)
133 features |= CpuFeatureNEON;
134 if (auxvHwCap & HWCAP_CRC32)
135 features |= CpuFeatureCRC32;
136 if (auxvHwCap & HWCAP_AES)
137 features |= CpuFeatureAES;
138 if (auxvHwCap & HWCAP_SVE)
139 features |= CpuFeatureSVE;
142 if (auxvHwCap & HWCAP_NEON)
143 features |= CpuFeatureNEON;
144 auxvHwCap = getauxval(AT_HWCAP2);
145 if (auxvHwCap & HWCAP2_CRC32)
146 features |= CpuFeatureCRC32;
147 if (auxvHwCap & HWCAP2_AES)
148 features |= CpuFeatureAES;
153#elif defined(Q_OS_DARWIN) && defined(Q_PROCESSOR_ARM)
155 size_t len =
sizeof(feature);
157#if defined(__ARM_NEON)
158 features |= CpuFeatureNEON;
160 #error "Misconfiguration, NEON should always be enabled on Apple hardware"
162#if defined(__ARM_FEATURE_CRC32)
163 features |= CpuFeatureCRC32;
164#elif defined(Q_OS_MACOS)
165 #error "Misconfiguration, CRC32 should always be enabled on Apple desktop hardware"
167 if (sysctlbyname(
"hw.optional.armv8_crc32", &feature, &len,
nullptr, 0) == 0)
168 features |= feature ? CpuFeatureCRC32 : 0;
170#if defined(__ARM_FEATURE_CRYPTO)
171 features |= CpuFeatureAES;
172#elif defined(Q_OS_MACOS)
173 #error "Misconfiguration, CRYPTO/AES should always be enabled on Apple desktop hardware"
175 if (sysctlbyname(
"hw.optional.arm.FEAT_AES", &feature, &len,
nullptr, 0) == 0)
176 features |= feature ? CpuFeatureAES : 0;
178#if defined(__ARM_FEATURE_SVE)
179 features |= CpuFeatureSVE;
181 if (sysctlbyname(
"hw.optional.arm.FEAT_SVE", &feature, &len,
nullptr, 0) == 0)
182 features |= feature ? CpuFeatureSVE : 0;
185#elif defined(Q_OS_WIN) && defined(Q_PROCESSOR_ARM_64)
186 features |= CpuFeatureNEON;
187 if (IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE) != 0)
188 features |= CpuFeatureCRC32;
189 if (IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) != 0)
190 features |= CpuFeatureAES;
193#if defined(__ARM_NEON__)
194 features |= CpuFeatureNEON;
196#if defined(__ARM_FEATURE_CRC32)
197 features |= CpuFeatureCRC32;
199#if defined(__ARM_FEATURE_CRYPTO)
200 features |= CpuFeatureAES;
202#if defined(__ARM_FEATURE_SVE)
203 features |= CpuFeatureSVE;
209#elif defined(Q_PROCESSOR_LOONGARCH)
210static inline quint64 detectProcessorFeatures()
212 quint64 features = 0;
213# if QT_CONFIG(getauxval)
214 quint64 hwcap = getauxval(AT_HWCAP);
216 if (hwcap & HWCAP_LOONGARCH_LSX)
217 features |= CpuFeatureLSX;
218 if (hwcap & HWCAP_LOONGARCH_LASX)
219 features |= CpuFeatureLASX;
221 enum LoongArchFeatures {
222 LOONGARCH_CFG2 = 0x2,
223 LOONGARCH_CFG2_LSX = (1 << 6),
224 LOONGARCH_CFG2_LASX = (1 << 7)
232 :
"r"(LOONGARCH_CFG2)
235 if (reg & LOONGARCH_CFG2_LSX)
236 features |= CpuFeatureLSX;
237 if (reg & LOONGARCH_CFG2_LASX)
238 features |= CpuFeatureLASX;
243#elif defined(Q_PROCESSOR_X86)
245#ifdef Q_PROCESSOR_X86_32
246# define PICreg "%%ebx"
248# define PICreg "%%rbx"
251# define X86_BASELINE "no-sse3"
253# define X86_BASELINE "no-sse"
256#if defined(Q_CC_GNU) || defined(Q_CC_CLANG)
258# undef QT_FUNCTION_TARGET_BASELINE
259# define QT_FUNCTION_TARGET_BASELINE __attribute__((target(X86_BASELINE)))
262QT_FUNCTION_TARGET_BASELINE
263static int maxBasicCpuidSupported()
265#if defined(Q_CC_EMSCRIPTEN)
267#elif defined(Q_CC_GNU)
270# if Q_PROCESSOR_X86 < 5
272 long cpuid_supported;
276 "xor $0x00200000, %0\n"
282 :
"=a" (cpuid_supported),
"=r" (tmp1)
284 if (!cpuid_supported)
289 asm (
"xchg " PICreg
", %1\n"
291 "xchg " PICreg
", %1\n"
292 :
"=&a" (result),
"=&r" (tmp1)
296#elif defined(Q_OS_WIN)
301#elif defined(Q_CC_GHS)
302 unsigned int info[4];
310QT_FUNCTION_TARGET_BASELINE
311static void cpuidFeatures01(uint &ecx, uint &edx)
313#if defined(Q_CC_GNU) && !defined(Q_CC_EMSCRIPTEN)
315 asm (
"xchg " PICreg
", %2\n"
317 "xchg " PICreg
", %2\n"
318 :
"=&c" (ecx),
"=&d" (edx),
"=&r" (tmp1)
320#elif defined(Q_OS_WIN)
325#elif defined(Q_CC_GHS)
326 unsigned int info[4];
337inline void __cpuidex(
int info[4],
int, __int64) { memset(info, 0, 4*
sizeof(
int));}
340QT_FUNCTION_TARGET_BASELINE
341static void cpuidFeatures07_00(uint &ebx, uint &ecx, uint &edx)
343#if defined(Q_CC_GNU) && !defined(Q_CC_EMSCRIPTEN)
345 qregisteruint rcx = 0;
346 qregisteruint rdx = 0;
347 asm (
"xchg " PICreg
", %0\n"
349 "xchg " PICreg
", %0\n"
350 :
"=&r" (rbx),
"+&c" (rcx),
"+&d" (rdx)
355#elif defined(Q_OS_WIN)
357 __cpuidex(info, 7, 0);
361#elif defined(Q_CC_GHS)
362 unsigned int info[4];
363 __CPUIDEX(7, 0, info);
374QT_FUNCTION_TARGET_BASELINE
375#if defined(Q_OS_WIN) && !(defined(Q_CC_GNU) || defined(Q_CC_GHS))
377inline quint64 _xgetbv(__int64) {
return 0; }
379static void xgetbv(uint in, uint &eax, uint &edx)
381#if (defined(Q_CC_GNU) && !defined(Q_CC_EMSCRIPTEN)) || defined(Q_CC_GHS)
382 asm (
".byte 0x0F, 0x01, 0xD0"
383 :
"=a" (eax),
"=d" (edx)
385#elif defined(Q_OS_WIN)
386 quint64 result = _xgetbv(in);
396QT_FUNCTION_TARGET_BASELINE
397static quint64 adjustedXcr0(quint64 xcr0)
400
401
402
403
404
405
406
407
411 constexpr quint64 kHasAVX512F = Q_UINT64_C(0x0000004000000000);
412 constexpr quintptr commpage =
sizeof(
void *) > 4 ? Q_UINT64_C(0x00007fffffe00000) : 0xffff0000;
413 constexpr quintptr cpu_capabilities64 = commpage + 0x10;
414 quint64 capab = *
reinterpret_cast<quint64 *>(cpu_capabilities64);
415 if (capab & kHasAVX512F)
416 xcr0 |= XSave_Avx512State;
422QT_FUNCTION_TARGET_BASELINE
423static quint64 detectProcessorFeatures()
425 quint64 features = 0;
426 int cpuidLevel = maxBasicCpuidSupported();
427#if Q_PROCESSOR_X86 < 5
431 assert(cpuidLevel >= 1);
434 uint results[X86CpuidMaxLeaf] = {};
435 cpuidFeatures01(results[Leaf01ECX], results[Leaf01EDX]);
437 cpuidFeatures07_00(results[Leaf07_00EBX], results[Leaf07_00ECX], results[Leaf07_00EDX]);
440 for (uint i = 0; i < arraysize(x86_locators); ++i) {
441 uint word = x86_locators[i] / 32;
442 uint bit = 1U << (x86_locators[i] % 32);
443 quint64 feature = Q_UINT64_C(1) << i;
444 if (results[word] & bit)
450 if (results[Leaf01ECX] & (1u << 27)) {
452 uint xgetbvA = 0, xgetbvD = 0;
453 xgetbv(0, xgetbvA, xgetbvD);
456 if (
sizeof(XSaveBits) >
sizeof(xgetbvA))
457 xcr0 |= quint64(xgetbvD) << 32;
458 xcr0 = adjustedXcr0(xcr0);
461 for (
auto req : xsave_requirements) {
462 if ((xcr0 & req.xsave_state) != req.xsave_state)
463 features &= ~req.cpu_features;
469#elif defined(Q_PROCESSOR_MIPS_32)
471#if defined(Q_OS_LINUX)
480 static const int chunk_size = 256;
485 QSimpleBuffer() : data(
nullptr), alloc(0), size(0) { }
486 ~QSimpleBuffer() { ::free(data); }
488 void resize(
unsigned newsize)
490 if (newsize > alloc) {
491 unsigned newalloc = chunk_size * ((newsize / chunk_size) + 1);
492 if (newalloc < newsize)
494 if (newalloc != alloc) {
495 data =
static_cast<
char *>(::realloc(data, newalloc));
501 void append(
const QSimpleBuffer &other,
unsigned appendsize)
503 unsigned oldsize = size;
504 resize(oldsize + appendsize);
505 ::memcpy(data + oldsize, other.data, appendsize);
507 void popleft(
unsigned amount)
512 ::memmove(data, data + amount, size);
518 return (data[size] =
'\0', data);
528static void bufReadLine(
int fd, QSimpleBuffer &line, QSimpleBuffer &buffer)
531 char *newline =
static_cast<
char *>(::memchr(buffer.data,
'\n', buffer.size));
533 unsigned piece_size = newline - buffer.data + 1;
534 line.append(buffer, piece_size);
535 buffer.popleft(piece_size);
536 line.resize(line.size - 1);
539 if (buffer.size + QSimpleBuffer::chunk_size > buffer.alloc) {
540 int oldsize = buffer.size;
541 buffer.resize(buffer.size + QSimpleBuffer::chunk_size);
542 buffer.size = oldsize;
545 ::qt_safe_read(fd, buffer.data + buffer.size, QSimpleBuffer::chunk_size);
547 buffer.size += read_bytes;
557static bool procCpuinfoContains(
const char *prefix,
const char *string)
559 int cpuinfo_fd = ::qt_safe_open(
"/proc/cpuinfo", O_RDONLY);
560 if (cpuinfo_fd == -1)
563 unsigned string_len = ::strlen(string);
564 unsigned prefix_len = ::strlen(prefix);
565 QSimpleBuffer line, buffer;
566 bool present =
false;
569 bufReadLine(cpuinfo_fd, line, buffer);
570 char *colon =
static_cast<
char *>(::memchr(line.data,
':', line.size));
571 if (colon && line.size > prefix_len + string_len) {
572 if (!::strncmp(prefix, line.data, prefix_len)) {
574 if (line.data[prefix_len] ==
':' || ::isspace(line.data[prefix_len])) {
576 char *found = ::strstr(line.cString(), string);
577 if (found && ::isspace(found[-1]) &&
578 (::isspace(found[string_len]) || found[string_len] ==
'\0')) {
587 ::qt_safe_close(cpuinfo_fd);
592static inline quint64 detectProcessorFeatures()
597#if defined __mips_dsp
598 flags |= CpuFeatureDSP;
599# if defined __mips_dsp_rev && __mips_dsp_rev >= 2
600 flags |= CpuFeatureDSPR2;
601# elif defined(Q_OS_LINUX)
602 if (procCpuinfoContains(
"cpu model",
"MIPS 74Kc") || procCpuinfoContains(
"cpu model",
"MIPS 74Kf"))
603 flags |= CpuFeatureDSPR2;
605#elif defined(Q_OS_LINUX)
606 if (procCpuinfoContains(
"ASEs implemented",
"dsp")) {
607 flags |= CpuFeatureDSP;
608 if (procCpuinfoContains(
"cpu model",
"MIPS 74Kc") || procCpuinfoContains(
"cpu model",
"MIPS 74Kf"))
609 flags |= CpuFeatureDSPR2;
632 auto minFeatureTest = minFeature;
633#if defined(Q_PROCESSOR_X86_64) && defined(cpu_feature_shstk)
637 minFeatureTest &= ~CpuFeatureSHSTK;
642 if (
char *disable = getenv(
"QT_NO_CPU_FEATURE"); disable && *disable) {
643#if _POSIX_C_SOURCE
>= 200112L
644 char *saveptr =
nullptr;
645 auto strtok = [&saveptr](
char *str,
const char *delim) {
646 return ::strtok_r(str, delim, &saveptr);
649 while (
char *token = strtok(disable,
" ")) {
653 f &= ~(Q_UINT64_C(1) << i);
658#ifdef RUNNING_ON_VALGRIND
659 bool runningOnValgrind = RUNNING_ON_VALGRIND;
661 bool runningOnValgrind =
false;
663 if (Q_UNLIKELY(!runningOnValgrind && minFeatureTest != 0 && (f & minFeatureTest) != minFeatureTest)) {
664 quint64 missing = minFeatureTest & ~quint64(f);
665 fprintf(stderr,
"Incompatible processor. This Qt build requires the following features:\n ");
667 if (missing & (Q_UINT64_C(1) << i))
670 fprintf(stderr,
"\n");
677 std::atomic_store_explicit(QT_MANGLE_NAMESPACE(qt_cpu_features), f,
std::memory_order_relaxed);
684 quint64 features = detectProcessorFeatures() & ~SimdInitialized;
685 printf(
"Processor features: ");
687 if (features & (Q_UINT64_C(1) << i))
689 minFeature & (Q_UINT64_C(1) << i) ?
"[required]" :
"");
692 printf(
"\n!!!!!!!!!!!!!!!!!!!!\n!!! Missing required features:");
694 if (features & (Q_UINT64_C(1) << i))
697 printf(
"\n!!! Applications will likely crash with \"Invalid Instruction\"\n!!!!!!!!!!!!!!!!!!!!");
702#if QT_SUPPORTS_INIT_PRIORITY
704struct QSimdInitializer
706 inline QSimdInitializer() { QT_MANGLE_NAMESPACE(qDetectCpuFeatures)(); }
711Q_DECL_INIT_PRIORITY(01)
static QSimdInitializer initializer;
#define QT_FUNCTION_TARGET_BASELINE
QT_FUNCTION_TARGET_BASELINE uint64_t QT_MANGLE_NAMESPACE qDetectCpuFeatures()
static constexpr auto SimdInitialized
static const int features_indices[]
static uint detectProcessorFeatures()
static const char features_string[]
static const quint64 minFeature
static const uint64_t qCompilerCpuFeatures