Skip to content

Commit 0863bd8

Browse files
authored
[LLVM] Add option to store Parent-pointer in ilist_node_base (llvm#94224)
This patch adds a new option for `ilist`, `ilist_parent<ParentTy>`, that enables storing an additional pointer in the `ilist_node_base` type to a specified "parent" type, and uses that option for `Instruction`. This is distinct from the `ilist_node_with_parent` class, despite their apparent similarities. The `ilist_node_with_parent` class is a subclass of `ilist_node` that requires its own subclasses to define a `getParent` method, which is then used by the owning `ilist` for some of its operations; it is purely an interface declaration. The `ilist_parent` option on the other hand is concerned with data, adding a parent field to the `ilist_node_base` class. Currently, we can use `BasicBlock::iterator` to insert instructions, _except_ when either the iterator is invalid (`NodePtr=0x0`), or when the iterator points to a sentinel value (`BasicBlock::end()`). This patch results in the sentinel value also having a valid pointer to its owning basic block, which allows us to use iterators for all insertions, without needing to store or pass an extra `BasicBlock *BB` argument alongside it.
1 parent 89fd195 commit 0863bd8

15 files changed

+345
-63
lines changed

llvm/include/llvm/ADT/ilist_base.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@
1515
namespace llvm {
1616

1717
/// Implementations of list algorithms using ilist_node_base.
18-
template <bool EnableSentinelTracking> class ilist_base {
18+
template <bool EnableSentinelTracking, class ParentPtrTy> class ilist_base {
1919
public:
20-
using node_base_type = ilist_node_base<EnableSentinelTracking>;
20+
using node_base_type = ilist_node_base<EnableSentinelTracking, ParentPtrTy>;
2121

2222
static void insertBeforeImpl(node_base_type &Next, node_base_type &N) {
2323
node_base_type &Prev = *Next.getPrev();

llvm/include/llvm/ADT/ilist_iterator.h

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,44 @@ template <> struct IteratorHelper<true> : ilist_detail::NodeAccess {
5050
template <class T> static void decrement(T *&I) { I = Access::getNext(*I); }
5151
};
5252

53+
/// Mixin class used to add a \a getNodeParent() function to iterators iff the
54+
/// list uses \a ilist_parent, calling through to the node's \a getParent(). For
55+
/// more details see \a ilist_node.
56+
template <class IteratorTy, class ParentPtrTy, bool IsConst>
57+
class iterator_parent_access;
58+
template <class IteratorTy, class ParentPtrTy>
59+
class iterator_parent_access<IteratorTy, ParentPtrTy, true> {
60+
public:
61+
inline const ParentPtrTy getNodeParent() const {
62+
return static_cast<IteratorTy *>(this)->NodePtr->getParent();
63+
}
64+
};
65+
template <class IteratorTy, class ParentPtrTy>
66+
class iterator_parent_access<IteratorTy, ParentPtrTy, false> {
67+
public:
68+
inline ParentPtrTy getNodeParent() {
69+
return static_cast<IteratorTy *>(this)->NodePtr->getParent();
70+
}
71+
};
72+
template <class IteratorTy>
73+
class iterator_parent_access<IteratorTy, void, true> {};
74+
template <class IteratorTy>
75+
class iterator_parent_access<IteratorTy, void, false> {};
76+
5377
} // end namespace ilist_detail
5478

5579
/// Iterator for intrusive lists based on ilist_node.
5680
template <class OptionsT, bool IsReverse, bool IsConst>
57-
class ilist_iterator : ilist_detail::SpecificNodeAccess<OptionsT> {
81+
class ilist_iterator : ilist_detail::SpecificNodeAccess<OptionsT>,
82+
public ilist_detail::iterator_parent_access<
83+
ilist_iterator<OptionsT, IsReverse, IsConst>,
84+
typename OptionsT::parent_ptr_ty, IsConst> {
5885
friend ilist_iterator<OptionsT, IsReverse, !IsConst>;
5986
friend ilist_iterator<OptionsT, !IsReverse, IsConst>;
6087
friend ilist_iterator<OptionsT, !IsReverse, !IsConst>;
88+
friend ilist_detail::iterator_parent_access<
89+
ilist_iterator<OptionsT, IsReverse, IsConst>,
90+
typename OptionsT::parent_ptr_ty, IsConst>;
6191

6292
using Traits = ilist_detail::IteratorTraits<OptionsT, IsConst>;
6393
using Access = ilist_detail::SpecificNodeAccess<OptionsT>;
@@ -168,6 +198,8 @@ class ilist_iterator : ilist_detail::SpecificNodeAccess<OptionsT> {
168198
return tmp;
169199
}
170200

201+
bool isValid() const { return NodePtr; }
202+
171203
/// Get the underlying ilist_node.
172204
node_pointer getNodePtr() const { return static_cast<node_pointer>(NodePtr); }
173205

@@ -179,10 +211,17 @@ class ilist_iterator : ilist_detail::SpecificNodeAccess<OptionsT> {
179211
/// but with the addition of two bits recording whether this position (when in
180212
/// a range) is half or fully open.
181213
template <class OptionsT, bool IsReverse, bool IsConst>
182-
class ilist_iterator_w_bits : ilist_detail::SpecificNodeAccess<OptionsT> {
214+
class ilist_iterator_w_bits
215+
: ilist_detail::SpecificNodeAccess<OptionsT>,
216+
public ilist_detail::iterator_parent_access<
217+
ilist_iterator_w_bits<OptionsT, IsReverse, IsConst>,
218+
typename OptionsT::parent_ptr_ty, IsConst> {
183219
friend ilist_iterator_w_bits<OptionsT, IsReverse, !IsConst>;
184220
friend ilist_iterator_w_bits<OptionsT, !IsReverse, IsConst>;
185221
friend ilist_iterator<OptionsT, !IsReverse, !IsConst>;
222+
friend ilist_detail::iterator_parent_access<
223+
ilist_iterator_w_bits<OptionsT, IsReverse, IsConst>,
224+
typename OptionsT::parent_ptr_ty, IsConst>;
186225

187226
using Traits = ilist_detail::IteratorTraits<OptionsT, IsConst>;
188227
using Access = ilist_detail::SpecificNodeAccess<OptionsT>;
@@ -319,6 +358,8 @@ class ilist_iterator_w_bits : ilist_detail::SpecificNodeAccess<OptionsT> {
319358
return tmp;
320359
}
321360

361+
bool isValid() const { return NodePtr; }
362+
322363
/// Get the underlying ilist_node.
323364
node_pointer getNodePtr() const { return static_cast<node_pointer>(NodePtr); }
324365

llvm/include/llvm/ADT/ilist_node.h

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,23 @@ namespace ilist_detail {
2424

2525
struct NodeAccess;
2626

27+
/// Mixin base class that is used to add \a getParent() and
28+
/// \a setParent(ParentPtrTy) methods to \a ilist_node_impl iff \a ilist_parent
29+
/// has been set in the list options.
30+
template <class NodeTy, class ParentPtrTy> class node_parent_access {
31+
public:
32+
inline const ParentPtrTy getParent() const {
33+
return static_cast<const NodeTy *>(this)->getNodeBaseParent();
34+
}
35+
inline ParentPtrTy getParent() {
36+
return static_cast<NodeTy *>(this)->getNodeBaseParent();
37+
}
38+
void setParent(ParentPtrTy Parent) {
39+
return static_cast<NodeTy *>(this)->setNodeBaseParent(Parent);
40+
}
41+
};
42+
template <class NodeTy> class node_parent_access<NodeTy, void> {};
43+
2744
} // end namespace ilist_detail
2845

2946
template <class OptionsT, bool IsReverse, bool IsConst> class ilist_iterator;
@@ -51,7 +68,11 @@ class ilist_select_iterator_type<true, Opts, arg1, arg2> {
5168
/// This is a wrapper around \a ilist_node_base whose main purpose is to
5269
/// provide type safety: you can't insert nodes of \a ilist_node_impl into the
5370
/// wrong \a simple_ilist or \a iplist.
54-
template <class OptionsT> class ilist_node_impl : OptionsT::node_base_type {
71+
template <class OptionsT>
72+
class ilist_node_impl
73+
: OptionsT::node_base_type,
74+
public ilist_detail::node_parent_access<
75+
ilist_node_impl<OptionsT>, typename OptionsT::parent_ptr_ty> {
5576
using value_type = typename OptionsT::value_type;
5677
using node_base_type = typename OptionsT::node_base_type;
5778
using list_base_type = typename OptionsT::list_base_type;
@@ -60,6 +81,8 @@ template <class OptionsT> class ilist_node_impl : OptionsT::node_base_type {
6081
friend struct ilist_detail::NodeAccess;
6182
friend class ilist_sentinel<OptionsT>;
6283

84+
friend class ilist_detail::node_parent_access<
85+
ilist_node_impl<OptionsT>, typename OptionsT::parent_ptr_ty>;
6386
friend class ilist_iterator<OptionsT, false, false>;
6487
friend class ilist_iterator<OptionsT, false, true>;
6588
friend class ilist_iterator<OptionsT, true, false>;
@@ -171,6 +194,20 @@ template <class OptionsT> class ilist_node_impl : OptionsT::node_base_type {
171194
/// }
172195
/// \endexample
173196
///
197+
/// When the \a ilist_parent<ParentTy> option is passed to an ilist_node and the
198+
/// owning ilist, each node contains a pointer to the ilist's owner. This adds
199+
/// \a getParent() and \a setParent(ParentTy*) methods to the ilist_node, which
200+
/// will be used for node access by the ilist if the node class publicly
201+
/// inherits from \a ilist_node_with_parent. By default, setParent() is not
202+
/// automatically called by the ilist; a SymbolTableList will call setParent()
203+
/// on inserted nodes, but the sentinel must still be manually set after the
204+
/// list is created (e.g. SymTabList.end()->setParent(Parent)).
205+
///
206+
/// The primary benefit of using ilist_parent is that a parent
207+
/// pointer will be stored in the sentinel, meaning that you can safely use \a
208+
/// ilist_iterator::getNodeParent() to get the node parent from any valid (i.e.
209+
/// non-null) iterator, even one that points to a sentinel value.
210+
///
174211
/// See \a is_valid_option for steps on adding a new option.
175212
template <class T, class... Options>
176213
class ilist_node

llvm/include/llvm/ADT/ilist_node_base.h

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,40 +13,61 @@
1313

1414
namespace llvm {
1515

16-
/// Base class for ilist nodes.
17-
///
18-
/// Optionally tracks whether this node is the sentinel.
19-
template <bool EnableSentinelTracking> class ilist_node_base;
16+
namespace ilist_detail {
17+
18+
template <class NodeBase, bool EnableSentinelTracking> class node_base_prevnext;
2019

21-
template <> class ilist_node_base<false> {
22-
ilist_node_base *Prev = nullptr;
23-
ilist_node_base *Next = nullptr;
20+
template <class NodeBase> class node_base_prevnext<NodeBase, false> {
21+
NodeBase *Prev = nullptr;
22+
NodeBase *Next = nullptr;
2423

2524
public:
26-
void setPrev(ilist_node_base *Prev) { this->Prev = Prev; }
27-
void setNext(ilist_node_base *Next) { this->Next = Next; }
28-
ilist_node_base *getPrev() const { return Prev; }
29-
ilist_node_base *getNext() const { return Next; }
25+
void setPrev(NodeBase *Prev) { this->Prev = Prev; }
26+
void setNext(NodeBase *Next) { this->Next = Next; }
27+
NodeBase *getPrev() const { return Prev; }
28+
NodeBase *getNext() const { return Next; }
3029

3130
bool isKnownSentinel() const { return false; }
3231
void initializeSentinel() {}
3332
};
3433

35-
template <> class ilist_node_base<true> {
36-
PointerIntPair<ilist_node_base *, 1> PrevAndSentinel;
37-
ilist_node_base *Next = nullptr;
34+
template <class NodeBase> class node_base_prevnext<NodeBase, true> {
35+
PointerIntPair<NodeBase *, 1> PrevAndSentinel;
36+
NodeBase *Next = nullptr;
3837

3938
public:
40-
void setPrev(ilist_node_base *Prev) { PrevAndSentinel.setPointer(Prev); }
41-
void setNext(ilist_node_base *Next) { this->Next = Next; }
42-
ilist_node_base *getPrev() const { return PrevAndSentinel.getPointer(); }
43-
ilist_node_base *getNext() const { return Next; }
39+
void setPrev(NodeBase *Prev) { PrevAndSentinel.setPointer(Prev); }
40+
void setNext(NodeBase *Next) { this->Next = Next; }
41+
NodeBase *getPrev() const { return PrevAndSentinel.getPointer(); }
42+
NodeBase *getNext() const { return Next; }
4443

4544
bool isSentinel() const { return PrevAndSentinel.getInt(); }
4645
bool isKnownSentinel() const { return isSentinel(); }
4746
void initializeSentinel() { PrevAndSentinel.setInt(true); }
4847
};
4948

49+
template <class ParentPtrTy> class node_base_parent {
50+
ParentPtrTy Parent = nullptr;
51+
52+
public:
53+
void setNodeBaseParent(ParentPtrTy Parent) { this->Parent = Parent; }
54+
inline const ParentPtrTy getNodeBaseParent() const { return Parent; }
55+
inline ParentPtrTy getNodeBaseParent() { return Parent; }
56+
};
57+
template <> class node_base_parent<void> {};
58+
59+
} // end namespace ilist_detail
60+
61+
/// Base class for ilist nodes.
62+
///
63+
/// Optionally tracks whether this node is the sentinel.
64+
template <bool EnableSentinelTracking, class ParentPtrTy>
65+
class ilist_node_base
66+
: public ilist_detail::node_base_prevnext<
67+
ilist_node_base<EnableSentinelTracking, ParentPtrTy>,
68+
EnableSentinelTracking>,
69+
public ilist_detail::node_base_parent<ParentPtrTy> {};
70+
5071
} // end namespace llvm
5172

5273
#endif // LLVM_ADT_ILIST_NODE_BASE_H

llvm/include/llvm/ADT/ilist_node_options.h

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515

1616
namespace llvm {
1717

18-
template <bool EnableSentinelTracking> class ilist_node_base;
19-
template <bool EnableSentinelTracking> class ilist_base;
18+
template <bool EnableSentinelTracking, class ParentPtrTy> class ilist_node_base;
19+
template <bool EnableSentinelTracking, class ParentPtrTy> class ilist_base;
2020

2121
/// Option to choose whether to track sentinels.
2222
///
@@ -39,6 +39,19 @@ template <class Tag> struct ilist_tag {};
3939
/// iterator class to store that information.
4040
template <bool ExtraIteratorBits> struct ilist_iterator_bits {};
4141

42+
/// Option to add a pointer to this list's owner in every node.
43+
///
44+
/// This option causes the \a ilist_base_node for this list to contain a pointer
45+
/// ParentTy *Parent, returned by \a ilist_base_node::getNodeBaseParent() and
46+
/// set by \a ilist_base_node::setNodeBaseParent(ParentTy *Parent). The parent
47+
/// value is not set automatically; the ilist owner should set itself as the
48+
/// parent of the list sentinel, and the parent should be set on each node
49+
/// inserted into the list. This value is also not used by
50+
/// \a ilist_node_with_parent::getNodeParent(), but is used by \a
51+
/// ilist_iterator::getNodeParent(), which allows the parent to be fetched from
52+
/// any valid (non-null) iterator to this list, including the sentinel.
53+
template <class ParentTy> struct ilist_parent {};
54+
4255
namespace ilist_detail {
4356

4457
/// Helper trait for recording whether an option is specified explicitly.
@@ -114,6 +127,21 @@ template <> struct extract_iterator_bits<> : std::false_type, is_implicit {};
114127
template <bool IteratorBits>
115128
struct is_valid_option<ilist_iterator_bits<IteratorBits>> : std::true_type {};
116129

130+
/// Extract node parent option.
131+
///
132+
/// Look through \p Options for the \a ilist_parent option, pulling out the
133+
/// custom parent type, using void as a default.
134+
template <class... Options> struct extract_parent;
135+
template <class ParentTy, class... Options>
136+
struct extract_parent<ilist_parent<ParentTy>, Options...> {
137+
typedef ParentTy *type;
138+
};
139+
template <class Option1, class... Options>
140+
struct extract_parent<Option1, Options...> : extract_parent<Options...> {};
141+
template <> struct extract_parent<> { typedef void type; };
142+
template <class ParentTy>
143+
struct is_valid_option<ilist_parent<ParentTy>> : std::true_type {};
144+
117145
/// Check whether options are valid.
118146
///
119147
/// The conjunction of \a is_valid_option on each individual option.
@@ -128,7 +156,7 @@ struct check_options<Option1, Options...>
128156
///
129157
/// This is usually computed via \a compute_node_options.
130158
template <class T, bool EnableSentinelTracking, bool IsSentinelTrackingExplicit,
131-
class TagT, bool HasIteratorBits>
159+
class TagT, bool HasIteratorBits, class ParentPtrTy>
132160
struct node_options {
133161
typedef T value_type;
134162
typedef T *pointer;
@@ -140,15 +168,18 @@ struct node_options {
140168
static const bool is_sentinel_tracking_explicit = IsSentinelTrackingExplicit;
141169
static const bool has_iterator_bits = HasIteratorBits;
142170
typedef TagT tag;
143-
typedef ilist_node_base<enable_sentinel_tracking> node_base_type;
144-
typedef ilist_base<enable_sentinel_tracking> list_base_type;
171+
typedef ParentPtrTy parent_ptr_ty;
172+
typedef ilist_node_base<enable_sentinel_tracking, parent_ptr_ty>
173+
node_base_type;
174+
typedef ilist_base<enable_sentinel_tracking, parent_ptr_ty> list_base_type;
145175
};
146176

147177
template <class T, class... Options> struct compute_node_options {
148178
typedef node_options<T, extract_sentinel_tracking<Options...>::value,
149179
extract_sentinel_tracking<Options...>::is_explicit,
150180
typename extract_tag<Options...>::type,
151-
extract_iterator_bits<Options...>::value>
181+
extract_iterator_bits<Options...>::value,
182+
typename extract_parent<Options...>::type>
152183
type;
153184
};
154185

llvm/include/llvm/IR/BasicBlock.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ class DbgMarker;
5959
class BasicBlock final : public Value, // Basic blocks are data objects also
6060
public ilist_node_with_parent<BasicBlock, Function> {
6161
public:
62-
using InstListType = SymbolTableList<Instruction, ilist_iterator_bits<true>>;
62+
using InstListType = SymbolTableList<Instruction, ilist_iterator_bits<true>,
63+
ilist_parent<BasicBlock>>;
6364
/// Flag recording whether or not this block stores debug-info in the form
6465
/// of intrinsic instructions (false) or non-instruction records (true).
6566
bool IsNewDbgInfoFormat;
@@ -172,10 +173,11 @@ class BasicBlock final : public Value, // Basic blocks are data objects also
172173
friend BasicBlock::iterator Instruction::eraseFromParent();
173174
friend BasicBlock::iterator Instruction::insertInto(BasicBlock *BB,
174175
BasicBlock::iterator It);
175-
friend class llvm::SymbolTableListTraits<llvm::Instruction,
176-
ilist_iterator_bits<true>>;
176+
friend class llvm::SymbolTableListTraits<
177+
llvm::Instruction, ilist_iterator_bits<true>, ilist_parent<BasicBlock>>;
177178
friend class llvm::ilist_node_with_parent<llvm::Instruction, llvm::BasicBlock,
178-
ilist_iterator_bits<true>>;
179+
ilist_iterator_bits<true>,
180+
ilist_parent<BasicBlock>>;
179181

180182
// Friendly methods that need to access us for the maintenence of
181183
// debug-info attachments.

llvm/include/llvm/IR/Instruction.h

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,13 @@ getDbgRecordRange(DbgMarker *);
4646

4747
class Instruction : public User,
4848
public ilist_node_with_parent<Instruction, BasicBlock,
49-
ilist_iterator_bits<true>> {
49+
ilist_iterator_bits<true>,
50+
ilist_parent<BasicBlock>> {
5051
public:
51-
using InstListType = SymbolTableList<Instruction, ilist_iterator_bits<true>>;
52+
using InstListType = SymbolTableList<Instruction, ilist_iterator_bits<true>,
53+
ilist_parent<BasicBlock>>;
54+
5255
private:
53-
BasicBlock *Parent;
5456
DebugLoc DbgLoc; // 'dbg' Metadata cache.
5557

5658
/// Relative order of this instruction in its parent basic block. Used for
@@ -149,9 +151,6 @@ class Instruction : public User,
149151
Instruction *user_back() { return cast<Instruction>(*user_begin());}
150152
const Instruction *user_back() const { return cast<Instruction>(*user_begin());}
151153

152-
inline const BasicBlock *getParent() const { return Parent; }
153-
inline BasicBlock *getParent() { return Parent; }
154-
155154
/// Return the module owning the function this instruction belongs to
156155
/// or nullptr it the function does not have a module.
157156
///
@@ -980,7 +979,8 @@ class Instruction : public User,
980979
};
981980

982981
private:
983-
friend class SymbolTableListTraits<Instruction, ilist_iterator_bits<true>>;
982+
friend class SymbolTableListTraits<Instruction, ilist_iterator_bits<true>,
983+
ilist_parent<BasicBlock>>;
984984
friend class BasicBlock; // For renumbering.
985985

986986
// Shadow Value::setValueSubclassData with a private forwarding method so that
@@ -993,8 +993,6 @@ class Instruction : public User,
993993
return Value::getSubclassDataFromValue();
994994
}
995995

996-
void setParent(BasicBlock *P);
997-
998996
protected:
999997
// Instruction subclasses can stick up to 15 bits of stuff into the
1000998
// SubclassData field of instruction with these members.

0 commit comments

Comments
 (0)