[llvm] dc3b514 - [llvm][mustache] Optimize accessor splitting with a single pass (#159198)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Nov 4 15:56:04 PST 2025
Author: Paul Kirth
Date: 2025-11-04T23:56:00Z
New Revision: dc3b5141cdf704bec28edeed78d6d72ebe0444ae
URL: https://github.com/llvm/llvm-project/commit/dc3b5141cdf704bec28edeed78d6d72ebe0444ae
DIFF: https://github.com/llvm/llvm-project/commit/dc3b5141cdf704bec28edeed78d6d72ebe0444ae.diff
LOG: [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% |
Added:
Modified:
llvm/lib/Support/Mustache.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp
index 012e1ffd534d2..9eb1ec2b8425c 100644
--- a/llvm/lib/Support/Mustache.cpp
+++ b/llvm/lib/Support/Mustache.cpp
@@ -34,6 +34,31 @@ static bool isContextFalsey(const json::Value *V) {
return isFalsey(*V);
}
+static void splitAndTrim(StringRef Str, SmallVectorImpl<StringRef> &Tokens) {
+ size_t CurrentPos = 0;
+ while (CurrentPos < Str.size()) {
+ // Find the next delimiter.
+ size_t DelimiterPos = Str.find('.', CurrentPos);
+
+ // If no delimiter is found, process the rest of the string.
+ if (DelimiterPos == StringRef::npos)
+ DelimiterPos = Str.size();
+
+ // Get the current part, which may have whitespace.
+ StringRef Part = Str.slice(CurrentPos, DelimiterPos);
+
+ // Manually trim the part without creating a new string object.
+ size_t Start = Part.find_first_not_of(" \t\r\n");
+ if (Start != StringRef::npos) {
+ size_t End = Part.find_last_not_of(" \t\r\n");
+ Tokens.push_back(Part.slice(Start, End + 1));
+ }
+
+ // Move past the delimiter for the next iteration.
+ CurrentPos = DelimiterPos + 1;
+ }
+}
+
static Accessor splitMustacheString(StringRef Str, MustacheContext &Ctx) {
// We split the mustache string into an accessor.
// For example:
@@ -46,13 +71,7 @@ static Accessor splitMustacheString(StringRef Str, MustacheContext &Ctx) {
// It's a literal, so it doesn't need to be saved.
Tokens.push_back(".");
} else {
- while (!Str.empty()) {
- StringRef Part;
- std::tie(Part, Str) = Str.split('.');
- // Each part of the accessor needs to be saved to the arena
- // to ensure it has a stable address.
- Tokens.push_back(Part.trim());
- }
+ splitAndTrim(Str, Tokens);
}
// Now, allocate memory for the array of StringRefs in the arena.
StringRef *ArenaTokens = Ctx.Allocator.Allocate<StringRef>(Tokens.size());
More information about the llvm-commits
mailing list