Skip to content

Commit dc3b514

Browse files
authored
[llvm][mustache] Optimize accessor splitting with a single pass (#159198)
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 4cdeb7d commit dc3b514

File tree

1 file changed

+26
-7
lines changed

1 file changed

+26
-7
lines changed

llvm/lib/Support/Mustache.cpp

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,31 @@ 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+
// Get the current part, which may have whitespace.
48+
StringRef Part = Str.slice(CurrentPos, DelimiterPos);
49+
50+
// Manually trim the part without creating a new string object.
51+
size_t Start = Part.find_first_not_of(" \t\r\n");
52+
if (Start != StringRef::npos) {
53+
size_t End = Part.find_last_not_of(" \t\r\n");
54+
Tokens.push_back(Part.slice(Start, End + 1));
55+
}
56+
57+
// Move past the delimiter for the next iteration.
58+
CurrentPos = DelimiterPos + 1;
59+
}
60+
}
61+
3762
static Accessor splitMustacheString(StringRef Str, MustacheContext &Ctx) {
3863
// We split the mustache string into an accessor.
3964
// For example:
@@ -46,13 +71,7 @@ static Accessor splitMustacheString(StringRef Str, MustacheContext &Ctx) {
4671
// It's a literal, so it doesn't need to be saved.
4772
Tokens.push_back(".");
4873
} 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-
}
74+
splitAndTrim(Str, Tokens);
5675
}
5776
// Now, allocate memory for the array of StringRefs in the arena.
5877
StringRef *ArenaTokens = Ctx.Allocator.Allocate<StringRef>(Tokens.size());

0 commit comments

Comments
 (0)