| //===- 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 |