Index: src/IceDefs.h |
diff --git a/src/IceDefs.h b/src/IceDefs.h |
index d9c0c234784e0d569ae6c83ed109bb981d37749f..eaf0dc02434c432fd0fb883a2596da0821e7fd56 100644 |
--- a/src/IceDefs.h |
+++ b/src/IceDefs.h |
@@ -73,6 +73,11 @@ class Variable; |
class VariableDeclaration; |
class VariablesMetadata; |
+/// SizeT is for holding small-ish limits like number of source operands in an |
+/// instruction. It is used instead of size_t (which may be 64-bits wide) when |
+/// we want to save space. |
+using SizeT = uint32_t; |
+ |
constexpr char GlobalOffsetTable[] = "_GLOBAL_OFFSET_TABLE_"; |
// makeUnique should be used when memory is expected to be allocated from the |
// heap (as opposed to allocated from some Allocator.) It is intended to be |
@@ -139,12 +144,127 @@ using NodeList = CfgVector<CfgNode *>; |
// Containers that use the default (global) allocator. |
using ConstantList = std::vector<Constant *>; |
using FunctionDeclarationList = std::vector<FunctionDeclaration *>; |
-using VariableDeclarationList = std::vector<VariableDeclaration *>; |
-/// SizeT is for holding small-ish limits like number of source operands in an |
-/// instruction. It is used instead of size_t (which may be 64-bits wide) when |
-/// we want to save space. |
-using SizeT = uint32_t; |
+/// VariableDeclarationList is a container for holding VariableDeclarations -- |
+/// i.e., Global Variables. It is also used to create said variables, and their |
+/// initializers in an arena. |
+class VariableDeclarationList { |
+ VariableDeclarationList(const VariableDeclarationList &) = delete; |
+ VariableDeclarationList &operator=(const VariableDeclarationList &) = delete; |
+ VariableDeclarationList(VariableDeclarationList &&) = delete; |
+ VariableDeclarationList &operator=(VariableDeclarationList &&) = delete; |
+ |
+public: |
+ using VariableDeclarationArray = std::vector<VariableDeclaration *>; |
+ |
+ VariableDeclarationList() : Arena(new ArenaAllocator()) {} |
+ |
+ ~VariableDeclarationList() { clearAndPurge(); } |
+ |
+ template <typename T> T *allocate_initializer(SizeT Count = 1) { |
+ static_assert( |
+ std::is_trivially_destructible<T>::value, |
+ "allocate_initializer can only allocate trivially destructible types."); |
+ return Arena->Allocate<T>(Count); |
+ } |
+ |
+ template <typename T> T *allocate_variable_declaration() { |
+ static_assert(!std::is_trivially_destructible<T>::value, |
+ "allocate_variable_declaration expects non-trivially " |
+ "destructible types."); |
+ T *Ret = Arena->Allocate<T>(); |
+ Dtors.emplace_back([Ret]() { Ret->~T(); }); |
+ return Ret; |
+ } |
+ |
+ // This do nothing method is invoked when a global variable is created, but it |
+ // will not be emitted. If we ever need to track the created variabled, having |
+ // this hook is handy. |
+ void willNotBeEmitted(VariableDeclaration *) {} |
+ |
+ /// Merges Other with this, effectively resetting Other to an empty state. |
+ void merge(VariableDeclarationList *Other) { |
+ assert(Other != nullptr); |
+ addArena(std::move(Other->Arena)); |
+ for (std::size_t i = 0; i < Other->MergedArenas.size(); ++i) { |
+ addArena(std::move(Other->MergedArenas[i])); |
+ } |
+ Other->MergedArenas.clear(); |
+ |
+ Dtors.insert(Dtors.end(), Other->Dtors.begin(), Other->Dtors.end()); |
+ Other->Dtors.clear(); |
+ |
+ Globals.insert(Globals.end(), Other->Globals.begin(), Other->Globals.end()); |
+ Other->Globals.clear(); |
+ } |
+ |
+ /// Destroys all GlobalVariables and initializers that this knows about |
+ /// (including those merged with it), and releases memory. |
+ void clearAndPurge() { |
+ if (Arena == nullptr) { |
+ // Arena is only null if this was merged, so we ensure there's no state |
+ // being held by this. |
+ assert(Dtors.empty()); |
+ assert(Globals.empty()); |
+ assert(MergedArenas.empty()); |
+ return; |
+ } |
+ // Invokes destructors in reverse creation order. |
+ for (auto Dtor = Dtors.rbegin(); Dtor != Dtors.rend(); ++Dtor) { |
+ (*Dtor)(); |
+ } |
+ Dtors.clear(); |
+ Globals.clear(); |
+ MergedArenas.clear(); |
+ Arena->Reset(); |
+ } |
+ |
+ /// Adapt the relevant parts of the std::vector<VariableDeclaration *> |
+ /// interface. |
+ /// @{ |
+ VariableDeclarationArray::iterator begin() { return Globals.begin(); } |
+ |
+ VariableDeclarationArray::iterator end() { return Globals.end(); } |
+ |
+ VariableDeclarationArray::const_iterator begin() const { |
+ return Globals.begin(); |
+ } |
+ |
+ VariableDeclarationArray::const_iterator end() const { return Globals.end(); } |
+ |
+ bool empty() const { return Globals.empty(); } |
+ |
+ VariableDeclarationArray::size_type size() const { return Globals.size(); } |
+ |
+ VariableDeclarationArray::reference |
+ at(VariableDeclarationArray::size_type Pos) { |
+ return Globals.at(Pos); |
+ } |
+ |
+ void push_back(VariableDeclaration *Global) { Globals.push_back(Global); } |
+ |
+ void reserve(VariableDeclarationArray::size_type Capacity) { |
+ Globals.reserve(Capacity); |
+ } |
+ |
+ void clear() { Globals.clear(); } |
+ |
+ VariableDeclarationArray::reference back() { return Globals.back(); } |
+ /// @} |
+ |
+private: |
+ using ArenaPtr = std::unique_ptr<ArenaAllocator>; |
+ using DestructorsArray = std::vector<std::function<void()>>; |
+ |
+ void addArena(ArenaPtr NewArena) { |
+ MergedArenas.emplace_back(std::move(NewArena)); |
+ } |
+ |
+ ArenaPtr Arena; |
+ VariableDeclarationArray Globals; |
+ DestructorsArray Dtors; |
+ std::vector<ArenaPtr> MergedArenas; |
+}; |
/// InstNumberT is for holding an instruction number. Instruction numbers are |
/// used for representing Variable live ranges. |