Skip to content

Commit 9f0f606

Browse files
[clang] Provide an SSE4.2 implementation of identifier token lexer (#68962)
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 --------- Co-authored-by: serge-sans-paille <[email protected]>
1 parent f681225 commit 9f0f606

File tree

1 file changed

+39
-7
lines changed

1 file changed

+39
-7
lines changed

clang/lib/Lex/Lexer.cpp

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@
4747
#include <tuple>
4848
#include <utility>
4949

50+
#ifdef __SSE4_2__
51+
#include <nmmintrin.h>
52+
#endif
53+
5054
using namespace clang;
5155

5256
//===----------------------------------------------------------------------===//
@@ -1847,19 +1851,47 @@ bool Lexer::LexUnicodeIdentifierStart(Token &Result, uint32_t C,
18471851
return true;
18481852
}
18491853

1854+
static const char *
1855+
fastParseASCIIIdentifier(const char *CurPtr,
1856+
[[maybe_unused]] const char *BufferEnd) {
1857+
#ifdef __SSE4_2__
1858+
alignas(16) static constexpr char AsciiIdentifierRange[16] = {
1859+
'_', '_', 'A', 'Z', 'a', 'z', '0', '9',
1860+
};
1861+
constexpr ssize_t BytesPerRegister = 16;
1862+
1863+
__m128i AsciiIdentifierRangeV =
1864+
_mm_load_si128((const __m128i *)AsciiIdentifierRange);
1865+
1866+
while (LLVM_LIKELY(BufferEnd - CurPtr >= BytesPerRegister)) {
1867+
__m128i Cv = _mm_loadu_si128((const __m128i *)(CurPtr));
1868+
1869+
int Consumed = _mm_cmpistri(AsciiIdentifierRangeV, Cv,
1870+
_SIDD_LEAST_SIGNIFICANT | _SIDD_CMP_RANGES |
1871+
_SIDD_UBYTE_OPS | _SIDD_NEGATIVE_POLARITY);
1872+
CurPtr += Consumed;
1873+
if (Consumed == BytesPerRegister)
1874+
continue;
1875+
return CurPtr;
1876+
}
1877+
#endif
1878+
1879+
unsigned char C = *CurPtr;
1880+
while (isAsciiIdentifierContinue(C))
1881+
C = *++CurPtr;
1882+
return CurPtr;
1883+
}
1884+
18501885
bool Lexer::LexIdentifierContinue(Token &Result, const char *CurPtr) {
18511886
// Match [_A-Za-z0-9]*, we have already matched an identifier start.
1887+
18521888
while (true) {
1853-
unsigned char C = *CurPtr;
1854-
// Fast path.
1855-
if (isAsciiIdentifierContinue(C)) {
1856-
++CurPtr;
1857-
continue;
1858-
}
1889+
1890+
CurPtr = fastParseASCIIIdentifier(CurPtr, BufferEnd);
18591891

18601892
unsigned Size;
18611893
// Slow path: handle trigraph, unicode codepoints, UCNs.
1862-
C = getCharAndSize(CurPtr, Size);
1894+
unsigned char C = getCharAndSize(CurPtr, Size);
18631895
if (isAsciiIdentifierContinue(C)) {
18641896
CurPtr = ConsumeChar(CurPtr, Size, Result);
18651897
continue;

0 commit comments

Comments
 (0)