Skip to content

Commit 088d272

Browse files
committed
[ADT][DebugInfo][RemoveDIs] Add extra bits to ilist_iterator for debug-info
...behind an experimental CMAKE option that's off by default. This patch adds a new ilist-iterator-like class that can carry two extra bits as well as the usual node pointer. This is part of the project to remove debug-intrinsics from LLVM: see the rationale here [0], they're needed to signal whether a "position" in a BasicBlock includes any debug-info before or after the iterator. This entirely duplicates ilist_iterator, attempting re-use showed it to be a false economy. It's enable-able through the existing ilist_node options interface, hence a few sites where the instruction-list type needs to be updated. The actual main feature, the extra bits in the class, aren't part of the class unless the cmake flag is given: this is because there's a compile-time cost associated with it, and I'd like to get everything in-tree but off-by-default so that we can do proper comparisons. Nothing actually makes use of this yet, but will do soon, see the Phab patch stack. [0] https://discourse.llvm.org/t/rfc-instruction-api-changes-needed-to-eliminate-debug-intrinsics-from-ir/68939 Differential Revision: https://reviews.llvm.org/D153777
1 parent 81d8fa5 commit 088d272

20 files changed

+483
-56
lines changed

llvm/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,9 @@ option(LLVM_USE_OPROFILE
643643
option(LLVM_EXTERNALIZE_DEBUGINFO
644644
"Generate dSYM files and strip executables and libraries (Darwin Only)" OFF)
645645

646+
option(LLVM_EXPERIMENTAL_DEBUGINFO_ITERATORS
647+
"Add extra Booleans to ilist_iterators to communicate facts for debug-info" OFF)
648+
646649
set(LLVM_CODESIGNING_IDENTITY "" CACHE STRING
647650
"Sign executables and dylibs with the given identity or skip if empty (Darwin Only)")
648651

llvm/cmake/modules/HandleLLVMOptions.cmake

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ if(LLVM_ENABLE_EXPENSIVE_CHECKS)
109109
endif()
110110
endif()
111111

112+
if(LLVM_EXPERIMENTAL_DEBUGINFO_ITERATORS)
113+
add_compile_definitions(EXPERIMENTAL_DEBUGINFO_ITERATORS)
114+
endif()
115+
112116
if (LLVM_ENABLE_STRICT_FIXED_SIZE_VECTORS)
113117
add_compile_definitions(STRICT_FIXED_SIZE_VECTORS)
114118
endif()

llvm/include/llvm/ADT/ilist_iterator.h

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,185 @@ class ilist_iterator : ilist_detail::SpecificNodeAccess<OptionsT> {
175175
bool isEnd() const { return NodePtr ? NodePtr->isSentinel() : false; }
176176
};
177177

178+
/// Iterator for intrusive lists based on ilist_node. Much like ilist_iterator,
179+
/// but with the addition of two bits recording whether this position (when in
180+
/// a range) is half or fully open.
181+
template <class OptionsT, bool IsReverse, bool IsConst>
182+
class ilist_iterator_w_bits : ilist_detail::SpecificNodeAccess<OptionsT> {
183+
friend ilist_iterator_w_bits<OptionsT, IsReverse, !IsConst>;
184+
friend ilist_iterator_w_bits<OptionsT, !IsReverse, IsConst>;
185+
friend ilist_iterator<OptionsT, !IsReverse, !IsConst>;
186+
187+
using Traits = ilist_detail::IteratorTraits<OptionsT, IsConst>;
188+
using Access = ilist_detail::SpecificNodeAccess<OptionsT>;
189+
190+
public:
191+
using value_type = typename Traits::value_type;
192+
using pointer = typename Traits::pointer;
193+
using reference = typename Traits::reference;
194+
using difference_type = ptrdiff_t;
195+
using iterator_category = std::bidirectional_iterator_tag;
196+
using const_pointer = typename OptionsT::const_pointer;
197+
using const_reference = typename OptionsT::const_reference;
198+
199+
private:
200+
using node_pointer = typename Traits::node_pointer;
201+
using node_reference = typename Traits::node_reference;
202+
203+
node_pointer NodePtr = nullptr;
204+
205+
#ifdef EXPERIMENTAL_DEBUGINFO_ITERATORS
206+
// (Default: Off) Allow extra position-information flags to be stored
207+
// in iterators, in aid of removing debug-info intrinsics from LLVM.
208+
209+
/// Is this position intended to contain any debug-info immediately before
210+
/// the position?
211+
mutable bool HeadInclusiveBit = false;
212+
/// Is this position intended to contain any debug-info immediately after
213+
/// the position?
214+
mutable bool TailInclusiveBit = false;
215+
#endif
216+
217+
public:
218+
/// Create from an ilist_node.
219+
explicit ilist_iterator_w_bits(node_reference N) : NodePtr(&N) {}
220+
221+
explicit ilist_iterator_w_bits(pointer NP)
222+
: NodePtr(Access::getNodePtr(NP)) {}
223+
explicit ilist_iterator_w_bits(reference NR)
224+
: NodePtr(Access::getNodePtr(&NR)) {}
225+
ilist_iterator_w_bits() = default;
226+
227+
// This is templated so that we can allow constructing a const iterator from
228+
// a nonconst iterator...
229+
template <bool RHSIsConst>
230+
ilist_iterator_w_bits(
231+
const ilist_iterator_w_bits<OptionsT, IsReverse, RHSIsConst> &RHS,
232+
std::enable_if_t<IsConst || !RHSIsConst, void *> = nullptr)
233+
: NodePtr(RHS.NodePtr) {
234+
#ifdef EXPERIMENTAL_DEBUGINFO_ITERATORS
235+
HeadInclusiveBit = RHS.HeadInclusiveBit;
236+
TailInclusiveBit = RHS.TailInclusiveBit;
237+
#endif
238+
}
239+
240+
// This is templated so that we can allow assigning to a const iterator from
241+
// a nonconst iterator...
242+
template <bool RHSIsConst>
243+
std::enable_if_t<IsConst || !RHSIsConst, ilist_iterator_w_bits &>
244+
operator=(const ilist_iterator_w_bits<OptionsT, IsReverse, RHSIsConst> &RHS) {
245+
NodePtr = RHS.NodePtr;
246+
#ifdef EXPERIMENTAL_DEBUGINFO_ITERATORS
247+
HeadInclusiveBit = RHS.HeadInclusiveBit;
248+
TailInclusiveBit = RHS.TailInclusiveBit;
249+
#endif
250+
return *this;
251+
}
252+
253+
/// Explicit conversion between forward/reverse iterators.
254+
///
255+
/// Translate between forward and reverse iterators without changing range
256+
/// boundaries. The resulting iterator will dereference (and have a handle)
257+
/// to the previous node, which is somewhat unexpected; but converting the
258+
/// two endpoints in a range will give the same range in reverse.
259+
///
260+
/// This matches std::reverse_iterator conversions.
261+
explicit ilist_iterator_w_bits(
262+
const ilist_iterator_w_bits<OptionsT, !IsReverse, IsConst> &RHS)
263+
: ilist_iterator_w_bits(++RHS.getReverse()) {}
264+
265+
/// Get a reverse iterator to the same node.
266+
///
267+
/// Gives a reverse iterator that will dereference (and have a handle) to the
268+
/// same node. Converting the endpoint iterators in a range will give a
269+
/// different range; for range operations, use the explicit conversions.
270+
ilist_iterator_w_bits<OptionsT, !IsReverse, IsConst> getReverse() const {
271+
if (NodePtr)
272+
return ilist_iterator_w_bits<OptionsT, !IsReverse, IsConst>(*NodePtr);
273+
return ilist_iterator_w_bits<OptionsT, !IsReverse, IsConst>();
274+
}
275+
276+
/// Const-cast.
277+
ilist_iterator_w_bits<OptionsT, IsReverse, false> getNonConst() const {
278+
if (NodePtr) {
279+
auto New = ilist_iterator_w_bits<OptionsT, IsReverse, false>(
280+
const_cast<typename ilist_iterator_w_bits<OptionsT, IsReverse,
281+
false>::node_reference>(
282+
*NodePtr));
283+
#ifdef EXPERIMENTAL_DEBUGINFO_ITERATORS
284+
New.HeadInclusiveBit = HeadInclusiveBit;
285+
New.TailInclusiveBit = TailInclusiveBit;
286+
#endif
287+
return New;
288+
}
289+
return ilist_iterator_w_bits<OptionsT, IsReverse, false>();
290+
}
291+
292+
// Accessors...
293+
reference operator*() const {
294+
assert(!NodePtr->isKnownSentinel());
295+
return *Access::getValuePtr(NodePtr);
296+
}
297+
pointer operator->() const { return &operator*(); }
298+
299+
// Comparison operators
300+
friend bool operator==(const ilist_iterator_w_bits &LHS,
301+
const ilist_iterator_w_bits &RHS) {
302+
return LHS.NodePtr == RHS.NodePtr;
303+
}
304+
friend bool operator!=(const ilist_iterator_w_bits &LHS,
305+
const ilist_iterator_w_bits &RHS) {
306+
return LHS.NodePtr != RHS.NodePtr;
307+
}
308+
309+
// Increment and decrement operators...
310+
ilist_iterator_w_bits &operator--() {
311+
NodePtr = IsReverse ? NodePtr->getNext() : NodePtr->getPrev();
312+
#ifdef EXPERIMENTAL_DEBUGINFO_ITERATORS
313+
HeadInclusiveBit = false;
314+
TailInclusiveBit = false;
315+
#endif
316+
return *this;
317+
}
318+
ilist_iterator_w_bits &operator++() {
319+
NodePtr = IsReverse ? NodePtr->getPrev() : NodePtr->getNext();
320+
#ifdef EXPERIMENTAL_DEBUGINFO_ITERATORS
321+
HeadInclusiveBit = false;
322+
TailInclusiveBit = false;
323+
#endif
324+
return *this;
325+
}
326+
ilist_iterator_w_bits operator--(int) {
327+
ilist_iterator_w_bits tmp = *this;
328+
--*this;
329+
return tmp;
330+
}
331+
ilist_iterator_w_bits operator++(int) {
332+
ilist_iterator_w_bits tmp = *this;
333+
++*this;
334+
return tmp;
335+
}
336+
337+
/// Get the underlying ilist_node.
338+
node_pointer getNodePtr() const { return static_cast<node_pointer>(NodePtr); }
339+
340+
/// Check for end. Only valid if ilist_sentinel_tracking<true>.
341+
bool isEnd() const { return NodePtr ? NodePtr->isSentinel() : false; }
342+
343+
#ifdef EXPERIMENTAL_DEBUGINFO_ITERATORS
344+
bool getHeadBit() const { return HeadInclusiveBit; }
345+
bool getTailBit() const { return TailInclusiveBit; }
346+
void setHeadBit(bool SetBit) const { HeadInclusiveBit = SetBit; }
347+
void setTailBit(bool SetBit) const { TailInclusiveBit = SetBit; }
348+
#else
349+
// Store and return no information if we're not using this feature.
350+
bool getHeadBit() const { return false; }
351+
bool getTailBit() const { return false; }
352+
void setHeadBit(bool SetBit) const { (void)SetBit; }
353+
void setTailBit(bool SetBit) const { (void)SetBit; }
354+
#endif
355+
};
356+
178357
template <typename From> struct simplify_type;
179358

180359
/// Allow ilist_iterators to convert into pointers to a node automatically when
@@ -192,6 +371,18 @@ template <class OptionsT, bool IsConst>
192371
struct simplify_type<const ilist_iterator<OptionsT, false, IsConst>>
193372
: simplify_type<ilist_iterator<OptionsT, false, IsConst>> {};
194373

374+
// ilist_iterator_w_bits should also be accessible via isa/dyn_cast.
375+
template <class OptionsT, bool IsConst>
376+
struct simplify_type<ilist_iterator_w_bits<OptionsT, false, IsConst>> {
377+
using iterator = ilist_iterator_w_bits<OptionsT, false, IsConst>;
378+
using SimpleType = typename iterator::pointer;
379+
380+
static SimpleType getSimplifiedValue(const iterator &Node) { return &*Node; }
381+
};
382+
template <class OptionsT, bool IsConst>
383+
struct simplify_type<const ilist_iterator_w_bits<OptionsT, false, IsConst>>
384+
: simplify_type<ilist_iterator_w_bits<OptionsT, false, IsConst>> {};
385+
195386
} // end namespace llvm
196387

