72
72
#include " swift/SILOptimizer/Utils/SILInliner.h"
73
73
#include " swift/SILOptimizer/Utils/SILOptFunctionBuilder.h"
74
74
#include " swift/SILOptimizer/Utils/SpecializationMangler.h"
75
+ #include " swift/SILOptimizer/Utils/StackNesting.h"
75
76
#include " llvm/ADT/SmallString.h"
77
+ #include " llvm/ADT/SmallSet.h"
76
78
#include " llvm/ADT/Statistic.h"
77
79
#include " llvm/Support/CommandLine.h"
78
80
#include " llvm/Support/Debug.h"
@@ -130,7 +132,8 @@ class ClosureSpecCloner : public SILClonerWithScopes<ClosureSpecCloner> {
130
132
SILValue
131
133
cloneCalleeConversion (SILValue calleeValue, SILValue NewClosure,
132
134
SILBuilder &Builder,
133
- SmallVectorImpl<PartialApplyInst *> &NeedsRelease);
135
+ SmallVectorImpl<PartialApplyInst *> &NeedsRelease,
136
+ llvm::DenseMap<SILValue, SILValue> &CapturedMap);
134
137
135
138
SILFunction *getCloned () { return &getBuilder ().getFunction (); }
136
139
static SILFunction *cloneFunction (SILOptFunctionBuilder &FunctionBuilder,
@@ -192,7 +195,18 @@ class CallSiteDescriptor {
192
195
}
193
196
194
197
bool closureHasRefSemanticContext () const {
195
- return isa<PartialApplyInst>(getClosure ());
198
+ return isa<PartialApplyInst>(getClosure ()) &&
199
+ !cast<PartialApplyInst>(getClosure ())->isOnStack ();
200
+ }
201
+
202
+ bool destroyIfPartialApplyStack (SILBuilder &B,
203
+ SingleValueInstruction *newClosure) const {
204
+ auto *PA = dyn_cast<PartialApplyInst>(newClosure);
205
+ if (!PA || !PA->isOnStack ())
206
+ return false ;
207
+ insertDestroyOfCapturedArguments (PA, B);
208
+ B.createDeallocStack (getClosure ()->getLoc (), PA);
209
+ return true ;
196
210
}
197
211
198
212
unsigned getClosureIndex () const { return ClosureIndex; }
@@ -207,12 +221,13 @@ class CallSiteDescriptor {
207
221
SingleValueInstruction *
208
222
createNewClosure (SILBuilder &B, SILValue V,
209
223
llvm::SmallVectorImpl<SILValue> &Args) const {
210
- if (isa <PartialApplyInst>(getClosure ()))
224
+ if (auto *PA = dyn_cast <PartialApplyInst>(getClosure ()))
211
225
return B.createPartialApply (getClosure ()->getLoc (), V, {}, Args,
212
226
getClosure ()
213
227
->getType ()
214
228
.getAs <SILFunctionType>()
215
- ->getCalleeConvention ());
229
+ ->getCalleeConvention (),
230
+ PA->isOnStack ());
216
231
217
232
assert (isa<ThinToThickFunctionInst>(getClosure ()) &&
218
233
" We only support partial_apply and thin_to_thick_function" );
@@ -256,6 +271,13 @@ class CallSiteDescriptor {
256
271
return getClosureParameterInfo ().isConsumed ();
257
272
}
258
273
274
+ bool isClosureOnStack () const {
275
+ auto *PA = dyn_cast<PartialApplyInst>(getClosure ());
276
+ if (!PA)
277
+ return false ;
278
+ return PA->isOnStack ();
279
+ }
280
+
259
281
bool isTrivialNoEscapeParameter () const {
260
282
auto ClosureParmFnTy =
261
283
getClosureParameterInfo ().getType ()->getAs <SILFunctionType>();
@@ -675,16 +697,29 @@ ClosureSpecCloner::initCloned(SILOptFunctionBuilder &FunctionBuilder,
675
697
// Clone a chain of ConvertFunctionInsts.
676
698
SILValue ClosureSpecCloner::cloneCalleeConversion (
677
699
SILValue calleeValue, SILValue NewClosure, SILBuilder &Builder,
678
- SmallVectorImpl<PartialApplyInst *> &NeedsRelease) {
700
+ SmallVectorImpl<PartialApplyInst *> &NeedsRelease,
701
+ llvm::DenseMap<SILValue, SILValue> &CapturedMap) {
702
+
703
+ // There might be a mark dependence on a previous closure value. Therefore, we
704
+ // add all closure values to the map.
705
+ auto addToOldToNewClosureMap = [&](SILValue origValue,
706
+ SILValue newValue) -> SILValue {
707
+ assert (!CapturedMap.count (origValue));
708
+ CapturedMap[origValue] = newValue;
709
+ return newValue;
710
+ };
711
+
679
712
if (calleeValue == CallSiteDesc.getClosure ())
680
- return NewClosure;
713
+ return addToOldToNewClosureMap (calleeValue, NewClosure) ;
681
714
682
715
if (auto *CFI = dyn_cast<ConvertFunctionInst>(calleeValue)) {
716
+ SILValue origCalleeValue = calleeValue;
683
717
calleeValue = cloneCalleeConversion (CFI->getOperand (), NewClosure, Builder,
684
- NeedsRelease);
685
- return Builder.createConvertFunction (CallSiteDesc.getLoc (), calleeValue,
686
- CFI->getType (),
687
- CFI->withoutActuallyEscaping ());
718
+ NeedsRelease, CapturedMap);
719
+ return addToOldToNewClosureMap (
720
+ origCalleeValue, Builder.createConvertFunction (
721
+ CallSiteDesc.getLoc (), calleeValue, CFI->getType (),
722
+ CFI->withoutActuallyEscaping ()));
688
723
}
689
724
690
725
if (auto *PAI = dyn_cast<PartialApplyInst>(calleeValue)) {
@@ -693,27 +728,52 @@ SILValue ClosureSpecCloner::cloneCalleeConversion(
693
728
->getType ()
694
729
.getAs <SILFunctionType>()
695
730
->isTrivialNoEscape ());
731
+ SILValue origCalleeValue = calleeValue;
696
732
calleeValue = cloneCalleeConversion (PAI->getArgument (0 ), NewClosure,
697
- Builder, NeedsRelease);
733
+ Builder, NeedsRelease, CapturedMap );
698
734
auto FunRef = Builder.createFunctionRef (CallSiteDesc.getLoc (),
699
735
PAI->getReferencedFunction ());
700
736
auto NewPA = Builder.createPartialApply (
701
737
CallSiteDesc.getLoc (), FunRef, {}, {calleeValue},
702
- PAI->getType ().getAs <SILFunctionType>()->getCalleeConvention ());
738
+ PAI->getType ().getAs <SILFunctionType>()->getCalleeConvention (),
739
+ PAI->isOnStack ());
740
+ // If the partial_apply is on stack we will emit a dealloc_stack in the
741
+ // epilog.
703
742
NeedsRelease.push_back (NewPA);
704
- return NewPA;
743
+ return addToOldToNewClosureMap (origCalleeValue, NewPA);
744
+ }
745
+
746
+ if (auto *MD = dyn_cast<MarkDependenceInst>(calleeValue)) {
747
+ SILValue origCalleeValue = calleeValue;
748
+ calleeValue = cloneCalleeConversion (MD->getValue (), NewClosure, Builder,
749
+ NeedsRelease, CapturedMap);
750
+ if (!CapturedMap.count (MD->getBase ())) {
751
+ CallSiteDesc.getClosure ()->dump ();
752
+ MD->dump ();
753
+ MD->getFunction ()->dump ();
754
+ }
755
+ assert (CapturedMap.count (MD->getBase ()));
756
+ return addToOldToNewClosureMap (
757
+ origCalleeValue,
758
+ Builder.createMarkDependence (CallSiteDesc.getLoc (), calleeValue,
759
+ CapturedMap[MD->getBase ()]));
705
760
}
706
761
762
+
707
763
auto *Cvt = cast<ConvertEscapeToNoEscapeInst>(calleeValue);
764
+ SILValue origCalleeValue = calleeValue;
708
765
calleeValue = cloneCalleeConversion (Cvt->getOperand (), NewClosure, Builder,
709
- NeedsRelease);
710
- return Builder.createConvertEscapeToNoEscape (
711
- CallSiteDesc.getLoc (), calleeValue, Cvt->getType (), true );
766
+ NeedsRelease, CapturedMap);
767
+ return addToOldToNewClosureMap (
768
+ origCalleeValue,
769
+ Builder.createConvertEscapeToNoEscape (CallSiteDesc.getLoc (), calleeValue,
770
+ Cvt->getType (), true ));
712
771
}
713
772
714
773
// / Populate the body of the cloned closure, modifying instructions as
715
- // / necessary. This is where we create the actual specialized BB Arguments.
774
+ // / necessary. This is where we create the actual specialized BB Arguments
716
775
void ClosureSpecCloner::populateCloned () {
776
+ bool needToUpdateStackNesting = false ;
717
777
SILFunction *Cloned = getCloned ();
718
778
SILFunction *ClosureUser = CallSiteDesc.getApplyCallee ();
719
779
@@ -752,10 +812,15 @@ void ClosureSpecCloner::populateCloned() {
752
812
unsigned NumTotalParams = ClosedOverFunConv.getNumParameters ();
753
813
unsigned NumNotCaptured = NumTotalParams - CallSiteDesc.getNumArguments ();
754
814
llvm::SmallVector<SILValue, 4 > NewPAIArgs;
815
+ llvm::DenseMap<SILValue, SILValue> CapturedMap;
816
+ unsigned idx = 0 ;
755
817
for (auto &PInfo : ClosedOverFunConv.getParameters ().slice (NumNotCaptured)) {
756
818
auto paramTy = ClosedOverFunConv.getSILType (PInfo);
757
819
SILValue MappedValue = ClonedEntryBB->createFunctionArgument (paramTy);
758
820
NewPAIArgs.push_back (MappedValue);
821
+ auto CapturedVal =
822
+ cast<PartialApplyInst>(CallSiteDesc.getClosure ())->getArgument (idx++);
823
+ CapturedMap[CapturedVal] = MappedValue;
759
824
}
760
825
761
826
SILBuilder &Builder = getBuilder ();
@@ -770,8 +835,9 @@ void ClosureSpecCloner::populateCloned() {
770
835
// Clone a chain of ConvertFunctionInsts. This can create further
771
836
// reabstraction partial_apply instructions.
772
837
SmallVector<PartialApplyInst*, 4 > NeedsRelease;
773
- SILValue ConvertedCallee = cloneCalleeConversion (
774
- CallSiteDesc.getClosureCallerArg (), NewClosure, Builder, NeedsRelease);
838
+ SILValue ConvertedCallee =
839
+ cloneCalleeConversion (CallSiteDesc.getClosureCallerArg (), NewClosure,
840
+ Builder, NeedsRelease, CapturedMap);
775
841
776
842
// Make sure that we actually emit the releases for reabstraction thunks. We
777
843
// have guaranteed earlier that we only allow reabstraction thunks if the
@@ -790,7 +856,8 @@ void ClosureSpecCloner::populateCloned() {
790
856
bool ClosureHasRefSemantics = CallSiteDesc.closureHasRefSemanticContext ();
791
857
if ((CallSiteDesc.isClosureGuaranteed () ||
792
858
CallSiteDesc.isTrivialNoEscapeParameter ()) &&
793
- (ClosureHasRefSemantics || !NeedsRelease.empty ())) {
859
+ (ClosureHasRefSemantics || !NeedsRelease.empty () ||
860
+ CallSiteDesc.isClosureOnStack ())) {
794
861
for (SILBasicBlock *BB : CallSiteDesc.getNonFailureExitBBs ()) {
795
862
SILBasicBlock *OpBB = getOpBasicBlock (BB);
796
863
@@ -804,9 +871,17 @@ void ClosureSpecCloner::populateCloned() {
804
871
if (ClosureHasRefSemantics)
805
872
Builder.createReleaseValue (Loc, SILValue (NewClosure),
806
873
Builder.getDefaultAtomicity ());
807
- for (auto PAI : NeedsRelease)
808
- Builder.createReleaseValue (Loc, SILValue (PAI),
809
- Builder.getDefaultAtomicity ());
874
+ else
875
+ needToUpdateStackNesting |=
876
+ CallSiteDesc.destroyIfPartialApplyStack (Builder, NewClosure);
877
+ for (auto PAI : NeedsRelease) {
878
+ if (PAI->isOnStack ())
879
+ needToUpdateStackNesting |=
880
+ CallSiteDesc.destroyIfPartialApplyStack (Builder, PAI);
881
+ else
882
+ Builder.createReleaseValue (Loc, SILValue (PAI),
883
+ Builder.getDefaultAtomicity ());
884
+ }
810
885
continue ;
811
886
}
812
887
@@ -825,11 +900,22 @@ void ClosureSpecCloner::populateCloned() {
825
900
if (ClosureHasRefSemantics)
826
901
Builder.createReleaseValue (Loc, SILValue (NewClosure),
827
902
Builder.getDefaultAtomicity ());
828
- for (auto PAI : NeedsRelease)
829
- Builder.createReleaseValue (Loc, SILValue (PAI),
830
- Builder.getDefaultAtomicity ());
903
+ else
904
+ needToUpdateStackNesting |=
905
+ CallSiteDesc.destroyIfPartialApplyStack (Builder, NewClosure);
906
+ for (auto PAI : NeedsRelease) {
907
+ if (PAI->isOnStack ())
908
+ needToUpdateStackNesting |=
909
+ CallSiteDesc.destroyIfPartialApplyStack (Builder, PAI);
910
+ else
911
+ Builder.createReleaseValue (Loc, SILValue (PAI),
912
+ Builder.getDefaultAtomicity ());
913
+ }
831
914
}
832
915
}
916
+ if (needToUpdateStackNesting) {
917
+ StackNesting ().correctStackNesting (Cloned);
918
+ }
833
919
}
834
920
835
921
// ===----------------------------------------------------------------------===//
@@ -913,6 +999,10 @@ static void markReabstractionPartialApplyAsUsed(
913
999
return markReabstractionPartialApplyAsUsed (FirstClosure, Cvt->getOperand (),
914
1000
UsedReabstractionClosure);
915
1001
}
1002
+ if (auto MD = dyn_cast<MarkDependenceInst>(Current)) {
1003
+ return markReabstractionPartialApplyAsUsed (FirstClosure, MD->getValue (),
1004
+ UsedReabstractionClosure);
1005
+ }
916
1006
llvm_unreachable (" Unexpect instruction" );
917
1007
}
918
1008
@@ -994,6 +1084,14 @@ bool SILClosureSpecializerTransform::gatherCallSites(
994
1084
// Live range end points.
995
1085
SmallVector<SILInstruction *, 8 > UsePoints;
996
1086
1087
+ // Set of possible arguments for mark_dependence. The base of a
1088
+ // mark_dependence we copy must be available in the specialized function.
1089
+ llvm::SmallSet<SILValue, 16 > PossibleMarkDependenceBases;
1090
+ if (auto *PA = dyn_cast<PartialApplyInst>(ClosureInst)) {
1091
+ for (auto Opd : PA->getArguments ())
1092
+ PossibleMarkDependenceBases.insert (Opd);
1093
+ }
1094
+
997
1095
bool HaveUsedReabstraction = false ;
998
1096
// Uses may grow in this loop.
999
1097
for (size_t UseIndex = 0 ; UseIndex < Uses.size (); ++UseIndex) {
@@ -1004,10 +1102,12 @@ bool SILClosureSpecializerTransform::gatherCallSites(
1004
1102
if (auto *CFI = dyn_cast<ConvertFunctionInst>(Use->getUser ())) {
1005
1103
// Push Uses in reverse order so they are visited in forward order.
1006
1104
Uses.append (CFI->getUses ().begin (), CFI->getUses ().end ());
1105
+ PossibleMarkDependenceBases.insert (CFI);
1007
1106
continue ;
1008
1107
}
1009
1108
if (auto *Cvt = dyn_cast<ConvertEscapeToNoEscapeInst>(Use->getUser ())) {
1010
1109
Uses.append (Cvt->getUses ().begin (), Cvt->getUses ().end ());
1110
+ PossibleMarkDependenceBases.insert (Cvt);
1011
1111
continue ;
1012
1112
}
1013
1113
@@ -1025,11 +1125,29 @@ bool SILClosureSpecializerTransform::gatherCallSites(
1025
1125
.getAs <SILFunctionType>()
1026
1126
->isTrivialNoEscape ()) {
1027
1127
Uses.append (PA->getUses ().begin (), PA->getUses ().end ());
1128
+ PossibleMarkDependenceBases.insert (PA);
1028
1129
HaveUsedReabstraction = true ;
1029
1130
}
1030
1131
continue ;
1031
1132
}
1032
1133
1134
+ // Look through mark_dependence on partial_apply [stack].
1135
+ if (auto *MD = dyn_cast<MarkDependenceInst>(Use->getUser ())) {
1136
+ // We can't copy a closure if the mark_dependence base is not
1137
+ // available in the specialized function.
1138
+ if (!PossibleMarkDependenceBases.count (MD->getBase ()))
1139
+ continue ;
1140
+ if (MD->getValue () == Use->get () &&
1141
+ MD->getValue ()->getType ().is <SILFunctionType>() &&
1142
+ MD->getValue ()
1143
+ ->getType ()
1144
+ .castTo <SILFunctionType>()
1145
+ ->isTrivialNoEscape ()) {
1146
+ Uses.append (MD->getUses ().begin (), MD->getUses ().end ());
1147
+ continue ;
1148
+ }
1149
+ }
1150
+
1033
1151
// If this use is not a full apply site that we can process or an apply
1034
1152
// inst with substitutions, there is nothing interesting for us to do,
1035
1153
// so continue...
0 commit comments