Skip to content

Commit 1d79fff

Browse files
committed
ADT: Give ilist<T>::reverse_iterator a handle to the current node
Reverse iterators to doubly-linked lists can be simpler (and cheaper) than std::reverse_iterator. Make it so. In particular, change ilist<T>::reverse_iterator so that it is *never* invalidated unless the node it references is deleted. This matches the guarantees of ilist<T>::iterator. (Note: MachineBasicBlock::iterator is *not* an ilist iterator, but a MachineInstrBundleIterator<MachineInstr>. This commit does not change MachineBasicBlock::reverse_iterator, but it does update MachineBasicBlock::reverse_instr_iterator. See note at end of commit message for details on bundle iterators.) Given the list (with the Sentinel showing twice for simplicity): [Sentinel] <-> A <-> B <-> [Sentinel] the following is now true: 1. begin() represents A. 2. begin() holds the pointer for A. 3. end() represents [Sentinel]. 4. end() holds the poitner for [Sentinel]. 5. rbegin() represents B. 6. rbegin() holds the pointer for B. 7. rend() represents [Sentinel]. 8. rend() holds the pointer for [Sentinel]. The changes are apple#6 and apple#8. Here are some properties from the old scheme (which used std::reverse_iterator): - rbegin() held the pointer for [Sentinel] and rend() held the pointer for A; - operator*() cost two dereferences instead of one; - converting from a valid iterator to its valid reverse_iterator involved a confusing increment; and - "RI++->erase()" left RI invalid. The unintuitive replacement was "RI->erase(), RE = end()". With vector-like data structures these properties are hard to avoid (since past-the-beginning is not a valid pointer), and don't impose a real cost (since there's still only one dereference, and all iterators are invalidated on erase). But with lists, this was a poor design. Specifically, the following code (which obviously works with normal iterators) now works with ilist::reverse_iterator as well: for (auto RI = L.rbegin(), RE = L.rend(); RI != RE;) fooThatMightRemoveArgFromList(*RI++); Converting between iterator and reverse_iterator for the same node uses the getReverse() function. reverse_iterator iterator::getReverse(); iterator reverse_iterator::getReverse(); Why doesn't iterator <=> reverse_iterator conversion use constructors? In order to catch and update old code, reverse_iterator does not even have an explicit conversion from iterator. It wouldn't be safe because there would be no reasonable way to catch all the bugs from the changed semantic (see the changes at call sites that are part of this patch). Old code used this API: std::reverse_iterator::reverse_iterator(iterator); iterator std::reverse_iterator::base(); Here's how to update from old code to new (that incorporates the semantic change), assuming I is an ilist<>::iterator and RI is an ilist<>::reverse_iterator: [Old] ==> [New] reverse_iterator(I) (--I).getReverse() reverse_iterator(I) ++I.getReverse() --reverse_iterator(I) I.getReverse() reverse_iterator(++I) I.getReverse() RI.base() (--RI).getReverse() RI.base() ++RI.getReverse() --RI.base() RI.getReverse() (++RI).base() RI.getReverse() delete &*RI, RE = end() delete &*RI++ RI->erase(), RE = end() RI++->erase() ======================================= Note: bundle iterators are out of scope ======================================= MachineBasicBlock::iterator, also known as MachineInstrBundleIterator<MachineInstr>, is a wrapper to represent MachineInstr bundles. The idea is that each operator++ takes you to the beginning of the next bundle. Implementing a sane reverse iterator for this is harder than ilist. Here are the options: - Use std::reverse_iterator<MBB::i>. Store a handle to the beginning of the next bundle. A call to operator*() runs a loop (usually operator--() will be called 1 time, for unbundled instructions). Increment/decrement just works. This is the status quo. - Store a handle to the final node in the bundle. A call to operator*() still runs a loop, but it iterates one time fewer (usually operator--() will be called 0 times, for unbundled instructions). Increment/decrement just works. - Make the ilist_sentinel<MachineInstr> *always* store that it's the sentinel (instead of just in asserts mode). Then the bundle iterator can sniff the sentinel bit in operator++(). I initially tried implementing the end() option as part of this commit, but updating iterator/reverse_iterator conversion call sites was error-prone. I have a WIP series of patches that implements the final option. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@280032 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 460ff94 commit 1d79fff

File tree

13 files changed

+230
-54
lines changed

13 files changed

+230
-54
lines changed

