[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