17#ifndef LLVM_SUPPORT_ALLOCATOR_H
18#define LLVM_SUPPORT_ALLOCATOR_H
21#include "llvm/Config/abi-breaking.h"
66 size_t SizeThreshold = SlabSize,
size_t GrowthDelay = 128,
70 AllocatorT, SlabSize, SizeThreshold, GrowthDelay, MinAlign>>,
75 static_assert(SizeThreshold <= SlabSize,
76 "The SizeThreshold must be at most the SlabSize to ensure "
77 "that objects larger than a slab go into their own memory "
79 static_assert(GrowthDelay > 0,
80 "GrowthDelay must be at least 1 which already increases the"
81 "slab size after each allocated slab.");
83 "MinAlign must be a power of two");
84 static_assert(
MinAlign <=
alignof(std::max_align_t),
85 "MinAlign must not exceed the alignment of fresh slabs");
97 EndSentinel(Old.EndSentinel), Slabs(
std::
move(Old.Slabs)),
98 CustomSizedSlabs(
std::
move(Old.CustomSizedSlabs)) {
99#if LLVM_ENABLE_ABI_BREAKING_CHECKS
100 RedZoneSize = Old.RedZoneSize;
102 Old.CurPtr =
nullptr;
105 Old.CustomSizedSlabs.clear();
109 DeallocateSlabs(Slabs.begin(), Slabs.end());
110 DeallocateCustomSizedSlabs();
114 DeallocateSlabs(Slabs.begin(), Slabs.end());
115 DeallocateCustomSizedSlabs();
118 EndSentinel =
RHS.EndSentinel;
119#if LLVM_ENABLE_ABI_BREAKING_CHECKS
120 RedZoneSize =
RHS.RedZoneSize;
122 Slabs = std::move(
RHS.Slabs);
123 CustomSizedSlabs = std::move(
RHS.CustomSizedSlabs);
124 AllocTy::operator=(std::move(
RHS.getAllocator()));
126 RHS.CurPtr =
nullptr;
129 RHS.CustomSizedSlabs.clear();
137 DeallocateCustomSizedSlabs();
138 CustomSizedSlabs.clear();
144 CurPtr = (
char *)Slabs.front();
145 EndSentinel =
uintptr_t(CurPtr) + SlabSize + 1;
148 DeallocateSlabs(std::next(Slabs.begin()), Slabs.end());
149 Slabs.erase(std::next(Slabs.begin()), Slabs.end());
160 size_t SizeToAllocate =
Size;
161#if LLVM_ADDRESS_SANITIZER_BUILD && LLVM_ENABLE_ABI_BREAKING_CHECKS
164 SizeToAllocate += RedZoneSize;
171 AlignedPtr =
alignAddr(CurPtr, Alignment);
172 uintptr_t AllocEndPtr = AlignedPtr + SizeToAllocate;
174 "Alignment + Size must not overflow");
179 CurPtr =
reinterpret_cast<char *
>(AllocEndPtr);
186 return reinterpret_cast<char *
>(AlignedPtr);
195 size_t PaddedSize = SizeToAllocate + Alignment.
value() - 1;
196 if (PaddedSize > SizeThreshold) {
202 CustomSizedSlabs.push_back(std::make_pair(NewSlab, PaddedSize));
206 char *AlignedPtr = (
char*)AlignedAddr;
215 assert(AlignedAddr + SizeToAllocate < EndSentinel &&
216 "Unable to allocate memory!");
217 char *AlignedPtr = (
char*)AlignedAddr;
218 CurPtr = AlignedPtr + SizeToAllocate;
226 assert(Alignment > 0 &&
"0-byte alignment is not allowed. Use 1 instead.");
243 size_t GetNumSlabs()
const {
return Slabs.size() + CustomSizedSlabs.size(); }
251 const char *
P =
static_cast<const char *
>(Ptr);
252 int64_t InSlabIdx = 0;
253 for (
size_t Idx = 0,
E = Slabs.size(); Idx <
E; Idx++) {
254 const char *S =
static_cast<const char *
>(Slabs[Idx]);
255 if (
P >= S &&
P < S + computeSlabSize(Idx))
256 return InSlabIdx +
static_cast<int64_t
>(
P - S);
257 InSlabIdx +=
static_cast<int64_t
>(computeSlabSize(Idx));
261 int64_t InCustomSizedSlabIdx = -1;
262 for (
const auto &Slab : CustomSizedSlabs) {
263 const char *S =
static_cast<const char *
>(Slab.first);
264 size_t Size = Slab.second;
265 if (
P >= S &&
P < S +
Size)
266 return InCustomSizedSlabIdx -
static_cast<int64_t
>(
P - S);
267 InCustomSizedSlabIdx -=
static_cast<int64_t
>(
Size);
278 assert(Out &&
"Wrong allocator used");
292 template <
typename T>
295 assert(Out %
alignof(
T) == 0 &&
"Wrong alignment information");
296 return Out /
alignof(
T);
300 size_t TotalMemory = 0;
301 for (
auto I = Slabs.begin(),
E = Slabs.end();
I !=
E; ++
I)
302 TotalMemory += computeSlabSize(std::distance(Slabs.begin(),
I));
303 for (
const auto &PtrAndSize : CustomSizedSlabs)
304 TotalMemory += PtrAndSize.second;
309#if LLVM_ENABLE_ABI_BREAKING_CHECKS
310 RedZoneSize = NewSize;
322 char *CurPtr =
nullptr;
334#if LLVM_ENABLE_ABI_BREAKING_CHECKS
337 size_t RedZoneSize = 1;
340 static size_t computeSlabSize(
unsigned SlabIdx) {
346 ((
size_t)1 << std::min<size_t>(30, SlabIdx / GrowthDelay));
351 void StartNewSlab() {
352 size_t AllocatedSlabSize = computeSlabSize(Slabs.
size());
355 alignof(std::max_align_t));
361 CurPtr = (
char *)(NewSlab);
362 EndSentinel =
uintptr_t(NewSlab) + AllocatedSlabSize + 1;
368 for (;
I !=
E; ++
I) {
369 size_t AllocatedSlabSize =
370 computeSlabSize(std::distance(Slabs.begin(),
I));
372 alignof(std::max_align_t));
377 void DeallocateCustomSizedSlabs() {
378 for (
auto &PtrAndSize : CustomSizedSlabs) {
379 void *Ptr = PtrAndSize.first;
380 size_t Size = PtrAndSize.second;
402 using BumpPtrAllocatorTy =
404 BumpPtrAllocatorTy Allocator;
410 Allocator.setRedZoneSize(0);
413 : Allocator(
std::
move(Old.Allocator)) {}
417 Allocator = std::move(
RHS.Allocator);
425 auto DestroyElements = [](
char *Begin,
char *End) {
427 for (
char *Ptr = Begin; Ptr +
sizeof(
T) <= End; Ptr +=
sizeof(
T))
428 reinterpret_cast<T *
>(Ptr)->~T();
431 for (
auto I = Allocator.Slabs.begin(),
E = Allocator.Slabs.end();
I !=
E;
433 size_t AllocatedSlabSize = BumpPtrAllocatorTy::computeSlabSize(
434 std::distance(Allocator.Slabs.begin(),
I));
436 char *End = *
I == Allocator.Slabs.back() ? Allocator.CurPtr
437 : (
char *)*
I + AllocatedSlabSize;
439 DestroyElements(Begin, End);
442 for (
auto &PtrAndSize : Allocator.CustomSizedSlabs) {
443 void *Ptr = PtrAndSize.first;
444 size_t Size = PtrAndSize.second;
457 if constexpr (
alignof(
T) <=
alignof(std::max_align_t))
458 return static_cast<T *
>(Allocator.Allocate(num *
sizeof(
T),
Align()));
459 return Allocator.Allocate<
T>(num);
466 return Allocator.identifyObject(Ptr);
472template <
typename AllocatorT,
size_t SlabSize,
size_t SizeThreshold,
473 size_t GrowthDelay,
size_t MinAlign>
482template <
typename AllocatorT,
size_t SlabSize,
size_t SizeThreshold,
483 size_t GrowthDelay,
size_t MinAlign>
486 GrowthDelay, MinAlign> &) {}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file defines MallocAllocator.
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define __asan_poison_memory_region(p, size)
#define __asan_unpoison_memory_region(p, size)
#define LLVM_ATTRIBUTE_NOINLINE
LLVM_ATTRIBUTE_NOINLINE - On compilers where we have a directive to do so, mark a method "not for inl...
#define LLVM_ATTRIBUTE_RETURNS_NONNULL
#define __msan_allocated_memory(p, size)
#define LLVM_LIKELY(EXPR)
This file defines the SmallVector class.
CRTP base class providing obvious overloads for the core Allocate() methods of LLVM-style allocators.
Allocate memory in an ever growing pool, as if by bump-pointer.
int64_t identifyKnownObject(const void *Ptr)
A wrapper around identifyObject that additionally asserts that the object is indeed within the alloca...
BumpPtrAllocatorImpl(T &&Allocator)
LLVM_ATTRIBUTE_RETURNS_NONNULL LLVM_ATTRIBUTE_NOINLINE void * AllocateSlow(size_t Size, size_t SizeToAllocate, Align Alignment)
BumpPtrAllocatorImpl & operator=(BumpPtrAllocatorImpl &&RHS)
LLVM_ATTRIBUTE_RETURNS_NONNULL void * Allocate(size_t Size, Align Alignment)
Allocate space at the specified alignment.
void Deallocate(const void *Ptr, size_t Size, size_t)
BumpPtrAllocatorImpl(BumpPtrAllocatorImpl &&Old)
size_t GetNumSlabs() const
void Reset()
Deallocate all but the current slab and reset the current pointer to the beginning of it,...
LLVM_ATTRIBUTE_RETURNS_NONNULL void * Allocate(size_t Size, size_t Alignment)
void setRedZoneSize(size_t NewSize)
friend class SpecificBumpPtrAllocator
int64_t identifyKnownAlignedObject(const void *Ptr)
A wrapper around identifyKnownObject.
size_t getTotalMemory() const
BumpPtrAllocatorImpl()=default
std::optional< int64_t > identifyObject(const void *Ptr)
void Deallocate(const void *Ptr, size_t Size, size_t Alignment)
LLVM_ATTRIBUTE_RETURNS_NONNULL void * Allocate(size_t Size, size_t Alignment)
typename SuperClass::iterator iterator
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
~SpecificBumpPtrAllocator()
std::optional< int64_t > identifyObject(const void *Ptr)
SpecificBumpPtrAllocator(SpecificBumpPtrAllocator &&Old)
T * Allocate(size_t num=1)
Allocate space for an array of objects without constructing them.
void DestroyAll()
Call the destructor of each allocated object and deallocate all but the current slab and reset the cu...
SpecificBumpPtrAllocator()
SpecificBumpPtrAllocator & operator=(SpecificBumpPtrAllocator &&RHS)
MallocAllocator & getAllocator()
A self-contained host- and target-independent arbitrary-precision floating-point software implementat...
LLVM_ABI void printBumpPtrAllocatorStats(unsigned NumSlabs, size_t TotalMemory)
This is an optimization pass for GlobalISel generic memory operations.
T bit_ceil(T Value)
Returns the smallest integral power of two no smaller than Value if Value is nonzero.
constexpr T MinAlign(U A, V B)
A and B are either alignments or offsets.
constexpr T alignToPowerOf2(U Value, V Align)
Will overflow only if result is not representable in T.
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
BumpPtrAllocatorImpl<> BumpPtrAllocator
The standard BumpPtrAllocator which just uses the default template parameters.
uintptr_t alignAddr(const void *Addr, Align Alignment)
Aligns Addr to Alignment bytes, rounding up.
Implement std::hash so that hash_code can be used in STL containers.
This struct is a compact representation of a valid (non-zero power of two) alignment.
static constexpr Align Of()
Allow constructions of constexpr Align from types.
constexpr uint64_t value() const
This is a hole in the type system and should not be abused.