57
57
58
58
#define DEBUG_TYPE " closure-specialization"
59
59
#include " swift/Basic/Range.h"
60
+ #include " swift/SIL/InstructionUtils.h"
60
61
#include " swift/SIL/SILCloner.h"
61
62
#include " swift/SIL/SILFunction.h"
62
63
#include " swift/SIL/SILInstruction.h"
@@ -123,8 +124,10 @@ class ClosureSpecCloner : public SILClonerWithScopes<ClosureSpecCloner> {
123
124
124
125
void populateCloned ();
125
126
126
- SILValue cloneCalleeConversion (SILValue calleeValue, SILValue NewClosure,
127
- SILBuilder &Builder);
127
+ SILValue
128
+ cloneCalleeConversion (SILValue calleeValue, SILValue NewClosure,
129
+ SILBuilder &Builder,
130
+ SmallVectorImpl<PartialApplyInst *> &NeedsRelease);
128
131
129
132
SILFunction *getCloned () { return &getBuilder ().getFunction (); }
130
133
static SILFunction *cloneFunction (const CallSiteDescriptor &CallSiteDesc,
@@ -274,7 +277,7 @@ struct ClosureInfo {
274
277
ValueLifetimeAnalysis::Frontier LifetimeFrontier;
275
278
llvm::SmallVector<CallSiteDescriptor, 8 > CallSites;
276
279
277
- ClosureInfo (SingleValueInstruction *Closure): Closure(Closure) {}
280
+ ClosureInfo (SingleValueInstruction *Closure) : Closure(Closure) {}
278
281
279
282
ClosureInfo (ClosureInfo &&) =default ;
280
283
ClosureInfo &operator =(ClosureInfo &&) =default ;
@@ -648,20 +651,39 @@ ClosureSpecCloner::initCloned(const CallSiteDescriptor &CallSiteDesc,
648
651
}
649
652
650
653
// Clone a chain of ConvertFunctionInsts.
651
- SILValue ClosureSpecCloner::cloneCalleeConversion (SILValue calleeValue,
652
- SILValue NewClosure,
653
- SILBuilder &Builder ) {
654
+ SILValue ClosureSpecCloner::cloneCalleeConversion (
655
+ SILValue calleeValue, SILValue NewClosure, SILBuilder &Builder ,
656
+ SmallVectorImpl<PartialApplyInst *> &NeedsRelease ) {
654
657
if (calleeValue == CallSiteDesc.getClosure ())
655
658
return NewClosure;
656
659
657
660
if (auto *CFI = dyn_cast<ConvertFunctionInst>(calleeValue)) {
658
- calleeValue = cloneCalleeConversion (CFI->getOperand (), NewClosure, Builder);
661
+ calleeValue = cloneCalleeConversion (CFI->getOperand (), NewClosure, Builder,
662
+ NeedsRelease);
659
663
return Builder.createConvertFunction (CallSiteDesc.getLoc (), calleeValue,
660
664
CFI->getType ());
661
665
}
662
666
667
+ if (auto *PAI = dyn_cast<PartialApplyInst>(calleeValue)) {
668
+ assert (isPartialApplyOfReabstractionThunk (PAI) && isSupportedClosure (PAI) &&
669
+ PAI->getArgument (0 )
670
+ ->getType ()
671
+ .getAs <SILFunctionType>()
672
+ ->isTrivialNoEscape ());
673
+ calleeValue = cloneCalleeConversion (PAI->getArgument (0 ), NewClosure,
674
+ Builder, NeedsRelease);
675
+ auto FunRef = Builder.createFunctionRef (CallSiteDesc.getLoc (),
676
+ PAI->getReferencedFunction ());
677
+ auto NewPA = Builder.createPartialApply (
678
+ CallSiteDesc.getLoc (), FunRef, {}, {calleeValue},
679
+ PAI->getType ().getAs <SILFunctionType>()->getCalleeConvention ());
680
+ NeedsRelease.push_back (NewPA);
681
+ return NewPA;
682
+ }
683
+
663
684
auto *Cvt = cast<ConvertEscapeToNoEscapeInst>(calleeValue);
664
- calleeValue = cloneCalleeConversion (Cvt->getOperand (), NewClosure, Builder);
685
+ calleeValue = cloneCalleeConversion (Cvt->getOperand (), NewClosure, Builder,
686
+ NeedsRelease);
665
687
return Builder.createConvertEscapeToNoEscape (
666
688
CallSiteDesc.getLoc (), calleeValue, Cvt->getType (), false , true );
667
689
}
@@ -718,9 +740,17 @@ void ClosureSpecCloner::populateCloned() {
718
740
Builder.createFunctionRef (CallSiteDesc.getLoc (), ClosedOverFun);
719
741
auto *NewClosure = CallSiteDesc.createNewClosure (Builder, FnVal, NewPAIArgs);
720
742
721
- // Clone a chain of ConvertFunctionInsts.
743
+ // Clone a chain of ConvertFunctionInsts. This can create further
744
+ // reabstraction partial_apply instructions.
745
+ SmallVector<PartialApplyInst*, 4 > NeedsRelease;
722
746
SILValue ConvertedCallee = cloneCalleeConversion (
723
- CallSiteDesc.getClosureCallerArg (), NewClosure, Builder);
747
+ CallSiteDesc.getClosureCallerArg (), NewClosure, Builder, NeedsRelease);
748
+
749
+ // Make sure that we actually emit the releases for reabstraction thunks. We
750
+ // have guaranteed earlier that we only allow reabstraction thunks if the
751
+ // closure was passed trivial.
752
+ assert (NeedsRelease.empty () || CallSiteDesc.isTrivialNoEscapeParameter ());
753
+
724
754
ValueMap.insert (std::make_pair (ClosureArg, ConvertedCallee));
725
755
726
756
BBMap.insert (std::make_pair (ClosureUserEntryBB, ClonedEntryBB));
@@ -736,10 +766,11 @@ void ClosureSpecCloner::populateCloned() {
736
766
737
767
// Then insert a release in all non failure exit BBs if our partial apply was
738
768
// guaranteed. This is b/c it was passed at +0 originally and we need to
739
- // balance the initial increment of the newly created closure.
769
+ // balance the initial increment of the newly created closure(s).
770
+ bool ClosureHasRefSemantics = CallSiteDesc.closureHasRefSemanticContext ();
740
771
if ((CallSiteDesc.isClosureGuaranteed () ||
741
772
CallSiteDesc.isTrivialNoEscapeParameter ()) &&
742
- CallSiteDesc. closureHasRefSemanticContext ( )) {
773
+ (ClosureHasRefSemantics || !NeedsRelease. empty () )) {
743
774
for (SILBasicBlock *BB : CallSiteDesc.getNonFailureExitBBs ()) {
744
775
SILBasicBlock *OpBB = BBMap[BB];
745
776
@@ -750,13 +781,21 @@ void ClosureSpecCloner::populateCloned() {
750
781
// that it will be executed at the end of the epilogue.
751
782
if (isa<ReturnInst>(TI)) {
752
783
Builder.setInsertionPoint (TI);
753
- Builder.createReleaseValue (Loc, SILValue (NewClosure),
754
- Builder.getDefaultAtomicity ());
784
+ if (ClosureHasRefSemantics)
785
+ Builder.createReleaseValue (Loc, SILValue (NewClosure),
786
+ Builder.getDefaultAtomicity ());
787
+ for (auto PAI : NeedsRelease)
788
+ Builder.createReleaseValue (Loc, SILValue (PAI),
789
+ Builder.getDefaultAtomicity ());
755
790
continue ;
756
791
} else if (isa<ThrowInst>(TI)) {
757
792
Builder.setInsertionPoint (TI);
758
- Builder.createReleaseValue (Loc, SILValue (NewClosure),
759
- Builder.getDefaultAtomicity ());
793
+ if (ClosureHasRefSemantics)
794
+ Builder.createReleaseValue (Loc, SILValue (NewClosure),
795
+ Builder.getDefaultAtomicity ());
796
+ for (auto PAI : NeedsRelease)
797
+ Builder.createReleaseValue (Loc, SILValue (PAI),
798
+ Builder.getDefaultAtomicity ());
760
799
continue ;
761
800
}
762
801
@@ -772,7 +811,12 @@ void ClosureSpecCloner::populateCloned() {
772
811
// value, we will retain the partial apply before we release it and
773
812
// potentially eliminate it.
774
813
Builder.setInsertionPoint (NoReturnApply.getInstruction ());
775
- Builder.createReleaseValue (Loc, SILValue (NewClosure), Builder.getDefaultAtomicity ());
814
+ if (ClosureHasRefSemantics)
815
+ Builder.createReleaseValue (Loc, SILValue (NewClosure),
816
+ Builder.getDefaultAtomicity ());
817
+ for (auto PAI : NeedsRelease)
818
+ Builder.createReleaseValue (Loc, SILValue (PAI),
819
+ Builder.getDefaultAtomicity ());
776
820
}
777
821
}
778
822
}
@@ -839,6 +883,27 @@ void SILClosureSpecializerTransform::run() {
839
883
invalidateAnalysis (SILAnalysis::InvalidationKind::Everything);
840
884
}
841
885
886
+ static void markReabstractionPartialApplyAsUsed (
887
+ SILValue FirstClosure, SILValue Current,
888
+ llvm::DenseSet<SingleValueInstruction *> &UsedReabstractionClosure) {
889
+ if (Current == FirstClosure)
890
+ return ;
891
+ if (auto PA = dyn_cast<PartialApplyInst>(Current)) {
892
+ UsedReabstractionClosure.insert (PA);
893
+ return markReabstractionPartialApplyAsUsed (FirstClosure, PA->getArgument (0 ),
894
+ UsedReabstractionClosure);
895
+ }
896
+ if (auto Cvt = dyn_cast<ConvertFunctionInst>(Current)) {
897
+ return markReabstractionPartialApplyAsUsed (FirstClosure, Cvt->getOperand (),
898
+ UsedReabstractionClosure);
899
+ }
900
+ if (auto Cvt = dyn_cast<ConvertEscapeToNoEscapeInst>(Current)) {
901
+ return markReabstractionPartialApplyAsUsed (FirstClosure, Cvt->getOperand (),
902
+ UsedReabstractionClosure);
903
+ }
904
+ llvm_unreachable (" Unexpect instruction" );
905
+ }
906
+
842
907
void SILClosureSpecializerTransform::gatherCallSites (
843
908
SILFunction *Caller,
844
909
llvm::SmallVectorImpl<ClosureInfo*> &ClosureCandidates,
@@ -848,6 +913,10 @@ void SILClosureSpecializerTransform::gatherCallSites(
848
913
// make sure that we do not handle call sites with multiple closure arguments.
849
914
llvm::DenseSet<FullApplySite> VisitedAI;
850
915
916
+ // We should not look at reabstraction closure twice who we ultimately ended
917
+ // up using as an argument that we specialize on.
918
+ llvm::DenseSet<SingleValueInstruction *> UsedReabstractionClosure;
919
+
851
920
// For each basic block BB in Caller...
852
921
for (auto &BB : *Caller) {
853
922
@@ -857,6 +926,8 @@ void SILClosureSpecializerTransform::gatherCallSites(
857
926
if (!isSupportedClosure (&II))
858
927
continue ;
859
928
auto ClosureInst = cast<SingleValueInstruction>(&II);
929
+ if (UsedReabstractionClosure.count (ClosureInst))
930
+ continue ;
860
931
861
932
ClosureInfo *CInfo = nullptr ;
862
933
@@ -868,6 +939,7 @@ void SILClosureSpecializerTransform::gatherCallSites(
868
939
// Live range end points.
869
940
SmallVector<SILInstruction *, 8 > UsePoints;
870
941
942
+ bool HaveUsedReabstraction = false ;
871
943
// Uses may grow in this loop.
872
944
for (size_t UseIndex = 0 ; UseIndex < Uses.size (); ++UseIndex) {
873
945
auto *Use = Uses[UseIndex];
@@ -883,6 +955,26 @@ void SILClosureSpecializerTransform::gatherCallSites(
883
955
Uses.append (Cvt->getUses ().begin (), Cvt->getUses ().end ());
884
956
continue ;
885
957
}
958
+
959
+ // Look through reabstraction thunks.
960
+ if (auto *PA = dyn_cast<PartialApplyInst>(Use->getUser ())) {
961
+ // Reabstraction can cause series of partial_apply to be emitted. It
962
+ // is okay to treat these like conversion instructions. Current
963
+ // restriction: if the partial_apply does not take ownership of its
964
+ // argument we don't need to analyze which partial_apply to emit
965
+ // release for (its all of them).
966
+ if (isPartialApplyOfReabstractionThunk (PA) &&
967
+ isSupportedClosure (PA) &&
968
+ PA->getArgument (0 )
969
+ ->getType ()
970
+ .getAs <SILFunctionType>()
971
+ ->isTrivialNoEscape ()) {
972
+ Uses.append (PA->getUses ().begin (), PA->getUses ().end ());
973
+ HaveUsedReabstraction = true ;
974
+ }
975
+ continue ;
976
+ }
977
+
886
978
// If this use is not an apply inst or an apply inst with
887
979
// substitutions, there is nothing interesting for us to do, so
888
980
// continue...
@@ -961,6 +1053,14 @@ void SILClosureSpecializerTransform::gatherCallSites(
961
1053
auto ParamInfo = AI.getSubstCalleeType ()->getParameters ();
962
1054
SILParameterInfo ClosureParamInfo = ParamInfo[ClosureParamIndex];
963
1055
1056
+ // We currently only support copying intermediate reabastraction
1057
+ // closures if the closure is ultimately passed trivially.
1058
+ bool IsClosurePassedTrivially = ClosureParamInfo.getType ()
1059
+ ->castTo <SILFunctionType>()
1060
+ ->isTrivialNoEscape ();
1061
+ if (HaveUsedReabstraction && !IsClosurePassedTrivially)
1062
+ continue ;
1063
+
964
1064
// Get all non-failure exit BBs in the Apply Callee if our partial apply
965
1065
// is guaranteed. If we do not understand one of the exit BBs, bail.
966
1066
//
@@ -969,11 +1069,12 @@ void SILClosureSpecializerTransform::gatherCallSites(
969
1069
//
970
1070
// However, thin_to_thick_function closures don't have a context and
971
1071
// don't need to be released.
1072
+ bool OnlyHaveThinToThickClosure =
1073
+ isa<ThinToThickFunctionInst>(ClosureInst) && !HaveUsedReabstraction;
1074
+
972
1075
llvm::TinyPtrVector<SILBasicBlock *> NonFailureExitBBs;
973
- if ((ClosureParamInfo.isGuaranteed () || ClosureParamInfo.getType ()
974
- ->castTo <SILFunctionType>()
975
- ->isTrivialNoEscape ()) &&
976
- !isa<ThinToThickFunctionInst>(ClosureInst) &&
1076
+ if ((ClosureParamInfo.isGuaranteed () || IsClosurePassedTrivially) &&
1077
+ !OnlyHaveThinToThickClosure &&
977
1078
!findAllNonFailureExitBBs (ApplyCallee, NonFailureExitBBs)) {
978
1079
continue ;
979
1080
}
@@ -983,6 +1084,10 @@ void SILClosureSpecializerTransform::gatherCallSites(
983
1084
if (!CInfo)
984
1085
CInfo = new ClosureInfo (ClosureInst);
985
1086
1087
+ // Mark the reabstraction closures as used.
1088
+ if (HaveUsedReabstraction)
1089
+ markReabstractionPartialApplyAsUsed (ClosureInst, Use->get (),
1090
+ UsedReabstractionClosure);
986
1091
// Now we know that CSDesc is profitable to specialize. Add it to our
987
1092
// call site list.
988
1093
CInfo->CallSites .push_back (
0 commit comments