Author: Thibault Monnier
Date: 2026-07-22T15:57:56+02:00
New Revision: 84301dd17f4261b4b8c293cd21b6641b3fdc0add

URL: 
https://github.com/llvm/llvm-project/commit/84301dd17f4261b4b8c293cd21b6641b3fdc0add
DIFF: 
https://github.com/llvm/llvm-project/commit/84301dd17f4261b4b8c293cd21b6641b3fdc0add.diff

LOG: [Clang][Lexer] Reland "Detect SSE4.2 availability at runtime in 
fastParseASCIIIdentifier" (#180631)

This PR reopens #175452 after it was merged then reverted by #177322
because of compilation failures and compatibility issues.

This change attempts to maximize usage of the SSE fast path in
`fastParseASCIIIdentifier`.

If the binary is compiled with SSE4.2 enabled, or if we are not
compiling for x86, then the behavior is the exact same, ensuring we have
no regressions.
Otherwise, we compile both the SSE fast path and the scalar loop. At
runtime, we check if SSE4.2 is available and dispatch to the right
function by using `__builtin_cpu_supports`. If it _is_ available, this
allows a net performance improvement. Otherwise, there's a very slight
but negligible regression... I believe that's perfectly reasonable for a
non-SSE4.2-supporting processor.

The benchmark results are available here:
https://llvm-compile-time-tracker.com/compare.php?from=3192fe2c7b08912cc72c86471a593165b615dc28&to=8960c57a2e5880616d2dd549f8422ca91c864e86&stat=instructions%3Au.

Added: 
    

Modified: 
    clang/lib/Lex/Lexer.cpp
    llvm/include/llvm/Support/Compiler.h

Removed: 
    


################################################################################
diff  --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp
index f7d44879a936d..5826485c8b16a 100644
--- a/clang/lib/Lex/Lexer.cpp
+++ b/clang/lib/Lex/Lexer.cpp
@@ -37,6 +37,7 @@
 #include "llvm/Support/SaveAndRestore.h"
 #include "llvm/Support/Unicode.h"
 #include "llvm/Support/UnicodeCharRanges.h"
+
 #include <algorithm>
 #include <cassert>
 #include <cstddef>
@@ -46,7 +47,7 @@
 #include <optional>
 #include <string>
 
-#ifdef __SSE4_2__
+#if LLVM_IS_X86
 #include <nmmintrin.h>
 #endif
 
@@ -1980,35 +1981,49 @@ bool Lexer::LexUnicodeIdentifierStart(Token &Result, 
uint32_t C,
   return true;
 }
 
-static const char *
-fastParseASCIIIdentifier(const char *CurPtr,
-                         [[maybe_unused]] const char *BufferEnd) {
-#ifdef __SSE4_2__
+static const char *fastParseASCIIIdentifierScalar(const char *CurPtr) {
+  unsigned char C = *CurPtr;
+  while (isAsciiIdentifierContinue(C))
+    C = *++CurPtr;
+  return CurPtr;
+}
+
+#if LLVM_IS_X86
+// Fast path for lexing ASCII identifiers using SSE4.2 instructions.
+LLVM_TARGET_SSE42 static const char *
+fastParseASCIIIdentifierSSE42(const char *CurPtr, const char *BufferEnd) {
   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);
+      _mm_load_si128(reinterpret_cast<const __m128i *>(AsciiIdentifierRange));
 
   while (LLVM_LIKELY(BufferEnd - CurPtr >= BytesPerRegister)) {
-    __m128i Cv = _mm_loadu_si128((const __m128i *)(CurPtr));
+    __m128i Cv = _mm_loadu_si128(reinterpret_cast<const __m128i *>(CurPtr));
 
-    int Consumed = _mm_cmpistri(AsciiIdentifierRangeV, Cv,
-                                _SIDD_LEAST_SIGNIFICANT | _SIDD_CMP_RANGES |
-                                    _SIDD_UBYTE_OPS | _SIDD_NEGATIVE_POLARITY);
+    const 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;
   }
+
+  return fastParseASCIIIdentifierScalar(CurPtr);
+}
 #endif
 
-  unsigned char C = *CurPtr;
-  while (isAsciiIdentifierContinue(C))
-    C = *++CurPtr;
-  return CurPtr;
+static const char *fastParseASCIIIdentifier(const char *CurPtr,
+                                            const char *BufferEnd) {
+#if LLVM_IS_X86
+  if (LLVM_LIKELY(LLVM_CPU_SUPPORTS_SSE42))
+    return fastParseASCIIIdentifierSSE42(CurPtr, BufferEnd);
+#endif
+  return fastParseASCIIIdentifierScalar(CurPtr);
 }
 
 bool Lexer::LexIdentifierContinue(Token &Result, const char *CurPtr) {

diff  --git a/llvm/include/llvm/Support/Compiler.h 
b/llvm/include/llvm/Support/Compiler.h
index cffab778deeb4..34b328ba1ac8a 100644
--- a/llvm/include/llvm/Support/Compiler.h
+++ b/llvm/include/llvm/Support/Compiler.h
@@ -773,4 +773,36 @@ void AnnotateIgnoreWritesEnd(const char *file, int line);
 #endif
 // clang-format on
 
+/// \macro LLVM_IS_X86
+/// Whether the target architecture is x86 / x86-64.
+#if defined(__x86_64__) || defined(__i386__)
+#define LLVM_IS_X86 1
+#else
+#define LLVM_IS_X86 0
+#endif
+
+/// \macro LLVM_TARGET_SSE42
+/// Function attribute to compile a function with SSE4.2 enabled.
+#if defined(__has_attribute) && __has_attribute(target)
+#define LLVM_TARGET_SSE42 __attribute__((target("sse4.2")))
+#else
+#define LLVM_TARGET_SSE42
+#endif
+
+#if __has_builtin(__builtin_cpu_supports) &&                                   
\
+    (defined(__linux__) || defined(__APPLE__))
+#define LLVM_CPU_SUPPORTS(feature) __builtin_cpu_supports(feature)
+#else
+#define LLVM_CPU_SUPPORTS(feature) 0
+#endif
+
+/// \macro LLVM_CPU_SUPPORTS_SSE42
+/// Expands to true if the runtime cpu supports SSE4.2, or if compiled with
+/// SSE4.2 enabled.
+#if defined(__SSE4_2__)
+#define LLVM_CPU_SUPPORTS_SSE42 1
+#else
+#define LLVM_CPU_SUPPORTS_SSE42 LLVM_CPU_SUPPORTS("sse4.2")
+#endif
+
 #endif


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to