1 //===- subzero/src/IceMemory.h - Memory management declarations -*- C++ -*-===// 2 // 3 // The Subzero Code Generator 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 /// 10 /// \file 11 /// \brief Declares some useful data structures and routines dealing with 12 /// memory management in Subzero (mostly, allocator types.) 13 /// 14 //===----------------------------------------------------------------------===// 15 16 #ifndef SUBZERO_SRC_ICEMEMORY_H 17 #define SUBZERO_SRC_ICEMEMORY_H 18 19 #include "IceTLS.h" 20 21 #include "llvm/Support/Allocator.h" 22 23 #include <cstddef> 24 #include <mutex> 25 26 namespace Ice { 27 28 class Cfg; 29 class GlobalContext; 30 class Liveness; 31 32 using ArenaAllocator = 33 llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator, /*SlabSize=*/1024 * 1024>; 34 35 class LockedArenaAllocator { 36 LockedArenaAllocator() = delete; 37 LockedArenaAllocator(const LockedArenaAllocator &) = delete; 38 LockedArenaAllocator &operator=(const LockedArenaAllocator &) = delete; 39 40 public: LockedArenaAllocator(ArenaAllocator * Alloc,std::mutex * Mutex)41 LockedArenaAllocator(ArenaAllocator *Alloc, std::mutex *Mutex) 42 : Alloc(Alloc), AutoLock(*Mutex) {} 43 LockedArenaAllocator(LockedArenaAllocator &&) = default; 44 LockedArenaAllocator &operator=(LockedArenaAllocator &&) = default; 45 ~LockedArenaAllocator() = default; 46 47 ArenaAllocator *operator->() { return Alloc; } 48 49 private: 50 ArenaAllocator *Alloc; 51 std::unique_lock<std::mutex> AutoLock; 52 }; 53 54 template <typename T, typename Traits> struct sz_allocator { 55 /// std::allocator interface implementation. 56 /// @{ 57 using value_type = T; 58 using pointer = T *; 59 using const_pointer = const T *; 60 using reference = T &; 61 using const_reference = const T &; 62 using size_type = std::size_t; 63 using difference_type = std::ptrdiff_t; 64 sz_allocatorsz_allocator65 sz_allocator() : Current() {} 66 template <class U> sz_allocatorsz_allocator67 sz_allocator(const sz_allocator<U, Traits> &) : Current() {} 68 addresssz_allocator69 pointer address(reference x) const { 70 return reinterpret_cast<pointer>(&reinterpret_cast<char &>(x)); 71 } addresssz_allocator72 const_pointer address(const_reference x) const { 73 return reinterpret_cast<const_pointer>(&reinterpret_cast<const char &>(x)); 74 } 75 allocatesz_allocator76 pointer allocate(size_type num) { 77 assert(current() != nullptr); 78 return current()->template Allocate<T>(num); 79 } 80 constructsz_allocator81 template <typename... A> void construct(pointer P, A &&... Args) { 82 new (static_cast<void *>(P)) T(std::forward<A>(Args)...); 83 } 84 deallocatesz_allocator85 void deallocate(pointer, size_type) {} 86 87 template <class U> struct rebind { typedef sz_allocator<U, Traits> other; }; 88 destroysz_allocator89 void destroy(pointer P) { P->~T(); } 90 /// @} 91 92 /// Manages the current underlying allocator. 93 /// @{ currentsz_allocator94 typename Traits::allocator_type current() { 95 if (!Traits::cache_allocator) { 96 // TODO(jpp): allocators should always be cacheable... maybe. Investigate. 97 return Traits::current(); 98 } 99 if (Current == nullptr) { 100 Current = Traits::current(); 101 } 102 assert(Current == Traits::current()); 103 return Current; 104 } initsz_allocator105 static void init() { Traits::init(); } 106 /// @} 107 typename Traits::allocator_type Current; 108 }; 109 110 template <class Traits> struct sz_allocator_scope { sz_allocator_scopesz_allocator_scope111 explicit sz_allocator_scope(typename Traits::manager_type *Manager) { 112 Traits::set_current(Manager); 113 } 114 ~sz_allocator_scopesz_allocator_scope115 ~sz_allocator_scope() { Traits::set_current(nullptr); } 116 }; 117 118 template <typename T, typename U, typename Traits> 119 inline bool operator==(const sz_allocator<T, Traits> &, 120 const sz_allocator<U, Traits> &) { 121 return true; 122 } 123 124 template <typename T, typename U, typename Traits> 125 inline bool operator!=(const sz_allocator<T, Traits> &, 126 const sz_allocator<U, Traits> &) { 127 return false; 128 } 129 130 class CfgAllocatorTraits { 131 CfgAllocatorTraits() = delete; 132 CfgAllocatorTraits(const CfgAllocatorTraits &) = delete; 133 CfgAllocatorTraits &operator=(const CfgAllocatorTraits &) = delete; 134 ~CfgAllocatorTraits() = delete; 135 136 public: 137 using allocator_type = ArenaAllocator *; 138 using manager_type = Cfg; 139 static constexpr bool cache_allocator = false; 140 init()141 static void init() { ICE_TLS_INIT_FIELD(CfgAllocator); } 142 143 static allocator_type current(); 144 static void set_current(const manager_type *Manager); 145 static void set_current(ArenaAllocator *Allocator); 146 static void set_current(std::nullptr_t); 147 148 private: 149 ICE_TLS_DECLARE_FIELD(ArenaAllocator *, CfgAllocator); 150 }; 151 152 template <typename T> 153 using CfgLocalAllocator = sz_allocator<T, CfgAllocatorTraits>; 154 155 using CfgLocalAllocatorScope = sz_allocator_scope<CfgAllocatorTraits>; 156 157 class LivenessAllocatorTraits { 158 LivenessAllocatorTraits() = delete; 159 LivenessAllocatorTraits(const LivenessAllocatorTraits &) = delete; 160 LivenessAllocatorTraits &operator=(const LivenessAllocatorTraits &) = delete; 161 ~LivenessAllocatorTraits() = delete; 162 163 public: 164 using allocator_type = ArenaAllocator *; 165 using manager_type = Liveness; 166 static constexpr bool cache_allocator = true; 167 init()168 static void init() { ICE_TLS_INIT_FIELD(LivenessAllocator); } 169 170 static allocator_type current(); 171 static void set_current(const manager_type *Manager); 172 173 private: 174 ICE_TLS_DECLARE_FIELD(ArenaAllocator *, LivenessAllocator); 175 }; 176 177 template <typename T> 178 using LivenessAllocator = sz_allocator<T, LivenessAllocatorTraits>; 179 180 using LivenessAllocatorScope = sz_allocator_scope<LivenessAllocatorTraits>; 181 182 } // end of namespace Ice 183 184 #endif // SUBZERO_SRC_ICEMEMORY_H 185