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