From 94b99f5949b7374a6667addf712ff4e4b690dbcd Mon Sep 17 00:00:00 2001 From: MerryMage Date: Sat, 6 Aug 2016 22:23:01 +0100 Subject: [PATCH] Common: Add an intrusive list implementation; remove use of boost::intrusive::list. --- src/CMakeLists.txt | 1 + src/common/intrusive_list.h | 282 ++++++++++++++++++++++ src/frontend/ir/ir.h | 7 +- src/frontend/ir/ir_emitter.cpp | 2 +- src/frontend/translate/translate_arm.cpp | 2 +- src/ir_opt/dead_code_elimination_pass.cpp | 2 +- 6 files changed, 289 insertions(+), 7 deletions(-) create mode 100644 src/common/intrusive_list.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 25993072..2e4d4283 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -43,6 +43,7 @@ set(HEADERS common/bit_util.h common/code_block.h common/common_types.h + common/intrusive_list.h common/memory_pool.h common/memory_util.h common/mp.h diff --git a/src/common/intrusive_list.h b/src/common/intrusive_list.h new file mode 100644 index 00000000..09ff6a1a --- /dev/null +++ b/src/common/intrusive_list.h @@ -0,0 +1,282 @@ +/* This file is part of the dynarmic project. + * Copyright (c) 2016 MerryMage + * This software may be used and distributed according to the terms of the GNU + * General Public License version 2 or any later version. + */ + +#pragma once + +#include +#include + +#include "common/assert.h" +#include "common/common_types.h" + +namespace Dynarmic { +namespace Common { + +template class IntrusiveListNode; +template class IntrusiveList; +template class IntrusiveListIterator; +template class IntrusiveListConstIterator; + +template +class IntrusiveListNode { +public: + IntrusiveListNode() : next(this), prev(this) {} + void UnlinkFromList() { + prev->next = next; + next->prev = prev; +#if !defined(NDEBUG) + next = prev = nullptr; +#endif + } +private: + friend class IntrusiveList; + friend class IntrusiveListIterator; + friend class IntrusiveListConstIterator; + IntrusiveListNode* next; + IntrusiveListNode* prev; +}; + +template +class IntrusiveList { +public: + /** + * Add an entry to the start of the list. + * @param node Node to add to the list. + */ + void Prepend(T& node) { + AddAfter(root.get(), static_cast*>(&node)); + } + + /** + * Add an entry to the end of the list + * @param node Node to add to the list. + */ + void Append(T& node) { + AddBefore(root.get(), static_cast*>(&node)); + } + + /** + * Add an entry after an existing node in this list + * @param existing_node Node to add new_node after. Must already be member of the list. + * @param new_node Node to add to the list. + */ + void AddAfter(T& existing, T& node) { + AddAfter(static_cast*>(&existing), static_cast*>(&node)); + } + + /** + * Add an entry before an existing node in this list + * @param existing_node Node to add new_node before. Must already be member of the list. + * @param new_node Node to add to the list. + */ + void AddBefore(T& existing, T& node) { + AddBefore(static_cast*>(&existing), static_cast*>(&node)); + } + + /** + * Removes node from list + * @param node Node to remove from list. + */ + void Remove(T& node) { + node.UnlinkFromList(); + } + + /** + * Is this list empty? + * @returns true if there are no nodes in this list. + */ + bool IsEmpty() { + return root->next == root.get(); + } + + IntrusiveListIterator begin(); + IntrusiveListIterator end(); + IntrusiveListIterator erase(const IntrusiveListIterator&); + IntrusiveListIterator iterator_to(T&); + + IntrusiveListConstIterator begin() const; + IntrusiveListConstIterator end() const; + IntrusiveListConstIterator iterator_to(T&) const; + +private: + friend class IntrusiveListIterator; + friend class IntrusiveListConstIterator; + + void AddAfter(IntrusiveListNode* existing_node, IntrusiveListNode* new_node) { + new_node->next = existing_node->next; + new_node->prev = existing_node; + existing_node->next->prev = new_node; + existing_node->next = new_node; + } + + void AddBefore(IntrusiveListNode* existing_node, IntrusiveListNode* new_node) { + new_node->next = existing_node; + new_node->prev = existing_node->prev; + existing_node->prev->next = new_node; + existing_node->prev = new_node; + } + + std::shared_ptr> root = std::make_shared>(); +}; + +template +class IntrusiveListIterator { +public: + IntrusiveListIterator() : root(nullptr), node(nullptr) {} + IntrusiveListIterator(IntrusiveList* list, IntrusiveListNode* node) : root(list->root.get()), node(node) {} + IntrusiveListIterator(const IntrusiveListIterator& other) : root(other.root), node(other.node) {} + IntrusiveListIterator& operator=(IntrusiveListIterator other) { + std::swap(root, other.root); + std::swap(node, other.node); + return *this; + } + + IntrusiveListIterator& operator++() { + node = node == root ? node : node->next; + return *this; + } + IntrusiveListIterator operator++(int) { + IntrusiveListIterator it(*this); + node = node == root ? node : node->next; + return it; + } + IntrusiveListIterator& operator--() { + node = node->prev == root ? node : node->prev; + return *this; + } + IntrusiveListIterator operator--(int) { + IntrusiveListIterator it(*this); + node = node->prev == root ? node : node->prev; + return it; + } + + bool operator==(const IntrusiveListIterator& other) const { + DEBUG_ASSERT(root == other.root); + return node == other.node; + } + bool operator!=(const IntrusiveListIterator& other) const { + return !(*this == other); + } + + const T& operator*() const { + DEBUG_ASSERT(node != root); + return *reinterpret_cast(node); + } + T& operator*() { + DEBUG_ASSERT(node != root); + return *reinterpret_cast(node); + } + T* operator->() { + DEBUG_ASSERT(node != root); + return reinterpret_cast(node); + } + const T* operator->() const { + DEBUG_ASSERT(node != root); + return reinterpret_cast(node); + } + +private: + friend class IntrusiveList; + IntrusiveListNode* root; + IntrusiveListNode* node; +}; + +template +class IntrusiveListConstIterator { +public: + IntrusiveListConstIterator() : root(nullptr), node(nullptr) {} + IntrusiveListConstIterator(const IntrusiveList* list, IntrusiveListNode* node) : root(list->root.get()), node(node) {} + IntrusiveListConstIterator(const IntrusiveListConstIterator& other) : root(other.root), node(other.node) {} + IntrusiveListConstIterator& operator=(IntrusiveListConstIterator other) { + std::swap(root, other.root); + std::swap(node, other.node); + return *this; + } + + IntrusiveListConstIterator& operator++() { + node = node == root ? node : node->next; + return *this; + } + IntrusiveListConstIterator operator++(int) { + IntrusiveListConstIterator it(*this); + node = node == root ? node : node->next; + return it; + } + IntrusiveListConstIterator& operator--() { + node = node->prev == root ? node : node->prev; + return *this; + } + IntrusiveListConstIterator operator--(int) { + IntrusiveListConstIterator it(*this); + node = node->prev == root ? node : node->prev; + return it; + } + + bool operator==(const IntrusiveListConstIterator& other) const { + DEBUG_ASSERT(root == other.root); + return node == other.node; + } + bool operator!=(const IntrusiveListConstIterator& other) const { + return !(*this == other); + } + + const T& operator*() const { + DEBUG_ASSERT(node != root); + return *reinterpret_cast(node); + } + const T* operator->() const { + DEBUG_ASSERT(node != root); + return reinterpret_cast(node); + } + +private: + friend class IntrusiveList; + IntrusiveListNode* root; + IntrusiveListNode* node; +}; + +template +IntrusiveListIterator IntrusiveList::begin() { + return IntrusiveListIterator(this, root->next); +} + +template +IntrusiveListIterator IntrusiveList::end() { + return IntrusiveListIterator(this, root.get()); +} + +template +IntrusiveListIterator IntrusiveList::erase(const IntrusiveListIterator& it) { + DEBUG_ASSERT(it.root == root.get() && it.node != it.root); + IntrusiveListNode* to_remove = it.node; + IntrusiveListIterator ret = it; + ++ret; + to_remove->UnlinkFromList(); + return ret; +} + +template +IntrusiveListIterator IntrusiveList::iterator_to(T& item) { + return IntrusiveListIterator(this, static_cast*>(&item)); +} + +template +IntrusiveListConstIterator IntrusiveList::begin() const { + return IntrusiveListConstIterator(this, root->next); +} + +template +IntrusiveListConstIterator IntrusiveList::end() const { + return IntrusiveListConstIterator(this, root.get()); +} + +template +IntrusiveListConstIterator IntrusiveList::iterator_to(T& item) const { + return IntrusiveListConstIterator(this, static_cast*>(&item)); +} + +} // namespace Common +} // namespace Dynarmic diff --git a/src/frontend/ir/ir.h b/src/frontend/ir/ir.h index 56433ddb..6a89c6d4 100644 --- a/src/frontend/ir/ir.h +++ b/src/frontend/ir/ir.h @@ -10,12 +10,12 @@ #include #include -#include #include #include #include "common/assert.h" #include "common/common_types.h" +#include "common/intrusive_list.h" #include "common/memory_pool.h" #include "frontend/arm_types.h" #include "frontend/ir/opcodes.h" @@ -113,8 +113,7 @@ private: } inner; }; -using InstListLinkMode = boost::intrusive::link_mode; -class Inst final : public boost::intrusive::list_base_hook { +class Inst final : public Common::IntrusiveListNode { public: Inst(Opcode op) : op(op) {} @@ -242,7 +241,7 @@ public: boost::optional cond_failed = {}; /// List of instructions in this block. - boost::intrusive::list instructions; + Common::IntrusiveList instructions; /// Memory pool for instruction list std::unique_ptr instruction_alloc_pool = std::make_unique(sizeof(Inst), 4096); /// Terminal instruction of this block. diff --git a/src/frontend/ir/ir_emitter.cpp b/src/frontend/ir/ir_emitter.cpp index e9b5b87d..d3bf1044 100644 --- a/src/frontend/ir/ir_emitter.cpp +++ b/src/frontend/ir/ir_emitter.cpp @@ -353,7 +353,7 @@ IR::Value IREmitter::Inst(IR::Opcode op, std::initializer_list args) index++; }); - block.instructions.push_back(*inst); + block.instructions.Append(*inst); return IR::Value(inst); } diff --git a/src/frontend/translate/translate_arm.cpp b/src/frontend/translate/translate_arm.cpp index 16090d12..f44dc5df 100644 --- a/src/frontend/translate/translate_arm.cpp +++ b/src/frontend/translate/translate_arm.cpp @@ -68,7 +68,7 @@ bool ArmTranslatorVisitor::ConditionPassed(Cond cond) { // non-AL cond - if (!ir.block.instructions.empty()) { + if (!ir.block.instructions.IsEmpty()) { // We've already emitted instructions. Quit for now, we'll make a new block here later. cond_state = ConditionalState::Break; ir.SetTerm(IR::Term::LinkBlock{ir.current_location}); diff --git a/src/ir_opt/dead_code_elimination_pass.cpp b/src/ir_opt/dead_code_elimination_pass.cpp index c3ffdb04..ee35d7b7 100644 --- a/src/ir_opt/dead_code_elimination_pass.cpp +++ b/src/ir_opt/dead_code_elimination_pass.cpp @@ -19,7 +19,7 @@ void DeadCodeElimination(IR::Block& block) { // We iterate over the instructions in reverse order. // This is because removing an instruction reduces the number of uses for earlier instructions. - if (block.instructions.empty()) { + if (block.instructions.IsEmpty()) { return; }