[clang] [clang] Provide an SSE4.2 implementation of identifier token lexer (PR #68962)

via cfe-commits cfe-commits at lists.llvm.org
Fri Oct 13 03:10:45 PDT 2023


https://github.com/serge-sans-paille updated https://github.com/llvm/llvm-project/pull/68962

>From ccf33cafada526241a3fb1aca9c2d280444b589b Mon Sep 17 00:00:00 2001
From: serge-sans-paille <sguelton at mozilla.com>
Date: Thu, 12 Oct 2023 22:30:30 +0200
Subject: [PATCH 1/3] [clang] Provide an SSE4.2 implementation of identifier
 token lexer

The _mm_cmpistri instruction can be used to quickly parse identifiers.

With this patch activated, clang pre-processes <iostream> 1.8% faster, and
sqlite3.c amalgametion 1.5% faster, based on time measurements and
number of executed instructions as measured by valgrind.

The introduction of an extra helper function in the regular case has no
impact on performance, see

    https://llvm-compile-time-tracker.com/compare.php?from=30240e428f0ec7d4a6d1b84f9f807ce12b46cfd1&to=12bcb016cde4579ca7b75397762098c03eb4f264&stat=instructions:u
---
 clang/lib/Lex/Lexer.cpp | 45 ++++++++++++++++++++++++++++++++++-------
 1 file changed, 38 insertions(+), 7 deletions(-)

diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp
index feed1b9ecd71a8d..f2d9eb3a8af4e3d 100644
--- a/clang/lib/Lex/Lexer.cpp
+++ b/clang/lib/Lex/Lexer.cpp
@@ -47,6 +47,10 @@
 #include <tuple>
 #include <utility>
 
+#ifdef __SSE4_2__
+#include <nmmintrin.h>
+#endif
+
 using namespace clang;
 
 //===----------------------------------------------------------------------===//
@@ -1847,19 +1851,46 @@ bool Lexer::LexUnicodeIdentifierStart(Token &Result, uint32_t C,
   return true;
 }
 
+static const char *fastParseASCIIIdentifier(const char *CurPtr, const char* BufferEnd) {
+#ifdef __SSE4_2__
+  static constexpr char AsciiIdentifierRange[16] = {
+      '_', '_', 'A', 'Z', 'a', 'z', '0', '9',
+  };
+  constexpr ssize_t BytesPerRegister = 16;
+
+  while (LLVM_LIKELY(BufferEnd - CurPtr >= BytesPerRegister)) {
+    __m128i AsciiIdentifierRangeV = _mm_loadu_si128((const __m128i *)AsciiIdentifierRange);
+
+      __m128i Cv = _mm_loadu_si128((const __m128i *)(CurPtr));
+      int Consumed =
+          _mm_cmpistri(AsciiIdentifierRangeV, Cv,
+                       _SIDD_LEAST_SIGNIFICANT | _SIDD_CMP_RANGES |
+                           _SIDD_UBYTE_OPS | _SIDD_NEGATIVE_POLARITY);
+      CurPtr += Consumed;
+      if (Consumed == BytesPerRegister)
+        continue;
+      return CurPtr;
+  }
+#else
+  (void)BufferEnd;
+#endif
+
+  unsigned char C = *CurPtr;
+  while (isAsciiIdentifierContinue(C))
+    C = *++CurPtr;
+  return CurPtr;
+}
+
 bool Lexer::LexIdentifierContinue(Token &Result, const char *CurPtr) {
   // Match [_A-Za-z0-9]*, we have already matched an identifier start.
+
   while (true) {
-    unsigned char C = *CurPtr;
-    // Fast path.
-    if (isAsciiIdentifierContinue(C)) {
-      ++CurPtr;
-      continue;
-    }
+
+    CurPtr = fastParseASCIIIdentifier(CurPtr, BufferEnd);
 
     unsigned Size;
     // Slow path: handle trigraph, unicode codepoints, UCNs.
-    C = getCharAndSize(CurPtr, Size);
+    unsigned char C = getCharAndSize(CurPtr, Size);
     if (isAsciiIdentifierContinue(C)) {
       CurPtr = ConsumeChar(CurPtr, Size, Result);
       continue;

>From 280c93ff5e04c0acf2162a63c12bae2ecf886c92 Mon Sep 17 00:00:00 2001
From: serge-sans-paille <sguelton at mozilla.com>
Date: Fri, 13 Oct 2023 12:06:49 +0200
Subject: [PATCH 2/3] fixup! [clang] Provide an SSE4.2 implementation of
 identifier token lexer

---
 clang/lib/Lex/Lexer.cpp | 28 +++++++++++++++-------------
 1 file changed, 15 insertions(+), 13 deletions(-)

diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp
index f2d9eb3a8af4e3d..11cc57a7a237733 100644
--- a/clang/lib/Lex/Lexer.cpp
+++ b/clang/lib/Lex/Lexer.cpp
@@ -1851,25 +1851,27 @@ bool Lexer::LexUnicodeIdentifierStart(Token &Result, uint32_t C,
   return true;
 }
 
-static const char *fastParseASCIIIdentifier(const char *CurPtr, const char* BufferEnd) {
+static const char *fastParseASCIIIdentifier(const char *CurPtr,
+                                            const char *BufferEnd) {
 #ifdef __SSE4_2__
-  static constexpr char AsciiIdentifierRange[16] = {
+  alignas(16) static constexpr char AsciiIdentifierRange[16] = {
       '_', '_', 'A', 'Z', 'a', 'z', '0', '9',
   };
   constexpr ssize_t BytesPerRegister = 16;
 
+  __m128i AsciiIdentifierRangeV =
+      _mm_load_si128((const __m128i *)AsciiIdentifierRange);
+
   while (LLVM_LIKELY(BufferEnd - CurPtr >= BytesPerRegister)) {
-    __m128i AsciiIdentifierRangeV = _mm_loadu_si128((const __m128i *)AsciiIdentifierRange);
-
-      __m128i Cv = _mm_loadu_si128((const __m128i *)(CurPtr));
-      int Consumed =
-          _mm_cmpistri(AsciiIdentifierRangeV, Cv,
-                       _SIDD_LEAST_SIGNIFICANT | _SIDD_CMP_RANGES |
-                           _SIDD_UBYTE_OPS | _SIDD_NEGATIVE_POLARITY);
-      CurPtr += Consumed;
-      if (Consumed == BytesPerRegister)
-        continue;
-      return CurPtr;
+    __m128i Cv = _mm_loadu_si128((const __m128i *)(CurPtr));
+
+    int Consumed = _mm_cmpistri(AsciiIdentifierRangeV, Cv,
+                                _SIDD_LEAST_SIGNIFICANT | _SIDD_CMP_RANGES |
+                                    _SIDD_UBYTE_OPS | _SIDD_NEGATIVE_POLARITY);
+    CurPtr += Consumed;
+    if (Consumed == BytesPerRegister)
+      continue;
+    return CurPtr;
   }
 #else
   (void)BufferEnd;

>From e030795a3b86b5b03802a70438e4c6ff1d4e97d7 Mon Sep 17 00:00:00 2001
From: serge-sans-paille <sguelton at mozilla.com>
Date: Fri, 13 Oct 2023 12:09:21 +0200
Subject: [PATCH 3/3] fixup! [clang] Provide an SSE4.2 implementation of
 identifier token lexer

---
 clang/lib/Lex/Lexer.cpp | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp
index 11cc57a7a237733..675ec28e514797e 100644
--- a/clang/lib/Lex/Lexer.cpp
+++ b/clang/lib/Lex/Lexer.cpp
@@ -1851,8 +1851,9 @@ bool Lexer::LexUnicodeIdentifierStart(Token &Result, uint32_t C,
   return true;
 }
 
-static const char *fastParseASCIIIdentifier(const char *CurPtr,
-                                            const char *BufferEnd) {
+static const char *
+fastParseASCIIIdentifier(const char *CurPtr,
+                         [[maybe_unused]] const char *BufferEnd) {
 #ifdef __SSE4_2__
   alignas(16) static constexpr char AsciiIdentifierRange[16] = {
       '_', '_', 'A', 'Z', 'a', 'z', '0', '9',
@@ -1873,8 +1874,6 @@ static const char *fastParseASCIIIdentifier(const char *CurPtr,
       continue;
     return CurPtr;
   }
-#else
-  (void)BufferEnd;
 #endif
 
   unsigned char C = *CurPtr;



More information about the cfe-commits mailing list