Skip to content

Commit 28deddc

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 735490e commit 28deddc

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
@@ -35,6 +35,32 @@ static bool isContextFalsey(const json::Value *V) {
3535
return isFalsey(*V);
3636
}
3737

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

0 commit comments

Comments
 (0)