diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2022-01-11 17:26:21 -0800 |
---|---|---|
committer | Thiago Macieira <thiago.macieira@intel.com> | 2022-12-04 17:56:45 -0800 |
commit | 1acd028b0c70d7b139e554f856b981648822a2a4 (patch) | |
tree | d1c706dde9ac7ece4b3757e9e646bfa32eba6929 /src/corelib | |
parent | 40083f380f1f9f6208c201941e620443a0cc8fb4 (diff) |
QString: move the body of qustrlen's SSE2 implementation
Change-Id: I0e5f6bec596a4a78bd3bfffd16c96189533ad94e
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
Diffstat (limited to 'src/corelib')
-rw-r--r-- | src/corelib/text/qstring.cpp | 72 |
1 files changed, 38 insertions, 34 deletions
diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp index e3c5de8fca..46ccae91b7 100644 --- a/src/corelib/text/qstring.cpp +++ b/src/corelib/text/qstring.cpp @@ -415,6 +415,42 @@ static Q_ALWAYS_INLINE __m128i mm_load8_zero_extend(const void *ptr) return _mm_unpacklo_epi8(data, _mm_setzero_si128()); } +[[maybe_unused]] ATTRIBUTE_NO_SANITIZE +static qsizetype qustrlen_sse2(const char16_t *str) noexcept +{ + // find the 16-byte alignment immediately prior or equal to str + quintptr misalignment = quintptr(str) & 0xf; + Q_ASSERT((misalignment & 1) == 0); + const char16_t *ptr = str - (misalignment / 2); + + // load 16 bytes and see if we have a null + // (aligned loads can never segfault) + const __m128i zeroes = _mm_setzero_si128(); + __m128i data = _mm_load_si128(reinterpret_cast<const __m128i *>(ptr)); + __m128i comparison = _mm_cmpeq_epi16(data, zeroes); + quint32 mask = _mm_movemask_epi8(comparison); + + // ignore the result prior to the beginning of str + mask >>= misalignment; + + // Have we found something in the first block? Need to handle it now + // because of the left shift above. + if (mask) + return qCountTrailingZeroBits(quint32(mask)) / 2; + + do { + ptr += 8; + data = _mm_load_si128(reinterpret_cast<const __m128i *>(ptr)); + + comparison = _mm_cmpeq_epi16(data, zeroes); + mask = _mm_movemask_epi8(comparison); + } while (mask == 0); + + // found a null + uint idx = qCountTrailingZeroBits(quint32(mask)); + return ptr - str + idx / 2; +} + // Scans from \a ptr to \a end until \a maskval is non-zero. Returns true if // the no non-zero was found. Returns false and updates \a ptr to point to the // first 16-bit word that has any bit set (note: if the input is 8-bit, \a ptr @@ -517,48 +553,16 @@ static bool simdTestMask(const char *&ptr, const char *end, quint32 maskval) } #endif -ATTRIBUTE_NO_SANITIZE qsizetype QtPrivate::qustrlen(const char16_t *str) noexcept { - qsizetype result = 0; - #if defined(__SSE2__) && !(defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer)) - // find the 16-byte alignment immediately prior or equal to str - quintptr misalignment = quintptr(str) & 0xf; - Q_ASSERT((misalignment & 1) == 0); - const char16_t *ptr = str - (misalignment / 2); - - // load 16 bytes and see if we have a null - // (aligned loads can never segfault) - const __m128i zeroes = _mm_setzero_si128(); - __m128i data = _mm_load_si128(reinterpret_cast<const __m128i *>(ptr)); - __m128i comparison = _mm_cmpeq_epi16(data, zeroes); - quint32 mask = _mm_movemask_epi8(comparison); - - // ignore the result prior to the beginning of str - mask >>= misalignment; - - // Have we found something in the first block? Need to handle it now - // because of the left shift above. - if (mask) - return qCountTrailingZeroBits(quint32(mask)) / 2; - - do { - ptr += 8; - data = _mm_load_si128(reinterpret_cast<const __m128i *>(ptr)); - - comparison = _mm_cmpeq_epi16(data, zeroes); - mask = _mm_movemask_epi8(comparison); - } while (mask == 0); - - // found a null - uint idx = qCountTrailingZeroBits(quint32(mask)); - return ptr - str + idx / 2; + return qustrlen_sse2(str); #endif if (sizeof(wchar_t) == sizeof(char16_t)) return wcslen(reinterpret_cast<const wchar_t *>(str)); + qsizetype result = 0; while (*str++) ++result; return result; |