[clang] [clang-tools-extra] [lldb] [llvm] [Allocator] Drop RedZoneSize (non-sanitizer) and BytesAllocated members (PR #205711)
Fangrui Song via cfe-commits
cfe-commits at lists.llvm.org
Sat Jun 27 18:14:43 PDT 2026
https://github.com/MaskRay updated https://github.com/llvm/llvm-project/pull/205711
>From 676391112ac372a3e7c06d659ac133d71173b0e7 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Wed, 24 Jun 2026 09:23:21 -0700
Subject: [PATCH 1/6] [Allocator] Drop RedZoneSize (non-sanitizer) and
BytesAllocated members
`RedZoneSize` is only read inside `#if LLVM_ADDRESS_SANITIZER_BUILD`.
Remove it for other builds.
`BytesAllocated` is incremented on every Allocate (a hot-path memory
read-modify-write) only to back `getBytesAllocated()`. Drop the member.
There is a measurable stage2 instruction-count reduction.
https://llvm-compile-time-tracker.com/compare.php?from=25a6b5be6853b2c493ef392d41e43dd35ad4839a&to=8ebc975635ad717deb392d20b50f1a1f6bb16054&stat=instructions:u
Migrate the in-tree consumers:
- TableGen dumpAllocationStats drops the line; the clangd debug log reports
getTotalMemory().
- clang's PPMemoryAllocationsTest measures getTotalMemory()/#define; over 1M
defines this is 120.06 B/define, matching the prior ~120 B, so the existing
bound holds.
- lldb's ConstString MemoryStats (https://reviews.llvm.org/D117914)
drops bytes_used/bytes_unused
Aided by Claude Opus 4.8
---
clang-tools-extra/clangd/CompileCommands.cpp | 4 +-
.../unittests/Lex/PPMemoryAllocationsTest.cpp | 11 +++--
lldb/include/lldb/Utility/ConstString.h | 3 --
lldb/source/Target/Statistics.cpp | 2 -
lldb/source/Utility/ConstString.cpp | 1 -
.../commands/statistics/basic/TestStats.py | 2 -
llvm/include/llvm/Support/Allocator.h | 33 ++++++-------
.../llvm/Support/PerThreadBumpPtrAllocator.h | 12 ++---
llvm/lib/TableGen/Record.cpp | 1 -
.../unittests/ADT/ConcurrentHashtableTest.cpp | 47 -------------------
.../DebugInfo/MSF/MappedBlockStreamTest.cpp | 12 -----
llvm/unittests/Support/AllocatorTest.cpp | 6 +--
.../Support/PerThreadBumpPtrAllocatorTest.cpp | 8 ++--
.../Support/ThreadSafeAllocatorTest.cpp | 2 +-
14 files changed, 32 insertions(+), 112 deletions(-)
diff --git a/clang-tools-extra/clangd/CompileCommands.cpp b/clang-tools-extra/clangd/CompileCommands.cpp
index e8005435e1836..b5965d163d7db 100644
--- a/clang-tools-extra/clangd/CompileCommands.cpp
+++ b/clang-tools-extra/clangd/CompileCommands.cpp
@@ -560,8 +560,8 @@ llvm::ArrayRef<ArgStripper::Rule> ArgStripper::rulesFor(llvm::StringRef Arg) {
dlog(" {0} #={1} *={2} Mode={3}", R.Text, R.ExactArgs, R.PrefixArgs,
int(R.Modes));
}
- dlog("Table spellings={0} rules={1} string-bytes={2}", Result->size(),
- RuleCount, Result->getAllocator().getBytesAllocated());
+ dlog("Table spellings={0} rules={1} allocator-bytes={2}", Result->size(),
+ RuleCount, Result->getAllocator().getTotalMemory());
#endif
// The static table will never be destroyed.
return Result.release();
diff --git a/clang/unittests/Lex/PPMemoryAllocationsTest.cpp b/clang/unittests/Lex/PPMemoryAllocationsTest.cpp
index f873774eb2019..ebdb0346b3bed 100644
--- a/clang/unittests/Lex/PPMemoryAllocationsTest.cpp
+++ b/clang/unittests/Lex/PPMemoryAllocationsTest.cpp
@@ -77,10 +77,13 @@ TEST_F(PPMemoryAllocationsTest, PPMacroDefinesAllocations) {
PP.LexTokensUntilEOF();
- size_t NumAllocated = PP.getPreprocessorAllocator().getBytesAllocated();
- float BytesPerDefine = float(NumAllocated) / float(NumMacros);
- llvm::errs() << "Num preprocessor allocations for " << NumMacros
- << " #define: " << NumAllocated << "\n";
+ // Use the total slab memory held by the preprocessor's allocator as a proxy.
+ // Over a million #defines the per-allocation slab overhead is negligible, so
+ // this closely tracks the bytes requested for storing the macro information.
+ size_t TotalMemory = PP.getPreprocessorAllocator().getTotalMemory();
+ float BytesPerDefine = float(TotalMemory) / float(NumMacros);
+ llvm::errs() << "Preprocessor allocator memory for " << NumMacros
+ << " #define: " << TotalMemory << "\n";
llvm::errs() << "Bytes per #define: " << BytesPerDefine << "\n";
// On arm64-apple-macos, we get around 120 bytes per define.
// Assume a reasonable upper bound based on that number that we don't want
diff --git a/lldb/include/lldb/Utility/ConstString.h b/lldb/include/lldb/Utility/ConstString.h
index 1bfefec9638a5..4452df1ecc6b1 100644
--- a/lldb/include/lldb/Utility/ConstString.h
+++ b/lldb/include/lldb/Utility/ConstString.h
@@ -393,10 +393,7 @@ class ConstString {
struct MemoryStats {
size_t GetBytesTotal() const { return bytes_total; }
- size_t GetBytesUsed() const { return bytes_used; }
- size_t GetBytesUnused() const { return bytes_total - bytes_used; }
size_t bytes_total = 0;
- size_t bytes_used = 0;
};
static MemoryStats GetMemoryStats();
diff --git a/lldb/source/Target/Statistics.cpp b/lldb/source/Target/Statistics.cpp
index 9fee5108e736a..6227d099642f2 100644
--- a/lldb/source/Target/Statistics.cpp
+++ b/lldb/source/Target/Statistics.cpp
@@ -111,8 +111,6 @@ json::Value ModuleStats::ToJSON() const {
llvm::json::Value ConstStringStats::ToJSON() const {
json::Object obj;
obj.try_emplace<int64_t>("bytesTotal", stats.GetBytesTotal());
- obj.try_emplace<int64_t>("bytesUsed", stats.GetBytesUsed());
- obj.try_emplace<int64_t>("bytesUnused", stats.GetBytesUnused());
return obj;
}
diff --git a/lldb/source/Utility/ConstString.cpp b/lldb/source/Utility/ConstString.cpp
index 3d79731a47d5a..8def38c03dceb 100644
--- a/lldb/source/Utility/ConstString.cpp
+++ b/lldb/source/Utility/ConstString.cpp
@@ -196,7 +196,6 @@ class Pool {
std::shared_lock<PoolMutex> lock(pool.m_mutex);
const Allocator &alloc = pool.m_string_map.getAllocator();
stats.bytes_total += alloc.getTotalMemory();
- stats.bytes_used += alloc.getBytesAllocated();
}
return stats;
}
diff --git a/lldb/test/API/commands/statistics/basic/TestStats.py b/lldb/test/API/commands/statistics/basic/TestStats.py
index a32b8feecc5cf..c65d1d8785160 100644
--- a/lldb/test/API/commands/statistics/basic/TestStats.py
+++ b/lldb/test/API/commands/statistics/basic/TestStats.py
@@ -348,8 +348,6 @@ def test_memory(self):
strings = memory["strings"]
strings_keys = [
"bytesTotal",
- "bytesUsed",
- "bytesUnused",
]
self.verify_keys(strings, '"strings"', strings_keys, None)
diff --git a/llvm/include/llvm/Support/Allocator.h b/llvm/include/llvm/Support/Allocator.h
index 92027cceea3bf..cebe4d6e925b3 100644
--- a/llvm/include/llvm/Support/Allocator.h
+++ b/llvm/include/llvm/Support/Allocator.h
@@ -96,11 +96,12 @@ class BumpPtrAllocatorImpl
BumpPtrAllocatorImpl(BumpPtrAllocatorImpl &&Old)
: AllocTy(std::move(Old.getAllocator())), CurPtr(Old.CurPtr),
EndSentinel(Old.EndSentinel), Slabs(std::move(Old.Slabs)),
- CustomSizedSlabs(std::move(Old.CustomSizedSlabs)),
- BytesAllocated(Old.BytesAllocated), RedZoneSize(Old.RedZoneSize) {
+ CustomSizedSlabs(std::move(Old.CustomSizedSlabs)) {
+#if LLVM_ADDRESS_SANITIZER_BUILD
+ RedZoneSize = Old.RedZoneSize;
+#endif
Old.CurPtr = nullptr;
Old.EndSentinel = 0;
- Old.BytesAllocated = 0;
Old.Slabs.clear();
Old.CustomSizedSlabs.clear();
}
@@ -116,15 +117,15 @@ class BumpPtrAllocatorImpl
CurPtr = RHS.CurPtr;
EndSentinel = RHS.EndSentinel;
- BytesAllocated = RHS.BytesAllocated;
+#if LLVM_ADDRESS_SANITIZER_BUILD
RedZoneSize = RHS.RedZoneSize;
+#endif
Slabs = std::move(RHS.Slabs);
CustomSizedSlabs = std::move(RHS.CustomSizedSlabs);
AllocTy::operator=(std::move(RHS.getAllocator()));
RHS.CurPtr = nullptr;
RHS.EndSentinel = 0;
- RHS.BytesAllocated = 0;
RHS.Slabs.clear();
RHS.CustomSizedSlabs.clear();
return *this;
@@ -141,7 +142,6 @@ class BumpPtrAllocatorImpl
return;
// Reset the state.
- BytesAllocated = 0;
CurPtr = (char *)Slabs.front();
EndSentinel = uintptr_t(CurPtr) + SlabSize + 1;
@@ -158,9 +158,6 @@ class BumpPtrAllocatorImpl
// Allocate(0, N) is valid, it returns a non-null pointer (which should not
// be dereferenced).
LLVM_ATTRIBUTE_RETURNS_NONNULL void *Allocate(size_t Size, Align Alignment) {
- // Keep track of how many bytes we've allocated.
- BytesAllocated += Size;
-
size_t SizeToAllocate = Size;
#if LLVM_ADDRESS_SANITIZER_BUILD
// Add trailing bytes as a "red zone" under ASan.
@@ -308,15 +305,18 @@ class BumpPtrAllocatorImpl
return TotalMemory;
}
- size_t getBytesAllocated() const { return BytesAllocated; }
+ /// BumpPtrAllocator no longer tracks the number of bytes requested; this
+ /// always returns 0. Use getTotalMemory() for the amount of memory held.
+ size_t getBytesAllocated() const { return 0; }
- void setRedZoneSize(size_t NewSize) {
+ void setRedZoneSize([[maybe_unused]] size_t NewSize) {
+#if LLVM_ADDRESS_SANITIZER_BUILD
RedZoneSize = NewSize;
+#endif
}
void PrintStats() const {
- detail::printBumpPtrAllocatorStats(Slabs.size(), BytesAllocated,
- getTotalMemory());
+ detail::printBumpPtrAllocatorStats(Slabs.size(), 0, getTotalMemory());
}
private:
@@ -335,14 +335,11 @@ class BumpPtrAllocatorImpl
/// Custom-sized slabs allocated for too-large allocation requests.
SmallVector<std::pair<void *, size_t>, 0> CustomSizedSlabs;
- /// How many bytes we've allocated.
- ///
- /// Used so that we can compute how much space was wasted.
- size_t BytesAllocated = 0;
-
+#if LLVM_ADDRESS_SANITIZER_BUILD
/// The number of bytes to put between allocations when running under
/// a sanitizer.
size_t RedZoneSize = 1;
+#endif
static size_t computeSlabSize(unsigned SlabIdx) {
// Scale the actual allocated slab size based on the number of slabs
diff --git a/llvm/include/llvm/Support/PerThreadBumpPtrAllocator.h b/llvm/include/llvm/Support/PerThreadBumpPtrAllocator.h
index f94d18f62e9ab..a11b0cb14bd66 100644
--- a/llvm/include/llvm/Support/PerThreadBumpPtrAllocator.h
+++ b/llvm/include/llvm/Support/PerThreadBumpPtrAllocator.h
@@ -82,15 +82,9 @@ class PerThreadAllocator
return TotalMemory;
}
- /// Return allocated size by all allocators.
- size_t getBytesAllocated() const {
- size_t BytesAllocated = 0;
-
- for (size_t Idx = 0; Idx < getNumberOfAllocators(); Idx++)
- BytesAllocated += Allocators[Idx].getBytesAllocated();
-
- return BytesAllocated;
- }
+ /// The underlying allocators no longer track the number of bytes requested;
+ /// this always returns 0. Use getTotalMemory() for the memory held.
+ size_t getBytesAllocated() const { return 0; }
/// Set red zone for all allocators.
void setRedZoneSize(size_t NewSize) {
diff --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp
index e21588101dc37..e9d7febf12272 100644
--- a/llvm/lib/TableGen/Record.cpp
+++ b/llvm/lib/TableGen/Record.cpp
@@ -120,7 +120,6 @@ void detail::RecordKeeperImpl::dumpAllocationStats(raw_ostream &OS) const {
OS << "TheVarBitInitPool size = " << TheVarBitInitPool.size() << '\n';
OS << "TheVarDefInitPool size = " << TheVarDefInitPool.size() << '\n';
OS << "TheFieldInitPool size = " << TheFieldInitPool.size() << '\n';
- OS << "Bytes allocated = " << Allocator.getBytesAllocated() << '\n';
OS << "Total allocator memory = " << Allocator.getTotalMemory() << "\n\n";
OS << "Number of records instantiated = " << LastRecordID << '\n';
diff --git a/llvm/unittests/ADT/ConcurrentHashtableTest.cpp b/llvm/unittests/ADT/ConcurrentHashtableTest.cpp
index 05c480959142b..446b41795143e 100644
--- a/llvm/unittests/ADT/ConcurrentHashtableTest.cpp
+++ b/llvm/unittests/ADT/ConcurrentHashtableTest.cpp
@@ -49,7 +49,6 @@ TEST(ConcurrentHashTableTest, AddStringEntries) {
parallel::TaskGroup tg;
tg.spawn([&]() {
- size_t AllocatedBytesAtStart = Allocator.getBytesAllocated();
std::pair<String *, bool> res1 = HashTable.insert("1");
// Check entry is inserted.
EXPECT_TRUE(res1.first->getKey() == "1");
@@ -79,8 +78,6 @@ TEST(ConcurrentHashTableTest, AddStringEntries) {
// Check first entry is still valid.
EXPECT_TRUE(res1.first->getKey() == "1");
- // Check data was allocated by allocator.
- EXPECT_TRUE(Allocator.getBytesAllocated() > AllocatedBytesAtStart);
// Check statistic.
std::string StatisticString;
@@ -107,15 +104,10 @@ TEST(ConcurrentHashTableTest, AddStringMultiplueEntries) {
tg.spawn([&]() {
// Check insertion.
for (size_t I = 0; I < NumElements; I++) {
- BumpPtrAllocator &ThreadLocalAllocator =
- Allocator.getThreadLocalAllocator();
- size_t AllocatedBytesAtStart = ThreadLocalAllocator.getBytesAllocated();
std::string StringForElement = formatv("{0}", I);
std::pair<String *, bool> Entry = HashTable.insert(StringForElement);
EXPECT_TRUE(Entry.second);
EXPECT_TRUE(Entry.first->getKey() == StringForElement);
- EXPECT_TRUE(ThreadLocalAllocator.getBytesAllocated() >
- AllocatedBytesAtStart);
}
std::string StatisticString;
@@ -129,16 +121,10 @@ TEST(ConcurrentHashTableTest, AddStringMultiplueEntries) {
// Check insertion of duplicates.
for (size_t I = 0; I < NumElements; I++) {
- BumpPtrAllocator &ThreadLocalAllocator =
- Allocator.getThreadLocalAllocator();
- size_t AllocatedBytesAtStart = ThreadLocalAllocator.getBytesAllocated();
std::string StringForElement = formatv("{0}", I);
std::pair<String *, bool> Entry = HashTable.insert(StringForElement);
EXPECT_FALSE(Entry.second);
EXPECT_TRUE(Entry.first->getKey() == StringForElement);
- // Check no additional bytes were allocated for duplicate.
- EXPECT_TRUE(ThreadLocalAllocator.getBytesAllocated() ==
- AllocatedBytesAtStart);
}
// Check statistic.
@@ -165,15 +151,10 @@ TEST(ConcurrentHashTableTest, AddStringMultiplueEntriesWithResize) {
tg.spawn([&]() {
// Check insertion.
for (size_t I = 0; I < NumElements; I++) {
- BumpPtrAllocator &ThreadLocalAllocator =
- Allocator.getThreadLocalAllocator();
- size_t AllocatedBytesAtStart = ThreadLocalAllocator.getBytesAllocated();
std::string StringForElement = formatv("{0} {1}", I, I + 100);
std::pair<String *, bool> Entry = HashTable.insert(StringForElement);
EXPECT_TRUE(Entry.second);
EXPECT_TRUE(Entry.first->getKey() == StringForElement);
- EXPECT_TRUE(ThreadLocalAllocator.getBytesAllocated() >
- AllocatedBytesAtStart);
}
std::string StatisticString;
@@ -187,16 +168,10 @@ TEST(ConcurrentHashTableTest, AddStringMultiplueEntriesWithResize) {
// Check insertion of duplicates.
for (size_t I = 0; I < NumElements; I++) {
- BumpPtrAllocator &ThreadLocalAllocator =
- Allocator.getThreadLocalAllocator();
- size_t AllocatedBytesAtStart = ThreadLocalAllocator.getBytesAllocated();
std::string StringForElement = formatv("{0} {1}", I, I + 100);
std::pair<String *, bool> Entry = HashTable.insert(StringForElement);
EXPECT_FALSE(Entry.second);
EXPECT_TRUE(Entry.first->getKey() == StringForElement);
- // Check no additional bytes were allocated for duplicate.
- EXPECT_TRUE(ThreadLocalAllocator.getBytesAllocated() ==
- AllocatedBytesAtStart);
}
// Check statistic.
@@ -217,15 +192,10 @@ TEST(ConcurrentHashTableTest, AddStringEntriesParallel) {
// Check parallel insertion.
parallelFor(0, NumElements, [&](size_t I) {
- BumpPtrAllocator &ThreadLocalAllocator =
- Allocator.getThreadLocalAllocator();
- size_t AllocatedBytesAtStart = ThreadLocalAllocator.getBytesAllocated();
std::string StringForElement = formatv("{0}", I);
std::pair<String *, bool> Entry = HashTable.insert(StringForElement);
EXPECT_TRUE(Entry.second);
EXPECT_TRUE(Entry.first->getKey() == StringForElement);
- EXPECT_TRUE(ThreadLocalAllocator.getBytesAllocated() >
- AllocatedBytesAtStart);
});
std::string StatisticString;
@@ -239,16 +209,10 @@ TEST(ConcurrentHashTableTest, AddStringEntriesParallel) {
// Check parallel insertion of duplicates.
parallelFor(0, NumElements, [&](size_t I) {
- BumpPtrAllocator &ThreadLocalAllocator =
- Allocator.getThreadLocalAllocator();
- size_t AllocatedBytesAtStart = ThreadLocalAllocator.getBytesAllocated();
std::string StringForElement = formatv("{0}", I);
std::pair<String *, bool> Entry = HashTable.insert(StringForElement);
EXPECT_FALSE(Entry.second);
EXPECT_TRUE(Entry.first->getKey() == StringForElement);
- // Check no additional bytes were allocated for duplicate.
- EXPECT_TRUE(ThreadLocalAllocator.getBytesAllocated() ==
- AllocatedBytesAtStart);
});
// Check statistic.
@@ -268,15 +232,10 @@ TEST(ConcurrentHashTableTest, AddStringEntriesParallelWithResize) {
// Check parallel insertion.
parallelFor(0, NumElements, [&](size_t I) {
- BumpPtrAllocator &ThreadLocalAllocator =
- Allocator.getThreadLocalAllocator();
- size_t AllocatedBytesAtStart = ThreadLocalAllocator.getBytesAllocated();
std::string StringForElement = formatv("{0}", I);
std::pair<String *, bool> Entry = HashTable.insert(StringForElement);
EXPECT_TRUE(Entry.second);
EXPECT_TRUE(Entry.first->getKey() == StringForElement);
- EXPECT_TRUE(ThreadLocalAllocator.getBytesAllocated() >
- AllocatedBytesAtStart);
});
std::string StatisticString;
@@ -290,16 +249,10 @@ TEST(ConcurrentHashTableTest, AddStringEntriesParallelWithResize) {
// Check parallel insertion of duplicates.
parallelFor(0, NumElements, [&](size_t I) {
- BumpPtrAllocator &ThreadLocalAllocator =
- Allocator.getThreadLocalAllocator();
- size_t AllocatedBytesAtStart = ThreadLocalAllocator.getBytesAllocated();
std::string StringForElement = formatv("{0}", I);
std::pair<String *, bool> Entry = HashTable.insert(StringForElement);
EXPECT_FALSE(Entry.second);
EXPECT_TRUE(Entry.first->getKey() == StringForElement);
- // Check no additional bytes were allocated for duplicate.
- EXPECT_TRUE(ThreadLocalAllocator.getBytesAllocated() ==
- AllocatedBytesAtStart);
});
// Check statistic.
diff --git a/llvm/unittests/DebugInfo/MSF/MappedBlockStreamTest.cpp b/llvm/unittests/DebugInfo/MSF/MappedBlockStreamTest.cpp
index d1f04e9b28a34..86be4ee0f2aab 100644
--- a/llvm/unittests/DebugInfo/MSF/MappedBlockStreamTest.cpp
+++ b/llvm/unittests/DebugInfo/MSF/MappedBlockStreamTest.cpp
@@ -110,7 +110,6 @@ TEST(MappedBlockStreamTest, ReadOntoNonEmptyBuffer) {
StringRef Str = "ZYXWVUTSRQPONMLKJIHGFEDCBA";
EXPECT_THAT_ERROR(R.readFixedString(Str, 1), Succeeded());
EXPECT_EQ(Str, StringRef("A"));
- EXPECT_EQ(0U, F.Allocator.getBytesAllocated());
}
// Tests that a read which crosses a block boundary, but where the subsequent
@@ -124,12 +123,10 @@ TEST(MappedBlockStreamTest, ZeroCopyReadContiguousBreak) {
StringRef Str;
EXPECT_THAT_ERROR(R.readFixedString(Str, 2), Succeeded());
EXPECT_EQ(Str, StringRef("AB"));
- EXPECT_EQ(0U, F.Allocator.getBytesAllocated());
R.setOffset(6);
EXPECT_THAT_ERROR(R.readFixedString(Str, 4), Succeeded());
EXPECT_EQ(Str, StringRef("GHIJ"));
- EXPECT_EQ(0U, F.Allocator.getBytesAllocated());
}
// Tests that a read which crosses a block boundary and cannot be referenced
@@ -143,7 +140,6 @@ TEST(MappedBlockStreamTest, CopyReadNonContiguousBreak) {
StringRef Str;
EXPECT_THAT_ERROR(R.readFixedString(Str, 10), Succeeded());
EXPECT_EQ(Str, StringRef("ABCDEFGHIJ"));
- EXPECT_EQ(10U, F.Allocator.getBytesAllocated());
}
// Test that an out of bounds read which doesn't cross a block boundary
@@ -157,7 +153,6 @@ TEST(MappedBlockStreamTest, InvalidReadSizeNoBreak) {
R.setOffset(10);
EXPECT_THAT_ERROR(R.readFixedString(Str, 1), Failed());
- EXPECT_EQ(0U, F.Allocator.getBytesAllocated());
}
// Test that an out of bounds read which crosses a contiguous block boundary
@@ -171,7 +166,6 @@ TEST(MappedBlockStreamTest, InvalidReadSizeContiguousBreak) {
R.setOffset(6);
EXPECT_THAT_ERROR(R.readFixedString(Str, 5), Failed());
- EXPECT_EQ(0U, F.Allocator.getBytesAllocated());
}
// Test that an out of bounds read which crosses a discontiguous block
@@ -184,7 +178,6 @@ TEST(MappedBlockStreamTest, InvalidReadSizeNonContiguousBreak) {
StringRef Str;
EXPECT_THAT_ERROR(R.readFixedString(Str, 11), Failed());
- EXPECT_EQ(0U, F.Allocator.getBytesAllocated());
}
// Tests that a read which is entirely contained within a single block but
@@ -197,7 +190,6 @@ TEST(MappedBlockStreamTest, ZeroCopyReadNoBreak) {
StringRef Str;
EXPECT_THAT_ERROR(R.readFixedString(Str, 1), Succeeded());
EXPECT_EQ(Str, StringRef("A"));
- EXPECT_EQ(0U, F.Allocator.getBytesAllocated());
}
// Tests that a read which is not aligned on the same boundary as a previous
@@ -212,13 +204,11 @@ TEST(MappedBlockStreamTest, UnalignedOverlappingRead) {
StringRef Str2;
EXPECT_THAT_ERROR(R.readFixedString(Str1, 7), Succeeded());
EXPECT_EQ(Str1, StringRef("ABCDEFG"));
- EXPECT_EQ(7U, F.Allocator.getBytesAllocated());
R.setOffset(2);
EXPECT_THAT_ERROR(R.readFixedString(Str2, 3), Succeeded());
EXPECT_EQ(Str2, StringRef("CDE"));
EXPECT_EQ(Str1.data() + 2, Str2.data());
- EXPECT_EQ(7U, F.Allocator.getBytesAllocated());
}
// Tests that a read which is not aligned on the same boundary as a previous
@@ -233,12 +223,10 @@ TEST(MappedBlockStreamTest, UnalignedOverlappingReadFail) {
StringRef Str2;
EXPECT_THAT_ERROR(R.readFixedString(Str1, 6), Succeeded());
EXPECT_EQ(Str1, StringRef("ABCDEF"));
- EXPECT_EQ(6U, F.Allocator.getBytesAllocated());
R.setOffset(4);
EXPECT_THAT_ERROR(R.readFixedString(Str2, 4), Succeeded());
EXPECT_EQ(Str2, StringRef("EFGH"));
- EXPECT_EQ(10U, F.Allocator.getBytesAllocated());
}
TEST(MappedBlockStreamTest, WriteBeyondEndOfStream) {
diff --git a/llvm/unittests/Support/AllocatorTest.cpp b/llvm/unittests/Support/AllocatorTest.cpp
index d6f80e0948dc4..744967de9004e 100644
--- a/llvm/unittests/Support/AllocatorTest.cpp
+++ b/llvm/unittests/Support/AllocatorTest.cpp
@@ -105,24 +105,20 @@ TEST(AllocatorTest, TestAlignment) {
// we end up creating a slab for it.
TEST(AllocatorTest, TestZero) {
BumpPtrAllocator Alloc;
- Alloc.setRedZoneSize(0); // else our arithmetic is all off
+ Alloc.setRedZoneSize(0); // else the slab count below is off under ASan
EXPECT_EQ(0u, Alloc.GetNumSlabs());
- EXPECT_EQ(0u, Alloc.getBytesAllocated());
void *Empty = Alloc.Allocate(0, 1);
EXPECT_NE(Empty, nullptr) << "Allocate is __attribute__((returns_nonnull))";
EXPECT_EQ(1u, Alloc.GetNumSlabs()) << "Allocated a slab to point to";
- EXPECT_EQ(0u, Alloc.getBytesAllocated());
void *Large = Alloc.Allocate(4096, 1);
EXPECT_EQ(1u, Alloc.GetNumSlabs());
- EXPECT_EQ(4096u, Alloc.getBytesAllocated());
EXPECT_EQ(Empty, Large);
void *Empty2 = Alloc.Allocate(0, 1);
EXPECT_NE(Empty2, nullptr);
EXPECT_EQ(1u, Alloc.GetNumSlabs());
- EXPECT_EQ(4096u, Alloc.getBytesAllocated());
}
// Test allocating just over the slab size. This tests a bug where before the
diff --git a/llvm/unittests/Support/PerThreadBumpPtrAllocatorTest.cpp b/llvm/unittests/Support/PerThreadBumpPtrAllocatorTest.cpp
index d30de997f0fd1..4ac5ac4e1ff3b 100644
--- a/llvm/unittests/Support/PerThreadBumpPtrAllocatorTest.cpp
+++ b/llvm/unittests/Support/PerThreadBumpPtrAllocatorTest.cpp
@@ -26,13 +26,11 @@ TEST(PerThreadBumpPtrAllocatorTest, Simple) {
(uint64_t *)Allocator.Allocate(sizeof(uint64_t), alignof(uint64_t));
*Var = 0xFE;
EXPECT_EQ(0xFEul, *Var);
- EXPECT_EQ(sizeof(uint64_t), Allocator.getBytesAllocated());
- EXPECT_TRUE(Allocator.getBytesAllocated() <= Allocator.getTotalMemory());
+ EXPECT_LE(sizeof(uint64_t), Allocator.getTotalMemory());
PerThreadBumpPtrAllocator Allocator2(std::move(Allocator));
- EXPECT_EQ(sizeof(uint64_t), Allocator2.getBytesAllocated());
- EXPECT_TRUE(Allocator2.getBytesAllocated() <= Allocator2.getTotalMemory());
+ EXPECT_LE(sizeof(uint64_t), Allocator2.getTotalMemory());
EXPECT_EQ(0xFEul, *Var);
});
@@ -49,7 +47,7 @@ TEST(PerThreadBumpPtrAllocatorTest, ParallelAllocation) {
*ptr = Idx;
});
- EXPECT_EQ(sizeof(uint64_t) * NumAllocations, Allocator.getBytesAllocated());
+ EXPECT_LE(sizeof(uint64_t) * NumAllocations, Allocator.getTotalMemory());
EXPECT_EQ(Allocator.getNumberOfAllocators(), parallel::getThreadCount());
}
diff --git a/llvm/unittests/Support/ThreadSafeAllocatorTest.cpp b/llvm/unittests/Support/ThreadSafeAllocatorTest.cpp
index b3d9430fc0f30..107a3a8b59cca 100644
--- a/llvm/unittests/Support/ThreadSafeAllocatorTest.cpp
+++ b/llvm/unittests/Support/ThreadSafeAllocatorTest.cpp
@@ -117,7 +117,7 @@ TEST(ThreadSafeAllocatorTest, AllocWithAlign) {
Threads.wait();
Alloc.applyLocked([](BumpPtrAllocator &Alloc) {
- EXPECT_EQ(4950U * sizeof(int), Alloc.getBytesAllocated());
+ EXPECT_LE(4950U * sizeof(int), Alloc.getTotalMemory());
});
}
>From ab7893af453595553dedc23be537222c3aba4107 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Wed, 24 Jun 2026 19:28:03 -0700
Subject: [PATCH 2/6] remove getBytesAllocated
---
llvm/include/llvm/Support/Allocator.h | 4 ----
llvm/include/llvm/Support/PerThreadBumpPtrAllocator.h | 4 ----
2 files changed, 8 deletions(-)
diff --git a/llvm/include/llvm/Support/Allocator.h b/llvm/include/llvm/Support/Allocator.h
index cebe4d6e925b3..1c0bfd0127e7b 100644
--- a/llvm/include/llvm/Support/Allocator.h
+++ b/llvm/include/llvm/Support/Allocator.h
@@ -305,10 +305,6 @@ class BumpPtrAllocatorImpl
return TotalMemory;
}
- /// BumpPtrAllocator no longer tracks the number of bytes requested; this
- /// always returns 0. Use getTotalMemory() for the amount of memory held.
- size_t getBytesAllocated() const { return 0; }
-
void setRedZoneSize([[maybe_unused]] size_t NewSize) {
#if LLVM_ADDRESS_SANITIZER_BUILD
RedZoneSize = NewSize;
diff --git a/llvm/include/llvm/Support/PerThreadBumpPtrAllocator.h b/llvm/include/llvm/Support/PerThreadBumpPtrAllocator.h
index a11b0cb14bd66..0448fb2a12a9b 100644
--- a/llvm/include/llvm/Support/PerThreadBumpPtrAllocator.h
+++ b/llvm/include/llvm/Support/PerThreadBumpPtrAllocator.h
@@ -82,10 +82,6 @@ class PerThreadAllocator
return TotalMemory;
}
- /// The underlying allocators no longer track the number of bytes requested;
- /// this always returns 0. Use getTotalMemory() for the memory held.
- size_t getBytesAllocated() const { return 0; }
-
/// Set red zone for all allocators.
void setRedZoneSize(size_t NewSize) {
for (size_t Idx = 0; Idx < getNumberOfAllocators(); Idx++)
>From 7798f6a5952a75be12f979d8e374edd4da8036f8 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Thu, 25 Jun 2026 22:24:38 -0700
Subject: [PATCH 3/6] use LLVM_ENABLE_ABI_BREAKING_CHECKS
---
llvm/include/llvm/Support/Allocator.h | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
diff --git a/llvm/include/llvm/Support/Allocator.h b/llvm/include/llvm/Support/Allocator.h
index 1c0bfd0127e7b..f8d1eadb62d95 100644
--- a/llvm/include/llvm/Support/Allocator.h
+++ b/llvm/include/llvm/Support/Allocator.h
@@ -18,6 +18,7 @@
#define LLVM_SUPPORT_ALLOCATOR_H
#include "llvm/ADT/SmallVector.h"
+#include "llvm/Config/abi-breaking.h"
#include "llvm/Support/Alignment.h"
#include "llvm/Support/AllocatorBase.h"
#include "llvm/Support/Compiler.h"
@@ -97,7 +98,7 @@ class BumpPtrAllocatorImpl
: AllocTy(std::move(Old.getAllocator())), CurPtr(Old.CurPtr),
EndSentinel(Old.EndSentinel), Slabs(std::move(Old.Slabs)),
CustomSizedSlabs(std::move(Old.CustomSizedSlabs)) {
-#if LLVM_ADDRESS_SANITIZER_BUILD
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
RedZoneSize = Old.RedZoneSize;
#endif
Old.CurPtr = nullptr;
@@ -117,7 +118,7 @@ class BumpPtrAllocatorImpl
CurPtr = RHS.CurPtr;
EndSentinel = RHS.EndSentinel;
-#if LLVM_ADDRESS_SANITIZER_BUILD
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
RedZoneSize = RHS.RedZoneSize;
#endif
Slabs = std::move(RHS.Slabs);
@@ -159,8 +160,9 @@ class BumpPtrAllocatorImpl
// be dereferenced).
LLVM_ATTRIBUTE_RETURNS_NONNULL void *Allocate(size_t Size, Align Alignment) {
size_t SizeToAllocate = Size;
-#if LLVM_ADDRESS_SANITIZER_BUILD
- // Add trailing bytes as a "red zone" under ASan.
+#if LLVM_ADDRESS_SANITIZER_BUILD && LLVM_ENABLE_ABI_BREAKING_CHECKS
+ // Add trailing bytes as a "red zone" under ASan. RedZoneSize only exists
+ // when conditions are true.
SizeToAllocate += RedZoneSize;
#endif
SizeToAllocate = alignToPowerOf2(SizeToAllocate, MinAlign);
@@ -306,7 +308,7 @@ class BumpPtrAllocatorImpl
}
void setRedZoneSize([[maybe_unused]] size_t NewSize) {
-#if LLVM_ADDRESS_SANITIZER_BUILD
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
RedZoneSize = NewSize;
#endif
}
@@ -331,9 +333,9 @@ class BumpPtrAllocatorImpl
/// Custom-sized slabs allocated for too-large allocation requests.
SmallVector<std::pair<void *, size_t>, 0> CustomSizedSlabs;
-#if LLVM_ADDRESS_SANITIZER_BUILD
- /// The number of bytes to put between allocations when running under
- /// a sanitizer.
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+ /// The number of bytes to put between allocations when running under a
+ /// sanitizer.
size_t RedZoneSize = 1;
#endif
>From 3fce221bd5e3321c85964c69aec00f4c11605fad Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Thu, 25 Jun 2026 22:57:14 -0700
Subject: [PATCH 4/6] fix comment
---
llvm/include/llvm/Support/Allocator.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/include/llvm/Support/Allocator.h b/llvm/include/llvm/Support/Allocator.h
index f8d1eadb62d95..f40b5194848db 100644
--- a/llvm/include/llvm/Support/Allocator.h
+++ b/llvm/include/llvm/Support/Allocator.h
@@ -162,7 +162,7 @@ class BumpPtrAllocatorImpl
size_t SizeToAllocate = Size;
#if LLVM_ADDRESS_SANITIZER_BUILD && LLVM_ENABLE_ABI_BREAKING_CHECKS
// Add trailing bytes as a "red zone" under ASan. RedZoneSize only exists
- // when conditions are true.
+ // when both conditions are true.
SizeToAllocate += RedZoneSize;
#endif
SizeToAllocate = alignToPowerOf2(SizeToAllocate, MinAlign);
>From 312cbca5c83f82376e22719335315140fda20623 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Sat, 27 Jun 2026 17:30:22 -0700
Subject: [PATCH 5/6] rebase; remove getBytesAllocated(); fix llubi
---
llvm/include/llvm/Support/Allocator.h | 4 +---
llvm/lib/Support/Allocator.cpp | 5 +----
llvm/tools/llubi/lib/Context.cpp | 6 +++---
llvm/tools/llubi/lib/Context.h | 1 +
4 files changed, 6 insertions(+), 10 deletions(-)
diff --git a/llvm/include/llvm/Support/Allocator.h b/llvm/include/llvm/Support/Allocator.h
index a5081f71bfa48..b9ed2ce0c5fee 100644
--- a/llvm/include/llvm/Support/Allocator.h
+++ b/llvm/include/llvm/Support/Allocator.h
@@ -314,7 +314,7 @@ class BumpPtrAllocatorImpl
}
void PrintStats() const {
- detail::printBumpPtrAllocatorStats(Slabs.size(), 0, getTotalMemory());
+ detail::printBumpPtrAllocatorStats(Slabs.size(), getTotalMemory());
}
private:
@@ -467,8 +467,6 @@ template <typename T> class SpecificBumpPtrAllocator {
std::optional<int64_t> identifyObject(const void *Ptr) {
return Allocator.identifyObject(Ptr);
}
-
- size_t getBytesAllocated() const { return Allocator.getBytesAllocated(); }
};
} // end namespace llvm
diff --git a/llvm/lib/Support/Allocator.cpp b/llvm/lib/Support/Allocator.cpp
index 1af5744bf301e..6ff68f1be3d63 100644
--- a/llvm/lib/Support/Allocator.cpp
+++ b/llvm/lib/Support/Allocator.cpp
@@ -17,12 +17,9 @@ namespace llvm {
namespace detail {
-void printBumpPtrAllocatorStats(unsigned NumSlabs, size_t BytesAllocated,
- size_t TotalMemory) {
+void printBumpPtrAllocatorStats(unsigned NumSlabs, size_t TotalMemory) {
errs() << "\nNumber of memory regions: " << NumSlabs << '\n'
- << "Bytes used: " << BytesAllocated << '\n'
<< "Bytes allocated: " << TotalMemory << '\n'
- << "Bytes wasted: " << (TotalMemory - BytesAllocated)
<< " (includes alignment, etc)\n";
}
diff --git a/llvm/tools/llubi/lib/Context.cpp b/llvm/tools/llubi/lib/Context.cpp
index bd7c966a1c7e9..e89f7a43b45c6 100644
--- a/llvm/tools/llubi/lib/Context.cpp
+++ b/llvm/tools/llubi/lib/Context.cpp
@@ -368,9 +368,8 @@ const MaterializedConstant *Context::getConstantValue(Constant *C) {
if (Val.isNone())
return nullptr;
if (!Val.isCacheable()) {
- assert(NoncacheableConstBuffer.getBytesAllocated() <=
- 1024 * sizeof(MaterializedConstant) &&
- "Unbounded temporary buffer.");
+ assert(NoncacheableConstCount <= 1024 && "Unbounded temporary buffer.");
+ ++NoncacheableConstCount;
return new (NoncacheableConstBuffer.Allocate())
MaterializedConstant(std::move(Val));
}
@@ -380,6 +379,7 @@ const MaterializedConstant *Context::getConstantValue(Constant *C) {
void Context::resetNoncacheableConstantBuffer() {
NoncacheableConstBuffer.DestroyAll();
+ NoncacheableConstCount = 0;
}
APInt Context::getTag(uint32_t BitWidth, Provenance &Prov) {
diff --git a/llvm/tools/llubi/lib/Context.h b/llvm/tools/llubi/lib/Context.h
index d8e3450c4accd..097f0d1e0ab8b 100644
--- a/llvm/tools/llubi/lib/Context.h
+++ b/llvm/tools/llubi/lib/Context.h
@@ -306,6 +306,7 @@ class Context {
// Temporary buffer for non-cacheable constants (e.g.,
// undef/ptrtoint/inttoptr).
SpecificBumpPtrAllocator<MaterializedConstant> NoncacheableConstBuffer;
+ size_t NoncacheableConstCount = 0;
DenseMap<Function *, Pointer> FuncAddrMap;
DenseMap<BasicBlock *, Pointer> BlockAddrMap;
DenseMap<uint64_t, std::pair<Function *, IntrusiveRefCntPtr<MemoryObject>>>
>From bc4e719904cbe922986d5e9020f735f0b205cbee Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Sat, 27 Jun 2026 18:14:29 -0700
Subject: [PATCH 6/6] fix printBumpPtrAllocatorStats
---
llvm/include/llvm/Support/Allocator.h | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/llvm/include/llvm/Support/Allocator.h b/llvm/include/llvm/Support/Allocator.h
index b9ed2ce0c5fee..bb0ca118e2015 100644
--- a/llvm/include/llvm/Support/Allocator.h
+++ b/llvm/include/llvm/Support/Allocator.h
@@ -37,9 +37,7 @@ namespace detail {
// We call out to an external function to actually print the message as the
// printing code uses Allocator.h in its implementation.
-LLVM_ABI void printBumpPtrAllocatorStats(unsigned NumSlabs,
- size_t BytesAllocated,
- size_t TotalMemory);
+LLVM_ABI void printBumpPtrAllocatorStats(unsigned NumSlabs, size_t TotalMemory);
} // end namespace detail
More information about the cfe-commits
mailing list