[clang] [llvm] [Clang][Lexer] Reland "Detect SSE4.2 availability at runtime in fastParseASCIIIdentifier" (PR #175452)
Thibault Monnier via cfe-commits
cfe-commits at lists.llvm.org
Sun Jan 18 08:03:32 PST 2026
https://github.com/Thibault-Monnier updated https://github.com/llvm/llvm-project/pull/175452
>From 4fc9a07698e1a4627a050ba6fa9df3f1f8725451 Mon Sep 17 00:00:00 2001
From: Thibault-Monnier <thibaultmonni at gmail.com>
Date: Thu, 11 Dec 2025 22:02:35 +0100
Subject: [PATCH 01/13] Detect sse4.2 availability at runtime to use it on
modern processors
---
clang/lib/Lex/Lexer.cpp | 35 ++++++++++++++++++++++++++---------
1 file changed, 26 insertions(+), 9 deletions(-)
diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp
index b282a600c0e56..3b8fa0b9b7f36 100644
--- a/clang/lib/Lex/Lexer.cpp
+++ b/clang/lib/Lex/Lexer.cpp
@@ -46,9 +46,7 @@
#include <string>
#include <tuple>
-#ifdef __SSE4_2__
#include <nmmintrin.h>
-#endif
using namespace clang;
@@ -1921,9 +1919,17 @@ bool Lexer::LexUnicodeIdentifierStart(Token &Result, uint32_t C,
}
static const char *
-fastParseASCIIIdentifier(const char *CurPtr,
- [[maybe_unused]] const char *BufferEnd) {
-#ifdef __SSE4_2__
+fastParseASCIIIdentifierScalar(const char *CurPtr,
+ [[maybe_unused]] const char *BufferEnd) {
+ unsigned char C = *CurPtr;
+ while (isAsciiIdentifierContinue(C))
+ C = *++CurPtr;
+ return CurPtr;
+}
+
+__attribute__((target("sse4.2"))) static const char *
+fastParseASCIIIdentifierSSE42(const char *CurPtr,
+ [[maybe_unused]] const char *BufferEnd) {
alignas(16) static constexpr char AsciiIdentifierRange[16] = {
'_', '_', 'A', 'Z', 'a', 'z', '0', '9',
};
@@ -1943,12 +1949,23 @@ fastParseASCIIIdentifier(const char *CurPtr,
continue;
return CurPtr;
}
+
+ return fastParseASCIIIdentifierScalar(CurPtr, BufferEnd);
+}
+
+static bool supportsSSE42() {
+ static bool SupportsSSE42 = __builtin_cpu_supports("sse4.2");
+ return SupportsSSE42;
+}
+
+static const char *fastParseASCIIIdentifier(const char *CurPtr,
+ const char *BufferEnd) {
+#ifndef __SSE4_2__
+ if (LLVM_UNLIKELY(!supportsSSE42()))
+ return fastParseASCIIIdentifierScalar(CurPtr, BufferEnd);
#endif
- unsigned char C = *CurPtr;
- while (isAsciiIdentifierContinue(C))
- C = *++CurPtr;
- return CurPtr;
+ return fastParseASCIIIdentifierSSE42(CurPtr, BufferEnd);
}
bool Lexer::LexIdentifierContinue(Token &Result, const char *CurPtr) {
>From ce3bf515e7a60bd58ff5871352979999f5864b4b Mon Sep 17 00:00:00 2001
From: Thibault-Monnier <thibaultmonni at gmail.com>
Date: Thu, 11 Dec 2025 23:15:40 +0100
Subject: [PATCH 02/13] Only on x86
---
clang/lib/Lex/Lexer.cpp | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp
index 3b8fa0b9b7f36..c195237dae1f4 100644
--- a/clang/lib/Lex/Lexer.cpp
+++ b/clang/lib/Lex/Lexer.cpp
@@ -46,7 +46,9 @@
#include <string>
#include <tuple>
+#if defined(__i386__) || defined(__x86_64__)
#include <nmmintrin.h>
+#endif
using namespace clang;
@@ -1927,6 +1929,8 @@ fastParseASCIIIdentifierScalar(const char *CurPtr,
return CurPtr;
}
+#if defined(__i386__) || defined(__x86_64__)
+
__attribute__((target("sse4.2"))) static const char *
fastParseASCIIIdentifierSSE42(const char *CurPtr,
[[maybe_unused]] const char *BufferEnd) {
@@ -1958,14 +1962,22 @@ static bool supportsSSE42() {
return SupportsSSE42;
}
+#endif
+
static const char *fastParseASCIIIdentifier(const char *CurPtr,
const char *BufferEnd) {
+#if !defined(__i386__) && !defined(__x86_64__)
+ return fastParseASCIIIdentifierScalar(CurPtr, BufferEnd);
+#else
+
#ifndef __SSE4_2__
if (LLVM_UNLIKELY(!supportsSSE42()))
return fastParseASCIIIdentifierScalar(CurPtr, BufferEnd);
#endif
return fastParseASCIIIdentifierSSE42(CurPtr, BufferEnd);
+
+#endif
}
bool Lexer::LexIdentifierContinue(Token &Result, const char *CurPtr) {
>From 2109fdd371822ec77f870c5edbbdfccaaa7615be Mon Sep 17 00:00:00 2001
From: Thibault-Monnier <thibaultmonni at gmail.com>
Date: Sun, 14 Dec 2025 11:32:30 +0100
Subject: [PATCH 03/13] Not on windows
---
clang/lib/Lex/Lexer.cpp | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp
index c195237dae1f4..86cfb47ca84d5 100644
--- a/clang/lib/Lex/Lexer.cpp
+++ b/clang/lib/Lex/Lexer.cpp
@@ -36,6 +36,7 @@
#include "llvm/Support/NativeFormatting.h"
#include "llvm/Support/Unicode.h"
#include "llvm/Support/UnicodeCharRanges.h"
+
#include <algorithm>
#include <cassert>
#include <cstddef>
@@ -1929,7 +1930,7 @@ fastParseASCIIIdentifierScalar(const char *CurPtr,
return CurPtr;
}
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__x86_64__) && !defined(_WIN32)
__attribute__((target("sse4.2"))) static const char *
fastParseASCIIIdentifierSSE42(const char *CurPtr,
@@ -1966,7 +1967,7 @@ static bool supportsSSE42() {
static const char *fastParseASCIIIdentifier(const char *CurPtr,
const char *BufferEnd) {
-#if !defined(__i386__) && !defined(__x86_64__)
+#if !defined(__i386__) && !defined(__x86_64__) || defined(_WIN32)
return fastParseASCIIIdentifierScalar(CurPtr, BufferEnd);
#else
>From d5485438edd460892bf210916827e0d92fc24065 Mon Sep 17 00:00:00 2001
From: Thibault-Monnier <thibaultmonni at gmail.com>
Date: Sun, 14 Dec 2025 14:37:43 +0100
Subject: [PATCH 04/13] Address comments
---
clang/lib/Lex/Lexer.cpp | 26 ++++++++++----------------
1 file changed, 10 insertions(+), 16 deletions(-)
diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp
index 86cfb47ca84d5..470579df233d1 100644
--- a/clang/lib/Lex/Lexer.cpp
+++ b/clang/lib/Lex/Lexer.cpp
@@ -1930,7 +1930,12 @@ fastParseASCIIIdentifierScalar(const char *CurPtr,
return CurPtr;
}
-#if defined(__i386__) || defined(__x86_64__) && !defined(_WIN32)
+// Fast path for lexing ASCII identifiers using SSE4.2 instructions.
+// Only enabled on x86/x86_64 when building with a compiler that supports
+// the 'target' attribute, which is used for runtime dispatch. Otherwise, we
+// fall back to the scalar implementation.
+#if (defined(__i386__) || defined(__x86_64__)) && defined(__has_attribute) && \
+ __has_attribute(target)
__attribute__((target("sse4.2"))) static const char *
fastParseASCIIIdentifierSSE42(const char *CurPtr,
@@ -1958,27 +1963,16 @@ fastParseASCIIIdentifierSSE42(const char *CurPtr,
return fastParseASCIIIdentifierScalar(CurPtr, BufferEnd);
}
-static bool supportsSSE42() {
- static bool SupportsSSE42 = __builtin_cpu_supports("sse4.2");
- return SupportsSSE42;
+__attribute__((target("sse4.2"))) static const char *
+fastParseASCIIIdentifier(const char *CurPtr, const char *BufferEnd) {
+ return fastParseASCIIIdentifierSSE42(CurPtr, BufferEnd);
}
+__attribute__((target("default")))
#endif
-
static const char *fastParseASCIIIdentifier(const char *CurPtr,
const char *BufferEnd) {
-#if !defined(__i386__) && !defined(__x86_64__) || defined(_WIN32)
return fastParseASCIIIdentifierScalar(CurPtr, BufferEnd);
-#else
-
-#ifndef __SSE4_2__
- if (LLVM_UNLIKELY(!supportsSSE42()))
- return fastParseASCIIIdentifierScalar(CurPtr, BufferEnd);
-#endif
-
- return fastParseASCIIIdentifierSSE42(CurPtr, BufferEnd);
-
-#endif
}
bool Lexer::LexIdentifierContinue(Token &Result, const char *CurPtr) {
>From 82cf41e460d2fa1105e9abbf925837fa9e9c7b45 Mon Sep 17 00:00:00 2001
From: Thibault-Monnier <thibaultmonni at gmail.com>
Date: Sun, 14 Dec 2025 19:32:29 +0100
Subject: [PATCH 05/13] Not on MSVC
---
clang/lib/Lex/Lexer.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp
index 470579df233d1..58cd9348d3027 100644
--- a/clang/lib/Lex/Lexer.cpp
+++ b/clang/lib/Lex/Lexer.cpp
@@ -1935,7 +1935,7 @@ fastParseASCIIIdentifierScalar(const char *CurPtr,
// the 'target' attribute, which is used for runtime dispatch. Otherwise, we
// fall back to the scalar implementation.
#if (defined(__i386__) || defined(__x86_64__)) && defined(__has_attribute) && \
- __has_attribute(target)
+ __has_attribute(target) && !defined(_MSC_VER)
__attribute__((target("sse4.2"))) static const char *
fastParseASCIIIdentifierSSE42(const char *CurPtr,
>From d7896bf4cd67116d8a3f59c74b51fce1c0f46951 Mon Sep 17 00:00:00 2001
From: Thibault-Monnier <thibaultmonni at gmail.com>
Date: Sun, 28 Dec 2025 17:48:49 +0100
Subject: [PATCH 06/13] Clean up
---
clang/lib/Lex/Lexer.cpp | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)
diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp
index 58cd9348d3027..ba950dc350edb 100644
--- a/clang/lib/Lex/Lexer.cpp
+++ b/clang/lib/Lex/Lexer.cpp
@@ -1921,9 +1921,7 @@ bool Lexer::LexUnicodeIdentifierStart(Token &Result, uint32_t C,
return true;
}
-static const char *
-fastParseASCIIIdentifierScalar(const char *CurPtr,
- [[maybe_unused]] const char *BufferEnd) {
+static const char *fastParseASCIIIdentifierScalar(const char *CurPtr) {
unsigned char C = *CurPtr;
while (isAsciiIdentifierContinue(C))
C = *++CurPtr;
@@ -1936,10 +1934,8 @@ fastParseASCIIIdentifierScalar(const char *CurPtr,
// fall back to the scalar implementation.
#if (defined(__i386__) || defined(__x86_64__)) && defined(__has_attribute) && \
__has_attribute(target) && !defined(_MSC_VER)
-
__attribute__((target("sse4.2"))) static const char *
-fastParseASCIIIdentifierSSE42(const char *CurPtr,
- [[maybe_unused]] const char *BufferEnd) {
+fastParseASCIIIdentifierSSE42(const char *CurPtr, const char *BufferEnd) {
alignas(16) static constexpr char AsciiIdentifierRange[16] = {
'_', '_', 'A', 'Z', 'a', 'z', '0', '9',
};
@@ -1960,7 +1956,7 @@ fastParseASCIIIdentifierSSE42(const char *CurPtr,
return CurPtr;
}
- return fastParseASCIIIdentifierScalar(CurPtr, BufferEnd);
+ return fastParseASCIIIdentifierScalar(CurPtr);
}
__attribute__((target("sse4.2"))) static const char *
@@ -1972,7 +1968,7 @@ __attribute__((target("default")))
#endif
static const char *fastParseASCIIIdentifier(const char *CurPtr,
const char *BufferEnd) {
- return fastParseASCIIIdentifierScalar(CurPtr, BufferEnd);
+ return fastParseASCIIIdentifierScalar(CurPtr);
}
bool Lexer::LexIdentifierContinue(Token &Result, const char *CurPtr) {
>From 079b0abf7aed81438f1a0b9aa8589399a0e6003a Mon Sep 17 00:00:00 2001
From: Thibault-Monnier <thibaultmonni at gmail.com>
Date: Sun, 11 Jan 2026 21:05:05 +0100
Subject: [PATCH 07/13] Not on windows + fix unused parameter warning
---
clang/lib/Lex/Lexer.cpp | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)
diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp
index ba950dc350edb..46b496b61c08c 100644
--- a/clang/lib/Lex/Lexer.cpp
+++ b/clang/lib/Lex/Lexer.cpp
@@ -1933,7 +1933,7 @@ static const char *fastParseASCIIIdentifierScalar(const char *CurPtr) {
// the 'target' attribute, which is used for runtime dispatch. Otherwise, we
// fall back to the scalar implementation.
#if (defined(__i386__) || defined(__x86_64__)) && defined(__has_attribute) && \
- __has_attribute(target) && !defined(_MSC_VER)
+ __has_attribute(target) && !defined(_WIN32)
__attribute__((target("sse4.2"))) static const char *
fastParseASCIIIdentifierSSE42(const char *CurPtr, const char *BufferEnd) {
alignas(16) static constexpr char AsciiIdentifierRange[16] = {
@@ -1959,15 +1959,11 @@ fastParseASCIIIdentifierSSE42(const char *CurPtr, const char *BufferEnd) {
return fastParseASCIIIdentifierScalar(CurPtr);
}
-__attribute__((target("sse4.2"))) static const char *
-fastParseASCIIIdentifier(const char *CurPtr, const char *BufferEnd) {
- return fastParseASCIIIdentifierSSE42(CurPtr, BufferEnd);
-}
-
__attribute__((target("default")))
#endif
-static const char *fastParseASCIIIdentifier(const char *CurPtr,
- const char *BufferEnd) {
+static const char *
+fastParseASCIIIdentifier(const char *CurPtr,
+ [[maybe_unused]] const char *BufferEnd) {
return fastParseASCIIIdentifierScalar(CurPtr);
}
>From 0cb3b5c0d61a814a947c20cdbfec7c2be83b80c9 Mon Sep 17 00:00:00 2001
From: Thibault-Monnier <thibaultmonni at gmail.com>
Date: Mon, 12 Jan 2026 19:56:20 +0100
Subject: [PATCH 08/13] Rename function to fix compilation error
---
clang/lib/Lex/Lexer.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp
index 46b496b61c08c..474b64e6e2341 100644
--- a/clang/lib/Lex/Lexer.cpp
+++ b/clang/lib/Lex/Lexer.cpp
@@ -1935,7 +1935,7 @@ static const char *fastParseASCIIIdentifierScalar(const char *CurPtr) {
#if (defined(__i386__) || defined(__x86_64__)) && defined(__has_attribute) && \
__has_attribute(target) && !defined(_WIN32)
__attribute__((target("sse4.2"))) static const char *
-fastParseASCIIIdentifierSSE42(const char *CurPtr, const char *BufferEnd) {
+fastParseASCIIIdentifier(const char *CurPtr, const char *BufferEnd) {
alignas(16) static constexpr char AsciiIdentifierRange[16] = {
'_', '_', 'A', 'Z', 'a', 'z', '0', '9',
};
>From f4d1e182a285725b487ab2c6bd909ec93bb24821 Mon Sep 17 00:00:00 2001
From: Thibault-Monnier <thibaultmonni at gmail.com>
Date: Mon, 12 Jan 2026 20:05:19 +0100
Subject: [PATCH 09/13] No runtime check when compiled with SSE4.2 support
(POC)
---
clang/lib/Lex/Lexer.cpp | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp
index 474b64e6e2341..dbef4af5ce01b 100644
--- a/clang/lib/Lex/Lexer.cpp
+++ b/clang/lib/Lex/Lexer.cpp
@@ -1932,8 +1932,9 @@ static const char *fastParseASCIIIdentifierScalar(const char *CurPtr) {
// Only enabled on x86/x86_64 when building with a compiler that supports
// the 'target' attribute, which is used for runtime dispatch. Otherwise, we
// fall back to the scalar implementation.
-#if (defined(__i386__) || defined(__x86_64__)) && defined(__has_attribute) && \
- __has_attribute(target) && !defined(_WIN32)
+#if defined(__SSE4_2__) || (defined(__i386__) || defined(__x86_64__)) && \
+ defined(__has_attribute) && \
+ __has_attribute(target) && !defined(_WIN32)
__attribute__((target("sse4.2"))) static const char *
fastParseASCIIIdentifier(const char *CurPtr, const char *BufferEnd) {
alignas(16) static constexpr char AsciiIdentifierRange[16] = {
@@ -1959,13 +1960,17 @@ fastParseASCIIIdentifier(const char *CurPtr, const char *BufferEnd) {
return fastParseASCIIIdentifierScalar(CurPtr);
}
+#ifndef __SSE4_2__
__attribute__((target("default")))
#endif
+#endif
+#ifndef __SSE4_2__
static const char *
fastParseASCIIIdentifier(const char *CurPtr,
[[maybe_unused]] const char *BufferEnd) {
return fastParseASCIIIdentifierScalar(CurPtr);
}
+#endif
bool Lexer::LexIdentifierContinue(Token &Result, const char *CurPtr) {
// Match [_A-Za-z0-9]*, we have already matched an identifier start.
>From 938aec79be93fcc8f1b8cfb829ce933727c36f22 Mon Sep 17 00:00:00 2001
From: Thibault-Monnier <thibaultmonni at gmail.com>
Date: Wed, 14 Jan 2026 20:07:23 +0100
Subject: [PATCH 10/13] Address comments & final fixes
---
clang/lib/Lex/Lexer.cpp | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp
index dbef4af5ce01b..7bfaf7a2f8c69 100644
--- a/clang/lib/Lex/Lexer.cpp
+++ b/clang/lib/Lex/Lexer.cpp
@@ -1929,13 +1929,16 @@ static const char *fastParseASCIIIdentifierScalar(const char *CurPtr) {
}
// Fast path for lexing ASCII identifiers using SSE4.2 instructions.
-// Only enabled on x86/x86_64 when building with a compiler that supports
-// the 'target' attribute, which is used for runtime dispatch. Otherwise, we
-// fall back to the scalar implementation.
+// Only enabled on x86/x86_64 when building with __SSE4_2__ enabled, or with a
+// compiler that supports the 'target' attribute, used for runtime dispatch.
+// Otherwise, we fall back to the scalar implementation.
+// We avoid runtime check on Windows because it is not yet well-supported.
#if defined(__SSE4_2__) || (defined(__i386__) || defined(__x86_64__)) && \
defined(__has_attribute) && \
__has_attribute(target) && !defined(_WIN32)
-__attribute__((target("sse4.2"))) static const char *
+// "used" is a hack to suppress a false-positive warning due to a bug in
+// clang-18 and less. See PR175452.
+__attribute__((target("sse4.2"), used)) static const char *
fastParseASCIIIdentifier(const char *CurPtr, const char *BufferEnd) {
alignas(16) static constexpr char AsciiIdentifierRange[16] = {
'_', '_', 'A', 'Z', 'a', 'z', '0', '9',
@@ -1965,9 +1968,7 @@ __attribute__((target("default")))
#endif
#endif
#ifndef __SSE4_2__
-static const char *
-fastParseASCIIIdentifier(const char *CurPtr,
- [[maybe_unused]] const char *BufferEnd) {
+static const char *fastParseASCIIIdentifier(const char *CurPtr, const char *) {
return fastParseASCIIIdentifierScalar(CurPtr);
}
#endif
>From e8370a9512f6851d39256139b722b09e783e0305 Mon Sep 17 00:00:00 2001
From: Thibault-Monnier <thibaultmonni at gmail.com>
Date: Thu, 15 Jan 2026 16:28:47 +0100
Subject: [PATCH 11/13] Try simplifying with macros
---
clang/lib/Lex/Lexer.cpp | 21 ++++++++-------------
llvm/include/llvm/Support/Compiler.h | 21 +++++++++++++++++++++
2 files changed, 29 insertions(+), 13 deletions(-)
diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp
index 7bfaf7a2f8c69..9a85d184b4c38 100644
--- a/clang/lib/Lex/Lexer.cpp
+++ b/clang/lib/Lex/Lexer.cpp
@@ -1933,12 +1933,10 @@ static const char *fastParseASCIIIdentifierScalar(const char *CurPtr) {
// compiler that supports the 'target' attribute, used for runtime dispatch.
// Otherwise, we fall back to the scalar implementation.
// We avoid runtime check on Windows because it is not yet well-supported.
-#if defined(__SSE4_2__) || (defined(__i386__) || defined(__x86_64__)) && \
- defined(__has_attribute) && \
- __has_attribute(target) && !defined(_WIN32)
-// "used" is a hack to suppress a false-positive warning due to a bug in
-// clang-18 and less. See PR175452.
-__attribute__((target("sse4.2"), used)) static const char *
+#if LLVM_SUPPORTS_RUNTIME_SSE42_CHECK
+// LLVM_ATTRIBUTE_USED is a hack to suppress a false-positive warning due to a
+// bug in clang-18 and less. See PR175452.
+LLVM_ATTRIBUTE_USED __attribute__((target("sse4.2"))) static const char *
fastParseASCIIIdentifier(const char *CurPtr, const char *BufferEnd) {
alignas(16) static constexpr char AsciiIdentifierRange[16] = {
'_', '_', 'A', 'Z', 'a', 'z', '0', '9',
@@ -1963,15 +1961,12 @@ fastParseASCIIIdentifier(const char *CurPtr, const char *BufferEnd) {
return fastParseASCIIIdentifierScalar(CurPtr);
}
-#ifndef __SSE4_2__
-__attribute__((target("default")))
+LLVM_UNLESS_SSE42(__attribute__((target("default"))))
#endif
-#endif
-#ifndef __SSE4_2__
-static const char *fastParseASCIIIdentifier(const char *CurPtr, const char *) {
+LLVM_UNLESS_SSE42(static const char *fastParseASCIIIdentifier(
+ const char *CurPtr, const char *) {
return fastParseASCIIIdentifierScalar(CurPtr);
-}
-#endif
+})
bool Lexer::LexIdentifierContinue(Token &Result, const char *CurPtr) {
// Match [_A-Za-z0-9]*, we have already matched an identifier start.
diff --git a/llvm/include/llvm/Support/Compiler.h b/llvm/include/llvm/Support/Compiler.h
index 56f498a36ae52..720079d83a37e 100644
--- a/llvm/include/llvm/Support/Compiler.h
+++ b/llvm/include/llvm/Support/Compiler.h
@@ -739,4 +739,25 @@ void AnnotateIgnoreWritesEnd(const char *file, int line);
#endif
// clang-format on
+/// \macro LLVM_UNLESS_SSE42
+/// Expands to its arguments only if SSE4.2 is not enabled.
+/// This can be used to annotate code that should only be compiled when SSE4.2
+/// is not available.
+#ifdef __SSE4_2__
+#define LLVM_UNLESS_SSE42(...)
+#else
+#define LLVM_UNLESS_SSE42(...) __VA_ARGS__
+#endif
+
+/// \macro LLVM_SUPPORTS_RUNTIME_SSE42_CHECK
+/// Expands to true if runtime detection of SSE4.2 is supported.
+/// This can be used to guard runtime checks for SSE4.2 support.
+#if defined(__SSE4_2__) || \
+ ((defined(__i386__) || defined(__x86_64__)) && defined(__has_attribute) && \
+ __has_attribute(target) && !defined(_WIN32))
+#define LLVM_SUPPORTS_RUNTIME_SSE42_CHECK 1
+#else
+#define LLVM_SUPPORTS_RUNTIME_SSE42_CHECK 0
+#endif
+
#endif
>From c5d70f488918b8e4106f4f47c0b504063f7ea4a2 Mon Sep 17 00:00:00 2001
From: Thibault-Monnier <thibaultmonni at gmail.com>
Date: Sun, 18 Jan 2026 13:39:03 +0100
Subject: [PATCH 12/13] Cleanup and address comments
---
clang/lib/Lex/Lexer.cpp | 19 +++++++++---------
llvm/include/llvm/Support/Compiler.h | 29 ++++++++++++++++------------
2 files changed, 26 insertions(+), 22 deletions(-)
diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp
index 9a85d184b4c38..754e815b7cd43 100644
--- a/clang/lib/Lex/Lexer.cpp
+++ b/clang/lib/Lex/Lexer.cpp
@@ -1930,13 +1930,11 @@ static const char *fastParseASCIIIdentifierScalar(const char *CurPtr) {
// Fast path for lexing ASCII identifiers using SSE4.2 instructions.
// Only enabled on x86/x86_64 when building with __SSE4_2__ enabled, or with a
-// compiler that supports the 'target' attribute, used for runtime dispatch.
-// Otherwise, we fall back to the scalar implementation.
-// We avoid runtime check on Windows because it is not yet well-supported.
-#if LLVM_SUPPORTS_RUNTIME_SSE42_CHECK
+// compiler and platform that support runtime dispatch.
+#if __SSE4_2__ || LLVM_SUPPORTS_RUNTIME_SSE42_CHECK
// LLVM_ATTRIBUTE_USED is a hack to suppress a false-positive warning due to a
// bug in clang-18 and less. See PR175452.
-LLVM_ATTRIBUTE_USED __attribute__((target("sse4.2"))) static const char *
+LLVM_ATTRIBUTE_USED LLVM_TARGET_SSE42 static const char *
fastParseASCIIIdentifier(const char *CurPtr, const char *BufferEnd) {
alignas(16) static constexpr char AsciiIdentifierRange[16] = {
'_', '_', 'A', 'Z', 'a', 'z', '0', '9',
@@ -1960,13 +1958,14 @@ fastParseASCIIIdentifier(const char *CurPtr, const char *BufferEnd) {
return fastParseASCIIIdentifierScalar(CurPtr);
}
-
-LLVM_UNLESS_SSE42(__attribute__((target("default"))))
#endif
-LLVM_UNLESS_SSE42(static const char *fastParseASCIIIdentifier(
- const char *CurPtr, const char *) {
+
+#ifndef __SSE4_2__
+LLVM_TARGET_DEFAULT static const char *
+fastParseASCIIIdentifier(const char *CurPtr, const char *) {
return fastParseASCIIIdentifierScalar(CurPtr);
-})
+}
+#endif
bool Lexer::LexIdentifierContinue(Token &Result, const char *CurPtr) {
// Match [_A-Za-z0-9]*, we have already matched an identifier start.
diff --git a/llvm/include/llvm/Support/Compiler.h b/llvm/include/llvm/Support/Compiler.h
index 720079d83a37e..a1caebba38edf 100644
--- a/llvm/include/llvm/Support/Compiler.h
+++ b/llvm/include/llvm/Support/Compiler.h
@@ -739,25 +739,30 @@ void AnnotateIgnoreWritesEnd(const char *file, int line);
#endif
// clang-format on
-/// \macro LLVM_UNLESS_SSE42
-/// Expands to its arguments only if SSE4.2 is not enabled.
-/// This can be used to annotate code that should only be compiled when SSE4.2
-/// is not available.
-#ifdef __SSE4_2__
-#define LLVM_UNLESS_SSE42(...)
-#else
-#define LLVM_UNLESS_SSE42(...) __VA_ARGS__
-#endif
-
/// \macro LLVM_SUPPORTS_RUNTIME_SSE42_CHECK
/// Expands to true if runtime detection of SSE4.2 is supported.
/// This can be used to guard runtime checks for SSE4.2 support.
-#if defined(__SSE4_2__) || \
- ((defined(__i386__) || defined(__x86_64__)) && defined(__has_attribute) && \
+#if ((defined(__i386__) || defined(__x86_64__)) && defined(__has_attribute) && \
__has_attribute(target) && !defined(_WIN32))
#define LLVM_SUPPORTS_RUNTIME_SSE42_CHECK 1
#else
#define LLVM_SUPPORTS_RUNTIME_SSE42_CHECK 0
#endif
+/// \macro LLVM_TARGET_DEFAULT
+/// Function attribute to compile a function with default target features.
+#if defined(__has_attribute) && __has_attribute(target)
+#define LLVM_TARGET_DEFAULT __attribute__((target("default")))
+#else
+#define LLVM_TARGET_DEFAULT
+#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
+
#endif
>From 75c2e61f04c8c42ef334d14c00e4f3b283bb7d0d Mon Sep 17 00:00:00 2001
From: Thibault-Monnier <thibaultmonni at gmail.com>
Date: Sun, 18 Jan 2026 15:31:28 +0100
Subject: [PATCH 13/13] Try fix breakage
---
clang/lib/Lex/Lexer.cpp | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp
index 754e815b7cd43..4831dd2ff0843 100644
--- a/clang/lib/Lex/Lexer.cpp
+++ b/clang/lib/Lex/Lexer.cpp
@@ -1931,7 +1931,7 @@ static const char *fastParseASCIIIdentifierScalar(const char *CurPtr) {
// Fast path for lexing ASCII identifiers using SSE4.2 instructions.
// Only enabled on x86/x86_64 when building with __SSE4_2__ enabled, or with a
// compiler and platform that support runtime dispatch.
-#if __SSE4_2__ || LLVM_SUPPORTS_RUNTIME_SSE42_CHECK
+#if defined(__SSE4_2__) || LLVM_SUPPORTS_RUNTIME_SSE42_CHECK
// LLVM_ATTRIBUTE_USED is a hack to suppress a false-positive warning due to a
// bug in clang-18 and less. See PR175452.
LLVM_ATTRIBUTE_USED LLVM_TARGET_SSE42 static const char *
@@ -1958,11 +1958,12 @@ fastParseASCIIIdentifier(const char *CurPtr, const char *BufferEnd) {
return fastParseASCIIIdentifierScalar(CurPtr);
}
+
#endif
#ifndef __SSE4_2__
-LLVM_TARGET_DEFAULT static const char *
-fastParseASCIIIdentifier(const char *CurPtr, const char *) {
+LLVM_TARGET_DEFAULT
+static const char *fastParseASCIIIdentifier(const char *CurPtr, const char *) {
return fastParseASCIIIdentifierScalar(CurPtr);
}
#endif
More information about the cfe-commits
mailing list