@@ -1138,14 +1138,50 @@ static bool releaseCapturedArgsOfDeadPartialApply(PartialApplyInst *PAI,
1138
1138
return true ;
1139
1139
}
1140
1140
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
+
1141
1154
// / TODO: Generalize this to general objects.
1142
1155
bool swift::tryDeleteDeadClosure (SingleValueInstruction *Closure,
1143
1156
InstModCallbacks Callbacks) {
1157
+ auto *PA = dyn_cast<PartialApplyInst>(Closure);
1158
+
1144
1159
// We currently only handle locally identified values that do not escape. We
1145
1160
// 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))
1147
1162
return false ;
1148
1163
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
+
1149
1185
// We only accept a user if it is an ARC object that can be removed if the
1150
1186
// object is dead. This should be expanded in the future. This also ensures
1151
1187
// that we are locally identified and non-escaping since we only allow for
@@ -1768,6 +1804,13 @@ swift::findLocalApplySites(FunctionRefBaseInst *FRI) {
1768
1804
std::back_inserter (worklist));
1769
1805
continue ;
1770
1806
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
+
1771
1814
// Look through any reference count instructions since these are not
1772
1815
// escapes:
1773
1816
case SILInstructionKind::CopyValueInst:
@@ -1778,6 +1821,8 @@ swift::findLocalApplySites(FunctionRefBaseInst *FRI) {
1778
1821
case SILInstructionKind::RetainValueInst:
1779
1822
case SILInstructionKind::ReleaseValueInst:
1780
1823
case SILInstructionKind::DestroyValueInst:
1824
+ // A partial_apply [stack] is deallocated with a dealloc_stack.
1825
+ case SILInstructionKind::DeallocStackInst:
1781
1826
continue ;
1782
1827
default :
1783
1828
break ;
0 commit comments