diff --git a/include/llvm/ADT/ilist.h b/include/llvm/ADT/ilist.h index c34434a1f76..3044a6c435f 100644 --- a/include/llvm/ADT/ilist.h +++ b/include/llvm/ADT/ilist.h @@ -251,11 +251,11 @@ public: pointer operator->() const { return &operator*(); } // Comparison operators - bool operator==(const ilist_iterator &RHS) const { - return NodePtr == RHS.NodePtr; + template bool operator==(const ilist_iterator &RHS) const { + return NodePtr == RHS.getNodePtrUnchecked(); } - bool operator!=(const ilist_iterator &RHS) const { - return NodePtr != RHS.NodePtr; + template bool operator!=(const ilist_iterator &RHS) const { + return NodePtr != RHS.getNodePtrUnchecked(); } // Increment and decrement operators... @@ -687,6 +687,30 @@ public: merge(RightHalf, comp); } void sort() { sort(op_less); } + + /// \brief Get the previous node, or \c nullptr for the list head. + NodeTy *getPrevNode(NodeTy &N) const { + auto I = N.getIterator(); + if (I == begin()) + return nullptr; + return &*std::prev(I); + } + /// \brief Get the previous node, or \c nullptr for the list head. + const NodeTy *getPrevNode(const NodeTy &N) const { + return getPrevNode(const_cast(N)); + } + + /// \brief Get the next node, or \c nullptr for the list tail. + NodeTy *getNextNode(NodeTy &N) const { + auto Next = std::next(N.getIterator()); + if (Next == end()) + return nullptr; + return &*Next; + } + /// \brief Get the next node, or \c nullptr for the list tail. + const NodeTy *getNextNode(const NodeTy &N) const { + return getNextNode(const_cast(N)); + } }; diff --git a/include/llvm/ADT/ilist_node.h b/include/llvm/ADT/ilist_node.h index 8f0538bcf6e..7e5a0e0e5ad 100644 --- a/include/llvm/ADT/ilist_node.h +++ b/include/llvm/ADT/ilist_node.h @@ -66,54 +66,55 @@ public: // FIXME: Stop downcasting to create the iterator (potential UB). return ilist_iterator(static_cast(this)); } +}; +/// An ilist node that can access its parent list. +/// +/// Requires \c NodeTy to have \a getParent() to find the parent node, and the +/// \c ParentTy to have \a getSublistAccess() to get a reference to the list. +template +class ilist_node_with_parent : public ilist_node { +protected: + ilist_node_with_parent() = default; + +private: + /// Forward to NodeTy::getParent(). + /// + /// Note: do not use the name "getParent()". We want a compile error + /// (instead of recursion) when the subclass fails to implement \a + /// getParent(). + const ParentTy *getNodeParent() const { + return static_cast(this)->getParent(); + } + +public: /// @name Adjacent Node Accessors /// @{ - - /// \brief Get the previous node, or 0 for the list head. + /// \brief Get the previous node, or \c nullptr for the list head. NodeTy *getPrevNode() { - NodeTy *Prev = this->getPrev(); - - // Check for sentinel. - if (!Prev->getNext()) - return nullptr; - - return Prev; + // Should be separated to a reused function, but then we couldn't use auto + // (and would need the type of the list). + const auto &List = + getNodeParent()->*(ParentTy::getSublistAccess((NodeTy *)nullptr)); + return List.getPrevNode(*static_cast(this)); } - - /// \brief Get the previous node, or 0 for the list head. + /// \brief Get the previous node, or \c nullptr for the list head. const NodeTy *getPrevNode() const { - const NodeTy *Prev = this->getPrev(); - - // Check for sentinel. - if (!Prev->getNext()) - return nullptr; - - return Prev; + return const_cast(this)->getPrevNode(); } - /// \brief Get the next node, or 0 for the list tail. + /// \brief Get the next node, or \c nullptr for the list tail. NodeTy *getNextNode() { - NodeTy *Next = getNext(); - - // Check for sentinel. - if (!Next->getNext()) - return nullptr; - - return Next; + // Should be separated to a reused function, but then we couldn't use auto + // (and would need the type of the list). + const auto &List = + getNodeParent()->*(ParentTy::getSublistAccess((NodeTy *)nullptr)); + return List.getNextNode(*static_cast(this)); } - - /// \brief Get the next node, or 0 for the list tail. + /// \brief Get the next node, or \c nullptr for the list tail. const NodeTy *getNextNode() const { - const NodeTy *Next = getNext(); - - // Check for sentinel. - if (!Next->getNext()) - return nullptr; - - return Next; + return const_cast(this)->getNextNode(); } - /// @} }; diff --git a/include/llvm/CodeGen/MachineBasicBlock.h b/include/llvm/CodeGen/MachineBasicBlock.h index db3b24e2e16..4f76b21fb00 100644 --- a/include/llvm/CodeGen/MachineBasicBlock.h +++ b/include/llvm/CodeGen/MachineBasicBlock.h @@ -65,7 +65,8 @@ private: void createNode(const MachineInstr &); }; -class MachineBasicBlock : public ilist_node { +class MachineBasicBlock + : public ilist_node_with_parent { public: /// Pair of physical register and lane mask. /// This is not simply a std::pair typedef because the members should be named @@ -272,6 +273,11 @@ public: reverse_iterator rend () { return instr_rend(); } const_reverse_iterator rend () const { return instr_rend(); } + /// Support for MachineInstr::getNextNode(). + static Instructions MachineBasicBlock::*getSublistAccess(MachineInstr *) { + return &MachineBasicBlock::Insts; + } + inline iterator_range terminators() { return iterator_range(getFirstTerminator(), end()); } diff --git a/include/llvm/CodeGen/MachineFunction.h b/include/llvm/CodeGen/MachineFunction.h index 82bbbcf5455..d163c971d4b 100644 --- a/include/llvm/CodeGen/MachineFunction.h +++ b/include/llvm/CodeGen/MachineFunction.h @@ -331,6 +331,12 @@ public: typedef std::reverse_iterator const_reverse_iterator; typedef std::reverse_iterator reverse_iterator; + /// Support for MachineBasicBlock::getNextNode(). + static BasicBlockListType MachineFunction::* + getSublistAccess(MachineBasicBlock *) { + return &MachineFunction::BasicBlocks; + } + /// addLiveIn - Add the specified physical register as a live-in value and /// create a corresponding virtual register for it. unsigned addLiveIn(unsigned PReg, const TargetRegisterClass *RC); diff --git a/include/llvm/CodeGen/MachineInstr.h b/include/llvm/CodeGen/MachineInstr.h index 34681ec44e9..607e2781960 100644 --- a/include/llvm/CodeGen/MachineInstr.h +++ b/include/llvm/CodeGen/MachineInstr.h @@ -48,7 +48,8 @@ class MachineMemOperand; /// MachineFunction is deleted, all the contained MachineInstrs are deallocated /// without having their destructor called. /// -class MachineInstr : public ilist_node { +class MachineInstr + : public ilist_node_with_parent { public: typedef MachineMemOperand **mmo_iterator; diff --git a/include/llvm/IR/BasicBlock.h b/include/llvm/IR/BasicBlock.h index fe5dca6a506..c6b54d308ce 100644 --- a/include/llvm/IR/BasicBlock.h +++ b/include/llvm/IR/BasicBlock.h @@ -50,7 +50,7 @@ struct SymbolTableListSentinelTraits /// modifying a program. However, the verifier will ensure that basic blocks /// are "well formed". class BasicBlock : public Value, // Basic blocks are data objects also - public ilist_node { + public ilist_node_with_parent { friend class BlockAddress; public: typedef SymbolTableList InstListType; diff --git a/include/llvm/IR/Instruction.h b/include/llvm/IR/Instruction.h index 581ac09cf0c..c7ba8721fe0 100644 --- a/include/llvm/IR/Instruction.h +++ b/include/llvm/IR/Instruction.h @@ -33,7 +33,8 @@ template <> struct SymbolTableListSentinelTraits : public ilist_half_embedded_sentinel_traits {}; -class Instruction : public User, public ilist_node { +class Instruction : public User, + public ilist_node_with_parent { void operator=(const Instruction &) = delete; Instruction(const Instruction &) = delete; diff --git a/include/llvm/MC/MCAssembler.h b/include/llvm/MC/MCAssembler.h index d69472bf2ec..aadfe1747f0 100644 --- a/include/llvm/MC/MCAssembler.h +++ b/include/llvm/MC/MCAssembler.h @@ -35,7 +35,7 @@ class MCSubtargetInfo; class MCValue; class MCAsmBackend; -class MCFragment : public ilist_node { +class MCFragment : public ilist_node_with_parent { friend class MCAsmLayout; MCFragment(const MCFragment &) = delete; diff --git a/include/llvm/MC/MCSection.h b/include/llvm/MC/MCSection.h index c049ad5455b..08af5334bc1 100644 --- a/include/llvm/MC/MCSection.h +++ b/include/llvm/MC/MCSection.h @@ -154,6 +154,11 @@ public: return const_cast(this)->getFragmentList(); } + /// Support for MCFragment::getNextNode(). + static FragmentListType MCSection::*getSublistAccess(MCFragment *) { + return &MCSection::Fragments; + } + const MCDummyFragment &getDummyFragment() const { return DummyFragment; } MCDummyFragment &getDummyFragment() { return DummyFragment; } diff --git a/unittests/ADT/ilistTest.cpp b/unittests/ADT/ilistTest.cpp index 4e5235ba03b..377dcc044dd 100644 --- a/unittests/ADT/ilistTest.cpp +++ b/unittests/ADT/ilistTest.cpp @@ -30,18 +30,18 @@ TEST(ilistTest, Basic) { ilist List; List.push_back(Node(1)); EXPECT_EQ(1, List.back().Value); - EXPECT_EQ(nullptr, List.back().getPrevNode()); - EXPECT_EQ(nullptr, List.back().getNextNode()); + EXPECT_EQ(nullptr, List.getPrevNode(List.back())); + EXPECT_EQ(nullptr, List.getNextNode(List.back())); List.push_back(Node(2)); EXPECT_EQ(2, List.back().Value); - EXPECT_EQ(2, List.front().getNextNode()->Value); - EXPECT_EQ(1, List.back().getPrevNode()->Value); + EXPECT_EQ(2, List.getNextNode(List.front())->Value); + EXPECT_EQ(1, List.getPrevNode(List.back())->Value); const ilist &ConstList = List; EXPECT_EQ(2, ConstList.back().Value); - EXPECT_EQ(2, ConstList.front().getNextNode()->Value); - EXPECT_EQ(1, ConstList.back().getPrevNode()->Value); + EXPECT_EQ(2, ConstList.getNextNode(ConstList.front())->Value); + EXPECT_EQ(1, ConstList.getPrevNode(ConstList.back())->Value); } TEST(ilistTest, SpliceOne) {