[llvm] [llvm] Improve implementation of StringRef::find_last_of and cie (PR #71865)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Nov 15 06:03:03 PST 2023
https://github.com/serge-sans-paille updated https://github.com/llvm/llvm-project/pull/71865
>From 5ebe6d8729ea7b9fa69f2c1ff39c8ddd76997503 Mon Sep 17 00:00:00 2001
From: serge-sans-paille <sguelton at mozilla.com>
Date: Thu, 9 Nov 2023 20:41:40 +0100
Subject: [PATCH] [llvm] Improve implementation of StringRef::find_last_of for
the usual case of 2 chars
Almost all usage of StringRef::find_last_of in Clang/LLVM use a Needle
of 2 elements, which can easily be optimized in SSE2. The IPC of the
improved version is significantly better as shown in
https://godbolt.org/z/h1dsdcMd8
And it does not require an extra structure.
---
llvm/lib/Support/StringRef.cpp | 33 ++++++++++++++++++++++++++++++++-
1 file changed, 32 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/Support/StringRef.cpp b/llvm/lib/Support/StringRef.cpp
index feee47ca693b251..c9923cdfdb76754 100644
--- a/llvm/lib/Support/StringRef.cpp
+++ b/llvm/lib/Support/StringRef.cpp
@@ -15,6 +15,10 @@
#include "llvm/Support/Error.h"
#include <bitset>
+#ifdef __SSE2__
+#include <emmintrin.h>
+#endif
+
using namespace llvm;
// MSVC emits references to this into the translation units which reference it.
@@ -268,17 +272,44 @@ StringRef::size_type StringRef::find_first_not_of(StringRef Chars,
return npos;
}
+#ifdef __SSE2__
+
+StringRef::size_type vectorized_find_last_of_specialized(const char *Data,
+ size_t Sz, char C0,
+ char C1) {
+ __m128i Needle0 = _mm_set1_epi8(Chars[0]);
+ __m128i Needle1 = _mm_set1_epi8(Chars[1]);
+ do {
+ Sz = Sz < 16 ? 0 : Sz - 16;
+ __m128i Buffer = _mm_loadu_si128((const __m128i *)(Data + Sz));
+ unsigned Mask = _mm_movemask_epi8(_mm_or_si128(
+ _mm_cmpeq_epi8(Buffer, Needle0), _mm_cmpeq_epi8(Buffer, Needle1)));
+ if (Mask != 0) {
+ return Sz + sizeof(Mask) * CHAR_BIT - llvm::countl_zero(Mask);
+ }
+ } while (Sz);
+ return npos;
+}
+#endif
+
/// find_last_of - Find the last character in the string that is in \arg C,
/// or npos if not found.
///
/// Note: O(size() + Chars.size())
StringRef::size_type StringRef::find_last_of(StringRef Chars,
size_t From) const {
+ size_type Sz = std::min(From, Length);
+
+#ifdef __SSE2__
+ if (Chars.size() == 2) {
+ return vectorized_find_last_of_specialized(Data, Sz, Chars[0], Chars[1]);
+#endif
+
std::bitset<1 << CHAR_BIT> CharBits;
for (char C : Chars)
CharBits.set((unsigned char)C);
- for (size_type i = std::min(From, Length) - 1, e = -1; i != e; --i)
+ for (size_type i = Sz - 1, e = -1; i != e; --i)
if (CharBits.test((unsigned char)Data[i]))
return i;
return npos;
More information about the llvm-commits
mailing list