Author: Timm Baeder
Date: 2025-09-18T15:26:02+02:00
New Revision: 29620d9b8971c4eea7f5407ca206ba04c6f78d01

URL: 
https://github.com/llvm/llvm-project/commit/29620d9b8971c4eea7f5407ca206ba04c6f78d01
DIFF: 
https://github.com/llvm/llvm-project/commit/29620d9b8971c4eea7f5407ca206ba04c6f78d01.diff

LOG: [clang][bytecode] Optimize InterpStack (#159400)

Replace `StackChunk::End` with `StackChunk::Size`, mark the allocating
code paths as unlikely and move `grow()` into the header, which allows
us to template this for the `Size` parameter. Since we only push our
primitive types on the stack and all the sizes are aligned to pointer
size multiples, this only results in a few instantiations.

Added: 
    

Modified: 
    clang/lib/AST/ByteCode/InterpStack.cpp
    clang/lib/AST/ByteCode/InterpStack.h

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/ByteCode/InterpStack.cpp 
b/clang/lib/AST/ByteCode/InterpStack.cpp
index 7920378f365f9..992546560eec4 100644
--- a/clang/lib/AST/ByteCode/InterpStack.cpp
+++ b/clang/lib/AST/ByteCode/InterpStack.cpp
@@ -24,9 +24,6 @@ InterpStack::~InterpStack() {
     std::free(Chunk->Next);
   if (Chunk)
     std::free(Chunk);
-  Chunk = nullptr;
-  StackSize = 0;
-  ItemTypes.clear();
 }
 
 // We keep the last chunk around to reuse.
@@ -56,29 +53,12 @@ void InterpStack::clearTo(size_t NewSize) {
   assert(size() == NewSize);
 }
 
-void *InterpStack::grow(size_t Size) {
-  assert(Size < ChunkSize - sizeof(StackChunk) && "Object too large");
-
-  if (!Chunk || sizeof(StackChunk) + Chunk->size() + Size > ChunkSize) {
-    if (Chunk && Chunk->Next) {
-      Chunk = Chunk->Next;
-    } else {
-      StackChunk *Next = new (std::malloc(ChunkSize)) StackChunk(Chunk);
-      if (Chunk)
-        Chunk->Next = Next;
-      Chunk = Next;
-    }
-  }
-
-  auto *Object = reinterpret_cast<void *>(Chunk->End);
-  Chunk->End += Size;
-  StackSize += Size;
-  return Object;
-}
-
 void *InterpStack::peekData(size_t Size) const {
   assert(Chunk && "Stack is empty!");
 
+  if (LLVM_LIKELY(Size <= Chunk->size()))
+    return reinterpret_cast<void *>(Chunk->start() + Chunk->Size - Size);
+
   StackChunk *Ptr = Chunk;
   while (Size > Ptr->size()) {
     Size -= Ptr->size();
@@ -86,24 +66,31 @@ void *InterpStack::peekData(size_t Size) const {
     assert(Ptr && "Offset too large");
   }
 
-  return reinterpret_cast<void *>(Ptr->End - Size);
+  return reinterpret_cast<void *>(Ptr->start() + Ptr->Size - Size);
 }
 
 void InterpStack::shrink(size_t Size) {
   assert(Chunk && "Chunk is empty!");
 
+  // Likely case is that we simply remove something from the current chunk.
+  if (LLVM_LIKELY(Size <= Chunk->size())) {
+    Chunk->Size -= Size;
+    StackSize -= Size;
+    return;
+  }
+
   while (Size > Chunk->size()) {
     Size -= Chunk->size();
     if (Chunk->Next) {
       std::free(Chunk->Next);
       Chunk->Next = nullptr;
     }
-    Chunk->End = Chunk->start();
+    Chunk->Size = 0;
     Chunk = Chunk->Prev;
     assert(Chunk && "Offset too large");
   }
 
-  Chunk->End -= Size;
+  Chunk->Size -= Size;
   StackSize -= Size;
 }
 

diff  --git a/clang/lib/AST/ByteCode/InterpStack.h 
b/clang/lib/AST/ByteCode/InterpStack.h
index b0f9f6e225682..c647dfa6d85ea 100644
--- a/clang/lib/AST/ByteCode/InterpStack.h
+++ b/clang/lib/AST/ByteCode/InterpStack.h
@@ -24,14 +24,14 @@ namespace interp {
 /// Stack frame storing temporaries and parameters.
 class InterpStack final {
 public:
-  InterpStack() {}
+  InterpStack() = default;
 
   /// Destroys the stack, freeing up storage.
   ~InterpStack();
 
   /// Constructs a value in place on the top of the stack.
   template <typename T, typename... Tys> void push(Tys &&...Args) {
-    new (grow(aligned_size<T>())) T(std::forward<Tys>(Args)...);
+    new (grow<aligned_size<T>()>()) T(std::forward<Tys>(Args)...);
     ItemTypes.push_back(toPrimType<T>());
   }
 
@@ -89,7 +89,7 @@ class InterpStack final {
 private:
   /// All stack slots are aligned to the native pointer alignment for storage.
   /// The size of an object is rounded up to a pointer alignment multiple.
-  template <typename T> constexpr size_t aligned_size() const {
+  template <typename T> static constexpr size_t aligned_size() {
     constexpr size_t PtrAlign = alignof(void *);
     return ((sizeof(T) + PtrAlign - 1) / PtrAlign) * PtrAlign;
   }
@@ -100,7 +100,30 @@ class InterpStack final {
   }
 
   /// Grows the stack to accommodate a value and returns a pointer to it.
-  void *grow(size_t Size);
+  template <size_t Size> void *grow() {
+    assert(Size < ChunkSize - sizeof(StackChunk) && "Object too large");
+    static_assert(aligned(Size));
+
+    // Allocate a new stack chunk if necessary.
+    if (LLVM_UNLIKELY(!Chunk)) {
+      Chunk = new (std::malloc(ChunkSize)) StackChunk(Chunk);
+    } else if (LLVM_UNLIKELY(Chunk->size() >
+                             ChunkSize - sizeof(StackChunk) - Size)) {
+      if (Chunk->Next) {
+        Chunk = Chunk->Next;
+      } else {
+        StackChunk *Next = new (std::malloc(ChunkSize)) StackChunk(Chunk);
+        Chunk->Next = Next;
+        Chunk = Next;
+      }
+    }
+
+    auto *Object = reinterpret_cast<void *>(Chunk->start() + Chunk->Size);
+    Chunk->Size += Size;
+    StackSize += Size;
+    return Object;
+  }
+
   /// Returns a pointer from the top of the stack.
   void *peekData(size_t Size) const;
   /// Shrinks the stack.
@@ -118,13 +141,13 @@ class InterpStack final {
   struct StackChunk {
     StackChunk *Next;
     StackChunk *Prev;
-    char *End;
+    uint32_t Size;
 
     StackChunk(StackChunk *Prev = nullptr)
-        : Next(nullptr), Prev(Prev), End(reinterpret_cast<char *>(this + 1)) {}
+        : Next(nullptr), Prev(Prev), Size(0) {}
 
     /// Returns the size of the chunk, minus the header.
-    size_t size() const { return End - start(); }
+    size_t size() const { return Size; }
 
     /// Returns a pointer to the start of the data region.
     char *start() { return reinterpret_cast<char *>(this + 1); }


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to