| //===- subzero/src/IceMemory.h - Memory management declarations -*- C++ -*-===// | |
| // | |
| // The Subzero Code Generator | |
| // | |
| // This file is distributed under the University of Illinois Open Source | |
| // License. See LICENSE.TXT for details. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| /// | |
| /// \file | |
| /// \brief Declares some useful data structures and routines dealing with | |
| /// memory management in Subzero (mostly, allocator types.) | |
| /// | |
| //===----------------------------------------------------------------------===// | |
| #ifndef SUBZERO_SRC_ICEMEMORY_H | |
| #define SUBZERO_SRC_ICEMEMORY_H | |
| #include "IceTLS.h" | |
| #include "llvm/Support/Allocator.h" | |
| #include <cstddef> | |
| #include <mutex> | |
| namespace Ice { | |
| class Cfg; | |
| class GlobalContext; | |
| class Liveness; | |
| using ArenaAllocator = | |
| llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator, /*SlabSize=*/1024 * 1024>; | |
| class LockedArenaAllocator { | |
| LockedArenaAllocator() = delete; | |
| LockedArenaAllocator(const LockedArenaAllocator &) = delete; | |
| LockedArenaAllocator &operator=(const LockedArenaAllocator &) = delete; | |
| public: | |
| LockedArenaAllocator(ArenaAllocator *Alloc, std::mutex *Mutex) | |
| : Alloc(Alloc), AutoLock(*Mutex) {} | |
| LockedArenaAllocator(LockedArenaAllocator &&) = default; | |
| LockedArenaAllocator &operator=(LockedArenaAllocator &&) = default; | |
| ~LockedArenaAllocator() = default; | |
| ArenaAllocator *operator->() { return Alloc; } | |
| private: | |
| ArenaAllocator *Alloc; | |
| std::unique_lock<std::mutex> AutoLock; | |
| }; | |
| template <typename T, typename Traits> struct sz_allocator { | |
| /// std::allocator interface implementation. | |
| /// @{ | |
| using value_type = T; | |
| using pointer = T *; | |
| using const_pointer = const T *; | |
| using reference = T &; | |
| using const_reference = const T &; | |
| using size_type = std::size_t; | |
| using difference_type = std::ptrdiff_t; | |
| sz_allocator() : Current() {} | |
| template <class U> | |
| sz_allocator(const sz_allocator<U, Traits> &) : Current() {} | |
| pointer address(reference x) const { | |
| return reinterpret_cast<pointer>(&reinterpret_cast<char &>(x)); | |
| } | |
| const_pointer address(const_reference x) const { | |
| return reinterpret_cast<const_pointer>(&reinterpret_cast<const char &>(x)); | |
| } | |
| pointer allocate(size_type num) { | |
| assert(current() != nullptr); | |
| return current()->template Allocate<T>(num); | |
| } | |
| template <typename... A> void construct(pointer P, A &&... Args) { | |
| new (static_cast<void *>(P)) T(std::forward<A>(Args)...); | |
| } | |
| void deallocate(pointer, size_type) {} | |
| template <class U> struct rebind { typedef sz_allocator<U, Traits> other; }; | |
| void destroy(pointer P) { P->~T(); } | |
| /// @} | |
| /// Manages the current underlying allocator. | |
| /// @{ | |
| typename Traits::allocator_type current() { | |
| if (!Traits::cache_allocator) { | |
| // TODO(jpp): allocators should always be cacheable... maybe. Investigate. | |
| return Traits::current(); | |
| } | |
| if (Current == nullptr) { | |
| Current = Traits::current(); | |
| } | |
| assert(Current == Traits::current()); | |
| return Current; | |
| } | |
| static void init() { Traits::init(); } | |
| /// @} | |
| typename Traits::allocator_type Current; | |
| }; | |
| template <class Traits> struct sz_allocator_scope { | |
| explicit sz_allocator_scope(typename Traits::manager_type *Manager) { | |
| Traits::set_current(Manager); | |
| } | |
| ~sz_allocator_scope() { Traits::set_current(nullptr); } | |
| }; | |
| template <typename T, typename U, typename Traits> | |
| inline bool operator==(const sz_allocator<T, Traits> &, | |
| const sz_allocator<U, Traits> &) { | |
| return true; | |
| } | |
| template <typename T, typename U, typename Traits> | |
| inline bool operator!=(const sz_allocator<T, Traits> &, | |
| const sz_allocator<U, Traits> &) { | |
| return false; | |
| } | |
| class CfgAllocatorTraits { | |
| CfgAllocatorTraits() = delete; | |
| CfgAllocatorTraits(const CfgAllocatorTraits &) = delete; | |
| CfgAllocatorTraits &operator=(const CfgAllocatorTraits &) = delete; | |
| ~CfgAllocatorTraits() = delete; | |
| public: | |
| using allocator_type = ArenaAllocator *; | |
| using manager_type = Cfg; | |
| static constexpr bool cache_allocator = false; | |
| static void init() { ICE_TLS_INIT_FIELD(CfgAllocator); } | |
| static allocator_type current(); | |
| static void set_current(const manager_type *Manager); | |
| static void set_current(ArenaAllocator *Allocator); | |
| static void set_current(std::nullptr_t); | |
| private: | |
| ICE_TLS_DECLARE_FIELD(ArenaAllocator *, CfgAllocator); | |
| }; | |
| template <typename T> | |
| using CfgLocalAllocator = sz_allocator<T, CfgAllocatorTraits>; | |
| using CfgLocalAllocatorScope = sz_allocator_scope<CfgAllocatorTraits>; | |
| class LivenessAllocatorTraits { | |
| LivenessAllocatorTraits() = delete; | |
| LivenessAllocatorTraits(const LivenessAllocatorTraits &) = delete; | |
| LivenessAllocatorTraits &operator=(const LivenessAllocatorTraits &) = delete; | |
| ~LivenessAllocatorTraits() = delete; | |
| public: | |
| using allocator_type = ArenaAllocator *; | |
| using manager_type = Liveness; | |
| static constexpr bool cache_allocator = true; | |
| static void init() { ICE_TLS_INIT_FIELD(LivenessAllocator); } | |
| static allocator_type current(); | |
| static void set_current(const manager_type *Manager); | |
| private: | |
| ICE_TLS_DECLARE_FIELD(ArenaAllocator *, LivenessAllocator); | |
| }; | |
| template <typename T> | |
| using LivenessAllocator = sz_allocator<T, LivenessAllocatorTraits>; | |
| using LivenessAllocatorScope = sz_allocator_scope<LivenessAllocatorTraits>; | |
| } // end of namespace Ice | |
| #endif // SUBZERO_SRC_ICEMEMORY_H |