Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qsimd.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// Copyright (C) 2022 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5// we need ICC to define the prototype for _rdseed64_step
6#define __INTEL_COMPILER_USE_INTRINSIC_PROTOTYPES
7#undef _FORTIFY_SOURCE // otherwise, the always_inline from stdio.h fail to inline
8
9#include "qsimd_p.h"
10#include "qalgorithms.h"
11
12#include <stdio.h>
13#include <string.h>
14
15#if defined(QT_NO_DEBUG) && !defined(NDEBUG)
16# define NDEBUG
17#endif
18#include <assert.h>
19
20#ifdef Q_OS_LINUX
21# include "../testlib/3rdparty/valgrind_p.h"
22#endif
23
24#define QT_FUNCTION_TARGET_BASELINE
25
26#if defined(Q_OS_WIN)
27# if !defined(Q_CC_GNU)
28# include <intrin.h>
29# endif
30# if defined(Q_PROCESSOR_ARM_64)
31# include <qt_windows.h>
32# include <processthreadsapi.h>
33# endif
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)
37# include <sys/auxv.h>
38
39// the kernel header definitions for HWCAP_*
40// (the ones we need/may need anyway)
41
42// copied from <asm/hwcap.h> (ARM)
43#define HWCAP_NEON 4096
44
45// copied from <asm/hwcap.h> (ARM):
46#define HWCAP2_AES (1 << 0)
47#define HWCAP2_CRC32 (1 << 4)
48
49// copied from <asm/hwcap.h> (Aarch64)
50#define HWCAP_AES (1 << 3)
51#define HWCAP_CRC32 (1 << 7)
52
53// copied from <linux/auxvec.h>
54#define AT_HWCAP 16 /* arch dependent hints at CPU capabilities */
55#define AT_HWCAP2 26 /* extension of AT_HWCAP */
56
57#elif defined(Q_CC_GHS)
58# include <INTEGRITY_types.h>
59#elif defined(Q_OS_DARWIN) && defined(Q_PROCESSOR_ARM)
60# include <sys/sysctl.h>
61#endif
62
64
65template <typename T, uint N> QT_FUNCTION_TARGET_BASELINE
66uint arraysize(T (&)[N])
67{
68 // Same as std::size, but with QT_FUNCTION_TARGET_BASELIE,
69 // otherwise some versions of GCC fail to compile.
70 return N;
71}
72
73#if defined(Q_PROCESSOR_ARM)
74/* Data:
75 neon
76 crc32
77 aes
78 */
79static const char features_string[] =
80 "\0"
81 " neon\0"
82 " crc32\0"
83 " aes\0";
84static const int features_indices[] = { 0, 1, 7, 14 };
85#elif defined(Q_PROCESSOR_MIPS)
86/* Data:
87 dsp
88 dspr2
89*/
90static const char features_string[] =
91 "\0"
92 " dsp\0"
93 " dspr2\0";
94
95static const int features_indices[] = {
96 0, 1, 6
97};
98#elif defined(Q_PROCESSOR_X86)
99# include "qsimd_x86.cpp" // generated by util/x86simdgen
100#else
101static const char features_string[] = "";
102static const int features_indices[] = { 0 };
103#endif
104// end generated
105
106#if defined(Q_PROCESSOR_ARM)
107static inline quint64 detectProcessorFeatures()
108{
109 quint64 features = 0;
110
111#if QT_CONFIG(getauxval)
112 unsigned long auxvHwCap = getauxval(AT_HWCAP);
113 if (auxvHwCap != 0) {
114# if defined(Q_PROCESSOR_ARM_64)
115 // For Aarch64:
116 features |= CpuFeatureNEON; // NEON is always available
117 if (auxvHwCap & HWCAP_CRC32)
118 features |= CpuFeatureCRC32;
119 if (auxvHwCap & HWCAP_AES)
120 features |= CpuFeatureAES;
121# else
122 // For ARM32:
123 if (auxvHwCap & HWCAP_NEON)
124 features |= CpuFeatureNEON;
125 auxvHwCap = getauxval(AT_HWCAP2);
126 if (auxvHwCap & HWCAP2_CRC32)
127 features |= CpuFeatureCRC32;
128 if (auxvHwCap & HWCAP2_AES)
129 features |= CpuFeatureAES;
130# endif
131 return features;
132 }
133 // fall back to compile-time flags if getauxval failed
134#elif defined(Q_OS_DARWIN) && defined(Q_PROCESSOR_ARM)
135 unsigned feature;
136 size_t len = sizeof(feature);
137 if (sysctlbyname("hw.optional.neon", &feature, &len, nullptr, 0) == 0)
138 features |= feature ? CpuFeatureNEON : 0;
139 if (sysctlbyname("hw.optional.armv8_crc32", &feature, &len, nullptr, 0) == 0)
140 features |= feature ? CpuFeatureCRC32 : 0;
141 // There is currently no optional value for crypto/AES.
142#if defined(__ARM_FEATURE_CRYPTO)
143 features |= CpuFeatureAES;
144#endif
145 return features;
146#elif defined(Q_OS_WIN) && defined(Q_PROCESSOR_ARM_64)
147 features |= CpuFeatureNEON;
148 if (IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE) != 0)
149 features |= CpuFeatureCRC32;
150 if (IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) != 0)
151 features |= CpuFeatureAES;
152 return features;
153#endif
154#if defined(__ARM_NEON__) || defined(__ARM_NEON)
155 features |= CpuFeatureNEON;
156#endif
157#if defined(__ARM_FEATURE_CRC32)
158 features |= CpuFeatureCRC32;
159#endif
160#if defined(__ARM_FEATURE_CRYPTO)
161 features |= CpuFeatureAES;
162#endif
163
164 return features;
165}
166
167#elif defined(Q_PROCESSOR_X86)
168
169#ifdef Q_PROCESSOR_X86_32
170# define PICreg "%%ebx"
171#else
172# define PICreg "%%rbx"
173#endif
174#ifdef __SSE2_MATH__
175# define X86_BASELINE "no-sse3"
176#else
177# define X86_BASELINE "no-sse"
178#endif
179
180#if defined(Q_CC_GNU)
181// lower the target for functions in this file
182# undef QT_FUNCTION_TARGET_BASELINE
183# define QT_FUNCTION_TARGET_BASELINE __attribute__((target(X86_BASELINE)))
184# define QT_FUNCTION_TARGET_STRING_BASELINE_RDRND \
185 X86_BASELINE "," QT_FUNCTION_TARGET_STRING_RDRND
186#endif
187
188static bool checkRdrndWorks() noexcept;
189
191static int maxBasicCpuidSupported()
192{
193#if defined(Q_CC_EMSCRIPTEN)
194 return 6; // All features supported by Emscripten
195#elif defined(Q_CC_GNU)
196 qregisterint tmp1;
197
198# if Q_PROCESSOR_X86 < 5
199 // check if the CPUID instruction is supported
200 long cpuid_supported;
201 asm ("pushf\n"
202 "pop %0\n"
203 "mov %0, %1\n"
204 "xor $0x00200000, %0\n"
205 "push %0\n"
206 "popf\n"
207 "pushf\n"
208 "pop %0\n"
209 "xor %1, %0\n" // %eax is now 0 if CPUID is not supported
210 : "=a" (cpuid_supported), "=r" (tmp1)
211 );
212 if (!cpuid_supported)
213 return 0;
214# endif
215
216 int result;
217 asm ("xchg " PICreg", %1\n"
218 "cpuid\n"
219 "xchg " PICreg", %1\n"
220 : "=&a" (result), "=&r" (tmp1)
221 : "0" (0)
222 : "ecx", "edx");
223 return result;
224#elif defined(Q_OS_WIN)
225 // Use the __cpuid function; if the CPUID instruction isn't supported, it will return 0
226 int info[4];
227 __cpuid(info, 0);
228 return info[0];
229#elif defined(Q_CC_GHS)
230 unsigned int info[4];
231 __CPUID(0, info);
232 return info[0];
233#else
234 return 0;
235#endif
236}
237
239static void cpuidFeatures01(uint &ecx, uint &edx)
240{
241#if defined(Q_CC_GNU) && !defined(Q_CC_EMSCRIPTEN)
242 qregisterint tmp1;
243 asm ("xchg " PICreg", %2\n"
244 "cpuid\n"
245 "xchg " PICreg", %2\n"
246 : "=&c" (ecx), "=&d" (edx), "=&r" (tmp1)
247 : "a" (1));
248#elif defined(Q_OS_WIN)
249 int info[4];
250 __cpuid(info, 1);
251 ecx = info[2];
252 edx = info[3];
253#elif defined(Q_CC_GHS)
254 unsigned int info[4];
255 __CPUID(1, info);
256 ecx = info[2];
257 edx = info[3];
258#else
259 Q_UNUSED(ecx);
260 Q_UNUSED(edx);
261#endif
262}
263
264#ifdef Q_OS_WIN
265inline void __cpuidex(int info[4], int, __int64) { memset(info, 0, 4*sizeof(int));}
266#endif
267
269static void cpuidFeatures07_00(uint &ebx, uint &ecx, uint &edx)
270{
271#if defined(Q_CC_GNU) && !defined(Q_CC_EMSCRIPTEN)
272 qregisteruint rbx; // in case it's 64-bit
273 qregisteruint rcx = 0;
274 qregisteruint rdx = 0;
275 asm ("xchg " PICreg", %0\n"
276 "cpuid\n"
277 "xchg " PICreg", %0\n"
278 : "=&r" (rbx), "+&c" (rcx), "+&d" (rdx)
279 : "a" (7));
280 ebx = rbx;
281 ecx = rcx;
282 edx = rdx;
283#elif defined(Q_OS_WIN)
284 int info[4];
285 __cpuidex(info, 7, 0);
286 ebx = info[1];
287 ecx = info[2];
288 edx = info[3];
289#elif defined(Q_CC_GHS)
290 unsigned int info[4];
291 __CPUIDEX(7, 0, info);
292 ebx = info[1];
293 ecx = info[2];
294 edx = info[3];
295#else
296 Q_UNUSED(ebx);
297 Q_UNUSED(ecx);
298 Q_UNUSED(edx);
299#endif
300}
301
303#if defined(Q_OS_WIN) && !(defined(Q_CC_GNU) || defined(Q_CC_GHS))
304// fallback overload in case this intrinsic does not exist: unsigned __int64 _xgetbv(unsigned int);
305inline quint64 _xgetbv(__int64) { return 0; }
306#endif
307static void xgetbv(uint in, uint &eax, uint &edx)
308{
309#if (defined(Q_CC_GNU) && !defined(Q_CC_EMSCRIPTEN)) || defined(Q_CC_GHS)
310 asm (".byte 0x0F, 0x01, 0xD0" // xgetbv instruction
311 : "=a" (eax), "=d" (edx)
312 : "c" (in));
313#elif defined(Q_OS_WIN)
314 quint64 result = _xgetbv(in);
315 eax = result;
316 edx = result >> 32;
317#else
318 Q_UNUSED(in);
319 Q_UNUSED(eax);
320 Q_UNUSED(edx);
321#endif
322}
323
325static quint64 adjustedXcr0(quint64 xcr0)
326{
327 /*
328 * Some OSes hide their capability of context-switching the AVX512 state in
329 * the XCR0 register. They do that so the first time we execute an
330 * instruction that may access the AVX512 state (requiring the EVEX prefix)
331 * they allocate the necessary context switch space.
332 *
333 * This behavior is deprecated with the XFD (Extended Feature Disable)
334 * register, but we can't change existing OSes.
335 */
336#ifdef Q_OS_DARWIN
337 // from <machine/cpu_capabilities.h> in xnu
338 // <https://github.com/apple/darwin-xnu/blob/xnu-4903.221.2/osfmk/i386/cpu_capabilities.h>
339 constexpr quint64 kHasAVX512F = Q_UINT64_C(0x0000004000000000);
340 constexpr quintptr commpage = sizeof(void *) > 4 ? Q_UINT64_C(0x00007fffffe00000) : 0xffff0000;
341 constexpr quintptr cpu_capabilities64 = commpage + 0x10;
342 quint64 capab = *reinterpret_cast<quint64 *>(cpu_capabilities64);
343 if (capab & kHasAVX512F)
344 xcr0 |= XSave_Avx512State;
345#endif
346
347 return xcr0;
348}
349
352{
353 quint64 features = 0;
354 int cpuidLevel = maxBasicCpuidSupported();
355#if Q_PROCESSOR_X86 < 5
356 if (cpuidLevel < 1)
357 return 0;
358#else
359 assert(cpuidLevel >= 1);
360#endif
361
363 cpuidFeatures01(results[Leaf01ECX], results[Leaf01EDX]);
364 if (cpuidLevel >= 7)
366
367 // populate our feature list
368 for (uint i = 0; i < arraysize(x86_locators); ++i) {
369 uint word = x86_locators[i] / 32;
370 uint bit = 1U << (x86_locators[i] % 32);
371 quint64 feature = Q_UINT64_C(1) << i;
372 if (results[word] & bit)
373 features |= feature;
374 }
375
376 // now check the AVX state
377 quint64 xcr0 = 0;
378 if (results[Leaf01ECX] & (1u << 27)) {
379 // XGETBV enabled
380 uint xgetbvA = 0, xgetbvD = 0;
381 xgetbv(0, xgetbvA, xgetbvD);
382
383 xcr0 = xgetbvA;
384 if (sizeof(XSaveBits) > sizeof(xgetbvA))
385 xcr0 |= quint64(xgetbvD) << 32;
386 xcr0 = adjustedXcr0(xcr0);
387 }
388
389 for (auto req : xsave_requirements) {
390 if ((xcr0 & req.xsave_state) != req.xsave_state)
391 features &= ~req.cpu_features;
392 }
393
394 if (features & CpuFeatureRDRND && !checkRdrndWorks())
395 features &= ~(CpuFeatureRDRND | CpuFeatureRDSEED);
396
397 return features;
398}
399
400#elif defined(Q_PROCESSOR_MIPS_32)
401
402#if defined(Q_OS_LINUX)
403//
404// Do not use QByteArray: it could use SIMD instructions itself at
405// some point, thus creating a recursive dependency. Instead, use a
406// QSimpleBuffer, which has the bare minimum needed to use memory
407// dynamically and read lines from /proc/cpuinfo of arbitrary sizes.
408//
409struct QSimpleBuffer
410{
411 static const int chunk_size = 256;
412 char *data;
413 unsigned alloc;
414 unsigned size;
415
416 QSimpleBuffer() : data(nullptr), alloc(0), size(0) { }
417 ~QSimpleBuffer() { ::free(data); }
418
419 void resize(unsigned newsize)
420 {
421 if (newsize > alloc) {
422 unsigned newalloc = chunk_size * ((newsize / chunk_size) + 1);
423 if (newalloc < newsize)
424 newalloc = newsize;
425 if (newalloc != alloc) {
426 data = static_cast<char *>(::realloc(data, newalloc));
427 alloc = newalloc;
428 }
429 }
430 size = newsize;
431 }
432 void append(const QSimpleBuffer &other, unsigned appendsize)
433 {
434 unsigned oldsize = size;
435 resize(oldsize + appendsize);
436 ::memcpy(data + oldsize, other.data, appendsize);
437 }
438 void popleft(unsigned amount)
439 {
440 if (amount >= size)
441 return resize(0);
442 size -= amount;
443 ::memmove(data, data + amount, size);
444 }
445 char *cString()
446 {
447 if (!alloc)
448 resize(1);
449 return (data[size] = '\0', data);
450 }
451};
452
453//
454// Uses a scratch "buffer" (which must be used for all reads done in the
455// same file descriptor) to read chunks of data from a file, to read
456// one line at a time. Lines include the trailing newline character ('\n').
457// On EOF, line.size is zero.
458//
459static void bufReadLine(int fd, QSimpleBuffer &line, QSimpleBuffer &buffer)
460{
461 for (;;) {
462 char *newline = static_cast<char *>(::memchr(buffer.data, '\n', buffer.size));
463 if (newline) {
464 unsigned piece_size = newline - buffer.data + 1;
465 line.append(buffer, piece_size);
466 buffer.popleft(piece_size);
467 line.resize(line.size - 1);
468 return;
469 }
470 if (buffer.size + QSimpleBuffer::chunk_size > buffer.alloc) {
471 int oldsize = buffer.size;
472 buffer.resize(buffer.size + QSimpleBuffer::chunk_size);
473 buffer.size = oldsize;
474 }
475 ssize_t read_bytes =
476 ::qt_safe_read(fd, buffer.data + buffer.size, QSimpleBuffer::chunk_size);
477 if (read_bytes > 0)
478 buffer.size += read_bytes;
479 else
480 return;
481 }
482}
483
484//
485// Checks if any line with a given prefix from /proc/cpuinfo contains
486// a certain string, surrounded by spaces.
487//
488static bool procCpuinfoContains(const char *prefix, const char *string)
489{
490 int cpuinfo_fd = ::qt_safe_open("/proc/cpuinfo", O_RDONLY);
491 if (cpuinfo_fd == -1)
492 return false;
493
494 unsigned string_len = ::strlen(string);
495 unsigned prefix_len = ::strlen(prefix);
496 QSimpleBuffer line, buffer;
497 bool present = false;
498 do {
499 line.resize(0);
500 bufReadLine(cpuinfo_fd, line, buffer);
501 char *colon = static_cast<char *>(::memchr(line.data, ':', line.size));
502 if (colon && line.size > prefix_len + string_len) {
503 if (!::strncmp(prefix, line.data, prefix_len)) {
504 // prefix matches, next character must be ':' or space
505 if (line.data[prefix_len] == ':' || ::isspace(line.data[prefix_len])) {
506 // Does it contain the string?
507 char *found = ::strstr(line.cString(), string);
508 if (found && ::isspace(found[-1]) &&
509 (::isspace(found[string_len]) || found[string_len] == '\0')) {
510 present = true;
511 break;
512 }
513 }
514 }
515 }
516 } while (line.size);
517
518 ::qt_safe_close(cpuinfo_fd);
519 return present;
520}
521#endif
522
523static inline quint64 detectProcessorFeatures()
524{
525 // NOTE: MIPS 74K cores are the only ones supporting DSPr2.
526 quint64 flags = 0;
527
528#if defined __mips_dsp
529 flags |= CpuFeatureDSP;
530# if defined __mips_dsp_rev && __mips_dsp_rev >= 2
531 flags |= CpuFeatureDSPR2;
532# elif defined(Q_OS_LINUX)
533 if (procCpuinfoContains("cpu model", "MIPS 74Kc") || procCpuinfoContains("cpu model", "MIPS 74Kf"))
534 flags |= CpuFeatureDSPR2;
535# endif
536#elif defined(Q_OS_LINUX)
537 if (procCpuinfoContains("ASEs implemented", "dsp")) {
538 flags |= CpuFeatureDSP;
539 if (procCpuinfoContains("cpu model", "MIPS 74Kc") || procCpuinfoContains("cpu model", "MIPS 74Kf"))
540 flags |= CpuFeatureDSPR2;
541 }
542#endif
543
544 return flags;
545}
546
547#else
549{
550 return 0;
551}
552#endif
553
554// record what CPU features were enabled by default in this Qt build
556
557static constexpr auto SimdInitialized = QCpuFeatureType(1) << (sizeof(QCpuFeatureType) * 8 - 1);
558Q_ATOMIC(QCpuFeatureType) QT_MANGLE_NAMESPACE(qt_cpu_features)[1] = { 0 };
559
562{
563 auto minFeatureTest = minFeature;
564#if defined(Q_PROCESSOR_X86_64) && defined(cpu_feature_shstk)
565 // Controlflow Enforcement Technology (CET) is an OS-assisted
566 // hardware-feature, meaning the CPUID bit may be disabled if the OS
567 // doesn't support it, but that's ok.
568 minFeatureTest &= ~CpuFeatureSHSTK;
569#endif
571
572 // Intentionally NOT qgetenv (this code runs too early)
573 if (char *disable = getenv("QT_NO_CPU_FEATURE"); disable && *disable) {
574#if _POSIX_C_SOURCE >= 200112L
575 char *saveptr = nullptr;
576 auto strtok = [&saveptr](char *str, const char *delim) {
577 return ::strtok_r(str, delim, &saveptr);
578 };
579#endif
580 while (char *token = strtok(disable, " ")) {
581 disable = nullptr;
582 for (uint i = 0; i < arraysize(features_indices); ++i) {
583 if (strcmp(token, features_string + features_indices[i]) == 0)
584 f &= ~(Q_UINT64_C(1) << i);
585 }
586 }
587 }
588
589#ifdef RUNNING_ON_VALGRIND
590 bool runningOnValgrind = RUNNING_ON_VALGRIND;
591#else
592 bool runningOnValgrind = false;
593#endif
594 if (Q_UNLIKELY(!runningOnValgrind && minFeatureTest != 0 && (f & minFeatureTest) != minFeatureTest)) {
595 quint64 missing = minFeatureTest & ~quint64(f);
596 fprintf(stderr, "Incompatible processor. This Qt build requires the following features:\n ");
597 for (uint i = 0; i < arraysize(features_indices); ++i) {
598 if (missing & (Q_UINT64_C(1) << i))
599 fprintf(stderr, "%s", features_string + features_indices[i]);
600 }
601 fprintf(stderr, "\n");
602 fflush(stderr);
603 qAbort();
604 }
605
606 assert((f & SimdInitialized) == 0);
608 std::atomic_store_explicit(QT_MANGLE_NAMESPACE(qt_cpu_features), f, std::memory_order_relaxed);
609 return f;
610}
611
614{
615 quint64 features = detectProcessorFeatures() & ~SimdInitialized;
616 printf("Processor features: ");
617 for (uint i = 0; i < arraysize(features_indices); ++i) {
618 if (features & (Q_UINT64_C(1) << i))
619 printf("%s%s", features_string + features_indices[i],
620 minFeature & (Q_UINT64_C(1) << i) ? "[required]" : "");
621 }
622 if ((features = (qCompilerCpuFeatures & ~features))) {
623 printf("\n!!!!!!!!!!!!!!!!!!!!\n!!! Missing required features:");
624 for (uint i = 0; i < arraysize(features_indices); ++i) {
625 if (features & (Q_UINT64_C(1) << i))
626 printf("%s", features_string + features_indices[i]);
627 }
628 printf("\n!!! Applications will likely crash with \"Invalid Instruction\"\n!!!!!!!!!!!!!!!!!!!!");
629 }
630 puts("");
631}
632
633#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND)
634
635# ifdef Q_PROCESSOR_X86_64
636# define _rdrandXX_step _rdrand64_step
637# define _rdseedXX_step _rdseed64_step
638# else
639# define _rdrandXX_step _rdrand32_step
640# define _rdseedXX_step _rdseed32_step
641# endif
642
643// The parameter to _rdrand64_step & _rdseed64_step is unsigned long long for
644// Clang and GCC but unsigned __int64 for MSVC and ICC, which is unsigned long
645// long on Windows, but unsigned long on Linux.
646namespace {
647template <typename F> struct ExtractParameter;
648template <typename T> struct ExtractParameter<int (T *)> { using Type = T; };
649using randuint = ExtractParameter<decltype(_rdrandXX_step)>::Type;
650}
651
652# if QT_COMPILER_SUPPORTS_HERE(RDSEED)
653static QT_FUNCTION_TARGET(RDSEED) unsigned *qt_random_rdseed(unsigned *ptr, unsigned *end) noexcept
654{
655 // Unlike for the RDRAND code below, the Intel whitepaper describing the
656 // use of the RDSEED instruction indicates we should not retry in a loop.
657 // If the independent bit generator used by RDSEED is out of entropy, it
658 // may take time to replenish.
659 // https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide
660 while (ptr + sizeof(randuint) / sizeof(*ptr) <= end) {
661 if (_rdseedXX_step(reinterpret_cast<randuint *>(ptr)) == 0)
662 goto out;
663 ptr += sizeof(randuint) / sizeof(*ptr);
664 }
665
666 if (sizeof(*ptr) != sizeof(randuint) && ptr != end) {
667 if (_rdseed32_step(ptr) == 0)
668 goto out;
669 ++ptr;
670 }
671
672out:
673 return ptr;
674}
675# else
676static unsigned *qt_random_rdseed(unsigned *ptr, unsigned *)
677{
678 return ptr;
679}
680# endif
681
682static QT_FUNCTION_TARGET(RDRND) unsigned *qt_random_rdrnd(unsigned *ptr, unsigned *end) noexcept
683{
684 int retries = 10;
685 while (ptr + sizeof(randuint)/sizeof(*ptr) <= end) {
686 if (_rdrandXX_step(reinterpret_cast<randuint *>(ptr)))
687 ptr += sizeof(randuint)/sizeof(*ptr);
688 else if (--retries == 0)
689 goto out;
690 }
691
692 while (sizeof(*ptr) != sizeof(randuint) && ptr != end) {
693 bool ok = _rdrand32_step(ptr);
694 if (!ok && --retries)
695 continue;
696 if (ok)
697 ++ptr;
698 break;
699 }
700
701out:
702 return ptr;
703}
704
706static bool checkRdrndWorks() noexcept
707{
708 /*
709 * Some AMD CPUs (e.g. AMD A4-6250J and AMD Ryzen 3000-series) have a
710 * failing random generation instruction, which always returns
711 * 0xffffffff, even when generation was "successful".
712 *
713 * This code checks if hardware random generator generates four consecutive
714 * equal numbers. If it does, then we probably have a failing one and
715 * should disable it completely.
716 *
717 * https://bugreports.qt.io/browse/QTBUG-69423
718 */
719 constexpr qsizetype TestBufferSize = 4;
720 unsigned testBuffer[TestBufferSize] = {};
721
722 unsigned *end = qt_random_rdrnd(testBuffer, testBuffer + TestBufferSize);
723 if (end < testBuffer + 3) {
724 // Random generation didn't produce enough data for us to make a
725 // determination whether it's working or not. Assume it isn't, but
726 // don't print a warning.
727 return false;
728 }
729
730 // Check the results for equality
731 if (testBuffer[0] == testBuffer[1]
732 && testBuffer[0] == testBuffer[2]
733 && (end < testBuffer + TestBufferSize || testBuffer[0] == testBuffer[3])) {
734 fprintf(stderr, "WARNING: CPU random generator seem to be failing, "
735 "disabling hardware random number generation\n"
736 "WARNING: RDRND generated:");
737 for (unsigned *ptr = testBuffer; ptr < end; ++ptr)
738 fprintf(stderr, " 0x%x", *ptr);
739 fprintf(stderr, "\n");
740 return false;
741 }
742
743 // We're good
744 return true;
745}
746
747QT_FUNCTION_TARGET(RDRND) qsizetype qRandomCpu(void *buffer, qsizetype count) noexcept
748{
749 unsigned *ptr = reinterpret_cast<unsigned *>(buffer);
750 unsigned *end = ptr + count;
751
752 if (qCpuHasFeature(RDSEED))
753 ptr = qt_random_rdseed(ptr, end);
754
755 // fill the buffer with RDRND if RDSEED didn't
756 ptr = qt_random_rdrnd(ptr, end);
757 return ptr - reinterpret_cast<unsigned *>(buffer);
758}
759#elif defined(Q_PROCESSOR_X86) && !defined(Q_PROCESSOR_ARM)
760static bool checkRdrndWorks() noexcept { return false; }
761#endif // Q_PROCESSOR_X86 && RDRND
762
763#if QT_SUPPORTS_INIT_PRIORITY
764namespace {
765struct QSimdInitializer
766{
767 inline QSimdInitializer() { QT_MANGLE_NAMESPACE(qDetectCpuFeatures)(); }
768};
769}
770
771// This is intentionally a dynamic initialization of the variable
772Q_DECL_INIT_PRIORITY(01) static QSimdInitializer initializer;
773#endif
774
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
QChar * data()
Returns a pointer to the data stored in the QString.
Definition qstring.h:1240
QString & append(QChar c)
Definition qstring.cpp:3252
void resize(qsizetype size)
Sets the size of the string to size characters.
Definition qstring.cpp:2668
QString str
[2]
a resize(100000)
list append(new Employee("Blackpool", "Stephen"))
Token token
Definition keywords.cpp:444
Combined button and popup list for selecting options.
QT_BEGIN_NAMESPACE void qAbort()
Definition qassert.cpp:24
#define assert
#define Q_UNLIKELY(x)
#define Q_DECL_COLD_FUNCTION
static int qt_safe_open(const char *pathname, int flags, mode_t mode=0777)
static qint64 qt_safe_read(int fd, void *data, qint64 maxlen)
static int qt_safe_close(int fd)
static ControlElement< T > * ptr(QWidget *widget)
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint GLuint end
GLenum GLenum GLsizei count
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLfloat GLfloat f
GLenum GLuint buffer
GLbitfield flags
GLuint64 GLenum GLint fd
GLuint in
GLuint64EXT * result
[6]
GLenum GLsizei len
QT_BEGIN_NAMESPACE QT_FUNCTION_TARGET_BASELINE uint arraysize(T(&)[N])
Definition qsimd.cpp:66
#define QT_FUNCTION_TARGET_BASELINE
Definition qsimd.cpp:24
QT_FUNCTION_TARGET_BASELINE uint64_t QT_MANGLE_NAMESPACE qDetectCpuFeatures()
Definition qsimd.cpp:561
QT_FUNCTION_TARGET_BASELINE void qDumpCPUFeatures()
Definition qsimd.cpp:613
static constexpr auto SimdInitialized
Definition qsimd.cpp:557
static const quint64 minFeature
Definition qsimd.cpp:555
static uint detectProcessorFeatures()
Definition qsimd.cpp:548
static const char features_string[]
Definition qsimd.cpp:101
static const int features_indices[]
Definition qsimd.cpp:102
#define qCpuHasFeature(feature)
Definition qsimd_p.h:387
#define QT_FUNCTION_TARGET(x)
Definition qsimd_p.h:133
static const uint64_t qCompilerCpuFeatures
Definition qsimd_p.h:324
unsigned QCpuFeatureType
Definition qsimd_p.h:368
#define Q_ATOMIC(T)
Definition qsimd_p.h:359
static const struct XSaveRequirementMapping xsave_requirements[]
XSaveBits
@ XSave_Avx512State
static const uint16_t x86_locators[]
Definition qsimd_x86.cpp:71
@ Leaf07_00EDX
Definition qsimd_x86.cpp:62
@ Leaf07_00EBX
Definition qsimd_x86.cpp:60
@ Leaf01EDX
Definition qsimd_x86.cpp:58
@ X86CpuidMaxLeaf
Definition qsimd_x86.cpp:68
@ Leaf07_00ECX
Definition qsimd_x86.cpp:61
@ Leaf01ECX
Definition qsimd_x86.cpp:59
#define QT_MANGLE_NAMESPACE(name)
#define Q_UNUSED(x)
#define Q_UINT64_C(c)
Definition qtypes.h:58
size_t quintptr
Definition qtypes.h:167
unsigned long long quint64
Definition qtypes.h:61
ptrdiff_t qsizetype
Definition qtypes.h:165
unsigned int uint
Definition qtypes.h:34
QTextStream out(stdout)
[7]
QObject::connect nullptr
QSharedPointer< T > other(t)
[5]
QHostInfo info
[0]
Definition moc.h:23