Skip to content

Commit d418192

Browse files
committed
SIL optimizer: fix a compile time performance problem in UpdatingInstructionIteratorRegistry
C++ closures can implicitly malloc. Avoid this by just capturing `this` and nothing else. Reduces the time spent in the SIL pass pipeline by 25% when compiling the stdlib core. rdar://88567996
1 parent 4e75c99 commit d418192

File tree

1 file changed

+32
-21
lines changed

1 file changed

+32
-21
lines changed

include/swift/SILOptimizer/Utils/UpdatingInstructionIterator.h

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -169,31 +169,33 @@ class UpdatingInstructionIteratorRegistry {
169169
SmallVector<UpdatingInstructionIterator *, 4> forwardIterators;
170170
SmallVector<UpdatingReverseInstructionIterator *, 4> reverseIterators;
171171

172+
std::function<void(SILInstruction *)> chainedDelete;
173+
std::function<void(SILInstruction *)> chainedNew;
174+
172175
/// Callbacks used when adding/deleting instructions.
173176
InstModCallbacks callbacks;
174177

175-
public:
176-
UpdatingInstructionIteratorRegistry(
177-
InstModCallbacks chainedCallbacks = InstModCallbacks()) {
178-
rechainCallbacks(chainedCallbacks);
179-
}
180-
181-
// The callbacks capture 'this'. So copying is invalid.
182-
UpdatingInstructionIteratorRegistry(
183-
const UpdatingInstructionIteratorRegistry &) = delete;
184-
185-
UpdatingInstructionIteratorRegistry &
186-
operator=(const UpdatingInstructionIteratorRegistry &) = delete;
187178

188-
InstModCallbacks &getCallbacks() { return callbacks; }
179+
public:
180+
UpdatingInstructionIteratorRegistry() :
181+
callbacks(InstModCallbacks()
182+
.onDelete([this](SILInstruction *toDelete) {
183+
notifyDelete(toDelete);
184+
toDelete->eraseFromParent();
185+
})
186+
.onCreateNewInst(
187+
[this](SILInstruction *newlyCreatedInst) {
188+
notifyNew(newlyCreatedInst);
189+
}))
190+
{}
189191

190-
void rechainCallbacks(InstModCallbacks chainedCallbacks) {
192+
UpdatingInstructionIteratorRegistry(InstModCallbacks &&chainedCallbacks) :
191193
// Copy the two std::functions that we need. The rest of the callbacks are
192194
// copied implicitly by assignment.
193-
auto chainedDelete = chainedCallbacks.deleteInstFunc;
194-
auto chainedNew = chainedCallbacks.createdNewInstFunc;
195-
callbacks = chainedCallbacks
196-
.onDelete([this, chainedDelete](SILInstruction *toDelete) {
195+
chainedDelete(std::move(chainedCallbacks.deleteInstFunc)),
196+
chainedNew(std::move(chainedCallbacks.createdNewInstFunc)),
197+
callbacks(std::move(chainedCallbacks
198+
.onDelete([this](SILInstruction *toDelete) {
197199
notifyDelete(toDelete);
198200
if (chainedDelete) {
199201
chainedDelete(toDelete);
@@ -202,13 +204,22 @@ class UpdatingInstructionIteratorRegistry {
202204
toDelete->eraseFromParent();
203205
})
204206
.onCreateNewInst(
205-
[this, chainedNew](SILInstruction *newlyCreatedInst) {
207+
[this](SILInstruction *newlyCreatedInst) {
206208
notifyNew(newlyCreatedInst);
207209
if (chainedNew) {
208210
chainedNew(newlyCreatedInst);
209211
}
210-
});
211-
}
212+
})))
213+
{}
214+
215+
// The callbacks capture 'this'. So copying is invalid.
216+
UpdatingInstructionIteratorRegistry(
217+
const UpdatingInstructionIteratorRegistry &) = delete;
218+
219+
UpdatingInstructionIteratorRegistry &
220+
operator=(const UpdatingInstructionIteratorRegistry &) = delete;
221+
222+
InstModCallbacks &getCallbacks() { return callbacks; }
212223

213224
void registerIterator(UpdatingInstructionIterator *i) {
214225
forwardIterators.push_back(i);

0 commit comments

Comments
 (0)