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> &) 68 : Current() {} 69 addresssz_allocator70 pointer address(reference x) const { 71 return reinterpret_cast<pointer>(&reinterpret_cast<char &>(x)); 72 } addresssz_allocator73 const_pointer address(const_reference x) const { 74 return reinterpret_cast<const_pointer>(&reinterpret_cast<const char &>(x)); 75 } 76 allocatesz_allocator77 pointer allocate(size_type num) { 78 assert(current() != nullptr); 79 return current()->template Allocate<T>(num); 80 } 81 constructsz_allocator82 template <typename... A> void construct(pointer P, A &&... Args) { 83 new (static_cast<void *>(P)) T(std::forward<A>(Args)...); 84 } 85 deallocatesz_allocator86 void deallocate(pointer, size_type) {} 87 88 template <class U> struct rebind { typedef sz_allocator<U, Traits> other; }; 89 destroysz_allocator90 void destroy(pointer P) { P->~T(); } 91 /// @} 92 93 /// Manages the current underlying allocator. 94 /// @{ currentsz_allocator95 typename Traits::allocator_type current() { 96 if (!Traits::cache_allocator) { 97 // TODO(jpp): allocators should always be cacheable... maybe. Investigate. 98 return Traits::current(); 99 } 100 if (Current == nullptr) { 101 Current = Traits::current(); 102 } 103 assert(Current == Traits::current()); 104 return Current; 105 } initsz_allocator106 static void init() { Traits::init(); } 107 /// @} 108 typename Traits::allocator_type Current; 109 }; 110 111 template <class Traits> struct sz_allocator_scope { sz_allocator_scopesz_allocator_scope112 explicit sz_allocator_scope(typename Traits::manager_type *Manager) { 113 Traits::set_current(Manager); 114 } 115 ~sz_allocator_scopesz_allocator_scope116 ~sz_allocator_scope() { Traits::set_current(nullptr); } 117 }; 118 119 template <typename T, typename U, typename Traits> 120 inline bool operator==(const sz_allocator<T, Traits> &, 121 const sz_allocator<U, Traits> &) { 122 return true; 123 } 124 125 template <typename T, typename U, typename Traits> 126 inline bool operator!=(const sz_allocator<T, Traits> &, 127 const sz_allocator<U, Traits> &) { 128 return false; 129 } 130 131 class CfgAllocatorTraits { 132 CfgAllocatorTraits() = delete; 133 CfgAllocatorTraits(const CfgAllocatorTraits &) = delete; 134 CfgAllocatorTraits &operator=(const CfgAllocatorTraits &) = delete; 135 ~CfgAllocatorTraits() = delete; 136 137 public: 138 using allocator_type = ArenaAllocator *; 139 using manager_type = Cfg; 140 static constexpr bool cache_allocator = false; 141 init()142 static void init() { ICE_TLS_INIT_FIELD(CfgAllocator); }; 143 144 static allocator_type current(); 145 static void set_current(const manager_type *Manager); 146 static void set_current(ArenaAllocator *Allocator); 147 static void set_current(std::nullptr_t); 148 149 private: 150 ICE_TLS_DECLARE_FIELD(ArenaAllocator *, CfgAllocator); 151 }; 152 153 template <typename T> 154 using CfgLocalAllocator = sz_allocator<T, CfgAllocatorTraits>; 155 156 using CfgLocalAllocatorScope = sz_allocator_scope<CfgAllocatorTraits>; 157 158 class LivenessAllocatorTraits { 159 LivenessAllocatorTraits() = delete; 160 LivenessAllocatorTraits(const LivenessAllocatorTraits &) = delete; 161 LivenessAllocatorTraits &operator=(const LivenessAllocatorTraits &) = delete; 162 ~LivenessAllocatorTraits() = delete; 163 164 public: 165 using allocator_type = ArenaAllocator *; 166 using manager_type = Liveness; 167 static constexpr bool cache_allocator = true; 168 init()169 static void init() { ICE_TLS_INIT_FIELD(LivenessAllocator); }; 170 171 static allocator_type current(); 172 static void set_current(const manager_type *Manager); 173 174 private: 175 ICE_TLS_DECLARE_FIELD(ArenaAllocator *, LivenessAllocator); 176 }; 177 178 template <typename T> 179 using LivenessAllocator = sz_allocator<T, LivenessAllocatorTraits>; 180 181 using LivenessAllocatorScope = sz_allocator_scope<LivenessAllocatorTraits>; 182 183 } // end of namespace Ice 184 185 #endif // SUBZERO_SRC_ICEMEMORY_H 186