Skip to content

Commit bd5f0a7

Browse files
committed
AllocBoxToStack: Remove bodies of closure functions left unused after specialization.
We can't remove the functions at this point in case they might have other function passes enqueued to run on them, but we can at least remove the function contents that are now unnecessary. We need to do this in cases when move-only types are involved, since the semantics of the move checker rely on unescaped captures being promoted before the pass runs, and we leave behind invalid SIL in the unpromoted code. rdar://110675352
1 parent 44ab03a commit bd5f0a7

File tree

3 files changed

+56
-8
lines changed

3 files changed

+56
-8
lines changed

lib/SILOptimizer/Transforms/AllocBoxToStack.cpp

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,9 +1213,51 @@ static void rewriteApplySites(AllocBoxToStackState &pass) {
12131213
auto *FRI = cast<FunctionRefInst>(Apply.getCallee());
12141214
Apply.getInstruction()->eraseFromParent();
12151215

1216-
// TODO: Erase from module if there are no more uses.
1217-
if (FRI->use_empty())
1216+
if (FRI->use_empty()) {
1217+
auto referencedFn = FRI->getReferencedFunction();
12181218
FRI->eraseFromParent();
1219+
1220+
// TODO: Erase from module if there are no more uses.
1221+
// If the function has no remaining references, it should eventually
1222+
// be deleted. We can't do that from a function pass, since the function
1223+
// is still queued up for other passes to run after this one, but we
1224+
// can at least gut the implementation, since subsequent passes that
1225+
// rely on stack promotion to occur (particularly closure lifetime
1226+
// fixup and move-only checking) may not be able to proceed in a
1227+
// sensible way on the now non-canonical original implementation.
1228+
if (referencedFn->getRefCount() == 0
1229+
&& !isPossiblyUsedExternally(referencedFn->getLinkage(),
1230+
referencedFn->getModule().isWholeModule())) {
1231+
LLVM_DEBUG(llvm::dbgs() << "*** Deleting original function " << referencedFn->getName() << "'s body since it is unused");
1232+
// Remove all non-entry blocks.
1233+
auto entryBB = referencedFn->begin();
1234+
auto nextBB = std::next(entryBB);
1235+
1236+
while (nextBB != referencedFn->end()) {
1237+
auto thisBB = nextBB;
1238+
++nextBB;
1239+
thisBB->eraseFromParent();
1240+
}
1241+
1242+
// Rewrite the entry block to only contain an unreachable.
1243+
auto loc = entryBB->begin()->getLoc();
1244+
entryBB->eraseAllInstructions(referencedFn->getModule());
1245+
{
1246+
SILBuilder b(&*entryBB);
1247+
b.createUnreachable(loc);
1248+
}
1249+
1250+
// Refresh the CFG in case we removed any function calls.
1251+
pass.CFGChanged = true;
1252+
1253+
// If the function has shared linkage, reduce this version to private
1254+
// linkage, because we don't want the deleted-body form to win in any
1255+
// ODR shootouts.
1256+
if (referencedFn->getLinkage() == SILLinkage::Shared) {
1257+
referencedFn->setLinkage(SILLinkage::Private);
1258+
}
1259+
}
1260+
}
12191261
}
12201262
}
12211263

test/SILOptimizer/allocbox_to_stack.sil

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -651,9 +651,13 @@ bb0(%0 : $Int, %1 : $*S<T>):
651651
return %9 : $Bool
652652
}
653653

654-
// CHECK-LABEL: sil shared [_semantics "sil.optimizer.moveonly.diagnostic.ignore"] @closure1
655-
sil shared @closure1 : $@convention(thin) <T where T : Count> (Int, @owned <τ_0_0 : Count> { var S<τ_0_0> } <T>) -> Bool {
654+
// This closure body gets specialized with unboxed capture parameters, so
655+
// the original function body is stubbed out once the call sites are all
656+
// specialized.
657+
// CHECK-LABEL: sil private [_semantics "sil.optimizer.moveonly.diagnostic.ignore"] @closure1
656658
// CHECK: bb0
659+
// CHECK-NEXT: unreachable
660+
sil shared @closure1 : $@convention(thin) <T where T : Count> (Int, @owned <τ_0_0 : Count> { var S<τ_0_0> } <T>) -> Bool {
657661
bb0(%0 : $Int, %1 : $<τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <T>):
658662
%2 = project_box %1 : $<τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <T>, 0
659663
%3 = function_ref @inner : $@convention(thin) (@owned @callee_owned () -> Bool) -> Bool
@@ -664,7 +668,6 @@ bb0(%0 : $Int, %1 : $<τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <T>):
664668
%7 = partial_apply %4<T>(%0, %5) : $@convention(thin) <τ_0_0 where τ_0_0 : Count> (Int, @owned <τ_0_0 : Count> { var S<τ_0_0> } <τ_0_0>) -> Bool
665669
%8 = apply %3(%7) : $@convention(thin) (@owned @callee_owned () -> Bool) -> Bool
666670
strong_release %1 : $<τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <T>
667-
// CHECK: return
668671
return %8 : $Bool
669672
}
670673

test/SILOptimizer/allocbox_to_stack_ownership.sil

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -751,9 +751,13 @@ bb0(%0 : $Int, %1 : $*S<T>):
751751
return %9 : $Bool
752752
}
753753

754-
// CHECK-LABEL: sil shared [_semantics "sil.optimizer.moveonly.diagnostic.ignore"] [ossa] @closure1
755-
sil shared [ossa] @closure1 : $@convention(thin) <T where T : Count> (Int, @owned <τ_0_0 : Count> { var S<τ_0_0> } <T>) -> Bool {
754+
// This closure body gets specialized with unboxed capture parameters, so
755+
// the original function body is stubbed out once the call sites are all
756+
// specialized.
757+
// CHECK-LABEL: sil private [_semantics "sil.optimizer.moveonly.diagnostic.ignore"] [ossa] @closure1
756758
// CHECK: bb0
759+
// CHECK: unreachable
760+
sil shared [ossa] @closure1 : $@convention(thin) <T where T : Count> (Int, @owned <τ_0_0 : Count> { var S<τ_0_0> } <T>) -> Bool {
757761
bb0(%0 : $Int, %1 : @owned $<τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <T>):
758762
%2 = project_box %1 : $<τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <T>, 0
759763
%3 = function_ref @inner : $@convention(thin) (@owned @callee_owned () -> Bool) -> Bool
@@ -764,7 +768,6 @@ bb0(%0 : $Int, %1 : @owned $<τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <T>)
764768
%7 = partial_apply %4<T>(%0, %5) : $@convention(thin) <τ_0_0 where τ_0_0 : Count> (Int, @owned <τ_0_0 : Count> { var S<τ_0_0> } <τ_0_0>) -> Bool
765769
%8 = apply %3(%7) : $@convention(thin) (@owned @callee_owned () -> Bool) -> Bool
766770
destroy_value %1 : $<τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <T>
767-
// CHECK: return
768771
return %8 : $Bool
769772
}
770773

0 commit comments

Comments
 (0)