197388
#endif // LLVM_ADT_ILIST_ITERATOR_H

llvm/include/llvm/ADT/ilist_node.h

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,22 @@ struct NodeAccess;
2727
} // end namespace ilist_detail
2828

2929
template <class OptionsT, bool IsReverse, bool IsConst> class ilist_iterator;
30+
template <class OptionsT, bool IsReverse, bool IsConst>
31+
class ilist_iterator_w_bits;
3032
template <class OptionsT> class ilist_sentinel;
3133

34+
// Selector for which iterator type to pick given the iterator-bits node option.
35+
template <bool use_iterator_bits, typename Opts, bool arg1, bool arg2>
36+
class ilist_select_iterator_type {
37+
public:
38+
using type = ilist_iterator<Opts, arg1, arg2>;
39+
};
40+
template <typename Opts, bool arg1, bool arg2>
41+
class ilist_select_iterator_type<true, Opts, arg1, arg2> {
42+
public:
43+
using type = ilist_iterator_w_bits<Opts, arg1, arg2>;
44+
};
45+
3246
/// Implementation for an ilist node.
3347
///
3448
/// Templated on an appropriate \a ilist_detail::node_options, usually computed
@@ -45,16 +59,29 @@ template <class OptionsT> class ilist_node_impl : OptionsT::node_base_type {
4559
friend typename OptionsT::list_base_type;
4660
friend struct ilist_detail::NodeAccess;
4761
friend class ilist_sentinel<OptionsT>;
62+
4863
friend class ilist_iterator<OptionsT, false, false>;
4964
friend class ilist_iterator<OptionsT, false, true>;
5065
friend class ilist_iterator<OptionsT, true, false>;
5166
friend class ilist_iterator<OptionsT, true, true>;
67+
friend class ilist_iterator_w_bits<OptionsT, false, false>;
68+
friend class ilist_iterator_w_bits<OptionsT, false, true>;
69+
friend class ilist_iterator_w_bits<OptionsT, true, false>;
70+
friend class ilist_iterator_w_bits<OptionsT, true, true>;
5271

5372
protected:
54-
using self_iterator = ilist_iterator<OptionsT, false, false>;
55-
using const_self_iterator = ilist_iterator<OptionsT, false, true>;
56-
using reverse_self_iterator = ilist_iterator<OptionsT, true, false>;
57-
using const_reverse_self_iterator = ilist_iterator<OptionsT, true, true>;
73+
using self_iterator =
74+
typename ilist_select_iterator_type<OptionsT::has_iterator_bits, OptionsT,
75+
false, false>::type;
76+
using const_self_iterator =
77+
typename ilist_select_iterator_type<OptionsT::has_iterator_bits, OptionsT,
78+
false, true>::type;
79+
using reverse_self_iterator =
80+
typename ilist_select_iterator_type<OptionsT::has_iterator_bits, OptionsT,
81+
true, false>::type;
82+
using const_reverse_self_iterator =
83+
typename ilist_select_iterator_type<OptionsT::has_iterator_bits, OptionsT,
84+
true, true>::type;
5885

5986
ilist_node_impl() = default;
6087

llvm/include/llvm/ADT/ilist_node_options.h

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,14 @@ template <bool EnableSentinelTracking> struct ilist_sentinel_tracking {};
3131
/// simultaneously. See \a ilist_node for usage examples.
3232
template <class Tag> struct ilist_tag {};
3333

34+
/// Option to add extra bits to the ilist_iterator.
35+
///
36+
/// Some use-cases (debug-info) need to know whether a position is intended
37+
/// to be half-open or fully open, i.e. whether to include any immediately
38+
/// adjacent debug-info in an operation. This option adds two bits to the
39+
/// iterator class to store that information.
40+
template <bool ExtraIteratorBits> struct ilist_iterator_bits {};
41+
3442
namespace ilist_detail {
3543

3644
/// Helper trait for recording whether an option is specified explicitly.
@@ -91,6 +99,21 @@ template <> struct extract_tag<> {
9199
};
92100
template <class Tag> struct is_valid_option<ilist_tag<Tag>> : std::true_type {};
93101

102+
/// Extract iterator bits option.
103+
///
104+
/// Look through \p Options for the \a ilist_iterator_bits option. Defaults
105+
/// to false.
106+
template <class... Options> struct extract_iterator_bits;
107+
template <bool IteratorBits, class... Options>
108+
struct extract_iterator_bits<ilist_iterator_bits<IteratorBits>, Options...>
109+
: std::integral_constant<bool, IteratorBits> {};
110+
template <class Option1, class... Options>
111+
struct extract_iterator_bits<Option1, Options...>
112+
: extract_iterator_bits<Options...> {};
113+
template <> struct extract_iterator_bits<> : std::false_type, is_implicit {};
114+
template <bool IteratorBits>
115+
struct is_valid_option<ilist_iterator_bits<IteratorBits>> : std::true_type {};
116+
94117
/// Check whether options are valid.
95118
///
96119
/// The conjunction of \a is_valid_option on each individual option.
@@ -105,7 +128,7 @@ struct check_options<Option1, Options...>
105128
///
106129
/// This is usually computed via \a compute_node_options.
107130
template <class T, bool EnableSentinelTracking, bool IsSentinelTrackingExplicit,
108-
class TagT>
131+
class TagT, bool HasIteratorBits>
109132
struct node_options {
110133
typedef T value_type;
111134
typedef T *pointer;
@@ -115,6 +138,7 @@ struct node_options {
115138

116139
static const bool enable_sentinel_tracking = EnableSentinelTracking;
117140
static const bool is_sentinel_tracking_explicit = IsSentinelTrackingExplicit;
141+
static const bool has_iterator_bits = HasIteratorBits;
118142
typedef TagT tag;
119143
typedef ilist_node_base<enable_sentinel_tracking> node_base_type;
120144
typedef ilist_base<enable_sentinel_tracking> list_base_type;
@@ -123,7 +147,8 @@ struct node_options {
123147
template <class T, class... Options> struct compute_node_options {
124148
typedef node_options<T, extract_sentinel_tracking<Options...>::value,
125149
extract_sentinel_tracking<Options...>::is_explicit,
126-
typename extract_tag<Options...>::type>
150+
typename extract_tag<Options...>::type,
151+
extract_iterator_bits<Options...>::value>
127152
type;
128153
};
129154

llvm/include/llvm/ADT/simple_ilist.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,18 @@ class simple_ilist
9292
using reference = typename OptionsT::reference;
9393
using const_pointer = typename OptionsT::const_pointer;
9494
using const_reference = typename OptionsT::const_reference;
95-
using iterator = ilist_iterator<OptionsT, false, false>;
96-
using const_iterator = ilist_iterator<OptionsT, false, true>;
97-
using reverse_iterator = ilist_iterator<OptionsT, true, false>;
98-
using const_reverse_iterator = ilist_iterator<OptionsT, true, true>;
95+
using iterator =
96+
typename ilist_select_iterator_type<OptionsT::has_iterator_bits, OptionsT,
97+
false, false>::type;
98+
using const_iterator =
99+
typename ilist_select_iterator_type<OptionsT::has_iterator_bits, OptionsT,
100+
false, true>::type;
101+
using reverse_iterator =
102+
typename ilist_select_iterator_type<OptionsT::has_iterator_bits, OptionsT,
103+
true, false>::type;
104+
using const_reverse_iterator =
105+
typename ilist_select_iterator_type<OptionsT::has_iterator_bits, OptionsT,
106+
true, true>::type;
99107
using size_type = size_t;
100108
using difference_type = ptrdiff_t;
101109

0 commit comments

Comments
 (0)