9
9
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10
10
//
11
11
// ===----------------------------------------------------------------------===//
12
+
12
13
#include " swift/SILOptimizer/Utils/Local.h"
13
14
#include " swift/SILOptimizer/Utils/CFG.h"
14
15
#include " swift/SILOptimizer/Analysis/Analysis.h"
@@ -892,6 +893,55 @@ static bool useDoesNotKeepClosureAlive(const SILInstruction *I) {
892
893
}
893
894
}
894
895
896
+ static SILValue createLifetimeExtendedAllocStack (
897
+ SILBuilder &Builder, SILLocation Loc, SILValue Arg,
898
+ ArrayRef<SILBasicBlock *> ExitingBlocks, InstModCallbacks Callbacks) {
899
+ AllocStackInst *ASI = nullptr ;
900
+ {
901
+ // Save our insert point and create a new alloc_stack in the initial BB and
902
+ // dealloc_stack in all exit blocks.
903
+ auto *OldInsertPt = &*Builder.getInsertionPoint ();
904
+ Builder.setInsertionPoint (Builder.getFunction ().begin ()->begin ());
905
+ ASI = Builder.createAllocStack (Loc, Arg->getType ());
906
+ Callbacks.CreatedNewInst (ASI);
907
+
908
+ for (auto *BB : ExitingBlocks) {
909
+ Builder.setInsertionPoint (BB->getTerminator ());
910
+ Callbacks.CreatedNewInst (Builder.createDeallocStack (Loc, ASI));
911
+ }
912
+ Builder.setInsertionPoint (OldInsertPt);
913
+ }
914
+ assert (ASI != nullptr );
915
+
916
+ // Then perform a copy_addr [take] [init] right after the partial_apply from
917
+ // the original address argument to the new alloc_stack that we have
918
+ // created.
919
+ Callbacks.CreatedNewInst (
920
+ Builder.createCopyAddr (Loc, Arg, ASI, IsTake, IsInitialization));
921
+
922
+ // Return the new alloc_stack inst that has the appropriate live range to
923
+ // destroy said values.
924
+ return ASI;
925
+ }
926
+
927
+ static bool shouldDestroyPartialApplyCapturedArg (SILValue Arg,
928
+ SILParameterInfo PInfo,
929
+ SILModule &M) {
930
+ // If we have a non-trivial type and the argument is passed in @inout, we do
931
+ // not need to destroy it here. This is something that is implicit in the
932
+ // partial_apply design that will be revisited when partial_apply is
933
+ // redesigned.
934
+ if (PInfo.isIndirectMutating ())
935
+ return false ;
936
+
937
+ // If we have a trivial type, we do not need to put in any extra releases.
938
+ if (Arg->getType ().isTrivial (M))
939
+ return false ;
940
+
941
+ // We handle all other cases.
942
+ return true ;
943
+ }
944
+
895
945
// *HEY YOU, YES YOU, PLEASE READ*. Even though a textual partial apply is
896
946
// printed with the convention of the closed over function upon it, all
897
947
// non-inout arguments to a partial_apply are passed at +1. This includes
@@ -902,20 +952,14 @@ static bool useDoesNotKeepClosureAlive(const SILInstruction *I) {
902
952
void swift::releasePartialApplyCapturedArg (SILBuilder &Builder, SILLocation Loc,
903
953
SILValue Arg, SILParameterInfo PInfo,
904
954
InstModCallbacks Callbacks) {
905
- // If we have a non-trivial type and the argument is passed in @inout, we do
906
- // not need to destroy it here. This is something that is implicit in the
907
- // partial_apply design that will be revisited when partial_apply is
908
- // redesigned.
909
- if (PInfo.isIndirectMutating ())
955
+ if (!shouldDestroyPartialApplyCapturedArg (Arg, PInfo, Builder.getModule ()))
910
956
return ;
911
957
912
- // If we have a trivial type, we do not need to put in any extra releases.
913
- if (Arg->getType ().isTrivial (Builder.getModule ()))
914
- return ;
915
-
916
- // Otherwise, we need to destroy the argument. If we have an address, just
917
- // emit a destroy_addr.
958
+ // Otherwise, we need to destroy the argument. If we have an address, we
959
+ // insert a destroy_addr and return. Any live range issues must have been
960
+ // dealt with by our caller.
918
961
if (Arg->getType ().isAddress ()) {
962
+ // Then emit the destroy_addr for this arg
919
963
SILInstruction *NewInst = Builder.emitDestroyAddrAndFold (Loc, Arg);
920
964
Callbacks.CreatedNewInst (NewInst);
921
965
return ;
@@ -959,30 +1003,68 @@ void swift::releasePartialApplyCapturedArg(SILBuilder &Builder, SILLocation Loc,
959
1003
// / For each captured argument of PAI, decrement the ref count of the captured
960
1004
// / argument as appropriate at each of the post dominated release locations
961
1005
// / found by Tracker.
962
- static void releaseCapturedArgsOfDeadPartialApply (PartialApplyInst *PAI,
1006
+ static bool releaseCapturedArgsOfDeadPartialApply (PartialApplyInst *PAI,
963
1007
ReleaseTracker &Tracker,
964
1008
InstModCallbacks Callbacks) {
965
1009
SILBuilderWithScope Builder (PAI);
966
1010
SILLocation Loc = PAI->getLoc ();
967
1011
CanSILFunctionType PAITy =
968
1012
PAI->getCallee ()->getType ().getAs <SILFunctionType>();
969
1013
970
- // Emit a destroy value for each captured closure argument.
971
1014
ArrayRef<SILParameterInfo> Params = PAITy->getParameters ();
972
- auto Args = PAI->getArguments ();
1015
+ llvm::SmallVector<SILValue, 8 > Args;
1016
+ for (SILValue v : PAI->getArguments ()) {
1017
+ // If any of our arguments contain open existentials, bail. We do not
1018
+ // support this for now so that we can avoid having to re-order stack
1019
+ // locations (a larger change).
1020
+ if (v->getType ().hasOpenedExistential ())
1021
+ return false ;
1022
+ Args.emplace_back (v);
1023
+ }
973
1024
unsigned Delta = Params.size () - Args.size ();
974
1025
assert (Delta <= Params.size () && " Error, more Args to partial apply than "
975
1026
" params in its interface." );
1027
+ Params = Params.drop_front (Delta);
1028
+
1029
+ llvm::SmallVector<SILBasicBlock *, 2 > ExitingBlocks;
1030
+ PAI->getFunction ()->findExitingBlocks (ExitingBlocks);
1031
+
1032
+ // Go through our argument list and create new alloc_stacks for each
1033
+ // non-trivial address value. This ensures that the memory location that we
1034
+ // are cleaning up has the same live range as the partial_apply. Otherwise, we
1035
+ // may be inserting destroy_addr of alloc_stack that have already been passed
1036
+ // to a dealloc_stack.
1037
+ for (unsigned i : reversed (indices (Args))) {
1038
+ SILValue Arg = Args[i];
1039
+ SILParameterInfo PInfo = Params[i];
1040
+
1041
+ // If we are not going to destroy this partial_apply, continue.
1042
+ if (!shouldDestroyPartialApplyCapturedArg (Arg, PInfo, Builder.getModule ()))
1043
+ continue ;
1044
+
1045
+ // If we have an object, we will not have live range issues, just continue.
1046
+ if (Arg->getType ().isObject ())
1047
+ continue ;
1048
+
1049
+ // Now that we know that we have a non-argument address, perform a take-init
1050
+ // of Arg into a lifetime extended alloc_stack
1051
+ Args[i] = createLifetimeExtendedAllocStack (Builder, Loc, Arg, ExitingBlocks,
1052
+ Callbacks);
1053
+ }
976
1054
1055
+ // Emit a destroy for each captured closure argument at each final release
1056
+ // point.
977
1057
for (auto *FinalRelease : Tracker.getFinalReleases ()) {
978
1058
Builder.setInsertionPoint (FinalRelease);
979
- for (unsigned AI = 0 , AE = Args. size (); AI != AE; ++AI ) {
980
- SILValue Arg = Args[AI ];
981
- SILParameterInfo Param = Params[AI + Delta ];
1059
+ for (unsigned i : indices (Args) ) {
1060
+ SILValue Arg = Args[i ];
1061
+ SILParameterInfo Param = Params[i ];
982
1062
983
1063
releasePartialApplyCapturedArg (Builder, Loc, Arg, Param, Callbacks);
984
1064
}
985
1065
}
1066
+
1067
+ return true ;
986
1068
}
987
1069
988
1070
// / TODO: Generalize this to general objects.
@@ -1007,8 +1089,12 @@ bool swift::tryDeleteDeadClosure(SILInstruction *Closure,
1007
1089
1008
1090
// If we have a partial_apply, release each captured argument at each one of
1009
1091
// the final release locations of the partial apply.
1010
- if (auto *PAI = dyn_cast<PartialApplyInst>(Closure))
1011
- releaseCapturedArgsOfDeadPartialApply (PAI, Tracker, Callbacks);
1092
+ if (auto *PAI = dyn_cast<PartialApplyInst>(Closure)) {
1093
+ // If we can not decrement the ref counts of the dead partial apply for any
1094
+ // reason, bail.
1095
+ if (!releaseCapturedArgsOfDeadPartialApply (PAI, Tracker, Callbacks))
1096
+ return false ;
1097
+ }
1012
1098
1013
1099
// Then delete all user instructions.
1014
1100
for (auto *User : Tracker.getTrackedUsers ()) {
0 commit comments