Skip to content

Commit

Permalink
ADT: Add sentinel tracking and custom tags to ilists
Browse files Browse the repository at this point in the history
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>).

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@281167 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
dexonsmith committed Sep 11, 2016
1 parent 990fea5 commit b4bd34e
Show file tree
Hide file tree
Showing 14 changed files with 642 additions and 156 deletions.
13 changes: 9 additions & 4 deletions include/llvm/ADT/ilist.h
Original file line number Diff line number Diff line change
Expand Up @@ -362,13 +362,18 @@ class iplist_impl : public TraitsT, IntrusiveListT {

/// 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;
Expand Down
6 changes: 3 additions & 3 deletions include/llvm/ADT/ilist_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
105 changes: 60 additions & 45 deletions include/llvm/ADT/ilist_iterator.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,21 @@ namespace llvm {

namespace ilist_detail {

template <class NodeTy> struct ConstCorrectNodeType {
typedef 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 NodeTy> struct ConstCorrectNodeType<const NodeTy> {
typedef const ilist_node<NodeTy> type;
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;
Expand All @@ -42,28 +52,29 @@ template <> struct IteratorHelper<true> : ilist_detail::NodeAccess {
} // 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:
Expand All @@ -76,30 +87,38 @@ class ilist_iterator : ilist_detail::SpecificNodeAccess<

// 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;
}

/// Convert from an iterator to its reverse.
///
/// 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; }
Expand All @@ -121,11 +140,11 @@ class ilist_iterator : ilist_detail::SpecificNodeAccess<

// 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) {
Expand All @@ -149,20 +168,16 @@ template <typename From> struct simplify_type;
/// 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;
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(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;
}
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

Expand Down
Loading

0 comments on commit b4bd34e

Please sign in to comment.