Skip to content

Commit 421c762

Browse files
authored
Merge pull request #67031 from jckarter/allocbox-to-stack-remove-unused-original-bodies
AllocBoxToStack: Remove bodies of closure functions left unused after specialization.
2 parents 6f8fd07 + bd5f0a7 commit 421c762

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)