Skip to content

Commit 8bcc66f

Browse files
committed
MandatoryInlining fixes for partial_apply [stack]
1 parent 84c1737 commit 8bcc66f

File tree

3 files changed

+77
-1
lines changed

3 files changed

+77
-1
lines changed

lib/SILOptimizer/Mandatory/MandatoryInlining.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,17 @@ static SILFunction *getCalleeFunction(
373373
return ThinToNoescapeCast->getOperand();
374374
}
375375

376+
// Ignore mark_dependence users. A partial_apply [stack] uses them to mark
377+
// the dependence of the trivial closure context value on the captured
378+
// arguments.
379+
if (auto *MD = dyn_cast<MarkDependenceInst>(CalleeValue)) {
380+
while (MD) {
381+
CalleeValue = MD->getValue();
382+
MD = dyn_cast<MarkDependenceInst>(CalleeValue);
383+
}
384+
return CalleeValue;
385+
}
386+
376387
auto *CFI = dyn_cast<ConvertEscapeToNoEscapeInst>(CalleeValue);
377388
if (!CFI)
378389
return CalleeValue;

lib/SILOptimizer/Utils/Local.cpp

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1138,14 +1138,50 @@ static bool releaseCapturedArgsOfDeadPartialApply(PartialApplyInst *PAI,
11381138
return true;
11391139
}
11401140

1141+
static bool
1142+
deadMarkDependenceUser(SILInstruction *Inst,
1143+
SmallVectorImpl<SILInstruction *> &DeleteInsts) {
1144+
if (!isa<MarkDependenceInst>(Inst))
1145+
return false;
1146+
DeleteInsts.push_back(Inst);
1147+
for (auto *Use : cast<SingleValueInstruction>(Inst)->getUses()) {
1148+
if (!deadMarkDependenceUser(Use->getUser(), DeleteInsts))
1149+
return false;
1150+
}
1151+
return true;
1152+
}
1153+
11411154
/// TODO: Generalize this to general objects.
11421155
bool swift::tryDeleteDeadClosure(SingleValueInstruction *Closure,
11431156
InstModCallbacks Callbacks) {
1157+
auto *PA = dyn_cast<PartialApplyInst>(Closure);
1158+
11441159
// We currently only handle locally identified values that do not escape. We
11451160
// also assume that the partial apply does not capture any addresses.
1146-
if (!isa<PartialApplyInst>(Closure) && !isa<ThinToThickFunctionInst>(Closure))
1161+
if (!PA && !isa<ThinToThickFunctionInst>(Closure))
11471162
return false;
11481163

1164+
// A stack allocated partial apply does not have any release users. Delete it
1165+
// if the only users are the dealloc_stack and mark_dependence instructions.
1166+
if (PA && PA->isOnStack()) {
1167+
SmallVector<SILInstruction*, 8> DeleteInsts;
1168+
for (auto *Use : PA->getUses()) {
1169+
if (isa<DeallocStackInst>(Use->getUser()) ||
1170+
isa<DebugValueInst>(Use->getUser()))
1171+
DeleteInsts.push_back(Use->getUser());
1172+
else if (!deadMarkDependenceUser(Use->getUser(), DeleteInsts))
1173+
return false;
1174+
}
1175+
for (auto *Inst : reverse(DeleteInsts))
1176+
Callbacks.DeleteInst(Inst);
1177+
Callbacks.DeleteInst(PA);
1178+
1179+
// Note: the lifetime of the captured arguments is managed outside of the
1180+
// trivial closure value i.e: there will already be releases for the
1181+
// captured arguments. Releasing captured arguments is not necessary.
1182+
return true;
1183+
}
1184+
11491185
// We only accept a user if it is an ARC object that can be removed if the
11501186
// object is dead. This should be expanded in the future. This also ensures
11511187
// that we are locally identified and non-escaping since we only allow for
@@ -1768,6 +1804,13 @@ swift::findLocalApplySites(FunctionRefBaseInst *FRI) {
17681804
std::back_inserter(worklist));
17691805
continue;
17701806

1807+
// A partial_apply [stack] marks its captured arguments with
1808+
// mark_dependence.
1809+
case SILInstructionKind::MarkDependenceInst:
1810+
copy(cast<SingleValueInstruction>(user)->getUses(),
1811+
std::back_inserter(worklist));
1812+
continue;
1813+
17711814
// Look through any reference count instructions since these are not
17721815
// escapes:
17731816
case SILInstructionKind::CopyValueInst:
@@ -1778,6 +1821,8 @@ swift::findLocalApplySites(FunctionRefBaseInst *FRI) {
17781821
case SILInstructionKind::RetainValueInst:
17791822
case SILInstructionKind::ReleaseValueInst:
17801823
case SILInstructionKind::DestroyValueInst:
1824+
// A partial_apply [stack] is deallocated with a dealloc_stack.
1825+
case SILInstructionKind::DeallocStackInst:
17811826
continue;
17821827
default:
17831828
break;

test/SILOptimizer/mandatory_inlining.sil

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1184,3 +1184,23 @@ bb0:
11841184
%3 = apply %2() : $@noescape () -> Builtin.Int32
11851185
return %3 : $Builtin.Int32
11861186
}
1187+
1188+
// CHECK-LABEL: sil @test_guaranteed_on_stack_closure
1189+
// CHECK: strong_retain %0 : $C
1190+
// CHECK: [[F:%.*]] = function_ref @use_c : $@convention(thin) (@guaranteed C) -> ()
1191+
// CHECK: apply [[F]](%0) : $@convention(thin) (@guaranteed C) -> ()
1192+
// CHECK: strong_release %0 : $C
1193+
// CHECK-NOT: strong_release
1194+
// CHECK: return
1195+
sil @test_guaranteed_on_stack_closure : $@convention(thin) (@guaranteed C) -> () {
1196+
bb0(%0: $C):
1197+
strong_retain %0 : $C
1198+
%closure_fun = function_ref @guaranteed_closure_func : $@convention(thin) (@guaranteed C) -> ()
1199+
%closure = partial_apply [on_stack] [callee_guaranteed] %closure_fun(%0) : $@convention(thin) (@guaranteed C) -> ()
1200+
%closure2 = mark_dependence %closure : $@noescape @callee_guaranteed () -> () on %0 : $C
1201+
apply %closure2() : $@noescape @callee_guaranteed () -> ()
1202+
strong_release %0: $C
1203+
dealloc_stack %closure : $@noescape @callee_guaranteed () -> ()
1204+
%tuple = tuple()
1205+
return %tuple : $()
1206+
}

0 commit comments

Comments
 (0)