17#ifndef LLVM_SUPPORT_ALLOCATOR_H
18#define LLVM_SUPPORT_ALLOCATOR_H
40 size_t BytesAllocated,
67 size_t SizeThreshold = SlabSize,
size_t GrowthDelay = 128,
71 AllocatorT, SlabSize, SizeThreshold, GrowthDelay, MinAlign>>,
76 static_assert(SizeThreshold <= SlabSize,
77 "The SizeThreshold must be at most the SlabSize to ensure "
78 "that objects larger than a slab go into their own memory "
80 static_assert(GrowthDelay > 0,
81 "GrowthDelay must be at least 1 which already increases the"
82 "slab size after each allocated slab.");
84 "MinAlign must be a power of two");
85 static_assert(
MinAlign <=
alignof(std::max_align_t),
86 "MinAlign must not exceed the alignment of fresh slabs");
98 End(Old.End), Slabs(
std::
move(Old.Slabs)),
99 CustomSizedSlabs(
std::
move(Old.CustomSizedSlabs)),
100 BytesAllocated(Old.BytesAllocated), RedZoneSize(Old.RedZoneSize) {
101 Old.CurPtr = Old.End =
nullptr;
102 Old.BytesAllocated = 0;
104 Old.CustomSizedSlabs.clear();
108 DeallocateSlabs(Slabs.begin(), Slabs.end());
109 DeallocateCustomSizedSlabs();
113 DeallocateSlabs(Slabs.begin(), Slabs.end());
114 DeallocateCustomSizedSlabs();
118 BytesAllocated =
RHS.BytesAllocated;
119 RedZoneSize =
RHS.RedZoneSize;
120 Slabs = std::move(
RHS.Slabs);
121 CustomSizedSlabs = std::move(
RHS.CustomSizedSlabs);
122 AllocTy::operator=(std::move(
RHS.getAllocator()));
124 RHS.CurPtr =
RHS.End =
nullptr;
125 RHS.BytesAllocated = 0;
127 RHS.CustomSizedSlabs.clear();
135 DeallocateCustomSizedSlabs();
136 CustomSizedSlabs.clear();
143 CurPtr = (
char *)Slabs.front();
144 End = CurPtr + SlabSize;
147 DeallocateSlabs(std::next(Slabs.begin()), Slabs.end());
148 Slabs.erase(std::next(Slabs.begin()), Slabs.end());
160 BytesAllocated +=
Size;
162 size_t SizeToAllocate =
Size;
163#if LLVM_ADDRESS_SANITIZER_BUILD
165 SizeToAllocate += RedZoneSize;
170 uintptr_t AlignedPtr = uintptr_t(CurPtr);
172 AlignedPtr =
alignAddr(CurPtr, Alignment);
173 uintptr_t AllocEndPtr = AlignedPtr + SizeToAllocate;
174 assert(AllocEndPtr >= uintptr_t(CurPtr) &&
175 "Alignment + Size must not overflow");
180 && CurPtr !=
nullptr)) {
181 CurPtr =
reinterpret_cast<char *
>(AllocEndPtr);
188 return reinterpret_cast<char *
>(AlignedPtr);
197 size_t PaddedSize = SizeToAllocate + Alignment.
value() - 1;
198 if (PaddedSize > SizeThreshold) {
204 CustomSizedSlabs.push_back(std::make_pair(NewSlab, PaddedSize));
206 uintptr_t AlignedAddr =
alignAddr(NewSlab, Alignment);
207 assert(AlignedAddr +
Size <= (uintptr_t)NewSlab + PaddedSize);
208 char *AlignedPtr = (
char*)AlignedAddr;
216 uintptr_t AlignedAddr =
alignAddr(CurPtr, Alignment);
217 assert(AlignedAddr + SizeToAllocate <= (uintptr_t)End &&
218 "Unable to allocate memory!");
219 char *AlignedPtr = (
char*)AlignedAddr;
220 CurPtr = AlignedPtr + SizeToAllocate;
228 assert(Alignment > 0 &&
"0-byte alignment is not allowed. Use 1 instead.");
245 size_t GetNumSlabs()
const {
return Slabs.size() + CustomSizedSlabs.size(); }
253 const char *
P =
static_cast<const char *
>(Ptr);
254 int64_t InSlabIdx = 0;
255 for (
size_t Idx = 0,
E = Slabs.size(); Idx <
E; Idx++) {
256 const char *S =
static_cast<const char *
>(Slabs[Idx]);
257 if (
P >= S &&
P < S + computeSlabSize(Idx))
258 return InSlabIdx +
static_cast<int64_t
>(
P - S);
259 InSlabIdx +=
static_cast<int64_t
>(computeSlabSize(Idx));
263 int64_t InCustomSizedSlabIdx = -1;
264 for (
const auto &Slab : CustomSizedSlabs) {
265 const char *S =
static_cast<const char *
>(Slab.first);
266 size_t Size = Slab.second;
267 if (
P >= S &&
P < S +
Size)
268 return InCustomSizedSlabIdx -
static_cast<int64_t
>(
P - S);
269 InCustomSizedSlabIdx -=
static_cast<int64_t
>(
Size);
280 assert(Out &&
"Wrong allocator used");
294 template <
typename T>
297 assert(Out %
alignof(
T) == 0 &&
"Wrong alignment information");
298 return Out /
alignof(
T);
302 size_t TotalMemory = 0;
303 for (
auto I = Slabs.begin(),
E = Slabs.end();
I !=
E; ++
I)
304 TotalMemory += computeSlabSize(std::distance(Slabs.begin(),
I));
305 for (
const auto &PtrAndSize : CustomSizedSlabs)
306 TotalMemory += PtrAndSize.second;
313 RedZoneSize = NewSize;
325 char *CurPtr =
nullptr;
339 size_t BytesAllocated = 0;
343 size_t RedZoneSize = 1;
345 static size_t computeSlabSize(
unsigned SlabIdx) {
351 ((
size_t)1 << std::min<size_t>(30, SlabIdx / GrowthDelay));
356 void StartNewSlab() {
357 size_t AllocatedSlabSize = computeSlabSize(Slabs.
size());
360 alignof(std::max_align_t));
366 CurPtr = (
char *)(NewSlab);
367 End = ((
char *)NewSlab) + AllocatedSlabSize;
373 for (;
I !=
E; ++
I) {
374 size_t AllocatedSlabSize =
375 computeSlabSize(std::distance(Slabs.begin(),
I));
377 alignof(std::max_align_t));
382 void DeallocateCustomSizedSlabs() {
383 for (
auto &PtrAndSize : CustomSizedSlabs) {
384 void *Ptr = PtrAndSize.first;
385 size_t Size = PtrAndSize.second;
407 using BumpPtrAllocatorTy =
409 BumpPtrAllocatorTy Allocator;
415 Allocator.setRedZoneSize(0);
418 : Allocator(
std::
move(Old.Allocator)) {}
422 Allocator = std::move(
RHS.Allocator);
430 auto DestroyElements = [](
char *Begin,
char *End) {
432 for (
char *Ptr = Begin; Ptr +
sizeof(
T) <= End; Ptr +=
sizeof(
T))
433 reinterpret_cast<T *
>(Ptr)->~T();
436 for (
auto I = Allocator.Slabs.begin(),
E = Allocator.Slabs.end();
I !=
E;
438 size_t AllocatedSlabSize = BumpPtrAllocatorTy::computeSlabSize(
439 std::distance(Allocator.Slabs.begin(),
I));
441 char *End = *
I == Allocator.Slabs.back() ? Allocator.CurPtr
442 : (
char *)*
I + AllocatedSlabSize;
444 DestroyElements(Begin, End);
447 for (
auto &PtrAndSize : Allocator.CustomSizedSlabs) {
448 void *Ptr = PtrAndSize.first;
449 size_t Size = PtrAndSize.second;
462 if constexpr (
alignof(
T) <=
alignof(std::max_align_t))
463 return static_cast<T *
>(Allocator.Allocate(num *
sizeof(
T),
Align()));
464 return Allocator.Allocate<
T>(num);
471 return Allocator.identifyObject(Ptr);
477template <
typename AllocatorT,
size_t SlabSize,
size_t SizeThreshold,
478 size_t GrowthDelay,
size_t MinAlign>
487template <
typename AllocatorT,
size_t SlabSize,
size_t SizeThreshold,
488 size_t GrowthDelay,
size_t MinAlign>
491 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
size_t getBytesAllocated() const
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 BytesAllocated, 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.