diff options
Diffstat (limited to 'src/corelib/global/qsimd.cpp')
-rw-r--r-- | src/corelib/global/qsimd.cpp | 393 |
1 files changed, 203 insertions, 190 deletions
diff --git a/src/corelib/global/qsimd.cpp b/src/corelib/global/qsimd.cpp index d91c1542c2..8bc5381591 100644 --- a/src/corelib/global/qsimd.cpp +++ b/src/corelib/global/qsimd.cpp @@ -1,76 +1,53 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2019 Intel Corporation. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2021 The Qt Company Ltd. +// Copyright (C) 2022 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only // we need ICC to define the prototype for _rdseed64_step #define __INTEL_COMPILER_USE_INTRINSIC_PROTOTYPES +#undef _FORTIFY_SOURCE // otherwise, the always_inline from stdio.h fail to inline #include "qsimd_p.h" #include "qalgorithms.h" -#include <QByteArray> + #include <stdio.h> +#include <string.h> + +#if defined(QT_NO_DEBUG) && !defined(NDEBUG) +# define NDEBUG +#endif +#include <assert.h> #ifdef Q_OS_LINUX # include "../testlib/3rdparty/valgrind_p.h" #endif +#define QT_FUNCTION_TARGET_BASELINE + #if defined(Q_OS_WIN) # if !defined(Q_CC_GNU) # include <intrin.h> # endif -#elif defined(Q_OS_LINUX) && (defined(Q_PROCESSOR_ARM) || defined(Q_PROCESSOR_MIPS_32)) -#include "private/qcore_unix_p.h" +# if defined(Q_PROCESSOR_ARM_64) +# include <qt_windows.h> +# include <processthreadsapi.h> +# endif +#elif defined(Q_OS_LINUX) && defined(Q_PROCESSOR_MIPS_32) +# include "private/qcore_unix_p.h" +#elif QT_CONFIG(getauxval) && defined(Q_PROCESSOR_ARM) +# include <sys/auxv.h> // the kernel header definitions for HWCAP_* // (the ones we need/may need anyway) // copied from <asm/hwcap.h> (ARM) -#define HWCAP_CRUNCH 1024 -#define HWCAP_THUMBEE 2048 #define HWCAP_NEON 4096 -#define HWCAP_VFPv3 8192 -#define HWCAP_VFPv3D16 16384 // copied from <asm/hwcap.h> (ARM): +#define HWCAP2_AES (1 << 0) #define HWCAP2_CRC32 (1 << 4) // copied from <asm/hwcap.h> (Aarch64) +#define HWCAP_AES (1 << 3) #define HWCAP_CRC32 (1 << 7) // copied from <linux/auxvec.h> @@ -78,106 +55,110 @@ #define AT_HWCAP2 26 /* extension of AT_HWCAP */ #elif defined(Q_CC_GHS) -#include <INTEGRITY_types.h> +# include <INTEGRITY_types.h> +#elif defined(Q_OS_DARWIN) && defined(Q_PROCESSOR_ARM) +# include <sys/sysctl.h> #endif QT_BEGIN_NAMESPACE -/* - * Use kdesdk/scripts/generate_string_table.pl to update the table below. Note - * we remove the terminating -1 that the script adds. - */ +template <typename T, uint N> QT_FUNCTION_TARGET_BASELINE +uint arraysize(T (&)[N]) +{ + // Same as std::size, but with QT_FUNCTION_TARGET_BASELIE, + // otherwise some versions of GCC fail to compile. + return N; +} -// begin generated #if defined(Q_PROCESSOR_ARM) /* Data: neon crc32 + aes */ static const char features_string[] = + "\0" " neon\0" " crc32\0" - "\0"; -static const int features_indices[] = { 0, 6 }; + " aes\0"; +static const int features_indices[] = { 0, 1, 7, 14 }; #elif defined(Q_PROCESSOR_MIPS) /* Data: dsp dspr2 */ static const char features_string[] = + "\0" " dsp\0" - " dspr2\0" - "\0"; + " dspr2\0"; static const int features_indices[] = { - 0, 5 + 0, 1, 6 }; #elif defined(Q_PROCESSOR_X86) # include "qsimd_x86.cpp" // generated by util/x86simdgen #else static const char features_string[] = ""; -static const int features_indices[] = { }; +static const int features_indices[] = { 0 }; #endif // end generated -#if defined (Q_OS_NACL) -static inline uint detectProcessorFeatures() -{ - return 0; -} -#elif defined(Q_PROCESSOR_ARM) +#if defined(Q_PROCESSOR_ARM) static inline quint64 detectProcessorFeatures() { quint64 features = 0; -#if defined(Q_OS_LINUX) -# if defined(Q_PROCESSOR_ARM_V8) && defined(Q_PROCESSOR_ARM_64) - features |= Q_UINT64_C(1) << CpuFeatureNEON; // NEON is always available on ARMv8 64bit. -# endif - int auxv = qt_safe_open("/proc/self/auxv", O_RDONLY); - if (auxv != -1) { - unsigned long vector[64]; - int nread; - while (features == 0) { - nread = qt_safe_read(auxv, (char *)vector, sizeof vector); - if (nread <= 0) { - // EOF or error - break; - } - - int max = nread / (sizeof vector[0]); - for (int i = 0; i < max; i += 2) { - if (vector[i] == AT_HWCAP) { -# if defined(Q_PROCESSOR_ARM_V8) && defined(Q_PROCESSOR_ARM_64) - // For Aarch64: - if (vector[i+1] & HWCAP_CRC32) - features |= Q_UINT64_C(1) << CpuFeatureCRC32; -# endif - // Aarch32, or ARMv7 or before: - if (vector[i+1] & HWCAP_NEON) - features |= Q_UINT64_C(1) << CpuFeatureNEON; - } -# if defined(Q_PROCESSOR_ARM_32) - // For Aarch32: - if (vector[i] == AT_HWCAP2) { - if (vector[i+1] & HWCAP2_CRC32) - features |= Q_UINT64_C(1) << CpuFeatureCRC32; - } +#if QT_CONFIG(getauxval) + unsigned long auxvHwCap = getauxval(AT_HWCAP); + if (auxvHwCap != 0) { +# if defined(Q_PROCESSOR_ARM_64) + // For Aarch64: + features |= CpuFeatureNEON; // NEON is always available + if (auxvHwCap & HWCAP_CRC32) + features |= CpuFeatureCRC32; + if (auxvHwCap & HWCAP_AES) + features |= CpuFeatureAES; +# else + // For ARM32: + if (auxvHwCap & HWCAP_NEON) + features |= CpuFeatureNEON; + auxvHwCap = getauxval(AT_HWCAP2); + if (auxvHwCap & HWCAP2_CRC32) + features |= CpuFeatureCRC32; + if (auxvHwCap & HWCAP2_AES) + features |= CpuFeatureAES; # endif - } - } - - qt_safe_close(auxv); return features; } - // fall back if /proc/self/auxv wasn't found + // fall back to compile-time flags if getauxval failed +#elif defined(Q_OS_DARWIN) && defined(Q_PROCESSOR_ARM) + unsigned feature; + size_t len = sizeof(feature); + if (sysctlbyname("hw.optional.neon", &feature, &len, nullptr, 0) == 0) + features |= feature ? CpuFeatureNEON : 0; + if (sysctlbyname("hw.optional.armv8_crc32", &feature, &len, nullptr, 0) == 0) + features |= feature ? CpuFeatureCRC32 : 0; + // There is currently no optional value for crypto/AES. +#if defined(__ARM_FEATURE_CRYPTO) + features |= CpuFeatureAES; #endif - -#if defined(__ARM_NEON__) - features |= Q_UINT64_C(1) << CpuFeatureNEON; + return features; +#elif defined(Q_OS_WIN) && defined(Q_PROCESSOR_ARM_64) + features |= CpuFeatureNEON; + if (IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE) != 0) + features |= CpuFeatureCRC32; + if (IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) != 0) + features |= CpuFeatureAES; + return features; +#endif +#if defined(__ARM_NEON__) || defined(__ARM_NEON) + features |= CpuFeatureNEON; #endif #if defined(__ARM_FEATURE_CRC32) - features |= Q_UINT64_C(1) << CpuFeatureCRC32; + features |= CpuFeatureCRC32; +#endif +#if defined(__ARM_FEATURE_CRYPTO) + features |= CpuFeatureAES; #endif return features; @@ -190,9 +171,23 @@ static inline quint64 detectProcessorFeatures() #else # define PICreg "%%rbx" #endif +#ifdef __SSE2_MATH__ +# define X86_BASELINE "no-sse3" +#else +# define X86_BASELINE "no-sse" +#endif + +#if defined(Q_CC_GNU) +// lower the target for functions in this file +# undef QT_FUNCTION_TARGET_BASELINE +# define QT_FUNCTION_TARGET_BASELINE __attribute__((target(X86_BASELINE))) +# define QT_FUNCTION_TARGET_STRING_BASELINE_RDRND \ + X86_BASELINE "," QT_FUNCTION_TARGET_STRING_RDRND +#endif static bool checkRdrndWorks() noexcept; +QT_FUNCTION_TARGET_BASELINE static int maxBasicCpuidSupported() { #if defined(Q_CC_EMSCRIPTEN) @@ -240,6 +235,7 @@ static int maxBasicCpuidSupported() #endif } +QT_FUNCTION_TARGET_BASELINE static void cpuidFeatures01(uint &ecx, uint &edx) { #if defined(Q_CC_GNU) && !defined(Q_CC_EMSCRIPTEN) @@ -269,6 +265,7 @@ static void cpuidFeatures01(uint &ecx, uint &edx) inline void __cpuidex(int info[4], int, __int64) { memset(info, 0, 4*sizeof(int));} #endif +QT_FUNCTION_TARGET_BASELINE static void cpuidFeatures07_00(uint &ebx, uint &ecx, uint &edx) { #if defined(Q_CC_GNU) && !defined(Q_CC_EMSCRIPTEN) @@ -302,6 +299,7 @@ static void cpuidFeatures07_00(uint &ebx, uint &ecx, uint &edx) #endif } +QT_FUNCTION_TARGET_BASELINE #if defined(Q_OS_WIN) && !(defined(Q_CC_GNU) || defined(Q_CC_GHS)) // fallback overload in case this intrinsic does not exist: unsigned __int64 _xgetbv(unsigned int); inline quint64 _xgetbv(__int64) { return 0; } @@ -323,22 +321,7 @@ static void xgetbv(uint in, uint &eax, uint &edx) #endif } -// Flags from the XCR0 state register -enum XCR0Flags { - X87 = 1 << 0, - XMM0_15 = 1 << 1, - YMM0_15Hi128 = 1 << 2, - BNDRegs = 1 << 3, - BNDCSR = 1 << 4, - OpMask = 1 << 5, - ZMM0_15Hi256 = 1 << 6, - ZMM16_31 = 1 << 7, - - SSEState = XMM0_15, - AVXState = XMM0_15 | YMM0_15Hi128, - AVX512State = AVXState | OpMask | ZMM0_15Hi256 | ZMM16_31 -}; - +QT_FUNCTION_TARGET_BASELINE static quint64 adjustedXcr0(quint64 xcr0) { /* @@ -358,59 +341,54 @@ static quint64 adjustedXcr0(quint64 xcr0) constexpr quintptr cpu_capabilities64 = commpage + 0x10; quint64 capab = *reinterpret_cast<quint64 *>(cpu_capabilities64); if (capab & kHasAVX512F) - xcr0 |= AVX512State; + xcr0 |= XSave_Avx512State; #endif return xcr0; } +QT_FUNCTION_TARGET_BASELINE static quint64 detectProcessorFeatures() { - static const quint64 AllAVX2 = CpuFeatureAVX2 | AllAVX512; - static const quint64 AllAVX = CpuFeatureAVX | AllAVX2; - quint64 features = 0; int cpuidLevel = maxBasicCpuidSupported(); #if Q_PROCESSOR_X86 < 5 if (cpuidLevel < 1) return 0; #else - Q_ASSERT(cpuidLevel >= 1); + assert(cpuidLevel >= 1); #endif uint results[X86CpuidMaxLeaf] = {}; - cpuidFeatures01(results[Leaf1ECX], results[Leaf1EDX]); + cpuidFeatures01(results[Leaf01ECX], results[Leaf01EDX]); if (cpuidLevel >= 7) - cpuidFeatures07_00(results[Leaf7_0EBX], results[Leaf7_0ECX], results[Leaf7_0EDX]); + cpuidFeatures07_00(results[Leaf07_00EBX], results[Leaf07_00ECX], results[Leaf07_00EDX]); // populate our feature list - for (uint i = 0; i < sizeof(x86_locators) / sizeof(x86_locators[0]); ++i) { + for (uint i = 0; i < arraysize(x86_locators); ++i) { uint word = x86_locators[i] / 32; uint bit = 1U << (x86_locators[i] % 32); - quint64 feature = Q_UINT64_C(1) << (i + 1); + quint64 feature = Q_UINT64_C(1) << i; if (results[word] & bit) features |= feature; } // now check the AVX state quint64 xcr0 = 0; - if (results[Leaf1ECX] & (1u << 27)) { + if (results[Leaf01ECX] & (1u << 27)) { // XGETBV enabled uint xgetbvA = 0, xgetbvD = 0; xgetbv(0, xgetbvA, xgetbvD); xcr0 = xgetbvA; - if (sizeof(XCR0Flags) > sizeof(xgetbvA)) + if (sizeof(XSaveBits) > sizeof(xgetbvA)) xcr0 |= quint64(xgetbvD) << 32; xcr0 = adjustedXcr0(xcr0); } - if ((xcr0 & AVXState) != AVXState) { - // support for YMM registers is disabled, disable all AVX - features &= ~AllAVX; - } else if ((xcr0 & AVX512State) != AVX512State) { - // support for ZMM registers or mask registers is disabled, disable all AVX512 - features &= ~AllAVX512; + for (auto req : xsave_requirements) { + if ((xcr0 & req.xsave_state) != req.xsave_state) + features &= ~req.cpu_features; } if (features & CpuFeatureRDRND && !checkRdrndWorks()) @@ -428,38 +406,46 @@ static quint64 detectProcessorFeatures() // QSimpleBuffer, which has the bare minimum needed to use memory // dynamically and read lines from /proc/cpuinfo of arbitrary sizes. // -struct QSimpleBuffer { +struct QSimpleBuffer +{ static const int chunk_size = 256; char *data; unsigned alloc; unsigned size; - QSimpleBuffer(): data(0), alloc(0), size(0) {} + QSimpleBuffer() : data(nullptr), alloc(0), size(0) { } ~QSimpleBuffer() { ::free(data); } - void resize(unsigned newsize) { + void resize(unsigned newsize) + { if (newsize > alloc) { unsigned newalloc = chunk_size * ((newsize / chunk_size) + 1); - if (newalloc < newsize) newalloc = newsize; + if (newalloc < newsize) + newalloc = newsize; if (newalloc != alloc) { - data = static_cast<char*>(::realloc(data, newalloc)); + data = static_cast<char *>(::realloc(data, newalloc)); alloc = newalloc; } } size = newsize; } - void append(const QSimpleBuffer &other, unsigned appendsize) { + void append(const QSimpleBuffer &other, unsigned appendsize) + { unsigned oldsize = size; resize(oldsize + appendsize); ::memcpy(data + oldsize, other.data, appendsize); } - void popleft(unsigned amount) { - if (amount >= size) return resize(0); + void popleft(unsigned amount) + { + if (amount >= size) + return resize(0); size -= amount; ::memmove(data, data + amount, size); } - char* cString() { - if (!alloc) resize(1); + char *cString() + { + if (!alloc) + resize(1); return (data[size] = '\0', data); } }; @@ -473,7 +459,7 @@ struct QSimpleBuffer { static void bufReadLine(int fd, QSimpleBuffer &line, QSimpleBuffer &buffer) { for (;;) { - char *newline = static_cast<char*>(::memchr(buffer.data, '\n', buffer.size)); + char *newline = static_cast<char *>(::memchr(buffer.data, '\n', buffer.size)); if (newline) { unsigned piece_size = newline - buffer.data + 1; line.append(buffer, piece_size); @@ -486,9 +472,12 @@ static void bufReadLine(int fd, QSimpleBuffer &line, QSimpleBuffer &buffer) buffer.resize(buffer.size + QSimpleBuffer::chunk_size); buffer.size = oldsize; } - ssize_t read_bytes = ::qt_safe_read(fd, buffer.data + buffer.size, QSimpleBuffer::chunk_size); - if (read_bytes > 0) buffer.size += read_bytes; - else return; + ssize_t read_bytes = + ::qt_safe_read(fd, buffer.data + buffer.size, QSimpleBuffer::chunk_size); + if (read_bytes > 0) + buffer.size += read_bytes; + else + return; } } @@ -509,7 +498,7 @@ static bool procCpuinfoContains(const char *prefix, const char *string) do { line.resize(0); bufReadLine(cpuinfo_fd, line, buffer); - char *colon = static_cast<char*>(::memchr(line.data, ':', line.size)); + char *colon = static_cast<char *>(::memchr(line.data, ':', line.size)); if (colon && line.size > prefix_len + string_len) { if (!::strncmp(prefix, line.data, prefix_len)) { // prefix matches, next character must be ':' or space @@ -537,18 +526,18 @@ static inline quint64 detectProcessorFeatures() quint64 flags = 0; #if defined __mips_dsp - flags |= Q_UINT64_C(1) << CpuFeatureDSP; + flags |= CpuFeatureDSP; # if defined __mips_dsp_rev && __mips_dsp_rev >= 2 - flags |= Q_UINT64_C(1) << CpuFeatureDSPR2; + flags |= CpuFeatureDSPR2; # elif defined(Q_OS_LINUX) if (procCpuinfoContains("cpu model", "MIPS 74Kc") || procCpuinfoContains("cpu model", "MIPS 74Kf")) - flags |= Q_UINT64_C(1) << CpuFeatureDSPR2; + flags |= CpuFeatureDSPR2; # endif #elif defined(Q_OS_LINUX) if (procCpuinfoContains("ASEs implemented", "dsp")) { - flags |= Q_UINT64_C(1) << CpuFeatureDSP; + flags |= CpuFeatureDSP; if (procCpuinfoContains("cpu model", "MIPS 74Kc") || procCpuinfoContains("cpu model", "MIPS 74Kf")) - flags |= Q_UINT64_C(1) << CpuFeatureDSPR2; + flags |= CpuFeatureDSPR2; } #endif @@ -562,26 +551,38 @@ static inline uint detectProcessorFeatures() } #endif -static const int features_count = (sizeof features_indices) / (sizeof features_indices[0]); - // record what CPU features were enabled by default in this Qt build static const quint64 minFeature = qCompilerCpuFeatures; -#ifdef Q_ATOMIC_INT64_IS_SUPPORTED -Q_CORE_EXPORT QBasicAtomicInteger<quint64> qt_cpu_features[1] = { Q_BASIC_ATOMIC_INITIALIZER(0) }; -#else -Q_CORE_EXPORT QBasicAtomicInteger<unsigned> qt_cpu_features[2] = { Q_BASIC_ATOMIC_INITIALIZER(0), Q_BASIC_ATOMIC_INITIALIZER(0) }; -#endif +static constexpr auto SimdInitialized = QCpuFeatureType(1) << (sizeof(QCpuFeatureType) * 8 - 1); +Q_ATOMIC(QCpuFeatureType) QT_MANGLE_NAMESPACE(qt_cpu_features)[1] = { 0 }; -quint64 qDetectCpuFeatures() +QT_FUNCTION_TARGET_BASELINE +uint64_t QT_MANGLE_NAMESPACE(qDetectCpuFeatures)() { - quint64 f = detectProcessorFeatures(); - QByteArray disable = qgetenv("QT_NO_CPU_FEATURE"); - if (!disable.isEmpty()) { - disable.prepend(' '); - for (int i = 0; i < features_count; ++i) { - if (disable.contains(features_string + features_indices[i])) - f &= ~(Q_UINT64_C(1) << i); + auto minFeatureTest = minFeature; +#if defined(Q_PROCESSOR_X86_64) && defined(cpu_feature_shstk) + // Controlflow Enforcement Technology (CET) is an OS-assisted + // hardware-feature, meaning the CPUID bit may be disabled if the OS + // doesn't support it, but that's ok. + minFeatureTest &= ~CpuFeatureSHSTK; +#endif + QCpuFeatureType f = detectProcessorFeatures(); + + // Intentionally NOT qgetenv (this code runs too early) + if (char *disable = getenv("QT_NO_CPU_FEATURE"); disable && *disable) { +#if _POSIX_C_SOURCE >= 200112L + char *saveptr = nullptr; + auto strtok = [&saveptr](char *str, const char *delim) { + return ::strtok_r(str, delim, &saveptr); + }; +#endif + while (char *token = strtok(disable, " ")) { + disable = nullptr; + for (uint i = 0; i < arraysize(features_indices); ++i) { + if (strcmp(token, features_string + features_indices[i]) == 0) + f &= ~(Q_UINT64_C(1) << i); + } } } @@ -590,38 +591,37 @@ quint64 qDetectCpuFeatures() #else bool runningOnValgrind = false; #endif - if (Q_UNLIKELY(!runningOnValgrind && minFeature != 0 && (f & minFeature) != minFeature)) { - quint64 missing = minFeature & ~f; + if (Q_UNLIKELY(!runningOnValgrind && minFeatureTest != 0 && (f & minFeatureTest) != minFeatureTest)) { + quint64 missing = minFeatureTest & ~quint64(f); fprintf(stderr, "Incompatible processor. This Qt build requires the following features:\n "); - for (int i = 0; i < features_count; ++i) { + for (uint i = 0; i < arraysize(features_indices); ++i) { if (missing & (Q_UINT64_C(1) << i)) fprintf(stderr, "%s", features_string + features_indices[i]); } fprintf(stderr, "\n"); fflush(stderr); - qFatal("Aborted. Incompatible processor: missing feature 0x%llx -%s.", missing, - features_string + features_indices[qCountTrailingZeroBits(missing)]); + qAbort(); } - qt_cpu_features[0].storeRelaxed(f | quint32(QSimdInitialized)); -#ifndef Q_ATOMIC_INT64_IS_SUPPORTED - qt_cpu_features[1].storeRelaxed(f >> 32); -#endif + assert((f & SimdInitialized) == 0); + f |= SimdInitialized; + std::atomic_store_explicit(QT_MANGLE_NAMESPACE(qt_cpu_features), f, std::memory_order_relaxed); return f; } +QT_FUNCTION_TARGET_BASELINE void qDumpCPUFeatures() { - quint64 features = qCpuFeatures() & ~quint64(QSimdInitialized); + quint64 features = detectProcessorFeatures() & ~SimdInitialized; printf("Processor features: "); - for (int i = 0; i < features_count; ++i) { + for (uint i = 0; i < arraysize(features_indices); ++i) { if (features & (Q_UINT64_C(1) << i)) printf("%s%s", features_string + features_indices[i], minFeature & (Q_UINT64_C(1) << i) ? "[required]" : ""); } if ((features = (qCompilerCpuFeatures & ~features))) { printf("\n!!!!!!!!!!!!!!!!!!!!\n!!! Missing required features:"); - for (int i = 0; i < features_count; ++i) { + for (uint i = 0; i < arraysize(features_indices); ++i) { if (features & (Q_UINT64_C(1) << i)) printf("%s", features_string + features_indices[i]); } @@ -657,10 +657,10 @@ static QT_FUNCTION_TARGET(RDSEED) unsigned *qt_random_rdseed(unsigned *ptr, unsi // If the independent bit generator used by RDSEED is out of entropy, it // may take time to replenish. // https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide - while (ptr + sizeof(randuint)/sizeof(*ptr) <= end) { + while (ptr + sizeof(randuint) / sizeof(*ptr) <= end) { if (_rdseedXX_step(reinterpret_cast<randuint *>(ptr)) == 0) goto out; - ptr += sizeof(randuint)/sizeof(*ptr); + ptr += sizeof(randuint) / sizeof(*ptr); } if (sizeof(*ptr) != sizeof(randuint) && ptr != end) { @@ -702,7 +702,8 @@ out: return ptr; } -static QT_FUNCTION_TARGET(RDRND) Q_DECL_COLD_FUNCTION bool checkRdrndWorks() noexcept +QT_FUNCTION_TARGET(BASELINE_RDRND) Q_DECL_COLD_FUNCTION +static bool checkRdrndWorks() noexcept { /* * Some AMD CPUs (e.g. AMD A4-6250J and AMD Ryzen 3000-series) have a @@ -755,8 +756,20 @@ QT_FUNCTION_TARGET(RDRND) qsizetype qRandomCpu(void *buffer, qsizetype count) no ptr = qt_random_rdrnd(ptr, end); return ptr - reinterpret_cast<unsigned *>(buffer); } -#elif defined(Q_PROCESSOR_X86) && !defined(Q_OS_NACL) && !defined(Q_PROCESSOR_ARM) +#elif defined(Q_PROCESSOR_X86) && !defined(Q_PROCESSOR_ARM) static bool checkRdrndWorks() noexcept { return false; } #endif // Q_PROCESSOR_X86 && RDRND +#if QT_SUPPORTS_INIT_PRIORITY +namespace { +struct QSimdInitializer +{ + inline QSimdInitializer() { QT_MANGLE_NAMESPACE(qDetectCpuFeatures)(); } +}; +} + +// This is intentionally a dynamic initialization of the variable +Q_DECL_INIT_PRIORITY(01) static QSimdInitializer initializer; +#endif + QT_END_NAMESPACE |