blob: fc19d7aaa74a92114ba6cd015281a2993c03f23b [file] [log] [blame]
//===- 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