mirror of
https://github.com/intel/llvm.git
synced 2026-02-01 08:56:15 +08:00
SourceManager: Vectorize ComputeLineNumbers for SSE2.
This method is very hot, it is called when emitting diagnostics, in -E mode and for many #pragma handlers. It scans through the whole source file to count newlines, records and caches them in a vector. The speedup from vectorization isn't very large, as we fall back to bytewise scanning when we hit a newline. There might be a way to avoid leaving the sse loop but everything I tried didn't work out because a call to push_back clobbers xmm registers. About 2% speedup on average on "clang -E > /dev/null" of all .cpp files in clang's lib/Sema. llvm-svn: 154204
This commit is contained in:
@@ -1037,6 +1037,10 @@ unsigned SourceManager::getPresumedColumnNumber(SourceLocation Loc,
|
||||
return getPresumedLoc(Loc).getColumn();
|
||||
}
|
||||
|
||||
#ifdef __SSE2__
|
||||
#include <emmintrin.h>
|
||||
#endif
|
||||
|
||||
static LLVM_ATTRIBUTE_NOINLINE void
|
||||
ComputeLineNumbers(DiagnosticsEngine &Diag, ContentCache *FI,
|
||||
llvm::BumpPtrAllocator &Alloc,
|
||||
@@ -1062,11 +1066,44 @@ static void ComputeLineNumbers(DiagnosticsEngine &Diag, ContentCache *FI,
|
||||
unsigned Offs = 0;
|
||||
while (1) {
|
||||
// Skip over the contents of the line.
|
||||
// TODO: Vectorize this? This is very performance sensitive for programs
|
||||
// with lots of diagnostics and in -E mode.
|
||||
const unsigned char *NextBuf = (const unsigned char *)Buf;
|
||||
|
||||
#ifdef __SSE2__
|
||||
// Try to skip to the next newline using SSE instructions. This is very
|
||||
// performance sensitive for programs with lots of diagnostics and in -E
|
||||
// mode.
|
||||
__m128i CRs = _mm_set1_epi8('\r');
|
||||
__m128i LFs = _mm_set1_epi8('\n');
|
||||
|
||||
// First fix up the alignment to 16 bytes.
|
||||
while (((uintptr_t)NextBuf & 0xF) != 0) {
|
||||
if (*NextBuf == '\n' || *NextBuf == '\r' || *NextBuf == '\0')
|
||||
goto FoundSpecialChar;
|
||||
++NextBuf;
|
||||
}
|
||||
|
||||
// Scan 16 byte chunks for '\r' and '\n'. Ignore '\0'.
|
||||
while (NextBuf+16 <= End) {
|
||||
__m128i Chunk = *(__m128i*)NextBuf;
|
||||
__m128i Cmp = _mm_or_si128(_mm_cmpeq_epi8(Chunk, CRs),
|
||||
_mm_cmpeq_epi8(Chunk, LFs));
|
||||
unsigned Mask = _mm_movemask_epi8(Cmp);
|
||||
|
||||
// If we found a newline, adjust the pointer and jump to the handling code.
|
||||
if (Mask != 0) {
|
||||
NextBuf += llvm::CountTrailingZeros_32(Mask);
|
||||
goto FoundSpecialChar;
|
||||
}
|
||||
NextBuf += 16;
|
||||
}
|
||||
#endif
|
||||
|
||||
while (*NextBuf != '\n' && *NextBuf != '\r' && *NextBuf != '\0')
|
||||
++NextBuf;
|
||||
|
||||
#ifdef __SSE2__
|
||||
FoundSpecialChar:
|
||||
#endif
|
||||
Offs += NextBuf-Buf;
|
||||
Buf = NextBuf;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user