Skip to content

Commit 24799e1

Browse files
committed
SIL: defer instruction deletion to the end of a pass run.
When an instruction is "deleted" from the SIL, it is put into the SILModule::scheduledForDeletion list. The instructions in this list are eventually deleted for real in SILModule::flushDeletedInsts(), which is called by the pass manager after each pass run. In other words: instruction deletion is deferred to the end of a pass. This avoids dangling instruction pointers within the run of a pass and in analysis caches. Note that the analysis invalidation mechanism ensures that analysis caches are invalidated before flushDeletedInsts().
1 parent ef306ca commit 24799e1

File tree

14 files changed

+120
-81
lines changed

14 files changed

+120
-81
lines changed

include/swift/SIL/SILBasicBlock.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,10 @@ public llvm::ilist_node<SILBasicBlock>, public SILAllocated<SILBasicBlock> {
127127
void push_back(SILInstruction *I);
128128
void push_front(SILInstruction *I);
129129
void remove(SILInstruction *I);
130-
iterator erase(SILInstruction *I);
130+
void erase(SILInstruction *I);
131+
void erase(SILInstruction *I, SILModule &module);
132+
133+
void eraseAllInstructions(SILModule &module);
131134

132135
SILInstruction &back() { return InstList.back(); }
133136
const SILInstruction &back() const {
@@ -439,8 +442,6 @@ public llvm::ilist_node<SILBasicBlock>, public SILAllocated<SILBasicBlock> {
439442
I.dropAllReferences();
440443
}
441444

442-
void eraseInstructions();
443-
444445
private:
445446
friend class SILArgument;
446447

include/swift/SIL/SILFunction.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -981,6 +981,10 @@ class SILFunction
981981

982982
void clear();
983983

984+
/// Like `clear`, but does not call `dropAllReferences`, which is the
985+
/// responsibility of the caller.
986+
void eraseAllBlocks();
987+
984988
/// Return the identity substitutions necessary to forward this call if it is
985989
/// generic.
986990
SubstitutionMap getForwardingSubstitutionMap();

include/swift/SIL/SILGlobalVariable.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,11 @@ class SILGlobalVariable
181181
StaticInitializerBlock.dropAllReferences();
182182
}
183183

184+
void clear() {
185+
dropAllReferences();
186+
StaticInitializerBlock.eraseAllInstructions(Module);
187+
}
188+
184189
/// Return whether this variable corresponds to a Clang node.
185190
bool hasClangNode() const;
186191

include/swift/SIL/SILInstruction.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,7 @@ class SILInstruction : public llvm::ilist_node<SILInstruction> {
320320
friend llvm::ilist_traits<SILInstruction>;
321321
friend llvm::ilist_traits<SILBasicBlock>;
322322
friend SILBasicBlock;
323+
friend SILModule;
323324

324325
/// A backreference to the containing basic block. This is maintained by
325326
/// ilist_traits<SILInstruction>.
@@ -381,6 +382,10 @@ class SILInstruction : public llvm::ilist_node<SILInstruction> {
381382
return C.allocateInst(Bytes, Alignment);
382383
}
383384

385+
/// Returns true if this instruction is removed from its function and
386+
/// scheduled to be deleted.
387+
bool isDeleted() const { return !ParentBB; }
388+
384389
enum class MemoryBehavior {
385390
None,
386391
/// The instruction may read memory.

include/swift/SIL/SILModule.h

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,17 @@ class SILModule {
189189
/// For consistency checking.
190190
size_t numAllocatedSlabs = 0;
191191

192+
/// When an instruction is "deleted" from the SIL, it is put into this list.
193+
/// The instructions in this list are eventually deleted for real in
194+
/// flushDeletedInsts(), which is called by the pass manager after each pass
195+
/// run.
196+
/// In other words: instruction deletion is deferred to the end of a pass.
197+
///
198+
/// This avoids dangling instruction pointers within the run of a pass and in
199+
/// analysis caches. Note that the analysis invalidation mechanism ensures
200+
/// that analysis caches are invalidated before flushDeletedInsts().
201+
llvm::iplist<SILInstruction> scheduledForDeletion;
202+
192203
/// The swift Module associated with this SILModule.
193204
ModuleDecl *TheSwiftModule;
194205

@@ -849,8 +860,17 @@ class SILModule {
849860
/// Allocate memory for an instruction using the module's internal allocator.
850861
void *allocateInst(unsigned Size, unsigned Align) const;
851862

852-
/// Deallocate memory of an instruction.
853-
void deallocateInst(SILInstruction *I);
863+
/// Called before \p I is removed from its basic block and scheduled for
864+
/// deletion.
865+
void willDeleteInstruction(SILInstruction *I);
866+
867+
/// Schedules the (already removed) instruction \p I for deletion.
868+
/// See scheduledForDeletion for details.
869+
void scheduleForDeletion(SILInstruction *I);
870+
871+
/// Deletes all scheuled instructions for real.
872+
/// See scheduledForDeletion for details.
873+
void flushDeletedInsts();
854874

855875
/// Looks up the llvm intrinsic ID and type for the builtin function.
856876
///

lib/SIL/IR/SILBasicBlock.cpp

Lines changed: 12 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -41,35 +41,8 @@ SILBasicBlock::~SILBasicBlock() {
4141
return;
4242
}
4343

44-
SILModule &M = getModule();
45-
46-
// Invalidate all of the basic block arguments.
47-
for (auto *Arg : ArgumentList) {
48-
M.notifyDeleteHandlers(Arg);
49-
}
50-
5144
dropAllReferences();
52-
53-
for (auto I = begin(), E = end(); I != E;) {
54-
auto Inst = &*I;
55-
++I;
56-
erase(Inst);
57-
}
58-
assert(InstList.empty());
59-
}
60-
61-
void SILBasicBlock::clearStaticInitializerBlock(SILModule &module) {
62-
assert(!getParent() && "not a global variable's static initializer block");
63-
assert(ArgumentList.empty() &&
64-
"a static initializer block must not have arguments");
65-
66-
for (auto I = begin(), E = end(); I != E;) {
67-
SILInstruction *Inst = &*I;
68-
++I;
69-
InstList.erase(Inst);
70-
module.deallocateInst(Inst);
71-
}
72-
assert(InstList.empty());
45+
eraseAllInstructions(getModule());
7346
}
7447

7548
int SILBasicBlock::getDebugID() const {
@@ -104,22 +77,21 @@ void SILBasicBlock::remove(SILInstruction *I) {
10477
InstList.remove(I);
10578
}
10679

107-
void SILBasicBlock::eraseInstructions() {
108-
for (auto It = begin(); It != end();) {
109-
auto *Inst = &*It++;
110-
Inst->replaceAllUsesOfAllResultsWithUndef();
111-
Inst->eraseFromParent();
80+
void SILBasicBlock::eraseAllInstructions(SILModule &module) {
81+
while (!empty()) {
82+
erase(&*begin(), module);
11283
}
11384
}
11485

11586
/// Returns the iterator following the erased instruction.
116-
SILBasicBlock::iterator SILBasicBlock::erase(SILInstruction *I) {
117-
// Notify the delete handlers that this instruction is going away.
118-
SILModule &module = getModule();
119-
module.notifyDeleteHandlers(I->asSILNode());
120-
auto nextIter = InstList.erase(I);
121-
module.deallocateInst(I);
122-
return nextIter;
87+
void SILBasicBlock::erase(SILInstruction *I) {
88+
erase(I, getModule());
89+
}
90+
91+
void SILBasicBlock::erase(SILInstruction *I, SILModule &module) {
92+
module.willDeleteInstruction(I);
93+
InstList.remove(I);
94+
module.scheduleForDeletion(I);
12395
}
12496

12597
/// This method unlinks 'self' from the containing SILFunction and deletes it.

lib/SIL/IR/SILFunction.cpp

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -201,16 +201,7 @@ SILFunction::~SILFunction() {
201201

202202
auto &M = getModule();
203203
for (auto &BB : *this) {
204-
for (auto I = BB.begin(), E = BB.end(); I != E;) {
205-
auto Inst = &*I;
206-
++I;
207-
SILInstruction::destroy(Inst);
208-
// TODO: It is only safe to directly deallocate an
209-
// instruction if this BB is being removed in scope
210-
// of destructing a SILFunction.
211-
M.deallocateInst(Inst);
212-
}
213-
BB.InstList.clearAndLeakNodesUnsafely();
204+
BB.eraseAllInstructions(M);
214205
}
215206

216207
assert(RefCount == 0 &&
@@ -689,6 +680,10 @@ bool SILFunction::isExternallyUsedSymbol() const {
689680

690681
void SILFunction::clear() {
691682
dropAllReferences();
683+
eraseAllBlocks();
684+
}
685+
686+
void SILFunction::eraseAllBlocks() {
692687
BlockList.clear();
693688
}
694689

lib/SIL/IR/SILGlobalVariable.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,7 @@ SILGlobalVariable::SILGlobalVariable(SILModule &Module, SILLinkage Linkage,
5858
}
5959

6060
SILGlobalVariable::~SILGlobalVariable() {
61-
StaticInitializerBlock.dropAllReferences();
62-
StaticInitializerBlock.clearStaticInitializerBlock(Module);
61+
clear();
6362
}
6463

6564
bool SILGlobalVariable::isPossiblyUsedExternally() const {

lib/SIL/IR/SILInstruction.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ void llvm::ilist_traits<SILInstruction>::addNodeToList(SILInstruction *I) {
6868

6969
void llvm::ilist_traits<SILInstruction>::removeNodeFromList(SILInstruction *I) {
7070
// When an instruction is removed from a BB, clear the parent pointer.
71-
assert(I->ParentBB && "Not in a list!");
7271
I->ParentBB = nullptr;
7372
}
7473

@@ -147,6 +146,12 @@ void SILInstruction::dropAllReferences() {
147146
OpI->drop();
148147
}
149148

149+
if (auto *termInst = dyn_cast<TermInst>(this)) {
150+
for (SILSuccessor &succ : termInst->getSuccessors()) {
151+
succ = nullptr;
152+
}
153+
}
154+
150155
// If we have a function ref inst, we need to especially drop its function
151156
// argument so that it gets a proper ref decrement.
152157
if (auto *FRI = dyn_cast<FunctionRefBaseInst>(this)) {

lib/SIL/IR/SILModule.cpp

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,9 @@ SILModule::~SILModule() {
126126
assert(!hasUnresolvedOpenedArchetypeDefinitions());
127127

128128
// Decrement ref count for each SILGlobalVariable with static initializers.
129-
for (SILGlobalVariable &v : silGlobals)
130-
v.dropAllReferences();
129+
for (SILGlobalVariable &v : silGlobals) {
130+
v.clear();
131+
}
131132

132133
for (auto vt : vtables)
133134
vt->~SILVTable();
@@ -143,10 +144,16 @@ SILModule::~SILModule() {
143144
F.dropDynamicallyReplacedFunction();
144145
F.clearSpecializeAttrs();
145146
}
147+
148+
for (SILFunction &F : *this) {
149+
F.eraseAllBlocks();
150+
}
151+
flushDeletedInsts();
146152
}
147153

148154
void SILModule::checkForLeaks() const {
149-
int instsInModule = 0;
155+
int instsInModule = std::distance(scheduledForDeletion.begin(),
156+
scheduledForDeletion.end());
150157
for (const SILFunction &F : *this) {
151158
for (const SILBasicBlock &block : F) {
152159
instsInModule += std::distance(block.begin(), block.end());
@@ -231,8 +238,30 @@ void *SILModule::allocateInst(unsigned Size, unsigned Align) const {
231238
return AlignedAlloc(Size, Align);
232239
}
233240

234-
void SILModule::deallocateInst(SILInstruction *I) {
235-
AlignedFree(I);
241+
void SILModule::willDeleteInstruction(SILInstruction *I) {
242+
// Update openedArchetypeDefs.
243+
if (auto *svi = dyn_cast<SingleValueInstruction>(I)) {
244+
if (CanArchetypeType archeTy = svi->getOpenedArchetype()) {
245+
OpenedArchetypeKey key = {archeTy, svi->getFunction()};
246+
assert(openedArchetypeDefs.lookup(key) == svi &&
247+
"archetype def was not registered");
248+
openedArchetypeDefs.erase(key);
249+
}
250+
}
251+
}
252+
253+
void SILModule::scheduleForDeletion(SILInstruction *I) {
254+
I->dropAllReferences();
255+
scheduledForDeletion.push_back(I);
256+
I->ParentBB = nullptr;
257+
}
258+
259+
void SILModule::flushDeletedInsts() {
260+
while (!scheduledForDeletion.empty()) {
261+
SILInstruction *inst = &*scheduledForDeletion.begin();
262+
scheduledForDeletion.erase(inst);
263+
AlignedFree(inst);
264+
}
236265
}
237266

238267
SILWitnessTable *

0 commit comments

Comments
 (0)