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)))
259# define QT_FUNCTION_TARGET_STRING_BASELINE_RDRND
260 X86_BASELINE "," QT_FUNCTION_TARGET_STRING_RDRND
263static bool checkRdrndWorks()
noexcept;
265QT_FUNCTION_TARGET_BASELINE
266static int maxBasicCpuidSupported()
268#if defined(Q_CC_EMSCRIPTEN)
270#elif defined(Q_CC_GNU)
273# if Q_PROCESSOR_X86 < 5
275 long cpuid_supported;
279 "xor $0x00200000, %0\n"
285 :
"=a" (cpuid_supported),
"=r" (tmp1)
287 if (!cpuid_supported)
292 asm (
"xchg " PICreg
", %1\n"
294 "xchg " PICreg
", %1\n"
295 :
"=&a" (result),
"=&r" (tmp1)
299#elif defined(Q_OS_WIN)
304#elif defined(Q_CC_GHS)
305 unsigned int info[4];
313QT_FUNCTION_TARGET_BASELINE
314static void cpuidFeatures01(uint &ecx, uint &edx)
316#if defined(Q_CC_GNU) && !defined(Q_CC_EMSCRIPTEN)
318 asm (
"xchg " PICreg
", %2\n"
320 "xchg " PICreg
", %2\n"
321 :
"=&c" (ecx),
"=&d" (edx),
"=&r" (tmp1)
323#elif defined(Q_OS_WIN)
328#elif defined(Q_CC_GHS)
329 unsigned int info[4];
340inline void __cpuidex(
int info[4],
int, __int64) { memset(info, 0, 4*
sizeof(
int));}
343QT_FUNCTION_TARGET_BASELINE
344static void cpuidFeatures07_00(uint &ebx, uint &ecx, uint &edx)
346#if defined(Q_CC_GNU) && !defined(Q_CC_EMSCRIPTEN)
348 qregisteruint rcx = 0;
349 qregisteruint rdx = 0;
350 asm (
"xchg " PICreg
", %0\n"
352 "xchg " PICreg
", %0\n"
353 :
"=&r" (rbx),
"+&c" (rcx),
"+&d" (rdx)
358#elif defined(Q_OS_WIN)
360 __cpuidex(info, 7, 0);
364#elif defined(Q_CC_GHS)
365 unsigned int info[4];
366 __CPUIDEX(7, 0, info);
377QT_FUNCTION_TARGET_BASELINE
378#if defined(Q_OS_WIN) && !(defined(Q_CC_GNU) || defined(Q_CC_GHS))
380inline quint64 _xgetbv(__int64) {
return 0; }
382static void xgetbv(uint in, uint &eax, uint &edx)
384#if (defined(Q_CC_GNU) && !defined(Q_CC_EMSCRIPTEN)) || defined(Q_CC_GHS)
385 asm (
".byte 0x0F, 0x01, 0xD0"
386 :
"=a" (eax),
"=d" (edx)
388#elif defined(Q_OS_WIN)
389 quint64 result = _xgetbv(in);
399QT_FUNCTION_TARGET_BASELINE
400static quint64 adjustedXcr0(quint64 xcr0)
403
404
405
406
407
408
409
410
414 constexpr quint64 kHasAVX512F = Q_UINT64_C(0x0000004000000000);
415 constexpr quintptr commpage =
sizeof(
void *) > 4 ? Q_UINT64_C(0x00007fffffe00000) : 0xffff0000;
416 constexpr quintptr cpu_capabilities64 = commpage + 0x10;
417 quint64 capab = *
reinterpret_cast<quint64 *>(cpu_capabilities64);
418 if (capab & kHasAVX512F)
419 xcr0 |= XSave_Avx512State;
425QT_FUNCTION_TARGET_BASELINE
426static quint64 detectProcessorFeatures()
428 quint64 features = 0;
429 int cpuidLevel = maxBasicCpuidSupported();
430#if Q_PROCESSOR_X86 < 5
434 assert(cpuidLevel >= 1);
437 uint results[X86CpuidMaxLeaf] = {};
438 cpuidFeatures01(results[Leaf01ECX], results[Leaf01EDX]);
440 cpuidFeatures07_00(results[Leaf07_00EBX], results[Leaf07_00ECX], results[Leaf07_00EDX]);
443 for (uint i = 0; i < arraysize(x86_locators); ++i) {
444 uint word = x86_locators[i] / 32;
445 uint bit = 1U << (x86_locators[i] % 32);
446 quint64 feature = Q_UINT64_C(1) << i;
447 if (results[word] & bit)
453 if (results[Leaf01ECX] & (1u << 27)) {
455 uint xgetbvA = 0, xgetbvD = 0;
456 xgetbv(0, xgetbvA, xgetbvD);
459 if (
sizeof(XSaveBits) >
sizeof(xgetbvA))
460 xcr0 |= quint64(xgetbvD) << 32;
461 xcr0 = adjustedXcr0(xcr0);
464 for (
auto req : xsave_requirements) {
465 if ((xcr0 & req.xsave_state) != req.xsave_state)
466 features &= ~req.cpu_features;
469 if (features & CpuFeatureRDRND && !checkRdrndWorks())
470 features &= ~(CpuFeatureRDRND | CpuFeatureRDSEED);
475#elif defined(Q_PROCESSOR_MIPS_32)
477#if defined(Q_OS_LINUX)
486 static const int chunk_size = 256;
491 QSimpleBuffer() : data(
nullptr), alloc(0), size(0) { }
492 ~QSimpleBuffer() { ::free(data); }
494 void resize(
unsigned newsize)
496 if (newsize > alloc) {
497 unsigned newalloc = chunk_size * ((newsize / chunk_size) + 1);
498 if (newalloc < newsize)
500 if (newalloc != alloc) {
501 data =
static_cast<
char *>(::realloc(data, newalloc));
507 void append(
const QSimpleBuffer &other,
unsigned appendsize)
509 unsigned oldsize = size;
510 resize(oldsize + appendsize);
511 ::memcpy(data + oldsize, other.data, appendsize);
513 void popleft(
unsigned amount)
518 ::memmove(data, data + amount, size);
524 return (data[size] =
'\0', data);
534static void bufReadLine(
int fd, QSimpleBuffer &line, QSimpleBuffer &buffer)
537 char *newline =
static_cast<
char *>(::memchr(buffer.data,
'\n', buffer.size));
539 unsigned piece_size = newline - buffer.data + 1;
540 line.append(buffer, piece_size);
541 buffer.popleft(piece_size);
542 line.resize(line.size - 1);
545 if (buffer.size + QSimpleBuffer::chunk_size > buffer.alloc) {
546 int oldsize = buffer.size;
547 buffer.resize(buffer.size + QSimpleBuffer::chunk_size);
548 buffer.size = oldsize;
551 ::qt_safe_read(fd, buffer.data + buffer.size, QSimpleBuffer::chunk_size);
553 buffer.size += read_bytes;
563static bool procCpuinfoContains(
const char *prefix,
const char *string)
565 int cpuinfo_fd = ::qt_safe_open(
"/proc/cpuinfo", O_RDONLY);
566 if (cpuinfo_fd == -1)
569 unsigned string_len = ::strlen(string);
570 unsigned prefix_len = ::strlen(prefix);
571 QSimpleBuffer line, buffer;
572 bool present =
false;
575 bufReadLine(cpuinfo_fd, line, buffer);
576 char *colon =
static_cast<
char *>(::memchr(line.data,
':', line.size));
577 if (colon && line.size > prefix_len + string_len) {
578 if (!::strncmp(prefix, line.data, prefix_len)) {
580 if (line.data[prefix_len] ==
':' || ::isspace(line.data[prefix_len])) {
582 char *found = ::strstr(line.cString(), string);
583 if (found && ::isspace(found[-1]) &&
584 (::isspace(found[string_len]) || found[string_len] ==
'\0')) {
593 ::qt_safe_close(cpuinfo_fd);
598static inline quint64 detectProcessorFeatures()
603#if defined __mips_dsp
604 flags |= CpuFeatureDSP;
605# if defined __mips_dsp_rev && __mips_dsp_rev >= 2
606 flags |= CpuFeatureDSPR2;
607# elif defined(Q_OS_LINUX)
608 if (procCpuinfoContains(
"cpu model",
"MIPS 74Kc") || procCpuinfoContains(
"cpu model",
"MIPS 74Kf"))
609 flags |= CpuFeatureDSPR2;
611#elif defined(Q_OS_LINUX)
612 if (procCpuinfoContains(
"ASEs implemented",
"dsp")) {
613 flags |= CpuFeatureDSP;
614 if (procCpuinfoContains(
"cpu model",
"MIPS 74Kc") || procCpuinfoContains(
"cpu model",
"MIPS 74Kf"))
615 flags |= CpuFeatureDSPR2;
638 auto minFeatureTest = minFeature;
639#if defined(Q_PROCESSOR_X86_64) && defined(cpu_feature_shstk)
643 minFeatureTest &= ~CpuFeatureSHSTK;
648 if (
char *disable = getenv(
"QT_NO_CPU_FEATURE"); disable && *disable) {
649#if _POSIX_C_SOURCE
>= 200112L
650 char *saveptr =
nullptr;
651 auto strtok = [&saveptr](
char *str,
const char *delim) {
652 return ::strtok_r(str, delim, &saveptr);
655 while (
char *token = strtok(disable,
" ")) {
659 f &= ~(Q_UINT64_C(1) << i);
664#ifdef RUNNING_ON_VALGRIND
665 bool runningOnValgrind = RUNNING_ON_VALGRIND;
667 bool runningOnValgrind =
false;
669 if (Q_UNLIKELY(!runningOnValgrind && minFeatureTest != 0 && (f & minFeatureTest) != minFeatureTest)) {
670 quint64 missing = minFeatureTest & ~quint64(f);
671 fprintf(stderr,
"Incompatible processor. This Qt build requires the following features:\n ");
673 if (missing & (Q_UINT64_C(1) << i))
674 fprintf(stderr,
"%s", features_string + features_indices[i]);
676 fprintf(stderr,
"\n");
683 std::atomic_store_explicit(QT_MANGLE_NAMESPACE(qt_cpu_features), f, std::memory_order_relaxed);
690 quint64 features = detectProcessorFeatures() & ~SimdInitialized;
691 printf(
"Processor features: ");
693 if (features & (Q_UINT64_C(1) << i))
695 minFeature & (Q_UINT64_C(1) << i) ?
"[required]" :
"");
698 printf(
"\n!!!!!!!!!!!!!!!!!!!!\n!!! Missing required features:");
700 if (features & (Q_UINT64_C(1) << i))
703 printf(
"\n!!! Applications will likely crash with \"Invalid Instruction\"\n!!!!!!!!!!!!!!!!!!!!");
710# ifdef Q_PROCESSOR_X86_64
711# define _rdrandXX_step _rdrand64_step
712# define _rdseedXX_step _rdseed64_step
714# define _rdrandXX_step _rdrand32_step
715# define _rdseedXX_step _rdseed32_step
722template <
typename F>
struct ExtractParameter;
723template <
typename T>
struct ExtractParameter<
int (T *)> {
using Type = T; };
724using randuint = ExtractParameter<
decltype(_rdrandXX_step)>::Type;
727# if QT_COMPILER_SUPPORTS_HERE(RDSEED)
728static QT_FUNCTION_TARGET(RDSEED)
unsigned *qt_random_rdseed(
unsigned *ptr,
unsigned *end)
noexcept
735 while (ptr +
sizeof(randuint) /
sizeof(*ptr) <= end) {
736 if (_rdseedXX_step(
reinterpret_cast<randuint *>(ptr)) == 0)
738 ptr +=
sizeof(randuint) /
sizeof(*ptr);
741 if (
sizeof(*ptr) !=
sizeof(randuint) && ptr != end) {
742 if (_rdseed32_step(ptr) == 0)
751static unsigned *qt_random_rdseed(
unsigned *ptr,
unsigned *)
757static QT_FUNCTION_TARGET(RDRND)
unsigned *qt_random_rdrnd(
unsigned *ptr,
unsigned *end)
noexcept
760 while (ptr +
sizeof(randuint)/
sizeof(*ptr) <= end) {
761 if (_rdrandXX_step(
reinterpret_cast<randuint *>(ptr)))
762 ptr +=
sizeof(randuint)/
sizeof(*ptr);
763 else if (--retries == 0)
767 while (
sizeof(*ptr) !=
sizeof(randuint) && ptr != end) {
768 bool ok = _rdrand32_step(ptr);
769 if (!ok && --retries)
780QT_FUNCTION_TARGET(BASELINE_RDRND) Q_DECL_COLD_FUNCTION
781static bool checkRdrndWorks()
noexcept
784
785
786
787
788
789
790
791
792
793
794 constexpr qsizetype TestBufferSize = 4;
795 unsigned testBuffer[TestBufferSize] = {};
800 if (_compilerCpuFeatures & CpuFeatureRDRND)
803 unsigned *end = qt_random_rdrnd(testBuffer, testBuffer + TestBufferSize);
804 if (end < testBuffer + 3) {
812 if (testBuffer[0] == testBuffer[1]
813 && testBuffer[0] == testBuffer[2]
814 && (end < testBuffer + TestBufferSize || testBuffer[0] == testBuffer[3])) {
815 fprintf(stderr,
"WARNING: CPU random generator seem to be failing, "
816 "disabling hardware random number generation\n"
817 "WARNING: RDRND generated:");
818 for (
unsigned *ptr = testBuffer; ptr < end; ++ptr)
819 fprintf(stderr,
" 0x%x", *ptr);
820 fprintf(stderr,
"\n");
828QT_FUNCTION_TARGET(RDRND) qsizetype qRandomCpu(
void *buffer, qsizetype count)
noexcept
830 unsigned *ptr =
reinterpret_cast<
unsigned *>(buffer);
831 unsigned *end = ptr + count;
833 if (qCpuHasFeature(RDSEED))
834 ptr = qt_random_rdseed(ptr, end);
837 ptr = qt_random_rdrnd(ptr, end);
838 return ptr -
reinterpret_cast<
unsigned *>(buffer);
840#elif defined(Q_PROCESSOR_X86) && !defined(Q_PROCESSOR_ARM)
841static bool checkRdrndWorks()
noexcept {
return false; }
844#if QT_SUPPORTS_INIT_PRIORITY
846struct QSimdInitializer
848 inline QSimdInitializer() { QT_MANGLE_NAMESPACE(qDetectCpuFeatures)(); }
853Q_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
#define QT_COMPILER_SUPPORTS_HERE(x)
static const uint64_t qCompilerCpuFeatures