6#define __INTEL_COMPILER_USE_INTRINSIC_PROTOTYPES
15#if defined(QT_NO_DEBUG) && !defined(NDEBUG)
21# include "../testlib/3rdparty/valgrind/valgrind_p.h"
24#define QT_FUNCTION_TARGET_BASELINE
27# if !defined(Q_CC_GNU)
30# if defined(Q_PROCESSOR_ARM_64)
31# include <qt_windows.h>
32# include <processthreadsapi.h>
34#elif defined(Q_OS_LINUX) && defined(Q_PROCESSOR_MIPS_32)
35# include "private/qcore_unix_p.h"
36#elif QT_CONFIG(getauxval) && (defined(Q_PROCESSOR_ARM) || defined(Q_PROCESSOR_LOONGARCH))
43#define HWCAP_NEON 4096
46#define HWCAP2_AES (1
<< 0
)
47#define HWCAP2_CRC32 (1
<< 4
)
50#define HWCAP_AES (1
<< 3
)
51#define HWCAP_CRC32 (1
<< 7
)
52#define HWCAP_SVE (1
<< 22
)
58#elif defined(Q_CC_GHS)
59# include <INTEGRITY_types.h>
60#elif defined(Q_OS_DARWIN) && defined(Q_PROCESSOR_ARM)
61# include <sys/sysctl.h>
67uint arraysize(T (&)[N])
74#if defined(Q_PROCESSOR_ARM)
76
77
78
79
80
81static const char features_string[] =
87static const int features_indices[] = { 0, 1, 7, 14, 19 };
88#elif defined(Q_PROCESSOR_MIPS)
90
91
92
93static const char features_string[] =
98static const int features_indices[] = {
101#elif defined(Q_PROCESSOR_LOONGARCH)
103
104
105
106static const char features_string[] =
111static const int features_indices[] = {
114#elif defined(Q_PROCESSOR_X86)
115# include "qsimd_x86.cpp"
122#if defined(Q_PROCESSOR_ARM)
123static inline quint64 detectProcessorFeatures()
125 quint64 features = 0;
127#if QT_CONFIG(getauxval)
128 unsigned long auxvHwCap = getauxval(AT_HWCAP);
129 if (auxvHwCap != 0) {
130# if defined(Q_PROCESSOR_ARM_64)
132 features |= CpuFeatureNEON;
133 if (auxvHwCap & HWCAP_CRC32)
134 features |= CpuFeatureCRC32;
135 if (auxvHwCap & HWCAP_AES)
136 features |= CpuFeatureAES;
137 if (auxvHwCap & HWCAP_SVE)
138 features |= CpuFeatureSVE;
141 if (auxvHwCap & HWCAP_NEON)
142 features |= CpuFeatureNEON;
143 auxvHwCap = getauxval(AT_HWCAP2);
144 if (auxvHwCap & HWCAP2_CRC32)
145 features |= CpuFeatureCRC32;
146 if (auxvHwCap & HWCAP2_AES)
147 features |= CpuFeatureAES;
152#elif defined(Q_OS_DARWIN) && defined(Q_PROCESSOR_ARM)
154 size_t len =
sizeof(feature);
156#if defined(__ARM_NEON)
157 features |= CpuFeatureNEON;
159 #error "Misconfiguration, NEON should always be enabled on Apple hardware"
161#if defined(__ARM_FEATURE_CRC32)
162 features |= CpuFeatureCRC32;
163#elif defined(Q_OS_MACOS)
164 #error "Misconfiguration, CRC32 should always be enabled on Apple desktop hardware"
166 if (sysctlbyname(
"hw.optional.armv8_crc32", &feature, &len,
nullptr, 0) == 0)
167 features |= feature ? CpuFeatureCRC32 : 0;
169#if defined(__ARM_FEATURE_CRYPTO)
170 features |= CpuFeatureAES;
171#elif defined(Q_OS_MACOS)
172 #error "Misconfiguration, CRYPTO/AES should always be enabled on Apple desktop hardware"
174 if (sysctlbyname(
"hw.optional.arm.FEAT_AES", &feature, &len,
nullptr, 0) == 0)
175 features |= feature ? CpuFeatureAES : 0;
177#if defined(__ARM_FEATURE_SVE)
178 features |= CpuFeatureSVE;
180 if (sysctlbyname(
"hw.optional.arm.FEAT_SVE", &feature, &len,
nullptr, 0) == 0)
181 features |= feature ? CpuFeatureSVE : 0;
184#elif defined(Q_OS_WIN) && defined(Q_PROCESSOR_ARM_64)
185 features |= CpuFeatureNEON;
186 if (IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE) != 0)
187 features |= CpuFeatureCRC32;
188 if (IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) != 0)
189 features |= CpuFeatureAES;
192#if defined(__ARM_NEON__)
193 features |= CpuFeatureNEON;
195#if defined(__ARM_FEATURE_CRC32)
196 features |= CpuFeatureCRC32;
198#if defined(__ARM_FEATURE_CRYPTO)
199 features |= CpuFeatureAES;
201#if defined(__ARM_FEATURE_SVE)
202 features |= CpuFeatureSVE;
208#elif defined(Q_PROCESSOR_LOONGARCH)
209static inline quint64 detectProcessorFeatures()
211 quint64 features = 0;
212# if QT_CONFIG(getauxval)
213 quint64 hwcap = getauxval(AT_HWCAP);
215 if (hwcap & HWCAP_LOONGARCH_LSX)
216 features |= CpuFeatureLSX;
217 if (hwcap & HWCAP_LOONGARCH_LASX)
218 features |= CpuFeatureLASX;
220 enum LoongArchFeatures {
221 LOONGARCH_CFG2 = 0x2,
222 LOONGARCH_CFG2_LSX = (1 << 6),
223 LOONGARCH_CFG2_LASX = (1 << 7)
231 :
"r"(LOONGARCH_CFG2)
234 if (reg & LOONGARCH_CFG2_LSX)
235 features |= CpuFeatureLSX;
236 if (reg & LOONGARCH_CFG2_LASX)
237 features |= CpuFeatureLASX;
242#elif defined(Q_PROCESSOR_X86)
244#ifdef Q_PROCESSOR_X86_32
245# define PICreg "%%ebx"
247# define PICreg "%%rbx"
250# define X86_BASELINE "no-sse3"
252# define X86_BASELINE "no-sse"
255#if defined(Q_CC_GNU) || defined(Q_CC_CLANG)
257# undef QT_FUNCTION_TARGET_BASELINE
258# define QT_FUNCTION_TARGET_BASELINE __attribute__((target(X86_BASELINE)))
261QT_FUNCTION_TARGET_BASELINE
262static int maxBasicCpuidSupported()
264#if defined(Q_CC_EMSCRIPTEN)
266#elif defined(Q_CC_GNU)
269# if Q_PROCESSOR_X86 < 5
271 long cpuid_supported;
275 "xor $0x00200000, %0\n"
281 :
"=a" (cpuid_supported),
"=r" (tmp1)
283 if (!cpuid_supported)
288 asm (
"xchg " PICreg
", %1\n"
290 "xchg " PICreg
", %1\n"
291 :
"=&a" (result),
"=&r" (tmp1)
295#elif defined(Q_OS_WIN)
300#elif defined(Q_CC_GHS)
301 unsigned int info[4];
309QT_FUNCTION_TARGET_BASELINE
310static void cpuidFeatures01(uint &ecx, uint &edx)
312#if defined(Q_CC_GNU) && !defined(Q_CC_EMSCRIPTEN)
314 asm (
"xchg " PICreg
", %2\n"
316 "xchg " PICreg
", %2\n"
317 :
"=&c" (ecx),
"=&d" (edx),
"=&r" (tmp1)
319#elif defined(Q_OS_WIN)
324#elif defined(Q_CC_GHS)
325 unsigned int info[4];
336inline void __cpuidex(
int info[4],
int, __int64) { memset(info, 0, 4*
sizeof(
int));}
339QT_FUNCTION_TARGET_BASELINE
340static void cpuidFeatures07_00(uint &ebx, uint &ecx, uint &edx)
342#if defined(Q_CC_GNU) && !defined(Q_CC_EMSCRIPTEN)
344 qregisteruint rcx = 0;
345 qregisteruint rdx = 0;
346 asm (
"xchg " PICreg
", %0\n"
348 "xchg " PICreg
", %0\n"
349 :
"=&r" (rbx),
"+&c" (rcx),
"+&d" (rdx)
354#elif defined(Q_OS_WIN)
356 __cpuidex(info, 7, 0);
360#elif defined(Q_CC_GHS)
361 unsigned int info[4];
362 __CPUIDEX(7, 0, info);
373QT_FUNCTION_TARGET_BASELINE
374#if defined(Q_OS_WIN) && !(defined(Q_CC_GNU) || defined(Q_CC_GHS))
376inline quint64 _xgetbv(__int64) {
return 0; }
378static void xgetbv(uint in, uint &eax, uint &edx)
380#if (defined(Q_CC_GNU) && !defined(Q_CC_EMSCRIPTEN)) || defined(Q_CC_GHS)
381 asm (
".byte 0x0F, 0x01, 0xD0"
382 :
"=a" (eax),
"=d" (edx)
384#elif defined(Q_OS_WIN)
385 quint64 result = _xgetbv(in);
395QT_FUNCTION_TARGET_BASELINE
396static quint64 adjustedXcr0(quint64 xcr0)
399
400
401
402
403
404
405
406
410 constexpr quint64 kHasAVX512F = Q_UINT64_C(0x0000004000000000);
411 constexpr quintptr commpage =
sizeof(
void *) > 4 ? Q_UINT64_C(0x00007fffffe00000) : 0xffff0000;
412 constexpr quintptr cpu_capabilities64 = commpage + 0x10;
413 quint64 capab = *
reinterpret_cast<quint64 *>(cpu_capabilities64);
414 if (capab & kHasAVX512F)
415 xcr0 |= XSave_Avx512State;
421QT_FUNCTION_TARGET_BASELINE
422static quint64 detectProcessorFeatures()
424 quint64 features = 0;
425 int cpuidLevel = maxBasicCpuidSupported();
426#if Q_PROCESSOR_X86 < 5
430 assert(cpuidLevel >= 1);
433 uint results[X86CpuidMaxLeaf] = {};
434 cpuidFeatures01(results[Leaf01ECX], results[Leaf01EDX]);
436 cpuidFeatures07_00(results[Leaf07_00EBX], results[Leaf07_00ECX], results[Leaf07_00EDX]);
439 for (uint i = 0; i < arraysize(x86_locators); ++i) {
440 uint word = x86_locators[i] / 32;
441 uint bit = 1U << (x86_locators[i] % 32);
442 quint64 feature = Q_UINT64_C(1) << i;
443 if (results[word] & bit)
449 if (results[Leaf01ECX] & (1u << 27)) {
451 uint xgetbvA = 0, xgetbvD = 0;
452 xgetbv(0, xgetbvA, xgetbvD);
455 if (
sizeof(XSaveBits) >
sizeof(xgetbvA))
456 xcr0 |= quint64(xgetbvD) << 32;
457 xcr0 = adjustedXcr0(xcr0);
460 for (
auto req : xsave_requirements) {
461 if ((xcr0 & req.xsave_state) != req.xsave_state)
462 features &= ~req.cpu_features;
468#elif defined(Q_PROCESSOR_MIPS_32)
470#if defined(Q_OS_LINUX)
479 static const int chunk_size = 256;
484 QSimpleBuffer() : data(
nullptr), alloc(0), size(0) { }
485 ~QSimpleBuffer() { ::free(data); }
487 void resize(
unsigned newsize)
489 if (newsize > alloc) {
490 unsigned newalloc = chunk_size * ((newsize / chunk_size) + 1);
491 if (newalloc < newsize)
493 if (newalloc != alloc) {
494 data =
static_cast<
char *>(::realloc(data, newalloc));
500 void append(
const QSimpleBuffer &other,
unsigned appendsize)
502 unsigned oldsize = size;
503 resize(oldsize + appendsize);
504 ::memcpy(data + oldsize, other.data, appendsize);
506 void popleft(
unsigned amount)
511 ::memmove(data, data + amount, size);
517 return (data[size] =
'\0', data);
527static void bufReadLine(
int fd, QSimpleBuffer &line, QSimpleBuffer &buffer)
530 char *newline =
static_cast<
char *>(::memchr(buffer.data,
'\n', buffer.size));
532 unsigned piece_size = newline - buffer.data + 1;
533 line.append(buffer, piece_size);
534 buffer.popleft(piece_size);
535 line.resize(line.size - 1);
538 if (buffer.size + QSimpleBuffer::chunk_size > buffer.alloc) {
539 int oldsize = buffer.size;
540 buffer.resize(buffer.size + QSimpleBuffer::chunk_size);
541 buffer.size = oldsize;
544 ::qt_safe_read(fd, buffer.data + buffer.size, QSimpleBuffer::chunk_size);
546 buffer.size += read_bytes;
556static bool procCpuinfoContains(
const char *prefix,
const char *string)
558 int cpuinfo_fd = ::qt_safe_open(
"/proc/cpuinfo", O_RDONLY);
559 if (cpuinfo_fd == -1)
562 unsigned string_len = ::strlen(string);
563 unsigned prefix_len = ::strlen(prefix);
564 QSimpleBuffer line, buffer;
565 bool present =
false;
568 bufReadLine(cpuinfo_fd, line, buffer);
569 char *colon =
static_cast<
char *>(::memchr(line.data,
':', line.size));
570 if (colon && line.size > prefix_len + string_len) {
571 if (!::strncmp(prefix, line.data, prefix_len)) {
573 if (line.data[prefix_len] ==
':' || ::isspace(line.data[prefix_len])) {
575 char *found = ::strstr(line.cString(), string);
576 if (found && ::isspace(found[-1]) &&
577 (::isspace(found[string_len]) || found[string_len] ==
'\0')) {
586 ::qt_safe_close(cpuinfo_fd);
591static inline quint64 detectProcessorFeatures()
596#if defined __mips_dsp
597 flags |= CpuFeatureDSP;
598# if defined __mips_dsp_rev && __mips_dsp_rev >= 2
599 flags |= CpuFeatureDSPR2;
600# elif defined(Q_OS_LINUX)
601 if (procCpuinfoContains(
"cpu model",
"MIPS 74Kc") || procCpuinfoContains(
"cpu model",
"MIPS 74Kf"))
602 flags |= CpuFeatureDSPR2;
604#elif defined(Q_OS_LINUX)
605 if (procCpuinfoContains(
"ASEs implemented",
"dsp")) {
606 flags |= CpuFeatureDSP;
607 if (procCpuinfoContains(
"cpu model",
"MIPS 74Kc") || procCpuinfoContains(
"cpu model",
"MIPS 74Kf"))
608 flags |= CpuFeatureDSPR2;
631 auto minFeatureTest = minFeature;
632#if defined(Q_PROCESSOR_X86_64) && defined(cpu_feature_shstk)
636 minFeatureTest &= ~CpuFeatureSHSTK;
641 if (
char *disable = getenv(
"QT_NO_CPU_FEATURE"); disable && *disable) {
642#if _POSIX_C_SOURCE
>= 200112L
643 char *saveptr =
nullptr;
644 auto strtok = [&saveptr](
char *str,
const char *delim) {
645 return ::strtok_r(str, delim, &saveptr);
648 while (
char *token = strtok(disable,
" ")) {
652 f &= ~(Q_UINT64_C(1) << i);
657#ifdef RUNNING_ON_VALGRIND
658 bool runningOnValgrind = RUNNING_ON_VALGRIND;
660 bool runningOnValgrind =
false;
662 if (Q_UNLIKELY(!runningOnValgrind && minFeatureTest != 0 && (f & minFeatureTest) != minFeatureTest)) {
663 quint64 missing = minFeatureTest & ~quint64(f);
664 fprintf(stderr,
"Incompatible processor. This Qt build requires the following features:\n ");
666 if (missing & (Q_UINT64_C(1) << i))
669 fprintf(stderr,
"\n");
676 std::atomic_store_explicit(QT_MANGLE_NAMESPACE(qt_cpu_features), f,
std::memory_order_relaxed);
683 quint64 features = detectProcessorFeatures() & ~SimdInitialized;
684 printf(
"Processor features: ");
686 if (features & (Q_UINT64_C(1) << i))
688 minFeature & (Q_UINT64_C(1) << i) ?
"[required]" :
"");
691 printf(
"\n!!!!!!!!!!!!!!!!!!!!\n!!! Missing required features:");
693 if (features & (Q_UINT64_C(1) << i))
696 printf(
"\n!!! Applications will likely crash with \"Invalid Instruction\"\n!!!!!!!!!!!!!!!!!!!!");
701#if QT_SUPPORTS_INIT_PRIORITY
703struct QSimdInitializer
705 inline QSimdInitializer() { QT_MANGLE_NAMESPACE(qDetectCpuFeatures)(); }
710Q_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