[llvm] r281167 - ADT: Add sentinel tracking and custom tags to ilists

Duncan P. N. Exon Smith via llvm-commits llvm-commits at lists.llvm.org
Sun Sep 11 09:20:53 PDT 2016


Author: dexonsmith
Date: Sun Sep 11 11:20:53 2016
New Revision: 281167

URL: http://llvm.org/viewvc/llvm-project?rev=281167&view=rev
Log:
ADT: Add sentinel tracking and custom tags to ilists

This adds two declarative configuration options for intrusive lists
(available for simple_ilist, iplist, and ilist).  Both of these options
affect ilist_node interoperability and need to be passed both to the
node and the list.  Instead of adding a new traits class, they're
specified as optional template parameters (in any order).

The two options:

 1. Pass ilist_sentinel_tracking<true> or ilist_sentinel_tracking<false>
    to control whether there's a bit on ilist_node "prev" pointer
    indicating whether it's the sentinel.  The default behaviour is to
    use a bit if and only if LLVM_ENABLE_ABI_BREAKING_CHECKS.

 2. Pass ilist_tag<TagA> and ilist_tag<TagB> to allow insertion of a
    single node into two different lists (simultaneously).

I have an immediate use-case for (1) ilist_sentinel_tracking: fixing the
validation semantics of MachineBasicBlock::reverse_iterator to match
ilist::reverse_iterator (ala r280032: see the comments at the end of the
commit message there).  I'm adding (2) ilist_tag in the same commit to
validate that the options framework supports expansion.  Justin Bogner
mentioned this might enable a possible cleanup in SelectionDAG, but I'll
leave this to others to explore.  In the meantime, the unit tests and
the comments for simple_ilist and ilist_node have usage examples.

Note that there's a layer of indirection to support optional,
out-of-order, template paramaters.  Internal classes are templated on an
instantiation of the non-variadic ilist_detail::node_options.
User-facing classes use ilist_detail::compute_node_options to compute
the correct instantiation of ilist_detail::node_options.

The comments for ilist_detail::is_valid_option describe how to add new
options (e.g., ilist_packed_int<int NumBits>).

Added:
    llvm/trunk/include/llvm/ADT/ilist_node_options.h
    llvm/trunk/unittests/ADT/IListNodeTest.cpp
Modified:
    llvm/trunk/include/llvm/ADT/ilist.h
    llvm/trunk/include/llvm/ADT/ilist_base.h
    llvm/trunk/include/llvm/ADT/ilist_iterator.h
    llvm/trunk/include/llvm/ADT/ilist_node.h
    llvm/trunk/include/llvm/ADT/ilist_node_base.h
    llvm/trunk/include/llvm/ADT/simple_ilist.h
    llvm/trunk/include/llvm/CodeGen/MachineInstrBundleIterator.h
    llvm/trunk/unittests/ADT/CMakeLists.txt
    llvm/trunk/unittests/ADT/IListBaseTest.cpp
    llvm/trunk/unittests/ADT/IListNodeBaseTest.cpp
    llvm/trunk/unittests/ADT/IListSentinelTest.cpp
    llvm/trunk/unittests/ADT/SimpleIListTest.cpp

Modified: llvm/trunk/include/llvm/ADT/ilist.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/ilist.h?rev=281167&r1=281166&r2=281167&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ADT/ilist.h (original)
+++ llvm/trunk/include/llvm/ADT/ilist.h Sun Sep 11 11:20:53 2016
@@ -362,13 +362,18 @@ public:
 
 /// An intrusive list with ownership and callbacks specified/controlled by
 /// ilist_traits, only with API safe for polymorphic types.
-template <class T>
-class iplist : public iplist_impl<simple_ilist<T>, ilist_traits<T>> {};
+///
+/// The \p Options parameters are the same as those for \a simple_ilist.  See
+/// there for a description of what's available.
+template <class T, class... Options>
+class iplist
+    : public iplist_impl<simple_ilist<T, Options...>, ilist_traits<T>> {};
 
 /// An intrusive list with ownership and callbacks specified/controlled by
 /// ilist_traits, with API that is unsafe for polymorphic types.