include/llvm/ADT/ilist.h

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
namespace llvm {
3636

3737
template<typename NodeTy, typename Traits> class iplist;
38-
template<typename NodeTy> class ilist_iterator;
38+
template <typename NodeTy, bool IsReverse> class ilist_iterator;
3939

4040
/// An access class for ilist_node private API.
4141
///
@@ -146,12 +146,30 @@ template <class NodeTy> struct ConstCorrectNodeType {
146146
template <class NodeTy> struct ConstCorrectNodeType<const NodeTy> {
147147
typedef const ilist_node<NodeTy> type;
148148
};
149+
150+
template <bool IsReverse = false> struct IteratorHelper {
151+
template <class T> static void increment(T *&I) {
152+
I = ilist_node_access::getNext(*I);
153+
}
154+
template <class T> static void decrement(T *&I) {
155+
I = ilist_node_access::getPrev(*I);
156+
}
157+
};
158+
template <> struct IteratorHelper<true> {
159+
template <class T> static void increment(T *&I) {
160+
IteratorHelper<false>::decrement(I);
161+
}
162+
template <class T> static void decrement(T *&I) {
163+
IteratorHelper<false>::increment(I);
164+
}
165+
};
166+
149167
} // end namespace ilist_detail
150168

151169
//===----------------------------------------------------------------------===//
152170
// Iterator for intrusive list.
153171
//
154-
template <typename NodeTy>
172+
template <typename NodeTy, bool IsReverse>
155173
class ilist_iterator
156174
: public std::iterator<std::bidirectional_iterator_tag, NodeTy, ptrdiff_t> {
157175
public:
@@ -185,19 +203,30 @@ class ilist_iterator
185203
// a nonconst iterator...
186204
template <class node_ty>
187205
ilist_iterator(
188-
const ilist_iterator<node_ty> &RHS,
206+
const ilist_iterator<node_ty, IsReverse> &RHS,
189207
typename std::enable_if<std::is_convertible<node_ty *, NodeTy *>::value,
190208
void *>::type = nullptr)
191209
: NodePtr(RHS.getNodePtr()) {}
192210

193211
// This is templated so that we can allow assigning to a const iterator from
194212
// a nonconst iterator...
195213
template <class node_ty>
196-
const ilist_iterator &operator=(const ilist_iterator<node_ty> &RHS) {
214+
const ilist_iterator &
215+
operator=(const ilist_iterator<node_ty, IsReverse> &RHS) {
197216
NodePtr = RHS.getNodePtr();
198217
return *this;
199218
}
200219

220+
/// Convert from an iterator to its reverse.
221+
///
222+
/// TODO: Roll this into the implicit constructor once we're sure that no one
223+
/// is relying on the std::reverse_iterator off-by-one semantics.
224+
ilist_iterator<NodeTy, !IsReverse> getReverse() const {
225+
if (NodePtr)
226+
return ilist_iterator<NodeTy, !IsReverse>(*NodePtr);
227+
return ilist_iterator<NodeTy, !IsReverse>();
228+
}
229+
201230
void reset(pointer NP) { NodePtr = NP; }
202231

203232
// Accessors...
@@ -217,12 +246,11 @@ class ilist_iterator
217246

218247
// Increment and decrement operators...
219248
ilist_iterator &operator--() {
220-
NodePtr = ilist_node_access::getPrev(*NodePtr);
221-
assert(NodePtr && "--'d off the beginning of an ilist!");
249+
ilist_detail::IteratorHelper<IsReverse>::decrement(NodePtr);
222250
return *this;
223251
}
224252
ilist_iterator &operator++() {
225-
NodePtr = ilist_node_access::getNext(*NodePtr);
253+
ilist_detail::IteratorHelper<IsReverse>::increment(NodePtr);
226254
return *this;
227255
}
228256
ilist_iterator operator--(int) {
@@ -356,8 +384,8 @@ class iplist : public Traits, ilist_base, ilist_node_access {
356384
typedef ilist_iterator<const NodeTy> const_iterator;
357385
typedef size_t size_type;
358386
typedef ptrdiff_t difference_type;
359-
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
360-
typedef std::reverse_iterator<iterator> reverse_iterator;
387+
typedef ilist_iterator<const NodeTy, true> const_reverse_iterator;
388+
typedef ilist_iterator<NodeTy, true> reverse_iterator;
361389

362390
iplist() = default;
363391
~iplist() { clear(); }
@@ -369,11 +397,10 @@ class iplist : public Traits, ilist_base, ilist_node_access {
369397
const_iterator end() const { return const_iterator(Sentinel); }
370398

371399
// reverse iterator creation methods.
372-
reverse_iterator rbegin() { return reverse_iterator(end()); }
373-
const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); }
374-
reverse_iterator rend() { return reverse_iterator(begin()); }
375-
const_reverse_iterator rend() const { return const_reverse_iterator(begin());}
376-
400+
reverse_iterator rbegin() { return ++reverse_iterator(Sentinel); }
401+
const_reverse_iterator rbegin() const{ return ++const_reverse_iterator(Sentinel); }
402+
reverse_iterator rend() { return reverse_iterator(Sentinel); }
403+
const_reverse_iterator rend() const { return const_reverse_iterator(Sentinel); }
377404

378405
// Miscellaneous inspection routines.
379406
size_type max_size() const { return size_type(-1); }

include/llvm/ADT/ilist_node.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,15 +51,16 @@ class ilist_node_base {
5151
};
5252

5353
struct ilist_node_access;
54-
template <typename NodeTy> class ilist_iterator;
54+
template <typename NodeTy, bool IsReverse = false> class ilist_iterator;
5555
template <typename NodeTy> class ilist_sentinel;
5656

5757
/// Templated wrapper class.
5858
template <typename NodeTy> class ilist_node : ilist_node_base {
5959
friend class ilist_base;
6060
friend struct ilist_node_access;
6161
friend struct ilist_traits<NodeTy>;
62-
friend class ilist_iterator<NodeTy>;
62+
friend class ilist_iterator<NodeTy, false>;
63+
friend class ilist_iterator<NodeTy, true>;
6364
friend class ilist_sentinel<NodeTy>;
6465

6566
protected:

include/llvm/CodeGen/MachineBasicBlock.h

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,8 @@ class MachineBasicBlock
150150

151151
typedef Instructions::iterator instr_iterator;
152152
typedef Instructions::const_iterator const_instr_iterator;
153-
typedef std::reverse_iterator<instr_iterator> reverse_instr_iterator;
154-
typedef
155-
std::reverse_iterator<const_instr_iterator> const_reverse_instr_iterator;
153+
typedef Instructions::reverse_iterator reverse_instr_iterator;
154+
typedef Instructions::const_reverse_iterator const_reverse_instr_iterator;
156155

157156
typedef MachineInstrBundleIterator<MachineInstr> iterator;
158157
typedef MachineInstrBundleIterator<const MachineInstr> const_iterator;
@@ -193,10 +192,14 @@ class MachineBasicBlock
193192
const_iterator begin() const { return instr_begin(); }
194193
iterator end () { return instr_end(); }
195194
const_iterator end () const { return instr_end(); }
196-
reverse_iterator rbegin() { return instr_rbegin(); }
197-
const_reverse_iterator rbegin() const { return instr_rbegin(); }
198-
reverse_iterator rend () { return instr_rend(); }
199-
const_reverse_iterator rend () const { return instr_rend(); }
195+
reverse_iterator rbegin() { return reverse_iterator(end()); }
196+
const_reverse_iterator rbegin() const {
197+
return const_reverse_iterator(end());
198+
}
199+
reverse_iterator rend() { return reverse_iterator(begin()); }
200+
const_reverse_iterator rend() const {
201+
return const_reverse_iterator(begin());
202+
}
200203

201204
/// Support for MachineInstr::getNextNode().
202205
static Instructions MachineBasicBlock::*getSublistAccess(MachineInstr *) {

include/llvm/CodeGen/MachineFunction.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -445,8 +445,8 @@ class MachineFunction {
445445
// Provide accessors for the MachineBasicBlock list...
446446
typedef BasicBlockListType::iterator iterator;
447447
typedef BasicBlockListType::const_iterator const_iterator;
448-
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
449-
typedef std::reverse_iterator<iterator> reverse_iterator;
448+
typedef BasicBlockListType::const_reverse_iterator const_reverse_iterator;
449+
typedef BasicBlockListType::reverse_iterator reverse_iterator;
450450

451451
/// Support for MachineBasicBlock::getNextNode().
452452
static BasicBlockListType MachineFunction::*

include/llvm/IR/SymbolTableListTraits.h

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,6 @@
3030
namespace llvm {
3131
class ValueSymbolTable;
3232

33-
template <typename NodeTy> class ilist_iterator;
34-
template <typename NodeTy, typename Traits> class iplist;
35-
template <typename Ty> struct ilist_traits;
36-
3733
/// Template metafunction to get the parent type for a symbol table list.
3834
///
3935
/// Implementations create a typedef called \c type so that we only need a
@@ -66,6 +62,7 @@ template <typename NodeTy> class SymbolTableList;
6662
template <typename ValueSubClass>
6763
class SymbolTableListTraits : public ilist_node_traits<ValueSubClass> {
6864
typedef SymbolTableList<ValueSubClass> ListTy;
65+
typedef ilist_iterator<ValueSubClass, false> iterator;
6966
typedef
7067
typename SymbolTableListParentType<ValueSubClass>::type ItemParentClass;
7168

@@ -94,10 +91,9 @@ class SymbolTableListTraits : public ilist_node_traits<ValueSubClass> {
9491
public:
9592
void addNodeToList(ValueSubClass *V);
9693
void removeNodeFromList(ValueSubClass *V);
97-
void transferNodesFromList(SymbolTableListTraits &L2,
98-
ilist_iterator<ValueSubClass> first,
99-
ilist_iterator<ValueSubClass> last);
100-
//private:
94+
void transferNodesFromList(SymbolTableListTraits &L2, iterator first,
95+
iterator last);
96+
// private:
10197
template<typename TPtr>
10298
void setSymTabObject(TPtr *, TPtr);
10399
static ValueSymbolTable *toPtr(ValueSymbolTable *P) { return P; }

lib/CodeGen/MachinePipeliner.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2880,8 +2880,7 @@ void SwingSchedulerDAG::removeDeadInstructions(MachineBasicBlock *KernelBB,
28802880
used = false;
28812881
}
28822882
if (!used) {
2883-
MI->eraseFromParent();
2884-
ME = (*MBB)->instr_rend();
2883+
MI++->eraseFromParent();
28852884
continue;
28862885
}
28872886
++MI;

lib/Target/Lanai/LanaiDelaySlotFiller.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) {
105105
// RET is generated as part of epilogue generation and hence we know
106106
// what the two instructions preceding it are and that it is safe to
107107
// insert RET above them.
108-
MachineBasicBlock::reverse_instr_iterator RI(I);
108+
MachineBasicBlock::reverse_instr_iterator RI = ++I.getReverse();
109109
assert(RI->getOpcode() == Lanai::LDW_RI && RI->getOperand(0).isReg() &&
110110
RI->getOperand(0).getReg() == Lanai::FP &&
111111
RI->getOperand(1).isReg() &&
@@ -117,8 +117,7 @@ bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) {
117117
RI->getOperand(0).getReg() == Lanai::SP &&
118118
RI->getOperand(1).isReg() &&
119119
RI->getOperand(1).getReg() == Lanai::FP);
120-
++RI;
121-
MachineBasicBlock::instr_iterator FI(RI.base());
120+
MachineBasicBlock::instr_iterator FI = RI.getReverse();
122121
MBB.splice(std::next(I), &MBB, FI, I);
123122
FilledSlots += 2;
124123
} else {
@@ -154,14 +153,14 @@ bool Filler::findDelayInstr(MachineBasicBlock &MBB,
154153
bool SawLoad = false;
155154
bool SawStore = false;
156155

157-
for (MachineBasicBlock::reverse_instr_iterator I(Slot); I != MBB.instr_rend();
158-
++I) {
156+
for (MachineBasicBlock::reverse_instr_iterator I = ++Slot.getReverse();
157+
I != MBB.instr_rend(); ++I) {
159158
// skip debug value
160159
if (I->isDebugValue())
161160
continue;
162161

163162
// Convert to forward iterator.
164-
MachineBasicBlock::instr_iterator FI(std::next(I).base());
163+
MachineBasicBlock::instr_iterator FI = I.getReverse();
165164

166165
if (I->hasUnmodeledSideEffects() || I->isInlineAsm() || I->isLabel() ||
167166
FI == LastFiller || I->isPseudo())

lib/Target/X86/X86FixupSetCC.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,8 @@ bool X86FixupSetCCPass::isSetCCr(unsigned Opcode) {
9999
MachineInstr *
100100
X86FixupSetCCPass::findFlagsImpDef(MachineBasicBlock *MBB,
101101
MachineBasicBlock::reverse_iterator MI) {
102-
auto MBBStart = MBB->instr_rend();
102+
// FIXME: Should this be instr_rend(), and MI be reverse_instr_iterator?
103+
auto MBBStart = MBB->rend();
103104
for (int i = 0; (i < SearchBound) && (MI != MBBStart); ++i, ++MI)
104105
for (auto &Op : MI->implicit_operands())
105106
if ((Op.getReg() == X86::EFLAGS) && (Op.isDef()))

lib/Transforms/Scalar/LoopRerollPass.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1412,13 +1412,12 @@ bool LoopReroll::DAGRootTracker::validate(ReductionTracker &Reductions) {
14121412
void LoopReroll::DAGRootTracker::replace(const SCEV *IterCount) {
14131413
BasicBlock *Header = L->getHeader();
14141414
// Remove instructions associated with non-base iterations.
1415-
for (BasicBlock::reverse_iterator J = Header->rbegin();
1416-
J != Header->rend();) {
1415+
for (BasicBlock::reverse_iterator J = Header->rbegin(), JE = Header->rend();
1416+
J != JE;) {
14171417
unsigned I = Uses[&*J].find_first();
14181418
if (I > 0 && I < IL_All) {
1419-
Instruction *D = &*J;
1420-
DEBUG(dbgs() << "LRR: removing: " << *D << "\n");
1421-
D->eraseFromParent();
1419+
DEBUG(dbgs() << "LRR: removing: " << *J << "\n");
1420+
J++->eraseFromParent();
14221421
continue;
14231422
}
14241423

lib/Transforms/Scalar/RewriteStatepointsForGC.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2578,8 +2578,8 @@ static void findLiveSetAtInst(Instruction *Inst, GCPtrLivenessData &Data,
25782578
// call result is not live (normal), nor are it's arguments
25792579
// (unless they're used again later). This adjustment is
25802580
// specifically what we need to relocate
2581-
BasicBlock::reverse_iterator rend(Inst->getIterator());
2582-
computeLiveInValues(BB->rbegin(), rend, LiveOut);
2581+
computeLiveInValues(BB->rbegin(), ++Inst->getIterator().getReverse(),
2582+
LiveOut);
25832583
LiveOut.remove(Inst);
25842584
Out.insert(LiveOut.begin(), LiveOut.end());
25852585
}

lib/Transforms/Vectorize/SLPVectorizer.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1868,9 +1868,9 @@ int BoUpSLP::getSpillCost() {
18681868
);
18691869

18701870
// Now find the sequence of instructions between PrevInst and Inst.
1871-
BasicBlock::reverse_iterator InstIt(Inst->getIterator()),
1872-
PrevInstIt(PrevInst->getIterator());
1873-
--PrevInstIt;
1871+
BasicBlock::reverse_iterator InstIt = ++Inst->getIterator().getReverse(),
1872+
PrevInstIt =
1873+
PrevInst->getIterator().getReverse();
18741874
while (InstIt != PrevInstIt) {
18751875
if (PrevInstIt == PrevInst->getParent()->rend()) {
18761876
PrevInstIt = Inst->getParent()->rbegin();
@@ -3036,9 +3036,10 @@ bool BoUpSLP::BlockScheduling::extendSchedulingRegion(Value *V) {
30363036
}
30373037
// Search up and down at the same time, because we don't know if the new
30383038
// instruction is above or below the existing scheduling region.
3039-
BasicBlock::reverse_iterator UpIter(ScheduleStart->getIterator());
3039+
BasicBlock::reverse_iterator UpIter =
3040+
++ScheduleStart->getIterator().getReverse();
30403041
BasicBlock::reverse_iterator UpperEnd = BB->rend();
3041-
BasicBlock::iterator DownIter(ScheduleEnd);
3042+
BasicBlock::iterator DownIter = ScheduleEnd->getIterator();
30423043
BasicBlock::iterator LowerEnd = BB->end();
30433044
for (;;) {
30443045
if (++ScheduleRegionSize > ScheduleRegionSizeLimit) {

unittests/ADT/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ set(ADTSources
1919
HashingTest.cpp
2020
ilistTestTemp.cpp
2121
IListBaseTest.cpp
22+
IListIteratorTest.cpp
2223
IListNodeBaseTest.cpp
2324
IListSentinelTest.cpp
2425
ImmutableMapTest.cpp

0 commit comments

Comments
 (0)