Skip to content

Commit 7d30130

Browse files
committed
[llvm][mustache] Optimize accessor splitting with a single pass
The splitMustacheString function previously used a loop of StringRef::split and StringRef::trim. This was inefficient as it scanned each segment of the accessor string multiple times. This change introduces a custom splitAndTrim function that performs both operations in a single pass over the string, reducing redundant work and improving performance, most notably in the number of CPU cycles executed. Metric | Baseline | Optimized | Change -------------- | -------- | --------- | ------- Time (ms) | 35.57 | 35.36 | -0.59% Cycles | 34.91M | 34.26M | -1.86% Instructions | 85.54M | 85.24M | -0.35% Branch Misses | 111.9K | 112.2K | +0.27% Cache Misses | 242.1K | 239.9K | -0.91%
1 parent 9808298 commit 7d30130

File tree

1 file changed

+27
-7
lines changed

1 file changed

+27
-7
lines changed

llvm/lib/Support/Mustache.cpp

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,32 @@ static bool isContextFalsey(const json::Value *V) {
3434
return isFalsey(*V);
3535
}
3636

37+
static void splitAndTrim(StringRef Str, SmallVectorImpl<StringRef> &Tokens) {
38+
size_t CurrentPos = 0;
39+
while (CurrentPos < Str.size()) {
40+
// Find the next delimiter.
41+
size_t DelimiterPos = Str.find('.', CurrentPos);
42+
43+
// If no delimiter is found, process the rest of the string.
44+
if (DelimiterPos == StringRef::npos) {
45+
DelimiterPos = Str.size();
46+
}
47+
48+
// Get the current part, which may have whitespace.
49+
StringRef Part = Str.slice(CurrentPos, DelimiterPos);
50+
51+
// Manually trim the part without creating a new string object.
52+
size_t Start = Part.find_first_not_of(" \t\r\n");
53+
if (Start != StringRef::npos) {
54+
size_t End = Part.find_last_not_of(" \t\r\n");
55+
Tokens.push_back(Part.slice(Start, End + 1));
56+
}
57+
58+
// Move past the delimiter for the next iteration.
59+
CurrentPos = DelimiterPos + 1;
60+
}
61+
}
62+
3763
static Accessor splitMustacheString(StringRef Str, MustacheContext &Ctx) {
3864
// We split the mustache string into an accessor.
3965
// For example:
@@ -46,13 +72,7 @@ static Accessor splitMustacheString(StringRef Str, MustacheContext &Ctx) {
4672
// It's a literal, so it doesn't need to be saved.
4773
Tokens.push_back(".");
4874
} else {
49-
while (!Str.empty()) {
50-
StringRef Part;
51-
std::tie(Part, Str) = Str.split('.');
52-
// Each part of the accessor needs to be saved to the arena
53-
// to ensure it has a stable address.
54-
Tokens.push_back(Part.trim());
55-
}
75+
splitAndTrim(Str, Tokens);
5676
}
5777
// Now, allocate memory for the array of StringRefs in the arena.
5878
StringRef *ArenaTokens = Ctx.Allocator.Allocate<StringRef>(Tokens.size());

0 commit comments

Comments
 (0)