[llvm] [LLVM] Add option to store Parent-pointer in ilist_node_base (PR #94224)

Stephen Tozer via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 18 04:05:48 PDT 2024


https://github.com/SLTozer updated https://github.com/llvm/llvm-project/pull/94224

>From 537c8f80bfed595ca3f061a2d53b5a8f5ce7802e Mon Sep 17 00:00:00 2001
From: Stephen Tozer <stephen.tozer at sony.com>
Date: Fri, 31 May 2024 18:14:06 +0100
Subject: [PATCH 1/5] Add option to store Parent-pointer in ilist_node_base

---
 llvm/include/llvm/ADT/ilist_base.h         |  4 +-
 llvm/include/llvm/ADT/ilist_iterator.h     | 10 +++++
 llvm/include/llvm/ADT/ilist_node.h         | 11 +++++
 llvm/include/llvm/ADT/ilist_node_base.h    | 51 ++++++++++++++++++++--
 llvm/include/llvm/ADT/ilist_node_options.h | 43 +++++++++++++++---
 llvm/include/llvm/IR/BasicBlock.h          | 10 +++--
 llvm/include/llvm/IR/Instruction.h         | 15 ++++---
 llvm/include/llvm/IR/ValueSymbolTable.h    |  4 +-
 llvm/lib/IR/BasicBlock.cpp                 |  5 ++-
 llvm/lib/IR/Instruction.cpp                | 25 +++++------
 10 files changed, 140 insertions(+), 38 deletions(-)

diff --git a/llvm/include/llvm/ADT/ilist_base.h b/llvm/include/llvm/ADT/ilist_base.h
index b8c098b951ade..000253a26012b 100644
--- a/llvm/include/llvm/ADT/ilist_base.h
+++ b/llvm/include/llvm/ADT/ilist_base.h
@@ -15,9 +15,9 @@
 namespace llvm {
 
 /// Implementations of list algorithms using ilist_node_base.
-template <bool EnableSentinelTracking> class ilist_base {
+template <bool EnableSentinelTracking, class ParentPtrTy> class ilist_base {
 public:
-  using node_base_type = ilist_node_base<EnableSentinelTracking>;
+  using node_base_type = ilist_node_base<EnableSentinelTracking, ParentPtrTy>;
 
   static void insertBeforeImpl(node_base_type &Next, node_base_type &N) {
     node_base_type &Prev = *Next.getPrev();
diff --git a/llvm/include/llvm/ADT/ilist_iterator.h b/llvm/include/llvm/ADT/ilist_iterator.h
index 2393c4d2c403c..635e050e0d09a 100644
--- a/llvm/include/llvm/ADT/ilist_iterator.h
+++ b/llvm/include/llvm/ADT/ilist_iterator.h
@@ -70,6 +70,7 @@ class ilist_iterator : ilist_detail::SpecificNodeAccess<OptionsT> {
   using iterator_category = std::bidirectional_iterator_tag;
   using const_pointer = typename OptionsT::const_pointer;
   using const_reference = typename OptionsT::const_reference;
+  using parent_ptr_ty = typename OptionsT::parent_ptr_ty;
 
 private:
   using node_pointer = typename Traits::node_pointer;
@@ -101,6 +102,8 @@ class ilist_iterator : ilist_detail::SpecificNodeAccess<OptionsT> {
     return *this;
   }
 
+  parent_ptr_ty getNodeParent() { return NodePtr->getNodeBaseParent(); }
+
   /// Explicit conversion between forward/reverse iterators.
   ///
   /// Translate between forward and reverse iterators without changing range
@@ -168,6 +171,8 @@ class ilist_iterator : ilist_detail::SpecificNodeAccess<OptionsT> {
     return tmp;
   }
 
+  bool isValid() const { return NodePtr; }
+
   /// Get the underlying ilist_node.
   node_pointer getNodePtr() const { return static_cast<node_pointer>(NodePtr); }
 
@@ -195,6 +200,7 @@ class ilist_iterator_w_bits : ilist_detail::SpecificNodeAccess<OptionsT> {
   using iterator_category = std::bidirectional_iterator_tag;
   using const_pointer = typename OptionsT::const_pointer;
   using const_reference = typename OptionsT::const_reference;
+  using parent_ptr_ty = typename OptionsT::parent_ptr_ty;
 
 private:
   using node_pointer = typename Traits::node_pointer;
@@ -319,6 +325,10 @@ class ilist_iterator_w_bits : ilist_detail::SpecificNodeAccess<OptionsT> {
     return tmp;
   }
 
+  parent_ptr_ty getNodeParent() { return NodePtr->getNodeBaseParent(); }
+
+  bool isValid() const { return NodePtr; }
+
   /// Get the underlying ilist_node.
   node_pointer getNodePtr() const { return static_cast<node_pointer>(NodePtr); }
 
diff --git a/llvm/include/llvm/ADT/ilist_node.h b/llvm/include/llvm/ADT/ilist_node.h
index 3b6f0dcc7b5e9..ec615497abee1 100644
--- a/llvm/include/llvm/ADT/ilist_node.h
+++ b/llvm/include/llvm/ADT/ilist_node.h
@@ -118,7 +118,9 @@ template <class OptionsT> class ilist_node_impl : OptionsT::node_base_type {
   }
 
   // Under-approximation, but always available for assertions.
+  using node_base_type::getNodeBaseParent;
   using node_base_type::isKnownSentinel;
+  using node_base_type::setNodeBaseParent;
 
   /// Check whether this is the sentinel node.
   ///
@@ -171,6 +173,15 @@ template <class OptionsT> class ilist_node_impl : OptionsT::node_base_type {
 /// }
 /// \endexample
 ///
+/// When the \a ilist_parent<ParentTy> option is passed to an ilist_node and the
+/// owning ilist, each node contains a pointer to the ilist's owner. This
+/// pointer does not have any automatic behaviour; set it manually, including
+/// for the sentinel node when the list is created. The primary benefit of this
+/// over declaring and using this pointer in the final node class is that the
+/// pointer will be added in the sentinel, meaning that you can safely use \a
+/// ilist_iterator::getNodeParent() to get the node parent from any valid (i.e.
+/// non-null) iterator, even a sentinel value.
+///
 /// See \a is_valid_option for steps on adding a new option.
 template <class T, class... Options>
 class ilist_node
diff --git a/llvm/include/llvm/ADT/ilist_node_base.h b/llvm/include/llvm/ADT/ilist_node_base.h
index f6c518e6eed7a..e396bb22fca02 100644
--- a/llvm/include/llvm/ADT/ilist_node_base.h
+++ b/llvm/include/llvm/ADT/ilist_node_base.h
@@ -16,9 +16,9 @@ namespace llvm {
 /// Base class for ilist nodes.
 ///
 /// Optionally tracks whether this node is the sentinel.
-template <bool EnableSentinelTracking> class ilist_node_base;
+template <bool EnableSentinelTracking, class ParentPtrTy> class ilist_node_base;
 
-template <> class ilist_node_base<false> {
+template <> class ilist_node_base<false, void> {
   ilist_node_base *Prev = nullptr;
   ilist_node_base *Next = nullptr;
 
@@ -28,11 +28,14 @@ template <> class ilist_node_base<false> {
   ilist_node_base *getPrev() const { return Prev; }
   ilist_node_base *getNext() const { return Next; }
 
+  void setNodeBaseParent(void) {}
+  inline void getNodeBaseParent() const {}
+
   bool isKnownSentinel() const { return false; }
   void initializeSentinel() {}
 };
 
-template <> class ilist_node_base<true> {
+template <> class ilist_node_base<true, void> {
   PointerIntPair<ilist_node_base *, 1> PrevAndSentinel;
   ilist_node_base *Next = nullptr;
 
@@ -42,6 +45,48 @@ template <> class ilist_node_base<true> {
   ilist_node_base *getPrev() const { return PrevAndSentinel.getPointer(); }
   ilist_node_base *getNext() const { return Next; }
 
+  void setNodeBaseParent(void) {}
+  inline void getNodeBaseParent() const {}
+
+  bool isSentinel() const { return PrevAndSentinel.getInt(); }
+  bool isKnownSentinel() const { return isSentinel(); }
+  void initializeSentinel() { PrevAndSentinel.setInt(true); }
+};
+
+template <class ParentPtrTy> class ilist_node_base<false, ParentPtrTy> {
+  ilist_node_base *Prev = nullptr;
+  ilist_node_base *Next = nullptr;
+  ParentPtrTy Parent = nullptr;
+
+public:
+  void setPrev(ilist_node_base *Prev) { this->Prev = Prev; }
+  void setNext(ilist_node_base *Next) { this->Next = Next; }
+  ilist_node_base *getPrev() const { return Prev; }
+  ilist_node_base *getNext() const { return Next; }
+
+  void setNodeBaseParent(ParentPtrTy Parent) { this->Parent = Parent; }
+  inline const ParentPtrTy getNodeBaseParent() const { return Parent; }
+  inline ParentPtrTy getNodeBaseParent() { return Parent; }
+
+  bool isKnownSentinel() const { return false; }
+  void initializeSentinel() {}
+};
+
+template <class ParentPtrTy> class ilist_node_base<true, ParentPtrTy> {
+  PointerIntPair<ilist_node_base *, 1> PrevAndSentinel;
+  ilist_node_base *Next = nullptr;
+  ParentPtrTy Parent = nullptr;
+
+public:
+  void setPrev(ilist_node_base *Prev) { PrevAndSentinel.setPointer(Prev); }
+  void setNext(ilist_node_base *Next) { this->Next = Next; }
+  ilist_node_base *getPrev() const { return PrevAndSentinel.getPointer(); }
+  ilist_node_base *getNext() const { return Next; }
+
+  void setNodeBaseParent(ParentPtrTy Parent) { this->Parent = Parent; }
+  inline const ParentPtrTy getNodeBaseParent() const { return Parent; }
+  inline ParentPtrTy getNodeBaseParent() { return Parent; }
+
   bool isSentinel() const { return PrevAndSentinel.getInt(); }
   bool isKnownSentinel() const { return isSentinel(); }
   void initializeSentinel() { PrevAndSentinel.setInt(true); }
diff --git a/llvm/include/llvm/ADT/ilist_node_options.h b/llvm/include/llvm/ADT/ilist_node_options.h
index e6e1068953e36..aa32162cd51e4 100644
--- a/llvm/include/llvm/ADT/ilist_node_options.h
+++ b/llvm/include/llvm/ADT/ilist_node_options.h
@@ -15,8 +15,8 @@
 
 namespace llvm {
 
-template <bool EnableSentinelTracking> class ilist_node_base;
-template <bool EnableSentinelTracking> class ilist_base;
+template <bool EnableSentinelTracking, class ParentPtrTy> class ilist_node_base;
+template <bool EnableSentinelTracking, class ParentPtrTy> class ilist_base;
 
 /// Option to choose whether to track sentinels.
 ///
@@ -39,6 +39,19 @@ template <class Tag> struct ilist_tag {};
 /// iterator class to store that information.
 template <bool ExtraIteratorBits> struct ilist_iterator_bits {};
 
+/// Option to add a pointer to this list's owner in every node.
+///
+/// This option causes the \a ilist_base_node for this list to contain a pointer
+/// ParentTy *Parent, returned by \a ilist_base_node::getNodeBaseParent() and
+/// set by \a ilist_base_node::setNodeBaseParent(ParentTy *Parent). The parent
+/// value is not set automatically; the ilist owner should set itself as the
+/// parent of the list sentinel, and the parent should be set on each node
+/// inserted into the list. This value is also not used by
+/// \a ilist_node_with_parent::getNodeParent(), but is used by \a
+/// ilist_iterator::getNodeParent(), which allows the parent to be fetched from
+/// any valid (non-null) iterator to this list, including the sentinel.
+template <class ParentTy> struct ilist_parent {};
+
 namespace ilist_detail {
 
 /// Helper trait for recording whether an option is specified explicitly.
@@ -114,6 +127,21 @@ template <> struct extract_iterator_bits<> : std::false_type, is_implicit {};
 template <bool IteratorBits>
 struct is_valid_option<ilist_iterator_bits<IteratorBits>> : std::true_type {};
 
+/// Extract node parent option.
+///
+/// Look through \p Options for the \a ilist_parent option, pulling out the
+/// custom parent type, using void as a default.
+template <class... Options> struct extract_parent;
+template <class ParentTy, class... Options>
+struct extract_parent<ilist_parent<ParentTy>, Options...> {
+  typedef ParentTy *type;
+};
+template <class Option1, class... Options>
+struct extract_parent<Option1, Options...> : extract_parent<Options...> {};
+template <> struct extract_parent<> { typedef void type; };
+template <class ParentTy>
+struct is_valid_option<ilist_parent<ParentTy>> : std::true_type {};
+
 /// Check whether options are valid.
 ///
 /// The conjunction of \a is_valid_option on each individual option.
@@ -128,7 +156,7 @@ struct check_options<Option1, Options...>
 ///
 /// This is usually computed via \a compute_node_options.
 template <class T, bool EnableSentinelTracking, bool IsSentinelTrackingExplicit,
-          class TagT, bool HasIteratorBits>
+          class TagT, bool HasIteratorBits, class ParentPtrTy>
 struct node_options {
   typedef T value_type;
   typedef T *pointer;
@@ -140,15 +168,18 @@ struct node_options {
   static const bool is_sentinel_tracking_explicit = IsSentinelTrackingExplicit;
   static const bool has_iterator_bits = HasIteratorBits;
   typedef TagT tag;
-  typedef ilist_node_base<enable_sentinel_tracking> node_base_type;
-  typedef ilist_base<enable_sentinel_tracking> list_base_type;
+  typedef ParentPtrTy parent_ptr_ty;
+  typedef ilist_node_base<enable_sentinel_tracking, parent_ptr_ty>
+      node_base_type;
+  typedef ilist_base<enable_sentinel_tracking, parent_ptr_ty> list_base_type;
 };
 
 template <class T, class... Options> struct compute_node_options {
   typedef node_options<T, extract_sentinel_tracking<Options...>::value,
                        extract_sentinel_tracking<Options...>::is_explicit,
                        typename extract_tag<Options...>::type,
-                       extract_iterator_bits<Options...>::value>
+                       extract_iterator_bits<Options...>::value,
+                       typename extract_parent<Options...>::type>
       type;
 };
 
diff --git a/llvm/include/llvm/IR/BasicBlock.h b/llvm/include/llvm/IR/BasicBlock.h
index e1220966e7e6e..80067f2652a2b 100644
--- a/llvm/include/llvm/IR/BasicBlock.h
+++ b/llvm/include/llvm/IR/BasicBlock.h
@@ -59,7 +59,8 @@ class DbgMarker;
 class BasicBlock final : public Value, // Basic blocks are data objects also
                          public ilist_node_with_parent<BasicBlock, Function> {
 public:
-  using InstListType = SymbolTableList<Instruction, ilist_iterator_bits<true>>;
+  using InstListType = SymbolTableList<Instruction, ilist_iterator_bits<true>,
+                                       ilist_parent<BasicBlock>>;
   /// Flag recording whether or not this block stores debug-info in the form
   /// of intrinsic instructions (false) or non-instruction records (true).
   bool IsNewDbgInfoFormat;
@@ -172,10 +173,11 @@ class BasicBlock final : public Value, // Basic blocks are data objects also
   friend BasicBlock::iterator Instruction::eraseFromParent();
   friend BasicBlock::iterator Instruction::insertInto(BasicBlock *BB,
                                                       BasicBlock::iterator It);
-  friend class llvm::SymbolTableListTraits<llvm::Instruction,
-                                           ilist_iterator_bits<true>>;
+  friend class llvm::SymbolTableListTraits<
+      llvm::Instruction, ilist_iterator_bits<true>, ilist_parent<BasicBlock>>;
   friend class llvm::ilist_node_with_parent<llvm::Instruction, llvm::BasicBlock,
-                                            ilist_iterator_bits<true>>;
+                                            ilist_iterator_bits<true>,
+                                            ilist_parent<BasicBlock>>;
 
   // Friendly methods that need to access us for the maintenence of
   // debug-info attachments.
diff --git a/llvm/include/llvm/IR/Instruction.h b/llvm/include/llvm/IR/Instruction.h
index 249be2799fa93..e1cb362ad20d0 100644
--- a/llvm/include/llvm/IR/Instruction.h
+++ b/llvm/include/llvm/IR/Instruction.h
@@ -46,11 +46,13 @@ getDbgRecordRange(DbgMarker *);
 
 class Instruction : public User,
                     public ilist_node_with_parent<Instruction, BasicBlock,
-                                                  ilist_iterator_bits<true>> {
+                                                  ilist_iterator_bits<true>,
+                                                  ilist_parent<BasicBlock>> {
 public:
-  using InstListType = SymbolTableList<Instruction, ilist_iterator_bits<true>>;
+  using InstListType = SymbolTableList<Instruction, ilist_iterator_bits<true>,
+                                       ilist_parent<BasicBlock>>;
+
 private:
-  BasicBlock *Parent;
   DebugLoc DbgLoc;                         // 'dbg' Metadata cache.
 
   /// Relative order of this instruction in its parent basic block. Used for
@@ -149,8 +151,8 @@ class Instruction : public User,
   Instruction       *user_back()       { return cast<Instruction>(*user_begin());}
   const Instruction *user_back() const { return cast<Instruction>(*user_begin());}
 
-  inline const BasicBlock *getParent() const { return Parent; }
-  inline       BasicBlock *getParent()       { return Parent; }
+  inline const BasicBlock *getParent() const { return getNodeBaseParent(); }
+  inline BasicBlock *getParent() { return getNodeBaseParent(); }
 
   /// Return the module owning the function this instruction belongs to
   /// or nullptr it the function does not have a module.
@@ -980,7 +982,8 @@ class Instruction : public User,
   };
 
 private:
-  friend class SymbolTableListTraits<Instruction, ilist_iterator_bits<true>>;
+  friend class SymbolTableListTraits<Instruction, ilist_iterator_bits<true>,
+                                     ilist_parent<BasicBlock>>;
   friend class BasicBlock; // For renumbering.
 
   // Shadow Value::setValueSubclassData with a private forwarding method so that
diff --git a/llvm/include/llvm/IR/ValueSymbolTable.h b/llvm/include/llvm/IR/ValueSymbolTable.h
index 6350f6a2435e4..cd1dbbe1688a1 100644
--- a/llvm/include/llvm/IR/ValueSymbolTable.h
+++ b/llvm/include/llvm/IR/ValueSymbolTable.h
@@ -28,6 +28,7 @@ class GlobalIFunc;
 class GlobalVariable;
 class Instruction;
 template <bool ExtraIteratorBits> struct ilist_iterator_bits;
+template <class ParentTy> struct ilist_parent;
 template <unsigned InternalLen> class SmallString;
 template <typename ValueSubClass, typename ... Args> class SymbolTableListTraits;
 
@@ -42,7 +43,8 @@ class ValueSymbolTable {
   friend class SymbolTableListTraits<GlobalAlias>;
   friend class SymbolTableListTraits<GlobalIFunc>;
   friend class SymbolTableListTraits<GlobalVariable>;
-  friend class SymbolTableListTraits<Instruction, ilist_iterator_bits<true>>;
+  friend class SymbolTableListTraits<Instruction, ilist_iterator_bits<true>,
+                                     ilist_parent<BasicBlock>>;
   friend class Value;
 
 /// @name Types
diff --git a/llvm/lib/IR/BasicBlock.cpp b/llvm/lib/IR/BasicBlock.cpp
index 29f2cbf611fa3..a5199f36c1cb5 100644
--- a/llvm/lib/IR/BasicBlock.cpp
+++ b/llvm/lib/IR/BasicBlock.cpp
@@ -175,8 +175,8 @@ template <> void llvm::invalidateParentIListOrdering(BasicBlock *BB) {
 
 // Explicit instantiation of SymbolTableListTraits since some of the methods
 // are not in the public header file...
-template class llvm::SymbolTableListTraits<Instruction,
-                                           ilist_iterator_bits<true>>;
+template class llvm::SymbolTableListTraits<
+    Instruction, ilist_iterator_bits<true>, ilist_parent<BasicBlock>>;
 
 BasicBlock::BasicBlock(LLVMContext &C, const Twine &Name, Function *NewParent,
                        BasicBlock *InsertBefore)
@@ -189,6 +189,7 @@ BasicBlock::BasicBlock(LLVMContext &C, const Twine &Name, Function *NewParent,
     assert(!InsertBefore &&
            "Cannot insert block before another block with no function!");
 
+  end().getNodePtr()->setNodeBaseParent(this);
   setName(Name);
   if (NewParent)
     setIsNewDbgInfoFormat(NewParent->IsNewDbgInfoFormat);
diff --git a/llvm/lib/IR/Instruction.cpp b/llvm/lib/IR/Instruction.cpp
index 29272e627a1d1..8e8131113a230 100644
--- a/llvm/lib/IR/Instruction.cpp
+++ b/llvm/lib/IR/Instruction.cpp
@@ -27,8 +27,7 @@ using namespace llvm;
 
 Instruction::Instruction(Type *ty, unsigned it, Use *Ops, unsigned NumOps,
                          InstListType::iterator InsertBefore)
-    : User(ty, Value::InstructionVal + it, Ops, NumOps), Parent(nullptr) {
-
+    : User(ty, Value::InstructionVal + it, Ops, NumOps) {
   // When called with an iterator, there must be a block to insert into.
   BasicBlock *BB = InsertBefore->getParent();
   assert(BB && "Instruction to insert before is not in a basic block!");
@@ -37,7 +36,7 @@ Instruction::Instruction(Type *ty, unsigned it, Use *Ops, unsigned NumOps,
 
 Instruction::Instruction(Type *ty, unsigned it, Use *Ops, unsigned NumOps,
                          Instruction *InsertBefore)
-  : User(ty, Value::InstructionVal + it, Ops, NumOps), Parent(nullptr) {
+    : User(ty, Value::InstructionVal + it, Ops, NumOps) {
 
   // If requested, insert this instruction into a basic block...
   if (InsertBefore) {
@@ -49,15 +48,14 @@ Instruction::Instruction(Type *ty, unsigned it, Use *Ops, unsigned NumOps,
 
 Instruction::Instruction(Type *ty, unsigned it, Use *Ops, unsigned NumOps,
                          BasicBlock *InsertAtEnd)
-    : User(ty, Value::InstructionVal + it, Ops, NumOps), Parent(nullptr) {
-
+    : User(ty, Value::InstructionVal + it, Ops, NumOps) {
   // If requested, append this instruction into the basic block.
   if (InsertAtEnd)
     insertInto(InsertAtEnd, InsertAtEnd->end());
 }
 
 Instruction::~Instruction() {
-  assert(!Parent && "Instruction still linked in the program!");
+  assert(!getParent() && "Instruction still linked in the program!");
 
   // Replace any extant metadata uses of this instruction with undef to
   // preserve debug info accuracy. Some alternatives include:
@@ -76,9 +74,7 @@ Instruction::~Instruction() {
   setMetadata(LLVMContext::MD_DIAssignID, nullptr);
 }
 
-void Instruction::setParent(BasicBlock *P) {
-  Parent = P;
-}
+void Instruction::setParent(BasicBlock *P) { setNodeBaseParent(P); }
 
 const Module *Instruction::getModule() const {
   return getParent()->getModule();
@@ -96,7 +92,7 @@ void Instruction::removeFromParent() {
 }
 
 void Instruction::handleMarkerRemoval() {
-  if (!Parent->IsNewDbgInfoFormat || !DebugMarker)
+  if (!getParent()->IsNewDbgInfoFormat || !DebugMarker)
     return;
 
   DebugMarker->removeMarker();
@@ -329,11 +325,12 @@ void Instruction::dropOneDbgRecord(DbgRecord *DVR) {
 }
 
 bool Instruction::comesBefore(const Instruction *Other) const {
-  assert(Parent && Other->Parent &&
+  assert(getParent() && Other->getParent() &&
          "instructions without BB parents have no order");
-  assert(Parent == Other->Parent && "cross-BB instruction order comparison");
-  if (!Parent->isInstrOrderValid())
-    Parent->renumberInstructions();
+  assert(getParent() == Other->getParent() &&
+         "cross-BB instruction order comparison");
+  if (!getParent()->isInstrOrderValid())
+    const_cast<BasicBlock *>(getParent())->renumberInstructions();
   return Order < Other->Order;
 }
 

>From d89ff98bd1be09c4eecce2c330e168bf2007f814 Mon Sep 17 00:00:00 2001
From: Stephen Tozer <stephen.tozer at sony.com>
Date: Mon, 3 Jun 2024 18:24:14 +0100
Subject: [PATCH 2/5] Add mixins to detail namespaces, add comments

---
 llvm/include/llvm/ADT/ilist_iterator.h  | 31 +++++++++-
 llvm/include/llvm/ADT/ilist_node.h      | 44 ++++++++++---
 llvm/include/llvm/ADT/ilist_node_base.h | 82 +++++++++----------------
 llvm/include/llvm/IR/Instruction.h      |  5 --
 llvm/lib/IR/BasicBlock.cpp              |  2 +-
 llvm/lib/IR/Instruction.cpp             |  2 -
 6 files changed, 93 insertions(+), 73 deletions(-)

diff --git a/llvm/include/llvm/ADT/ilist_iterator.h b/llvm/include/llvm/ADT/ilist_iterator.h
index 635e050e0d09a..5f27dd2f3f447 100644
--- a/llvm/include/llvm/ADT/ilist_iterator.h
+++ b/llvm/include/llvm/ADT/ilist_iterator.h
@@ -50,11 +50,38 @@ template <> struct IteratorHelper<true> : ilist_detail::NodeAccess {
   template <class T> static void decrement(T *&I) { I = Access::getNext(*I); }
 };
 
+/// Mixin class used to add a \a getNodeParent() function to iterators iff the
+/// list uses \a ilist_parent, calling through to the node's \a getParent(). For
+/// more details see \a ilist_node.
+template <class IteratorTy, class ParentPtrTy, bool IsConst>
+class iterator_parent_access;
+template <class IteratorTy, class ParentPtrTy>
+class iterator_parent_access<IteratorTy, ParentPtrTy, true> {
+public:
+  inline const ParentPtrTy getNodeParent() const {
+    return static_cast<IteratorTy *>(this)->NodePtr->getParent();
+  }
+};
+template <class IteratorTy, class ParentPtrTy>
+class iterator_parent_access<IteratorTy, ParentPtrTy, false> {
+public:
+  inline ParentPtrTy getNodeParent() {
+    return static_cast<IteratorTy *>(this)->NodePtr->getParent();
+  }
+};
+template <class IteratorTy>
+class iterator_parent_access<IteratorTy, void, true> {};
+template <class IteratorTy>
+class iterator_parent_access<IteratorTy, void, false> {};
+
 } // end namespace ilist_detail
 
 /// Iterator for intrusive lists  based on ilist_node.
 template <class OptionsT, bool IsReverse, bool IsConst>
-class ilist_iterator : ilist_detail::SpecificNodeAccess<OptionsT> {
+class ilist_iterator : ilist_detail::SpecificNodeAccess<OptionsT>,
+                       public ilist_detail::iterator_parent_access<
+                           ilist_iterator<OptionsT, IsReverse, IsConst>,
+                           typename OptionsT::parent_ptr_ty, IsConst> {
   friend ilist_iterator<OptionsT, IsReverse, !IsConst>;
   friend ilist_iterator<OptionsT, !IsReverse, IsConst>;
   friend ilist_iterator<OptionsT, !IsReverse, !IsConst>;
@@ -102,8 +129,6 @@ class ilist_iterator : ilist_detail::SpecificNodeAccess<OptionsT> {
     return *this;
   }
 
-  parent_ptr_ty getNodeParent() { return NodePtr->getNodeBaseParent(); }
-
   /// Explicit conversion between forward/reverse iterators.
   ///
   /// Translate between forward and reverse iterators without changing range
diff --git a/llvm/include/llvm/ADT/ilist_node.h b/llvm/include/llvm/ADT/ilist_node.h
index ec615497abee1..209fd209167e8 100644
--- a/llvm/include/llvm/ADT/ilist_node.h
+++ b/llvm/include/llvm/ADT/ilist_node.h
@@ -24,6 +24,23 @@ namespace ilist_detail {
 
 struct NodeAccess;
 
+/// Mixin base class that is used to add \a getParent() and
+/// \a setParent(ParentPtrTy) methods to \a ilist_node_impl iff \a ilist_parent
+/// has been set in the list options.
+template <class NodeTy, class ParentPtrTy> class node_parent_access {
+public:
+  inline const ParentPtrTy getParent() const {
+    return static_cast<const NodeTy *>(this)->getNodeBaseParent();
+  }
+  inline ParentPtrTy getParent() {
+    return static_cast<NodeTy *>(this)->getNodeBaseParent();
+  }
+  void setParent(ParentPtrTy Parent) {
+    return static_cast<NodeTy *>(this)->setNodeBaseParent(Parent);
+  }
+};
+template <class NodeTy> class node_parent_access<NodeTy, void> {};
+
 } // end namespace ilist_detail
 
 template <class OptionsT, bool IsReverse, bool IsConst> class ilist_iterator;
@@ -51,7 +68,11 @@ class ilist_select_iterator_type<true, Opts, arg1, arg2> {
 /// This is a wrapper around \a ilist_node_base whose main purpose is to
 /// provide type safety: you can't insert nodes of \a ilist_node_impl into the
 /// wrong \a simple_ilist or \a iplist.
-template <class OptionsT> class ilist_node_impl : OptionsT::node_base_type {
+template <class OptionsT>
+class ilist_node_impl
+    : OptionsT::node_base_type,
+      public ilist_detail::node_parent_access<
+          ilist_node_impl<OptionsT>, typename OptionsT::parent_ptr_ty> {
   using value_type = typename OptionsT::value_type;
   using node_base_type = typename OptionsT::node_base_type;
   using list_base_type = typename OptionsT::list_base_type;
@@ -60,6 +81,8 @@ template <class OptionsT> class ilist_node_impl : OptionsT::node_base_type {
   friend struct ilist_detail::NodeAccess;
   friend class ilist_sentinel<OptionsT>;
 
+  friend class ilist_detail::node_parent_access<
+      ilist_node_impl<OptionsT>, typename OptionsT::parent_ptr_ty>;
   friend class ilist_iterator<OptionsT, false, false>;
   friend class ilist_iterator<OptionsT, false, true>;
   friend class ilist_iterator<OptionsT, true, false>;
@@ -118,9 +141,7 @@ template <class OptionsT> class ilist_node_impl : OptionsT::node_base_type {
   }
 
   // Under-approximation, but always available for assertions.
-  using node_base_type::getNodeBaseParent;
   using node_base_type::isKnownSentinel;
-  using node_base_type::setNodeBaseParent;
 
   /// Check whether this is the sentinel node.
   ///
@@ -174,13 +195,18 @@ template <class OptionsT> class ilist_node_impl : OptionsT::node_base_type {
 /// \endexample
 ///
 /// When the \a ilist_parent<ParentTy> option is passed to an ilist_node and the
-/// owning ilist, each node contains a pointer to the ilist's owner. This
-/// pointer does not have any automatic behaviour; set it manually, including
-/// for the sentinel node when the list is created. The primary benefit of this
-/// over declaring and using this pointer in the final node class is that the
-/// pointer will be added in the sentinel, meaning that you can safely use \a
+/// owning ilist, each node contains a pointer to the ilist's owner. This adds
+/// \a getParent() and \a setParent(ParentTy*) methods to the ilist_node, which
+/// will be used for node access by the ilist if the node class publicly
+/// inherits from \a ilist_node_with_parent. By default, setParent() is not
+/// automatically called by the ilist; a SymbolTableList will call setParent()
+/// on inserted nodes, but the sentinel must still be manually set after the
+/// list is created (e.g. SymTabList.end()->setParent(Parent)).
+///
+/// The primary benefit of using ilist_parent is that a parent
+/// pointer will be stored in the sentinel, meaning that you can safely use \a
 /// ilist_iterator::getNodeParent() to get the node parent from any valid (i.e.
-/// non-null) iterator, even a sentinel value.
+/// non-null) iterator, even one that points to a sentinel value.
 ///
 /// See \a is_valid_option for steps on adding a new option.
 template <class T, class... Options>
diff --git a/llvm/include/llvm/ADT/ilist_node_base.h b/llvm/include/llvm/ADT/ilist_node_base.h
index e396bb22fca02..caad87cdd4d71 100644
--- a/llvm/include/llvm/ADT/ilist_node_base.h
+++ b/llvm/include/llvm/ADT/ilist_node_base.h
@@ -13,84 +13,60 @@
 
 namespace llvm {
 
-/// Base class for ilist nodes.
-///
-/// Optionally tracks whether this node is the sentinel.
-template <bool EnableSentinelTracking, class ParentPtrTy> class ilist_node_base;
+namespace ilist_detail {
 
-template <> class ilist_node_base<false, void> {
-  ilist_node_base *Prev = nullptr;
-  ilist_node_base *Next = nullptr;
+template <class NodeBase, bool EnableSentinelTracking> class node_base_prevnext;
 
-public:
-  void setPrev(ilist_node_base *Prev) { this->Prev = Prev; }
-  void setNext(ilist_node_base *Next) { this->Next = Next; }
-  ilist_node_base *getPrev() const { return Prev; }
-  ilist_node_base *getNext() const { return Next; }
+template <class NodeBase> class node_base_prevnext<NodeBase, false> {
+  NodeBase *Prev = nullptr;
+  NodeBase *Next = nullptr;
 
-  void setNodeBaseParent(void) {}
-  inline void getNodeBaseParent() const {}
+public:
+  void setPrev(NodeBase *Prev) { this->Prev = Prev; }
+  void setNext(NodeBase *Next) { this->Next = Next; }
+  NodeBase *getPrev() const { return Prev; }
+  NodeBase *getNext() const { return Next; }
 
   bool isKnownSentinel() const { return false; }
   void initializeSentinel() {}
 };
 
-template <> class ilist_node_base<true, void> {
-  PointerIntPair<ilist_node_base *, 1> PrevAndSentinel;
-  ilist_node_base *Next = nullptr;
+template <class NodeBase> class node_base_prevnext<NodeBase, true> {
+  PointerIntPair<NodeBase *, 1> PrevAndSentinel;
+  NodeBase *Next = nullptr;
 
 public:
-  void setPrev(ilist_node_base *Prev) { PrevAndSentinel.setPointer(Prev); }
-  void setNext(ilist_node_base *Next) { this->Next = Next; }
-  ilist_node_base *getPrev() const { return PrevAndSentinel.getPointer(); }
-  ilist_node_base *getNext() const { return Next; }
-
-  void setNodeBaseParent(void) {}
-  inline void getNodeBaseParent() const {}
+  void setPrev(NodeBase *Prev) { PrevAndSentinel.setPointer(Prev); }
+  void setNext(NodeBase *Next) { this->Next = Next; }
+  NodeBase *getPrev() const { return PrevAndSentinel.getPointer(); }
+  NodeBase *getNext() const { return Next; }
 
   bool isSentinel() const { return PrevAndSentinel.getInt(); }
   bool isKnownSentinel() const { return isSentinel(); }
   void initializeSentinel() { PrevAndSentinel.setInt(true); }
 };
 
-template <class ParentPtrTy> class ilist_node_base<false, ParentPtrTy> {
-  ilist_node_base *Prev = nullptr;
-  ilist_node_base *Next = nullptr;
+template <class ParentPtrTy> class node_base_parent {
   ParentPtrTy Parent = nullptr;
 
 public:
-  void setPrev(ilist_node_base *Prev) { this->Prev = Prev; }
-  void setNext(ilist_node_base *Next) { this->Next = Next; }
-  ilist_node_base *getPrev() const { return Prev; }
-  ilist_node_base *getNext() const { return Next; }
-
   void setNodeBaseParent(ParentPtrTy Parent) { this->Parent = Parent; }
   inline const ParentPtrTy getNodeBaseParent() const { return Parent; }
   inline ParentPtrTy getNodeBaseParent() { return Parent; }
-
-  bool isKnownSentinel() const { return false; }
-  void initializeSentinel() {}
 };
+template <> class node_base_parent<void> {};
 
-template <class ParentPtrTy> class ilist_node_base<true, ParentPtrTy> {
-  PointerIntPair<ilist_node_base *, 1> PrevAndSentinel;
-  ilist_node_base *Next = nullptr;
-  ParentPtrTy Parent = nullptr;
-
-public:
-  void setPrev(ilist_node_base *Prev) { PrevAndSentinel.setPointer(Prev); }
-  void setNext(ilist_node_base *Next) { this->Next = Next; }
-  ilist_node_base *getPrev() const { return PrevAndSentinel.getPointer(); }
-  ilist_node_base *getNext() const { return Next; }
-
-  void setNodeBaseParent(ParentPtrTy Parent) { this->Parent = Parent; }
-  inline const ParentPtrTy getNodeBaseParent() const { return Parent; }
-  inline ParentPtrTy getNodeBaseParent() { return Parent; }
+} // end namespace ilist_detail
 
-  bool isSentinel() const { return PrevAndSentinel.getInt(); }
-  bool isKnownSentinel() const { return isSentinel(); }
-  void initializeSentinel() { PrevAndSentinel.setInt(true); }
-};
+/// Base class for ilist nodes.
+///
+/// Optionally tracks whether this node is the sentinel.
+template <bool EnableSentinelTracking, class ParentPtrTy>
+class ilist_node_base
+    : public ilist_detail::node_base_prevnext<
+          ilist_node_base<EnableSentinelTracking, ParentPtrTy>,
+          EnableSentinelTracking>,
+      public ilist_detail::node_base_parent<ParentPtrTy> {};
 
 } // end namespace llvm
 
diff --git a/llvm/include/llvm/IR/Instruction.h b/llvm/include/llvm/IR/Instruction.h
index e1cb362ad20d0..0b636fc7ceaa3 100644
--- a/llvm/include/llvm/IR/Instruction.h
+++ b/llvm/include/llvm/IR/Instruction.h
@@ -151,9 +151,6 @@ class Instruction : public User,
   Instruction       *user_back()       { return cast<Instruction>(*user_begin());}
   const Instruction *user_back() const { return cast<Instruction>(*user_begin());}
 
-  inline const BasicBlock *getParent() const { return getNodeBaseParent(); }
-  inline BasicBlock *getParent() { return getNodeBaseParent(); }
-
   /// Return the module owning the function this instruction belongs to
   /// or nullptr it the function does not have a module.
   ///
@@ -996,8 +993,6 @@ class Instruction : public User,
     return Value::getSubclassDataFromValue();
   }
 
-  void setParent(BasicBlock *P);
-
 protected:
   // Instruction subclasses can stick up to 15 bits of stuff into the
   // SubclassData field of instruction with these members.
diff --git a/llvm/lib/IR/BasicBlock.cpp b/llvm/lib/IR/BasicBlock.cpp
index a5199f36c1cb5..b0caa97ed3918 100644
--- a/llvm/lib/IR/BasicBlock.cpp
+++ b/llvm/lib/IR/BasicBlock.cpp
@@ -189,7 +189,7 @@ BasicBlock::BasicBlock(LLVMContext &C, const Twine &Name, Function *NewParent,
     assert(!InsertBefore &&
            "Cannot insert block before another block with no function!");
 
-  end().getNodePtr()->setNodeBaseParent(this);
+  end().getNodePtr()->setParent(this);
   setName(Name);
   if (NewParent)
     setIsNewDbgInfoFormat(NewParent->IsNewDbgInfoFormat);
diff --git a/llvm/lib/IR/Instruction.cpp b/llvm/lib/IR/Instruction.cpp
index 8e8131113a230..a5d95de033418 100644
--- a/llvm/lib/IR/Instruction.cpp
+++ b/llvm/lib/IR/Instruction.cpp
@@ -74,8 +74,6 @@ Instruction::~Instruction() {
   setMetadata(LLVMContext::MD_DIAssignID, nullptr);
 }
 
-void Instruction::setParent(BasicBlock *P) { setNodeBaseParent(P); }
-
 const Module *Instruction::getModule() const {
   return getParent()->getModule();
 }

>From 7150d6125c222b03fb04848cf00bab959c59d8ba Mon Sep 17 00:00:00 2001
From: Stephen Tozer <stephen.tozer at sony.com>
Date: Tue, 4 Jun 2024 13:24:30 +0100
Subject: [PATCH 3/5] Update ilist_iterator_w_bits, missed it last commit

---
 llvm/include/llvm/ADT/ilist_iterator.h | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/llvm/include/llvm/ADT/ilist_iterator.h b/llvm/include/llvm/ADT/ilist_iterator.h
index 5f27dd2f3f447..6e591d306eac6 100644
--- a/llvm/include/llvm/ADT/ilist_iterator.h
+++ b/llvm/include/llvm/ADT/ilist_iterator.h
@@ -97,7 +97,6 @@ class ilist_iterator : ilist_detail::SpecificNodeAccess<OptionsT>,
   using iterator_category = std::bidirectional_iterator_tag;
   using const_pointer = typename OptionsT::const_pointer;
   using const_reference = typename OptionsT::const_reference;
-  using parent_ptr_ty = typename OptionsT::parent_ptr_ty;
 
 private:
   using node_pointer = typename Traits::node_pointer;
@@ -209,7 +208,11 @@ class ilist_iterator : ilist_detail::SpecificNodeAccess<OptionsT>,
 /// but with the addition of two bits recording whether this position (when in
 /// a range) is half or fully open.
 template <class OptionsT, bool IsReverse, bool IsConst>
-class ilist_iterator_w_bits : ilist_detail::SpecificNodeAccess<OptionsT> {
+class ilist_iterator_w_bits
+    : ilist_detail::SpecificNodeAccess<OptionsT>,
+      public ilist_detail::iterator_parent_access<
+          ilist_iterator_w_bits<OptionsT, IsReverse, IsConst>,
+          typename OptionsT::parent_ptr_ty, IsConst> {
   friend ilist_iterator_w_bits<OptionsT, IsReverse, !IsConst>;
   friend ilist_iterator_w_bits<OptionsT, !IsReverse, IsConst>;
   friend ilist_iterator<OptionsT, !IsReverse, !IsConst>;
@@ -225,7 +228,6 @@ class ilist_iterator_w_bits : ilist_detail::SpecificNodeAccess<OptionsT> {
   using iterator_category = std::bidirectional_iterator_tag;
   using const_pointer = typename OptionsT::const_pointer;
   using const_reference = typename OptionsT::const_reference;
-  using parent_ptr_ty = typename OptionsT::parent_ptr_ty;
 
 private:
   using node_pointer = typename Traits::node_pointer;
@@ -350,8 +352,6 @@ class ilist_iterator_w_bits : ilist_detail::SpecificNodeAccess<OptionsT> {
     return tmp;
   }
 
-  parent_ptr_ty getNodeParent() { return NodePtr->getNodeBaseParent(); }
-
   bool isValid() const { return NodePtr; }
 
   /// Get the underlying ilist_node.

>From 18cf52b4d4f580d8919e4cf0fe5497452282f876 Mon Sep 17 00:00:00 2001
From: Stephen Tozer <stephen.tozer at sony.com>
Date: Tue, 4 Jun 2024 14:13:40 +0100
Subject: [PATCH 4/5] Fix iterator_parent_access invalid private access

---
 llvm/include/llvm/ADT/ilist_iterator.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/llvm/include/llvm/ADT/ilist_iterator.h b/llvm/include/llvm/ADT/ilist_iterator.h
index 6e591d306eac6..16a45b5beac50 100644
--- a/llvm/include/llvm/ADT/ilist_iterator.h
+++ b/llvm/include/llvm/ADT/ilist_iterator.h
@@ -85,6 +85,9 @@ class ilist_iterator : ilist_detail::SpecificNodeAccess<OptionsT>,
   friend ilist_iterator<OptionsT, IsReverse, !IsConst>;
   friend ilist_iterator<OptionsT, !IsReverse, IsConst>;
   friend ilist_iterator<OptionsT, !IsReverse, !IsConst>;
+  friend ilist_detail::iterator_parent_access<
+                           ilist_iterator<OptionsT, IsReverse, IsConst>,
+                           typename OptionsT::parent_ptr_ty, IsConst>;
 
   using Traits = ilist_detail::IteratorTraits<OptionsT, IsConst>;
   using Access = ilist_detail::SpecificNodeAccess<OptionsT>;
@@ -216,6 +219,9 @@ class ilist_iterator_w_bits
   friend ilist_iterator_w_bits<OptionsT, IsReverse, !IsConst>;
   friend ilist_iterator_w_bits<OptionsT, !IsReverse, IsConst>;
   friend ilist_iterator<OptionsT, !IsReverse, !IsConst>;
+  friend ilist_detail::iterator_parent_access<
+                           ilist_iterator_w_bits<OptionsT, IsReverse, IsConst>,
+                           typename OptionsT::parent_ptr_ty, IsConst>;
 
   using Traits = ilist_detail::IteratorTraits<OptionsT, IsConst>;
   using Access = ilist_detail::SpecificNodeAccess<OptionsT>;

>From f385c48bda55b261ac8ae0fe7f1f9724d8bc54d2 Mon Sep 17 00:00:00 2001
From: Stephen Tozer <stephen.tozer at sony.com>
Date: Tue, 18 Jun 2024 12:05:30 +0100
Subject: [PATCH 5/5] Update unittests!

---
 llvm/unittests/ADT/IListBaseTest.cpp     |  4 +-
 llvm/unittests/ADT/IListNodeBaseTest.cpp | 98 +++++++++++++++++++++++-
 2 files changed, 99 insertions(+), 3 deletions(-)

diff --git a/llvm/unittests/ADT/IListBaseTest.cpp b/llvm/unittests/ADT/IListBaseTest.cpp
index 1c55eac5c5312..bd915688b190d 100644
--- a/llvm/unittests/ADT/IListBaseTest.cpp
+++ b/llvm/unittests/ADT/IListBaseTest.cpp
@@ -16,8 +16,10 @@ namespace {
 // Test fixture.
 template <typename T> class IListBaseTest : public ::testing::Test {};
 
+class Parent;
+
 // Test variants with the same test.
-typedef ::testing::Types<ilist_base<false>, ilist_base<true>>
+typedef ::testing::Types<ilist_base<false, void>, ilist_base<true, void>, ilist_base<false, Parent*>, ilist_base<true, Parent*>>
     IListBaseTestTypes;
 TYPED_TEST_SUITE(IListBaseTest, IListBaseTestTypes, );
 
diff --git a/llvm/unittests/ADT/IListNodeBaseTest.cpp b/llvm/unittests/ADT/IListNodeBaseTest.cpp
index 65f85fc3a237e..07f397d2ef0fe 100644
--- a/llvm/unittests/ADT/IListNodeBaseTest.cpp
+++ b/llvm/unittests/ADT/IListNodeBaseTest.cpp
@@ -13,8 +13,12 @@ using namespace llvm;
 
 namespace {
 
-typedef ilist_node_base<false> RawNode;
-typedef ilist_node_base<true> TrackingNode;
+class Parent {};
+
+typedef ilist_node_base<false, void> RawNode;
+typedef ilist_node_base<true, void> TrackingNode;
+typedef ilist_node_base<false, Parent*> ParentNode;
+typedef ilist_node_base<true, Parent*> ParentTrackingNode;
 
 TEST(IListNodeBaseTest, DefaultConstructor) {
   RawNode A;
@@ -27,6 +31,19 @@ TEST(IListNodeBaseTest, DefaultConstructor) {
   EXPECT_EQ(nullptr, TA.getNext());
   EXPECT_FALSE(TA.isKnownSentinel());
   EXPECT_FALSE(TA.isSentinel());
+
+  ParentNode PA;
+  EXPECT_EQ(nullptr, PA.getPrev());
+  EXPECT_EQ(nullptr, PA.getNext());
+  EXPECT_EQ(nullptr, PA.getNodeBaseParent());
+  EXPECT_FALSE(PA.isKnownSentinel());
+
+  ParentTrackingNode PTA;
+  EXPECT_EQ(nullptr, PTA.getPrev());
+  EXPECT_EQ(nullptr, PTA.getNext());
+  EXPECT_EQ(nullptr, PTA.getNodeBaseParent());
+  EXPECT_FALSE(PTA.isKnownSentinel());
+  EXPECT_FALSE(PTA.isSentinel());
 }
 
 TEST(IListNodeBaseTest, setPrevAndNext) {
@@ -63,6 +80,41 @@ TEST(IListNodeBaseTest, setPrevAndNext) {
   EXPECT_EQ(nullptr, TB.getNext());
   EXPECT_EQ(nullptr, TC.getPrev());
   EXPECT_EQ(nullptr, TC.getNext());
+
+  ParentNode PA, PB, PC;
+  PA.setPrev(&PB);
+  EXPECT_EQ(&PB, PA.getPrev());
+  EXPECT_EQ(nullptr, PA.getNext());
+  EXPECT_EQ(nullptr, PB.getPrev());
+  EXPECT_EQ(nullptr, PB.getNext());
+  EXPECT_EQ(nullptr, PC.getPrev());
+  EXPECT_EQ(nullptr, PC.getNext());
+
+  PA.setNext(&PC);
+  EXPECT_EQ(&PB, PA.getPrev());
+  EXPECT_EQ(&PC, PA.getNext());
+  EXPECT_EQ(nullptr, PB.getPrev());
+  EXPECT_EQ(nullptr, PB.getNext());
+  EXPECT_EQ(nullptr, PC.getPrev());
+  EXPECT_EQ(nullptr, PC.getNext());
+
+  ParentTrackingNode PTA, PTB, PTC;
+  PTA.setPrev(&PTB);
+  EXPECT_EQ(&PTB, PTA.getPrev());
+  EXPECT_EQ(nullptr, PTA.getNext());
+  EXPECT_EQ(nullptr, PTB.getPrev());
+  EXPECT_EQ(nullptr, PTB.getNext());
+  EXPECT_EQ(nullptr, PTC.getPrev());
+  EXPECT_EQ(nullptr, PTC.getNext());
+
+  PTA.setNext(&PTC);
+  EXPECT_EQ(&PTB, PTA.getPrev());
+  EXPECT_EQ(&PTC, PTA.getNext());
+  EXPECT_EQ(nullptr, PTB.getPrev());
+  EXPECT_EQ(nullptr, PTB.getNext());
+  EXPECT_EQ(nullptr, PTC.getPrev());
+  EXPECT_EQ(nullptr, PTC.getNext());
+
 }
 
 TEST(IListNodeBaseTest, isKnownSentinel) {
@@ -94,6 +146,48 @@ TEST(IListNodeBaseTest, isKnownSentinel) {
   EXPECT_TRUE(TA.isSentinel());
   EXPECT_EQ(&TB, TA.getPrev());
   EXPECT_EQ(&TB, TA.getNext());
+
+  // Without sentinel tracking (with Parent).
+  ParentNode PA, PB;
+  EXPECT_FALSE(PA.isKnownSentinel());
+  PA.setPrev(&PB);
+  PA.setNext(&PB);
+  EXPECT_EQ(&PB, PA.getPrev());
+  EXPECT_EQ(&PB, PA.getNext());
+  EXPECT_FALSE(PA.isKnownSentinel());
+  PA.initializeSentinel();
+  EXPECT_FALSE(PA.isKnownSentinel());
+  EXPECT_EQ(&PB, PA.getPrev());
+  EXPECT_EQ(&PB, PA.getNext());
+
+  // With sentinel tracking (with Parent).
+  ParentTrackingNode PTA, PTB;
+  EXPECT_FALSE(PTA.isKnownSentinel());
+  EXPECT_FALSE(PTA.isSentinel());
+  PTA.setPrev(&PTB);
+  PTA.setNext(&PTB);
+  EXPECT_EQ(&PTB, PTA.getPrev());
+  EXPECT_EQ(&PTB, PTA.getNext());
+  EXPECT_FALSE(PTA.isKnownSentinel());
+  EXPECT_FALSE(PTA.isSentinel());
+  PTA.initializeSentinel();
+  EXPECT_TRUE(PTA.isKnownSentinel());
+  EXPECT_TRUE(PTA.isSentinel());
+  EXPECT_EQ(&PTB, PTA.getPrev());
+  EXPECT_EQ(&PTB, PTA.getNext());
+}
+
+TEST(IListNodeBaseTest, setNodeBaseParent) {
+  Parent Par;
+  ParentNode PA;
+  EXPECT_EQ(nullptr, PA.getNodeBaseParent());
+  PA.setNodeBaseParent(&Par);
+  EXPECT_EQ(&Par, PA.getNodeBaseParent());
+
+  ParentTrackingNode PTA;
+  EXPECT_EQ(nullptr, PTA.getNodeBaseParent());
+  PTA.setNodeBaseParent(&Par);
+  EXPECT_EQ(&Par, PTA.getNodeBaseParent());
 }
 
 } // end namespace



More information about the llvm-commits mailing list