Skip to content

Commit b8efc38

Browse files
committed
SIL: simplify deleting instruction while iterating over instructions.
Add `deletableInstructions()` and `reverseDeletableInstructions()` in SILBasicBlock. It allows deleting instructions while iterating over all instructions of the block. This is a replacement for `InstructionDeleter::updatingRange()`. It's a simpler implementation than the existing `UpdatingListIterator` and `UpdatingInstructionIteratorRegistry`, because it just needs to keep the prev/next pointers for "deleted" instructions instead of the iterator-registration machinery. It's also safer, because it doesn't require to delete instructions via a specific instance of an InstructionDeleter (which can be missed easily).
1 parent 4078157 commit b8efc38

File tree

12 files changed

+143
-339
lines changed

12 files changed

+143
-339
lines changed

include/swift/SIL/SILBasicBlock.h

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,51 @@ class SILFunction;
3131
class SILArgument;
3232
class SILPrintContext;
3333

34+
/// Instruction iterator which allows to "delete" instructions while iterating
35+
/// over the instruction list.
36+
///
37+
/// Iteration with this iterator allows to delete the current, the next or any
38+
/// instruction in the list while iterating.
39+
/// This works because instruction deletion is deferred (for details see
40+
/// `SILModule::scheduledForDeletion`) and removing an instruction from the list
41+
/// keeps the prev/next pointers (see `SILInstructionListBase`).
42+
template <typename IteratorBase>
43+
class DeletableInstructionsIterator {
44+
using Self = DeletableInstructionsIterator<IteratorBase>;
45+
46+
IteratorBase base;
47+
IteratorBase end;
48+
49+
public:
50+
using value_type = typename IteratorBase::value_type;
51+
using difference_type = ptrdiff_t;
52+
using pointer = value_type *;
53+
using iterator_category = std::forward_iterator_tag;
54+
55+
DeletableInstructionsIterator(IteratorBase base, IteratorBase end)
56+
: base(base), end(end) {}
57+
58+
value_type &operator*() const { return *base; }
59+
60+
SILInstruction *operator->() const { return base.operator->(); }
61+
62+
Self &operator++() {
63+
// If the current instruction is "deleted" (which means: removed from the
64+
// list), it's prev/next pointers still point to the next instruction which
65+
// is still in the list - or "deleted", too.
66+
++base;
67+
// Skip over all deleted instructions. Eventually we reach an instruction
68+
// is still in the list (= not "deleted") or the end iterator.
69+
while (base != end && base->isDeleted()) {
70+
++base;
71+
}
72+
return *this;
73+
}
74+
75+
bool operator==(const Self &rhs) const { return base == rhs.base; }
76+
bool operator!=(const Self &rhs) const { return !(*this == rhs); }
77+
};
78+
3479
class SILBasicBlock :
3580
public llvm::ilist_node<SILBasicBlock>, public SILAllocated<SILBasicBlock>,
3681
public SwiftObjectHeader {
@@ -184,6 +229,20 @@ public SwiftObjectHeader {
184229
const_reverse_iterator rbegin() const { return InstList.rbegin(); }
185230
const_reverse_iterator rend() const { return InstList.rend(); }
186231

232+
/// Allows deleting instructions while iterating over all instructions of the
233+
/// block.
234+
///
235+
/// For details see `DeletableInstructionsIterator`.
236+
llvm::iterator_range<DeletableInstructionsIterator<iterator>>
237+
deletableInstructions() { return {{begin(), end()}, {end(), end()}}; }
238+
239+
/// Allows deleting instructions while iterating over all instructions of the
240+
/// block in reverse order.
241+
///
242+
/// For details see `DeletableInstructionsIterator`.
243+
llvm::iterator_range<DeletableInstructionsIterator<reverse_iterator>>
244+
reverseDeletableInstructions() { return {{rbegin(), rend()}, {rend(), rend()}}; }
245+
187246
TermInst *getTerminator() {
188247
assert(!InstList.empty() && "Can't get successors for malformed block");
189248
return cast<TermInst>(&InstList.back());

include/swift/SIL/SILInstruction.h

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,58 @@
4949
#include "llvm/Support/TrailingObjects.h"
5050
#include <array>
5151

52+
namespace llvm {
53+
namespace ilist_detail {
54+
55+
/// The base class of the instruction list in SILBasicBlock.
56+
///
57+
/// We need a custom base class to not clear the prev/next pointers when
58+
/// removing an instruction from the list.
59+
class SILInstructionListBase : public ilist_base<false> {
60+
public:
61+
/// Remove an instruction from the list.
62+
///
63+
/// In contrast to the default implementation, it does not clear the prev/
64+
/// next pointers in the node. This is needed to being able to remove
65+
/// instructions from the list while iterating over the list.
66+
/// For details see `DeletableInstructionsIterator`.
67+
template <class T> static void remove(T &N) {
68+
node_base_type *Prev = N.getPrev();
69+
node_base_type *Next = N.getNext();
70+
Next->setPrev(Prev);
71+
Prev->setNext(Next);
72+
}
73+
74+
template <class T> static void insertBefore(T &Next, T &N) {
75+
insertBeforeImpl(Next, N);
76+
}
77+
78+
template <class T> static void transferBefore(T &Next, T &First, T &Last) {
79+
transferBeforeImpl(Next, First, Last);
80+
}
81+
};
82+
83+
// This template specialization is needed to replace the default instruction
84+
// list base class with `SILInstructionListBase`.
85+
template <> struct compute_node_options<::swift::SILInstruction> {
86+
struct type {
87+
typedef ::swift::SILInstruction value_type;
88+
typedef value_type *pointer;
89+
typedef value_type &reference;
90+
typedef const value_type *const_pointer;
91+
typedef const value_type &const_reference;
92+
93+
static const bool enable_sentinel_tracking = false;
94+
static const bool is_sentinel_tracking_explicit = false;
95+
typedef void tag;
96+
typedef ilist_node_base<enable_sentinel_tracking> node_base_type;
97+
typedef SILInstructionListBase list_base_type;
98+
};
99+
};
100+
101+
} // end namespace ilist_detail
102+
} // end llvm namespace
103+
52104
namespace swift {
53105

54106
class AllocationInst;

include/swift/SILOptimizer/Utils/InstructionDeleter.h

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,6 @@
9797

9898
#include "swift/SIL/SILInstruction.h"
9999
#include "swift/SILOptimizer/Utils/InstModCallbacks.h"
100-
#include "swift/SILOptimizer/Utils/UpdatingInstructionIterator.h"
101100

102101
namespace swift {
103102

@@ -116,29 +115,16 @@ class InstructionDeleter {
116115
/// instruction's operands. This has to be deterministic.
117116
SmallSetVector<SILInstruction *, 8> deadInstructions;
118117

119-
UpdatingInstructionIteratorRegistry iteratorRegistry;
118+
/// Callbacks used when adding/deleting instructions.
119+
InstModCallbacks callbacks;
120120

121121
public:
122-
InstructionDeleter() : deadInstructions(), iteratorRegistry() {}
122+
InstructionDeleter() : deadInstructions() {}
123123

124-
InstructionDeleter(InstModCallbacks &&chainedCallbacks)
125-
: deadInstructions(), iteratorRegistry(std::move(chainedCallbacks)) {}
124+
InstructionDeleter(InstModCallbacks &&callbacks)
125+
: deadInstructions(), callbacks(std::move(callbacks)) {}
126126

127-
UpdatingInstructionIteratorRegistry &getIteratorRegistry() {
128-
return iteratorRegistry;
129-
}
130-
131-
InstModCallbacks &getCallbacks() { return iteratorRegistry.getCallbacks(); }
132-
133-
llvm::iterator_range<UpdatingInstructionIterator>
134-
updatingRange(SILBasicBlock *bb) {
135-
return iteratorRegistry.makeIteratorRange(bb);
136-
}
137-
138-
llvm::iterator_range<UpdatingReverseInstructionIterator>
139-
updatingReverseRange(SILBasicBlock *bb) {
140-
return iteratorRegistry.makeReverseIteratorRange(bb);
141-
}
127+
InstModCallbacks &getCallbacks() { return callbacks; }
142128

143129
bool hadCallbackInvocation() const {
144130
return const_cast<InstructionDeleter *>(this)

0 commit comments

Comments
 (0)