From 4f37cf2ce544dad5b207161536566627b6b0b1ef Mon Sep 17 00:00:00 2001 From: Nick Shaforostoff Date: Sun, 28 Feb 2021 20:02:18 +0100 Subject: [PATCH] string 16<->8 bits conversion: SIMD on arm32 this adds emulation for 2 NEON commands that armv7 lacks this increases conversion speed by around 50% in my simple tests Change-Id: I4f52d353184e9a8d88089de60e17bd5670637c0c Reviewed-by: Allan Sandfeld Jensen --- src/corelib/global/qsimd_p.h | 16 ++++++++++++++++ src/corelib/text/qstring.cpp | 4 ++-- src/corelib/text/qstringconverter.cpp | 4 ++-- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/corelib/global/qsimd_p.h b/src/corelib/global/qsimd_p.h index 2f2d49348f..fbb5f0f021 100644 --- a/src/corelib/global/qsimd_p.h +++ b/src/corelib/global/qsimd_p.h @@ -274,6 +274,22 @@ QT_END_NAMESPACE // __ARM_NEON__ is not defined on AArch64, but we need it in our NEON detection. #define __ARM_NEON__ #endif + +#ifndef Q_PROCESSOR_ARM_64 // vaddv is only available on Aarch64 +inline uint16_t vaddvq_u16(uint16x8_t v8) +{ + const uint64x2_t v2 = vpaddlq_u32(vpaddlq_u16(v8)); + const uint64x1_t v1 = vadd_u64(vget_low_u64(v2), vget_high_u64(v2)); + return vget_lane_u16(vreinterpret_u16_u64(v1), 0); +} + +inline uint8_t vaddv_u8(uint8x8_t v8) +{ + const uint64x1_t v1 = vpaddl_u32(vpaddl_u16(vpaddl_u8(v8))); + return vget_lane_u8(vreinterpret_u8_u64(v1), 0); +} +#endif + #endif // AArch64/ARM64 #if defined(Q_PROCESSOR_ARM_V8) && defined(__ARM_FEATURE_CRC32) diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp index 24e725ee9a..49e56d26d6 100644 --- a/src/corelib/text/qstring.cpp +++ b/src/corelib/text/qstring.cpp @@ -333,7 +333,7 @@ const char16_t *QtPrivate::qustrchr(QStringView str, char16_t c) noexcept [=](int i) { return n[i] == c; }, [=](int i) { return n + i; }); # endif -#elif defined(__ARM_NEON__) && defined(Q_PROCESSOR_ARM_64) // vaddv is only available on Aarch64 +#elif defined(__ARM_NEON__) const uint16x8_t vmask = { 1, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 1 << 7 }; const uint16x8_t ch_vec = vdupq_n_u16(c); for (const char16_t *next = n + 8; next <= e; n = next, next += 8) { @@ -1004,7 +1004,7 @@ static int ucstrncmp(const QChar *a, const QChar *b, size_t l) }; return UnrollTailLoop<3>::exec(l, 0, lambda, lambda); #endif -#if defined(__ARM_NEON__) && defined(Q_PROCESSOR_ARM_64) // vaddv is only available on Aarch64 +#ifdef __ARM_NEON__ if (l >= 8) { const QChar *end = a + l; const uint16x8_t mask = { 1, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 1 << 7 }; diff --git a/src/corelib/text/qstringconverter.cpp b/src/corelib/text/qstringconverter.cpp index 524bb4cc03..df9efe7f67 100644 --- a/src/corelib/text/qstringconverter.cpp +++ b/src/corelib/text/qstringconverter.cpp @@ -61,7 +61,7 @@ enum { Endian = 0, Data = 1 }; static const uchar utf8bom[] = { 0xef, 0xbb, 0xbf }; #if (defined(__SSE2__) && defined(QT_COMPILER_SUPPORTS_SSE2)) \ - || (defined(__ARM_NEON__) && defined(Q_PROCESSOR_ARM_64)) + || defined(__ARM_NEON__) static Q_ALWAYS_INLINE uint qBitScanReverse(unsigned v) noexcept { #if defined(__cpp_lib_int_pow2) && __cpp_lib_int_pow2 >= 202002L @@ -360,7 +360,7 @@ static void simdCompareAscii(const char8_t *&src8, const char8_t *end8, const ch src8 += offset; src16 += offset; } -#elif defined(__ARM_NEON__) && defined(Q_PROCESSOR_ARM_64) // vaddv is only available on Aarch64 +#elif defined(__ARM_NEON__) static inline bool simdEncodeAscii(uchar *&dst, const ushort *&nextAscii, const ushort *&src, const ushort *end) { uint16x8_t maxAscii = vdupq_n_u16(0x7f);