-template <class T> class ilist : public iplist<T> {
-  typedef iplist<T> base_list_type;
+template <class T, class... Options>
+class ilist : public iplist<T, Options...> {
+  typedef iplist<T, Options...> base_list_type;
 
 public:
   typedef typename base_list_type::size_type size_type;

Modified: llvm/trunk/include/llvm/ADT/ilist_base.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/ilist_base.h?rev=281167&r1=281166&r2=281167&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ADT/ilist_base.h (original)
+++ llvm/trunk/include/llvm/ADT/ilist_base.h Sun Sep 11 11:20:53 2016
@@ -18,10 +18,10 @@
 namespace llvm {
 
 /// Implementations of list algorithms using ilist_node_base.
-class ilist_base {
-  typedef ilist_node_base node_base_type;
-
+template <bool EnableSentinelTracking> class ilist_base {
 public:
+  typedef ilist_node_base<EnableSentinelTracking> node_base_type;
+
   static void insertBeforeImpl(node_base_type &Next, node_base_type &N) {
     node_base_type &Prev = *Next.getPrev();
     N.setNext(&Next);

Modified: llvm/trunk/include/llvm/ADT/ilist_iterator.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/ilist_iterator.h?rev=281167&r1=281166&r2=281167&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ADT/ilist_iterator.h (original)
+++ llvm/trunk/include/llvm/ADT/ilist_iterator.h Sun Sep 11 11:20:53 2016
@@ -20,11 +20,21 @@ namespace llvm {
 
 namespace ilist_detail {
 
-template <class NodeTy> struct ConstCorrectNodeType {
-  typedef ilist_node<NodeTy> type;
-};
-template <class NodeTy> struct ConstCorrectNodeType<const NodeTy> {
-  typedef const ilist_node<NodeTy> type;
+/// Find const-correct node types.
+template <class OptionsT, bool IsConst> struct IteratorTraits;
+template <class OptionsT> struct IteratorTraits<OptionsT, false> {
+  typedef typename OptionsT::value_type value_type;
+  typedef typename OptionsT::pointer pointer;
+  typedef typename OptionsT::reference reference;
+  typedef ilist_node_impl<OptionsT> *node_pointer;
+  typedef ilist_node_impl<OptionsT> &node_reference;
+};
+template <class OptionsT> struct IteratorTraits<OptionsT, true> {
+  typedef const typename OptionsT::value_type value_type;
+  typedef typename OptionsT::const_pointer pointer;
+  typedef typename OptionsT::const_reference reference;
+  typedef const ilist_node_impl<OptionsT> *node_pointer;
+  typedef const ilist_node_impl<OptionsT> &node_reference;
 };
 
 template <bool IsReverse> struct IteratorHelper;
@@ -42,28 +52,29 @@ template <> struct IteratorHelper<true>
 } // end namespace ilist_detail
 
 /// Iterator for intrusive lists  based on ilist_node.
-template <typename NodeTy, bool IsReverse>
-class ilist_iterator : ilist_detail::SpecificNodeAccess<
-                           typename std::remove_const<NodeTy>::type> {
-  typedef ilist_detail::SpecificNodeAccess<
-      typename std::remove_const<NodeTy>::type>
-      Access;
+template <class OptionsT, bool IsReverse, bool IsConst>
+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>;
+
+  typedef ilist_detail::IteratorTraits<OptionsT, IsConst> Traits;
+  typedef ilist_detail::SpecificNodeAccess<OptionsT> Access;
 
 public:
-  typedef NodeTy value_type;
-  typedef value_type *pointer;
-  typedef value_type &reference;
+  typedef typename Traits::value_type value_type;
+  typedef typename Traits::pointer pointer;
+  typedef typename Traits::reference reference;
   typedef ptrdiff_t difference_type;
   typedef std::bidirectional_iterator_tag iterator_category;
 
-  typedef typename std::add_const<value_type>::type *const_pointer;
-  typedef typename std::add_const<value_type>::type &const_reference;
-
-  typedef typename ilist_detail::ConstCorrectNodeType<NodeTy>::type node_type;
-  typedef node_type *node_pointer;
-  typedef node_type &node_reference;
+  typedef typename OptionsT::const_pointer const_pointer;
+  typedef typename OptionsT::const_reference const_reference;
 
 private:
+  typedef typename Traits::node_pointer node_pointer;
+  typedef typename Traits::node_reference node_reference;
+
   node_pointer NodePtr;
 
 public:
@@ -76,19 +87,18 @@ public:
 
   // This is templated so that we can allow constructing a const iterator from
   // a nonconst iterator...
-  template <class node_ty>
+  template <bool RHSIsConst>
   ilist_iterator(
-      const ilist_iterator<node_ty, IsReverse> &RHS,
-      typename std::enable_if<std::is_convertible<node_ty *, NodeTy *>::value,
-                              void *>::type = nullptr)
-      : NodePtr(RHS.getNodePtr()) {}
+      const ilist_iterator<OptionsT, IsReverse, RHSIsConst> &RHS,
+      typename std::enable_if<IsConst || !RHSIsConst, void *>::type = nullptr)
+      : NodePtr(RHS.NodePtr) {}
 
   // This is templated so that we can allow assigning to a const iterator from
   // a nonconst iterator...
-  template <class node_ty>
-  const ilist_iterator &
-  operator=(const ilist_iterator<node_ty, IsReverse> &RHS) {
-    NodePtr = RHS.getNodePtr();
+  template <bool RHSIsConst>
+  typename std::enable_if<IsConst || !RHSIsConst, ilist_iterator &>::type
+  operator=(const ilist_iterator<OptionsT, IsReverse, RHSIsConst> &RHS) {
+    NodePtr = RHS.NodePtr;
     return *this;
   }
 
@@ -96,10 +106,19 @@ public:
   ///
   /// TODO: Roll this into the implicit constructor once we're sure that no one
   /// is relying on the std::reverse_iterator off-by-one semantics.
-  ilist_iterator<NodeTy, !IsReverse> getReverse() const {
+  ilist_iterator<OptionsT, !IsReverse, IsConst> getReverse() const {
+    if (NodePtr)
+      return ilist_iterator<OptionsT, !IsReverse, IsConst>(*NodePtr);
+    return ilist_iterator<OptionsT, !IsReverse, IsConst>();
+  }
+
+  /// Const-cast.
+  ilist_iterator<OptionsT, IsReverse, false> getNonConst() const {
     if (NodePtr)
-      return ilist_iterator<NodeTy, !IsReverse>(*NodePtr);
-    return ilist_iterator<NodeTy, !IsReverse>();
+      return ilist_iterator<OptionsT, IsReverse, false>(
+          const_cast<typename ilist_iterator<OptionsT, IsReverse,
+                                             false>::node_reference>(*NodePtr));
+    return ilist_iterator<OptionsT, IsReverse, false>();
   }
 
   void reset(pointer NP) { NodePtr = NP; }
@@ -121,11 +140,11 @@ public:
 
   // Increment and decrement operators...
   ilist_iterator &operator--() {
-    ilist_detail::IteratorHelper<IsReverse>::decrement(NodePtr);
+    NodePtr = IsReverse ? NodePtr->getNext() : NodePtr->getPrev();
     return *this;
   }
   ilist_iterator &operator++() {
-    ilist_detail::IteratorHelper<IsReverse>::increment(NodePtr);
+    NodePtr = IsReverse ? NodePtr->getPrev() : NodePtr->getNext();
     return *this;
   }
   ilist_iterator operator--(int) {
@@ -149,20 +168,16 @@ template <typename From> struct simplify
 /// used by the dyn_cast, cast, isa mechanisms...
 ///
 /// FIXME: remove this, since there is no implicit conversion to NodeTy.
-template <typename NodeTy> struct simplify_type<ilist_iterator<NodeTy>> {
-  typedef NodeTy *SimpleType;
-
-  static SimpleType getSimplifiedValue(ilist_iterator<NodeTy> &Node) {
-    return &*Node;
-  }
-};
-template <typename NodeTy> struct simplify_type<const ilist_iterator<NodeTy>> {
-  typedef /*const*/ NodeTy *SimpleType;
-
-  static SimpleType getSimplifiedValue(const ilist_iterator<NodeTy> &Node) {
-    return &*Node;
-  }
-};
+template <class OptionsT, bool IsConst>
+struct simplify_type<ilist_iterator<OptionsT, false, IsConst>> {
+  typedef ilist_iterator<OptionsT, false, IsConst> iterator;
+  typedef typename iterator::pointer SimpleType;
+
+  static SimpleType getSimplifiedValue(const iterator &Node) { return &*Node; }
+};
+template <class OptionsT, bool IsConst>
+struct simplify_type<const ilist_iterator<OptionsT, false, IsConst>>
+    : simplify_type<ilist_iterator<OptionsT, false, IsConst>> {};
 
 } // end namespace llvm
 

Modified: llvm/trunk/include/llvm/ADT/ilist_node.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/ilist_node.h?rev=281167&r1=281166&r2=281167&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ADT/ilist_node.h (original)
+++ llvm/trunk/include/llvm/ADT/ilist_node.h Sun Sep 11 11:20:53 2016
@@ -16,6 +16,7 @@
 #define LLVM_ADT_ILIST_NODE_H
 
 #include "llvm/ADT/ilist_node_base.h"
+#include "llvm/ADT/ilist_node_options.h"
 
 namespace llvm {
 
@@ -26,46 +27,121 @@ struct NodeAccess;
 template<typename NodeTy>
 struct ilist_traits;
 
-template <typename NodeTy, bool IsReverse = false> class ilist_iterator;
-template <typename NodeTy> class ilist_sentinel;
+template <class OptionsT, bool IsReverse, bool IsConst> class ilist_iterator;
+template <class OptionsT> class ilist_sentinel;
 
-/// Templated wrapper class.
-template <typename NodeTy> class ilist_node : ilist_node_base {
-  friend class ilist_base;
+/// Implementation for an ilist node.
+///
+/// Templated on an appropriate \a ilist_detail::node_options, usually computed
+/// by \a ilist_detail::compute_node_options.
+///
+/// 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 {
+  typedef typename OptionsT::value_type value_type;
+  typedef typename OptionsT::node_base_type node_base_type;
+  typedef typename OptionsT::list_base_type list_base_type;
+
+  friend typename OptionsT::list_base_type;
   friend struct ilist_detail::NodeAccess;
-  friend struct ilist_traits<NodeTy>;
-  friend class ilist_iterator<NodeTy, false>;
-  friend class ilist_iterator<NodeTy, true>;
-  friend class ilist_sentinel<NodeTy>;
+  friend class ilist_sentinel<OptionsT>;
+  friend class ilist_iterator<OptionsT, false, false>;
+  friend class ilist_iterator<OptionsT, false, true>;
+  friend class ilist_iterator<OptionsT, true, false>;
+  friend class ilist_iterator<OptionsT, true, true>;
 
 protected:
-  ilist_node() = default;
+  ilist_node_impl() = default;
+
+  typedef ilist_iterator<OptionsT, false, false> self_iterator;
+  typedef ilist_iterator<OptionsT, false, true> const_self_iterator;
+  typedef ilist_iterator<OptionsT, true, false> reverse_self_iterator;
+  typedef ilist_iterator<OptionsT, true, true> const_reverse_self_iterator;
 
 private:
-  ilist_node *getPrev() {
-    return static_cast<ilist_node *>(ilist_node_base::getPrev());
+  ilist_node_impl *getPrev() {
+    return static_cast<ilist_node_impl *>(node_base_type::getPrev());
   }
-  ilist_node *getNext() {
-    return static_cast<ilist_node *>(ilist_node_base::getNext());
+  ilist_node_impl *getNext() {
+    return static_cast<ilist_node_impl *>(node_base_type::getNext());
   }
 
-  const ilist_node *getPrev() const {
-    return static_cast<ilist_node *>(ilist_node_base::getPrev());
+  const ilist_node_impl *getPrev() const {
+    return static_cast<ilist_node_impl *>(node_base_type::getPrev());
   }
-  const ilist_node *getNext() const {
-    return static_cast<ilist_node *>(ilist_node_base::getNext());
+  const ilist_node_impl *getNext() const {
+    return static_cast<ilist_node_impl *>(node_base_type::getNext());
   }
 
-  void setPrev(ilist_node *N) { ilist_node_base::setPrev(N); }
-  void setNext(ilist_node *N) { ilist_node_base::setNext(N); }
+  void setPrev(ilist_node_impl *N) { node_base_type::setPrev(N); }
+  void setNext(ilist_node_impl *N) { node_base_type::setNext(N); }
 
 public:
-  ilist_iterator<NodeTy> getIterator() { return ilist_iterator<NodeTy>(*this); }
-  ilist_iterator<const NodeTy> getIterator() const {
-    return ilist_iterator<const NodeTy>(*this);
+  self_iterator getIterator() { return self_iterator(*this); }
+  const_self_iterator getIterator() const { return const_self_iterator(*this); }
+
+  // Under-approximation, but always available for assertions.
+  using node_base_type::isKnownSentinel;
+
+  /// Check whether this is the sentinel node.
+  ///
+  /// This requires sentinel tracking to be explicitly enabled.  Use the
+  /// ilist_sentinel_tracking<true> option to get this API.
+  bool isSentinel() const {
+    static_assert(OptionsT::is_sentinel_tracking_explicit,
+                  "Use ilist_sentinel_tracking<true> to enable isSentinel()");
+    return node_base_type::isSentinel();
   }
+};
 
-  using ilist_node_base::isKnownSentinel;
+/// An intrusive list node.
+///
+/// A base class to enable membership in intrusive lists, including \a
+/// simple_ilist, \a iplist, and \a ilist.  The first template parameter is the
+/// \a value_type for the list.
+///
+/// An ilist node can be configured with compile-time options to change
+/// behaviour and/or add API.
+///
+/// By default, an \a ilist_node knows whether it is the list sentinel (an
+/// instance of \a ilist_sentinel) if and only if
+/// LLVM_ENABLE_ABI_BREAKING_CHECKS.  The function \a isKnownSentinel() always
+/// returns \c false tracking is off.  Sentinel tracking steals a bit from the
+/// "prev" link, which adds a mask operation when decrementing an iterator, but
+/// enables bug-finding assertions in \a ilist_iterator.
+///
+/// To turn sentinel tracking on all the time, pass in the
+/// ilist_sentinel_tracking<true> template parameter.  This also enables the \a
+/// isSentinel() function.  The same option must be passed to the intrusive
+/// list.  (ilist_sentinel_tracking<false> turns sentinel tracking off all the
+/// time.)
+///
+/// A type can inherit from ilist_node multiple times by passing in different
+/// \a ilist_tag options.  This allows a single instance to be inserted into
+/// multiple lists simultaneously, where each list is given the same tag.
+///
+/// \example
+/// struct A {};
+/// struct B {};
+/// struct N : ilist_node<N, ilist_tag<A>>, ilist_node<N, ilist_tag<B>> {};
+///
+/// void foo() {
+///   simple_ilist<N, ilist_tag<A>> ListA;
+///   simple_ilist<N, ilist_tag<B>> ListB;
+///   N N1;
+///   ListA.push_back(N1);
+///   ListB.push_back(N1);
+/// }
+/// \endexample
+///
+/// See \a is_valid_option for steps on adding a new option.
+template <class T, class... Options>
+class ilist_node
+    : public ilist_node_impl<
+          typename ilist_detail::compute_node_options<T, Options...>::type> {
+  static_assert(ilist_detail::check_options<Options...>::value,
+                "Unrecognized node option!");
 };
 
 namespace ilist_detail {
@@ -77,58 +153,71 @@ namespace ilist_detail {
 /// Using this class outside of the ilist implementation is unsupported.
 struct NodeAccess {
 protected:
-  template <typename T> static ilist_node<T> *getNodePtr(T *N) { return N; }
-  template <typename T> static const ilist_node<T> *getNodePtr(const T *N) {
+  template <class OptionsT>
+  static ilist_node_impl<OptionsT> *getNodePtr(typename OptionsT::pointer N) {
     return N;
   }
-  template <typename T> static T *getValuePtr(ilist_node<T> *N) {
-    return static_cast<T *>(N);
+  template <class OptionsT>
+  static const ilist_node_impl<OptionsT> *
+  getNodePtr(typename OptionsT::const_pointer N) {
+    return N;
   }
-  template <typename T> static const T *getValuePtr(const ilist_node<T> *N) {
-    return static_cast<const T *>(N);
+  template <class OptionsT>
+  static typename OptionsT::pointer getValuePtr(ilist_node_impl<OptionsT> *N) {
+    return static_cast<typename OptionsT::pointer>(N);
+  }
+  template <class OptionsT>
+  static typename OptionsT::const_pointer
+  getValuePtr(const ilist_node_impl<OptionsT> *N) {
+    return static_cast<typename OptionsT::const_pointer>(N);
   }
 
-  template <typename T> static ilist_node<T> *getPrev(ilist_node<T> &N) {
+  template <class OptionsT>
+  static ilist_node_impl<OptionsT> *getPrev(ilist_node_impl<OptionsT> &N) {
     return N.getPrev();
   }
-  template <typename T> static ilist_node<T> *getNext(ilist_node<T> &N) {
+  template <class OptionsT>
+  static ilist_node_impl<OptionsT> *getNext(ilist_node_impl<OptionsT> &N) {
     return N.getNext();
   }
-  template <typename T>
-  static const ilist_node<T> *getPrev(const ilist_node<T> &N) {
+  template <class OptionsT>
+  static const ilist_node_impl<OptionsT> *
+  getPrev(const ilist_node_impl<OptionsT> &N) {
     return N.getPrev();
   }
-  template <typename T>
-  static const ilist_node<T> *getNext(const ilist_node<T> &N) {
+  template <class OptionsT>
+  static const ilist_node_impl<OptionsT> *
+  getNext(const ilist_node_impl<OptionsT> &N) {
     return N.getNext();
   }
 };
 
-template <class T> struct SpecificNodeAccess : NodeAccess {
+template <class OptionsT> struct SpecificNodeAccess : NodeAccess {
 protected:
-  typedef T *pointer;
-  typedef const T *const_pointer;
-  typedef ilist_node<T> node_type;
+  typedef typename OptionsT::pointer pointer;
+  typedef typename OptionsT::const_pointer const_pointer;
+  typedef ilist_node_impl<OptionsT> node_type;
 
   static node_type *getNodePtr(pointer N) {
-    return NodeAccess::getNodePtr<T>(N);
+    return NodeAccess::getNodePtr<OptionsT>(N);
   }
-  static const ilist_node<T> *getNodePtr(const_pointer N) {
-    return NodeAccess::getNodePtr<T>(N);
+  static const node_type *getNodePtr(const_pointer N) {
+    return NodeAccess::getNodePtr<OptionsT>(N);
   }
   static pointer getValuePtr(node_type *N) {
-    return NodeAccess::getValuePtr<T>(N);
+    return NodeAccess::getValuePtr<OptionsT>(N);
   }
   static const_pointer getValuePtr(const node_type *N) {
-    return NodeAccess::getValuePtr<T>(N);
+    return NodeAccess::getValuePtr<OptionsT>(N);
   }
 };
 } // end namespace ilist_detail
 
-template <typename NodeTy> class ilist_sentinel : public ilist_node<NodeTy> {
+template <class OptionsT>
+class ilist_sentinel : public ilist_node_impl<OptionsT> {
 public:
   ilist_sentinel() {
-    ilist_node_base::initializeSentinel();
+    this->initializeSentinel();
     reset();
   }
 
@@ -144,8 +233,8 @@ public:
 ///
 /// 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 <typename NodeTy, typename ParentTy>
-class ilist_node_with_parent : public ilist_node<NodeTy> {
+template <typename NodeTy, typename ParentTy, class... Options>
+class ilist_node_with_parent : public ilist_node<NodeTy, Options...> {
 protected:
   ilist_node_with_parent() = default;
 

Modified: llvm/trunk/include/llvm/ADT/ilist_node_base.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/ilist_node_base.h?rev=281167&r1=281166&r2=281167&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ADT/ilist_node_base.h (original)
+++ llvm/trunk/include/llvm/ADT/ilist_node_base.h Sun Sep 11 11:20:53 2016
@@ -15,31 +15,37 @@
 namespace llvm {
 
 /// Base class for ilist nodes.
-class ilist_node_base {
-#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
-  PointerIntPair<ilist_node_base *, 1> PrevAndSentinel;
-#else
+///
+/// Optionally tracks whether this node is the sentinel.
+template <bool EnableSentinelTracking> class ilist_node_base;
+
+template <> class ilist_node_base<false> {
   ilist_node_base *Prev = nullptr;
-#endif
   ilist_node_base *Next = nullptr;
 
 public:
-#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
-  void setPrev(ilist_node_base *Prev) { PrevAndSentinel.setPointer(Prev); }
-  ilist_node_base *getPrev() const { return PrevAndSentinel.getPointer(); }
-
-  bool isKnownSentinel() const { return PrevAndSentinel.getInt(); }
-  void initializeSentinel() { PrevAndSentinel.setInt(true); }
-#else
   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; }
 
   bool isKnownSentinel() const { return false; }
   void initializeSentinel() {}
-#endif
+};
 
+template <> class ilist_node_base<true> {
+  PointerIntPair<ilist_node_base *, 1> PrevAndSentinel;
+  ilist_node_base *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; }
+
+  bool isSentinel() const { return PrevAndSentinel.getInt(); }
+  bool isKnownSentinel() const { return isSentinel(); }
+  void initializeSentinel() { PrevAndSentinel.setInt(true); }
 };
 
 } // end namespace llvm

Added: llvm/trunk/include/llvm/ADT/ilist_node_options.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/ilist_node_options.h?rev=281167&view=auto
==============================================================================
--- llvm/trunk/include/llvm/ADT/ilist_node_options.h (added)
+++ llvm/trunk/include/llvm/ADT/ilist_node_options.h Sun Sep 11 11:20:53 2016
@@ -0,0 +1,128 @@
+//===- llvm/ADT/ilist_node_options.h - ilist_node Options -------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_ILIST_NODE_OPTIONS_H
+#define LLVM_ADT_ILIST_NODE_OPTIONS_H
+
+namespace llvm {
+
+template <bool EnableSentinelTracking> class ilist_node_base;
+template <bool EnableSentinelTracking> class ilist_base;
+
+/// Option to choose whether to track sentinels.
+///
+/// This option affects the ABI for the nodes.  When not specified explicitly,
+/// the ABI depends on LLVM_ENABLE_ABI_BREAKING_CHECKS.  Specify explicitly to
+/// enable \a ilist_node::isSentinel().
+template <bool EnableSentinelTracking> struct ilist_sentinel_tracking {};
+
+/// Option to specify a tag for the node type.
+///
+/// This option allows a single value type to be inserted in multiple lists
+/// simultaneously.  See \a ilist_node for usage examples.
+template <class Tag> struct ilist_tag {};
+
+namespace ilist_detail {
+
+/// Helper trait for recording whether an option is specified explicitly.
+template <bool IsExplicit> struct explicitness {
+  static const bool is_explicit = IsExplicit;
+};
+typedef explicitness<true> is_explicit;
+typedef explicitness<false> is_implicit;
+
+/// Check whether an option is valid.
+///
+/// The steps for adding and enabling a new ilist option include:
+/// \li define the option, ilist_foo<Bar>, above;
+/// \li add new parameters for Bar to \a ilist_detail::node_options;
+/// \li add an extraction meta-function, ilist_detail::extract_foo;
+/// \li call extract_foo from \a ilist_detail::compute_node_options and pass it
+/// into \a ilist_detail::node_options; and
+/// \li specialize \c is_valid_option<ilist_foo<Bar>> to inherit from \c
+/// std::true_type to get static assertions passing in \a simple_ilist and \a
+/// ilist_node.
+template <class Option> struct is_valid_option : std::false_type {};
+
+/// Extract sentinel tracking option.
+///
+/// Look through \p Options for the \a ilist_sentinel_tracking option, with the
+/// default depending on LLVM_ENABLE_ABI_BREAKING_CHECKS.
+template <class... Options> struct extract_sentinel_tracking;
+template <bool EnableSentinelTracking, class... Options>
+struct extract_sentinel_tracking<
+    ilist_sentinel_tracking<EnableSentinelTracking>, Options...>
+    : std::integral_constant<bool, EnableSentinelTracking>, is_explicit {};
+template <class Option1, class... Options>
+struct extract_sentinel_tracking<Option1, Options...>
+    : extract_sentinel_tracking<Options...> {};
+#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
+template <> struct extract_sentinel_tracking<> : std::true_type, is_implicit {};
+#else
+template <>
+struct extract_sentinel_tracking<> : std::false_type, is_implicit {};
+#endif
+template <bool EnableSentinelTracking>
+struct is_valid_option<ilist_sentinel_tracking<EnableSentinelTracking>>
+    : std::true_type {};
+
+/// Extract custom tag option.
+///
+/// Look through \p Options for the \a ilist_tag option, pulling out the
+/// custom tag type, using void as a default.
+template <class... Options> struct extract_tag;
+template <class Tag, class... Options>
+struct extract_tag<ilist_tag<Tag>, Options...> {
+  typedef Tag type;
+};
+template <class Option1, class... Options>
+struct extract_tag<Option1, Options...> : extract_tag<Options...> {};
+template <> struct extract_tag<> { typedef void type; };
+template <class Tag> struct is_valid_option<ilist_tag<Tag>> : std::true_type {};
+
+/// Check whether options are valid.
+///
+/// The conjunction of \a is_valid_option on each individual option.
+template <class... Options> struct check_options;
+template <> struct check_options<> : std::true_type {};
+template <class Option1, class... Options>
+struct check_options<Option1, Options...>
+    : std::integral_constant<bool, is_valid_option<Option1>::value &&
+                                       check_options<Options...>::value> {};
+
+/// Traits for options for \a ilist_node.
+///
+/// This is usually computed via \a compute_node_options.
+template <class T, bool EnableSentinelTracking, bool IsSentinelTrackingExplicit,
+          class TagT>
+struct node_options {
+  typedef T value_type;
+  typedef T *pointer;
+  typedef T &reference;
+  typedef const T *const_pointer;
+  typedef const T &const_reference;
+
+  static const bool enable_sentinel_tracking = EnableSentinelTracking;
+  static const bool is_sentinel_tracking_explicit = IsSentinelTrackingExplicit;
+  typedef TagT tag;
+  typedef ilist_node_base<enable_sentinel_tracking> node_base_type;
+  typedef ilist_base<enable_sentinel_tracking> 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>
+      type;
+};
+
+} // end namespace ilist_detail
+} // end namespace llvm
+
+#endif // LLVM_ADT_ILIST_NODE_OPTIONS_H

Modified: llvm/trunk/include/llvm/ADT/simple_ilist.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/simple_ilist.h?rev=281167&r1=281166&r2=281167&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ADT/simple_ilist.h (original)
+++ llvm/trunk/include/llvm/ADT/simple_ilist.h Sun Sep 11 11:20:53 2016
@@ -46,23 +46,54 @@ namespace llvm {
 /// eraseAndDispose(), and \a clearAndDispose().  These have different names
 /// because the extra semantic is otherwise non-obvious.  They are equivalent
 /// to calling \a std::for_each() on the range to be discarded.
-template <typename T>
-class simple_ilist : ilist_base, ilist_detail::SpecificNodeAccess<T> {
-  typedef ilist_base list_base_type;
-  ilist_sentinel<T> Sentinel;
+///
+/// The currently available \p Options customize the nodes in the list.  The
+/// same options must be specified in the \a ilist_node instantation for
+/// compatibility (although the order is irrelevant).
+/// \li Use \a ilist_tag to designate which ilist_node for a given \p T this
+/// list should use.  This is useful if a type \p T is part of multiple,
+/// independent lists simultaneously.
+/// \li Use \a ilist_sentinel_tracking to always (or never) track whether a
+/// node is a sentinel.  Specifying \c true enables the \a
+/// ilist_node::isSentinel() API.  Unlike \a ilist_node::isKnownSentinel(),
+/// which is only appropriate for assertions, \a ilist_node::isSentinel() is
+/// appropriate for real logic.
+///
+/// Here are examples of \p Options usage:
+/// \li \c simple_ilist<T> gives the defaults.  \li \c
+/// simple_ilist<T,ilist_sentinel_tracking<true>> enables the \a
+/// ilist_node::isSentinel() API.
+/// \li \c simple_ilist<T,ilist_tag<A>,ilist_sentinel_tracking<false>>
+/// specifies a tag of A and that tracking should be off (even when
+/// LLVM_ENABLE_ABI_BREAKING_CHECKS are enabled).
+/// \li \c simple_ilist<T,ilist_sentinel_tracking<false>,ilist_tag<A>> is
+/// equivalent to the last.
+///
+/// See \a is_valid_option for steps on adding a new option.
+template <typename T, class... Options>
+class simple_ilist
+    : ilist_detail::compute_node_options<T, Options...>::type::list_base_type,
+      ilist_detail::SpecificNodeAccess<
+          typename ilist_detail::compute_node_options<T, Options...>::type> {
+  static_assert(ilist_detail::check_options<Options...>::value,
+                "Unrecognized node option!");
+  typedef
+      typename ilist_detail::compute_node_options<T, Options...>::type OptionsT;
+  typedef typename OptionsT::list_base_type list_base_type;
+  ilist_sentinel<OptionsT> Sentinel;
 
 public:
-  typedef T value_type;
-  typedef T *pointer;
-  typedef T &reference;
-  typedef const T *const_pointer;
-  typedef const T &const_reference;
-  typedef ilist_iterator<T> iterator;
-  typedef ilist_iterator<const T> const_iterator;
+  typedef typename OptionsT::value_type value_type;
+  typedef typename OptionsT::pointer pointer;
+  typedef typename OptionsT::reference reference;
+  typedef typename OptionsT::const_pointer const_pointer;
+  typedef typename OptionsT::const_reference const_reference;
+  typedef ilist_iterator<OptionsT, false, false> iterator;
+  typedef ilist_iterator<OptionsT, false, true> const_iterator;
+  typedef ilist_iterator<OptionsT, true, false> reverse_iterator;
+  typedef ilist_iterator<OptionsT, true, true> const_reverse_iterator;
   typedef size_t size_type;
   typedef ptrdiff_t difference_type;
-  typedef ilist_iterator<const T, true> const_reverse_iterator;
-  typedef ilist_iterator<T, true> reverse_iterator;
 
   simple_ilist() = default;
   ~simple_ilist() = default;
@@ -222,9 +253,9 @@ public:
   ///@}
 };
 
-template <class T>
+template <class T, class... Options>
 template <class Compare>
-void simple_ilist<T>::merge(simple_ilist<T> &RHS, Compare comp) {
+void simple_ilist<T, Options...>::merge(simple_ilist &RHS, Compare comp) {
   if (this == &RHS || RHS.empty())
     return;
   iterator LI = begin(), LE = end();
@@ -244,9 +275,9 @@ void simple_ilist<T>::merge(simple_ilist
   splice(LE, RHS, RI, RE);
 }
 
-template <class T>
+template <class T, class... Options>
 template <class Compare>
-void simple_ilist<T>::sort(Compare comp) {
+void simple_ilist<T, Options...>::sort(Compare comp) {
   // Vacuously sorted.
   if (empty() || std::next(begin()) == end())
     return;
@@ -257,7 +288,7 @@ void simple_ilist<T>::sort(Compare comp)
     ++Center;
     ++End;
   }
-  simple_ilist<T> RHS;
+  simple_ilist RHS;
   RHS.splice(RHS.end(), *this, Center, end());
 
   // Sort the sublists and merge back together.

Modified: llvm/trunk/include/llvm/CodeGen/MachineInstrBundleIterator.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/MachineInstrBundleIterator.h?rev=281167&r1=281166&r2=281167&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/MachineInstrBundleIterator.h (original)
+++ llvm/trunk/include/llvm/CodeGen/MachineInstrBundleIterator.h Sun Sep 11 11:20:53 2016
@@ -19,10 +19,22 @@
 
 namespace llvm {
 
+template <class T> struct MachineInstrBundleIteratorTraits {
+  typedef simple_ilist<T> list_type;
+  typedef typename list_type::iterator instr_iterator;
+  typedef typename list_type::iterator nonconst_instr_iterator;
+};
+template <class T> struct MachineInstrBundleIteratorTraits<const T> {
+  typedef simple_ilist<T> list_type;
+  typedef typename list_type::const_iterator instr_iterator;
+  typedef typename list_type::iterator nonconst_instr_iterator;
+};
+
 /// MachineBasicBlock iterator that automatically skips over MIs that are
 /// inside bundles (i.e. walk top level MIs only).
 template <typename Ty> class MachineInstrBundleIterator {
-  typedef ilist_iterator<Ty> instr_iterator;
+  typedef typename MachineInstrBundleIteratorTraits<Ty>::instr_iterator
+      instr_iterator;
   instr_iterator MII;
 
 public:
@@ -37,8 +49,8 @@ public:
 
 private:
   typedef typename std::remove_const<value_type>::type nonconst_value_type;
-  typedef ilist_node<nonconst_value_type> node_type;
-  typedef ilist_iterator<nonconst_value_type> nonconst_instr_iterator;
+  typedef typename MachineInstrBundleIteratorTraits<Ty>::nonconst_instr_iterator
+      nonconst_instr_iterator;
   typedef MachineInstrBundleIterator<nonconst_value_type> nonconst_iterator;
 
 public:
@@ -136,11 +148,7 @@ public:
 
   instr_iterator getInstrIterator() const { return MII; }
 
-  nonconst_iterator getNonConstIterator() const {
-    if (auto *N = const_cast<node_type *>(MII.getNodePtr()))
-      return nonconst_iterator(nonconst_instr_iterator(*N));
-    return nonconst_iterator();
-  }
+  nonconst_iterator getNonConstIterator() const { return MII.getNonConst(); }
 };
 
 } // end namespace llvm

Modified: llvm/trunk/unittests/ADT/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/CMakeLists.txt?rev=281167&r1=281166&r2=281167&view=diff
==============================================================================
--- llvm/trunk/unittests/ADT/CMakeLists.txt (original)
+++ llvm/trunk/unittests/ADT/CMakeLists.txt Sun Sep 11 11:20:53 2016
@@ -20,6 +20,7 @@ set(ADTSources
   IListBaseTest.cpp
   IListIteratorTest.cpp
   IListNodeBaseTest.cpp
+  IListNodeTest.cpp
   IListSentinelTest.cpp
   IListTest.cpp
   ImmutableMapTest.cpp

Modified: llvm/trunk/unittests/ADT/IListBaseTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/IListBaseTest.cpp?rev=281167&r1=281166&r2=281167&view=diff
==============================================================================
--- llvm/trunk/unittests/ADT/IListBaseTest.cpp (original)
+++ llvm/trunk/unittests/ADT/IListBaseTest.cpp Sun Sep 11 11:20:53 2016
@@ -14,11 +14,20 @@ using namespace llvm;
 
 namespace {
 
-typedef ilist_base list_base_type;
-typedef ilist_node_base node_base_type;
+// Test fixture.
+template <typename T> class IListBaseTest : public ::testing::Test {};
+
+// Test variants with the same test.
+typedef ::testing::Types<ilist_base<false>, ilist_base<true>>
+    IListBaseTestTypes;
+TYPED_TEST_CASE(IListBaseTest, IListBaseTestTypes);
+
+TYPED_TEST(IListBaseTest, insertBeforeImpl) {
+  typedef TypeParam list_base_type;
+  typedef typename list_base_type::node_base_type node_base_type;
 
-TEST(IListBaseTest, insertBeforeImpl) {
   node_base_type S, A, B;
+
   // [S] <-> [S]
   S.setPrev(&S);
   S.setNext(&S);
@@ -40,7 +49,10 @@ TEST(IListBaseTest, insertBeforeImpl) {
   EXPECT_EQ(&S, B.getNext());
 }
 
-TEST(IListBaseTest, removeImpl) {
+TYPED_TEST(IListBaseTest, removeImpl) {
+  typedef TypeParam list_base_type;
+  typedef typename list_base_type::node_base_type node_base_type;
+
   node_base_type S, A, B;
 
   // [S] <-> A <-> B <-> [S]
@@ -66,7 +78,10 @@ TEST(IListBaseTest, removeImpl) {
   EXPECT_EQ(nullptr, B.getNext());
 }
 
-TEST(IListBaseTest, removeRangeImpl) {
+TYPED_TEST(IListBaseTest, removeRangeImpl) {
+  typedef TypeParam list_base_type;
+  typedef typename list_base_type::node_base_type node_base_type;
+
   node_base_type S, A, B, C, D;
 
   // [S] <-> A <-> B <-> C <-> D <-> [S]
@@ -89,7 +104,10 @@ TEST(IListBaseTest, removeRangeImpl) {
   EXPECT_EQ(nullptr, C.getNext());
 }
 
-TEST(IListBaseTest, removeRangeImplAllButSentinel) {
+TYPED_TEST(IListBaseTest, removeRangeImplAllButSentinel) {
+  typedef TypeParam list_base_type;
+  typedef typename list_base_type::node_base_type node_base_type;
+
   node_base_type S, A, B;
 
   // [S] <-> A <-> B <-> [S]
@@ -106,7 +124,10 @@ TEST(IListBaseTest, removeRangeImplAllBu
   EXPECT_EQ(nullptr, B.getNext());
 }
 
-TEST(IListBaseTest, transferBeforeImpl) {
+TYPED_TEST(IListBaseTest, transferBeforeImpl) {
+  typedef TypeParam list_base_type;
+  typedef typename list_base_type::node_base_type node_base_type;
+
   node_base_type S1, S2, A, B, C, D, E;
 
   // [S1] <-> A <-> B <-> C <-> [S1]

Modified: llvm/trunk/unittests/ADT/IListNodeBaseTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/IListNodeBaseTest.cpp?rev=281167&r1=281166&r2=281167&view=diff
==============================================================================
--- llvm/trunk/unittests/ADT/IListNodeBaseTest.cpp (original)
+++ llvm/trunk/unittests/ADT/IListNodeBaseTest.cpp Sun Sep 11 11:20:53 2016
@@ -14,15 +14,24 @@ using namespace llvm;
 
 namespace {
 
+typedef ilist_node_base<false> RawNode;
+typedef ilist_node_base<true> TrackingNode;
+
 TEST(IListNodeBaseTest, DefaultConstructor) {
-  ilist_node_base A;
+  RawNode A;
   EXPECT_EQ(nullptr, A.getPrev());
   EXPECT_EQ(nullptr, A.getNext());
   EXPECT_FALSE(A.isKnownSentinel());
+
+  TrackingNode TA;
+  EXPECT_EQ(nullptr, TA.getPrev());
+  EXPECT_EQ(nullptr, TA.getNext());
+  EXPECT_FALSE(TA.isKnownSentinel());
+  EXPECT_FALSE(TA.isSentinel());
 }
 
 TEST(IListNodeBaseTest, setPrevAndNext) {
-  ilist_node_base A, B, C;
+  RawNode A, B, C;
   A.setPrev(&B);
   EXPECT_EQ(&B, A.getPrev());
   EXPECT_EQ(nullptr, A.getNext());
@@ -38,23 +47,54 @@ TEST(IListNodeBaseTest, setPrevAndNext)
   EXPECT_EQ(nullptr, B.getNext());
   EXPECT_EQ(nullptr, C.getPrev());
   EXPECT_EQ(nullptr, C.getNext());
+
+  TrackingNode TA, TB, TC;
+  TA.setPrev(&TB);
+  EXPECT_EQ(&TB, TA.getPrev());
+  EXPECT_EQ(nullptr, TA.getNext());
+  EXPECT_EQ(nullptr, TB.getPrev());
+  EXPECT_EQ(nullptr, TB.getNext());
+  EXPECT_EQ(nullptr, TC.getPrev());
+  EXPECT_EQ(nullptr, TC.getNext());
+
+  TA.setNext(&TC);
+  EXPECT_EQ(&TB, TA.getPrev());
+  EXPECT_EQ(&TC, TA.getNext());
+  EXPECT_EQ(nullptr, TB.getPrev());
+  EXPECT_EQ(nullptr, TB.getNext());
+  EXPECT_EQ(nullptr, TC.getPrev());
+  EXPECT_EQ(nullptr, TC.getNext());
 }
 
 TEST(IListNodeBaseTest, isKnownSentinel) {
-  ilist_node_base A, B;
+  // Without sentinel tracking.
+  RawNode A, B;
   EXPECT_FALSE(A.isKnownSentinel());
   A.setPrev(&B);
   A.setNext(&B);
   EXPECT_EQ(&B, A.getPrev());
   EXPECT_EQ(&B, A.getNext());
+  EXPECT_FALSE(A.isKnownSentinel());
   A.initializeSentinel();
-#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
-  EXPECT_TRUE(A.isKnownSentinel());
-#else
   EXPECT_FALSE(A.isKnownSentinel());
-#endif
   EXPECT_EQ(&B, A.getPrev());
   EXPECT_EQ(&B, A.getNext());
+
+  // With sentinel tracking.
+  TrackingNode TA, TB;
+  EXPECT_FALSE(TA.isKnownSentinel());
+  EXPECT_FALSE(TA.isSentinel());
+  TA.setPrev(&TB);
+  TA.setNext(&TB);
+  EXPECT_EQ(&TB, TA.getPrev());
+  EXPECT_EQ(&TB, TA.getNext());
+  EXPECT_FALSE(TA.isKnownSentinel());
+  EXPECT_FALSE(TA.isSentinel());
+  TA.initializeSentinel();
+  EXPECT_TRUE(TA.isKnownSentinel());
+  EXPECT_TRUE(TA.isSentinel());
+  EXPECT_EQ(&TB, TA.getPrev());
+  EXPECT_EQ(&TB, TA.getNext());
 }
 
 } // end namespace

Added: llvm/trunk/unittests/ADT/IListNodeTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/IListNodeTest.cpp?rev=281167&view=auto
==============================================================================
--- llvm/trunk/unittests/ADT/IListNodeTest.cpp (added)
+++ llvm/trunk/unittests/ADT/IListNodeTest.cpp Sun Sep 11 11:20:53 2016
@@ -0,0 +1,70 @@
+//===- unittests/ADT/IListNodeTest.cpp - ilist_node unit tests ------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/ilist_node.h"
+#include "gtest/gtest.h"
+#include <type_traits>
+
+using namespace llvm;
+using namespace llvm::ilist_detail;
+
+namespace {
+
+struct Node;
+
+struct TagA {};
+struct TagB {};
+
+TEST(IListNodeTest, Options) {
+  static_assert(
+      std::is_same<compute_node_options<Node>::type,
+                   compute_node_options<Node, ilist_tag<void>>::type>::value,
+      "default tag is void");
+  static_assert(
+      !std::is_same<compute_node_options<Node, ilist_tag<TagA>>::type,
+                    compute_node_options<Node, ilist_tag<void>>::type>::value,
+      "default tag is void, different from TagA");
+  static_assert(
+      !std::is_same<compute_node_options<Node, ilist_tag<TagA>>::type,
+                    compute_node_options<Node, ilist_tag<TagB>>::type>::value,
+      "TagA is not TagB");
+  static_assert(
+      std::is_same<
+          compute_node_options<Node, ilist_sentinel_tracking<false>>::type,
+          compute_node_options<Node, ilist_sentinel_tracking<false>,
+                               ilist_tag<void>>::type>::value,
+      "default tag is void, even with sentinel tracking off");
+  static_assert(
+      std::is_same<
+          compute_node_options<Node, ilist_sentinel_tracking<false>>::type,
+          compute_node_options<Node, ilist_tag<void>,
+                               ilist_sentinel_tracking<false>>::type>::value,
+      "order shouldn't matter");
+  static_assert(
+      std::is_same<
+          compute_node_options<Node, ilist_sentinel_tracking<true>>::type,
+          compute_node_options<Node, ilist_sentinel_tracking<true>,
+                               ilist_tag<void>>::type>::value,
+      "default tag is void, even with sentinel tracking on");
+  static_assert(
+      std::is_same<
+          compute_node_options<Node, ilist_sentinel_tracking<true>>::type,
+          compute_node_options<Node, ilist_tag<void>,
+                               ilist_sentinel_tracking<true>>::type>::value,
+      "order shouldn't matter");
+  static_assert(
+      std::is_same<
+          compute_node_options<Node, ilist_sentinel_tracking<true>,
+                               ilist_tag<TagA>>::type,
+          compute_node_options<Node, ilist_tag<TagA>,
+                               ilist_sentinel_tracking<true>>::type>::value,
+      "order shouldn't matter with real tags");
+}
+
+} // end namespace

Modified: llvm/trunk/unittests/ADT/IListSentinelTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/IListSentinelTest.cpp?rev=281167&r1=281166&r2=281167&view=diff
==============================================================================
--- llvm/trunk/unittests/ADT/IListSentinelTest.cpp (original)
+++ llvm/trunk/unittests/ADT/IListSentinelTest.cpp Sun Sep 11 11:20:53 2016
@@ -7,14 +7,26 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "llvm/ADT/ilist.h"
+#include "llvm/ADT/ilist_node.h"
 #include "gtest/gtest.h"
 
 using namespace llvm;
 
 namespace {
 
+template <class T, class... Options> struct PickSentinel {
+  typedef ilist_sentinel<
+      typename ilist_detail::compute_node_options<T, Options...>::type>
+      type;
+};
+
 class Node : public ilist_node<Node> {};
+class TrackingNode : public ilist_node<Node, ilist_sentinel_tracking<true>> {};
+typedef PickSentinel<Node>::type Sentinel;
+typedef PickSentinel<Node, ilist_sentinel_tracking<true>>::type
+    TrackingSentinel;
+typedef PickSentinel<Node, ilist_sentinel_tracking<false>>::type
+    NoTrackingSentinel;
 
 struct LocalAccess : ilist_detail::NodeAccess {
   using NodeAccess::getPrev;
@@ -22,7 +34,7 @@ struct LocalAccess : ilist_detail::NodeA
 };
 
 TEST(IListSentinelTest, DefaultConstructor) {
-  ilist_sentinel<Node> S;
+  Sentinel S;
   EXPECT_EQ(&S, LocalAccess::getPrev(S));
   EXPECT_EQ(&S, LocalAccess::getNext(S));
 #ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
@@ -30,6 +42,12 @@ TEST(IListSentinelTest, DefaultConstruct
 #else
   EXPECT_FALSE(S.isKnownSentinel());
 #endif
+
+  TrackingSentinel TS;
+  NoTrackingSentinel NTS;
+  EXPECT_TRUE(TS.isSentinel());
+  EXPECT_TRUE(TS.isKnownSentinel());
+  EXPECT_FALSE(NTS.isKnownSentinel());
 }
 
 TEST(IListSentinelTest, NormalNodeIsNotKnownSentinel) {
@@ -37,6 +55,9 @@ TEST(IListSentinelTest, NormalNodeIsNotK
   EXPECT_EQ(nullptr, LocalAccess::getPrev(N));
   EXPECT_EQ(nullptr, LocalAccess::getNext(N));
   EXPECT_FALSE(N.isKnownSentinel());
+
+  TrackingNode TN;
+  EXPECT_FALSE(TN.isSentinel());
 }
 
 } // end namespace

Modified: llvm/trunk/unittests/ADT/SimpleIListTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/SimpleIListTest.cpp?rev=281167&r1=281166&r2=281167&view=diff
==============================================================================
--- llvm/trunk/unittests/ADT/SimpleIListTest.cpp (original)
+++ llvm/trunk/unittests/ADT/SimpleIListTest.cpp Sun Sep 11 11:20:53 2016
@@ -583,4 +583,55 @@ TEST(SimpleIListTest, sortEmpty) {
   L.sort();
 }
 
+struct Tag1 {};
+struct Tag2 {};
+
+struct DoubleNode : ilist_node<DoubleNode, ilist_tag<Tag1>>,
+                    ilist_node<DoubleNode, ilist_tag<Tag2>> {
+  typedef ilist_node<DoubleNode, ilist_tag<Tag1>> Node1Type;
+  typedef ilist_node<DoubleNode, ilist_tag<Tag2>> Node2Type;
+
+  Node1Type::self_iterator getIterator1() { return Node1Type::getIterator(); }
+  Node2Type::self_iterator getIterator2() { return Node2Type::getIterator(); }
+  Node1Type::const_self_iterator getIterator1() const {
+    return Node1Type::getIterator();
+  }
+  Node2Type::const_self_iterator getIterator2() const {
+    return Node2Type::getIterator();
+  }
+};
+typedef simple_ilist<DoubleNode, ilist_tag<Tag1>> TaggedList1Type;
+typedef simple_ilist<DoubleNode, ilist_tag<Tag2>> TaggedList2Type;
+
+TEST(SimpleIListTest, TaggedLists) {
+  TaggedList1Type L1;
+  TaggedList2Type L2;
+
+  // Build the two lists, sharing a couple of nodes.
+  DoubleNode Ns[10];
+  int Order1[] = {0, 1, 2, 3, 4, 7, 9};
+  int Order2[] = {2, 5, 6, 7, 8, 4, 9, 1};
+  for (int I : Order1)
+    L1.push_back(Ns[I]);
+  for (int I : Order2)
+    L2.push_back(Ns[I]);
+
+  // Check that each list is correct.
+  EXPECT_EQ(sizeof(Order1) / sizeof(int), L1.size());
+  auto I1 = L1.begin();
+  for (int I : Order1) {
+    EXPECT_EQ(Ns[I].getIterator1(), I1);
+    EXPECT_EQ(&Ns[I], &*I1++);
+  }
+  EXPECT_EQ(L1.end(), I1);
+
+  EXPECT_EQ(sizeof(Order2) / sizeof(int), L2.size());
+  auto I2 = L2.begin();
+  for (int I : Order2) {
+    EXPECT_EQ(Ns[I].getIterator2(), I2);
+    EXPECT_EQ(&Ns[I], &*I2++);
+  }
+  EXPECT_EQ(L2.end(), I2);
+}
+
 } // end namespace




More information about the llvm-commits mailing list