Skip to content

Commit b823db8

Browse files
Merge pull request swiftlang#16752 from aschwaighofer/closure_specializer
Allow closure specialization of reabastraction thunks
2 parents e8b0b35 + 25038d8 commit b823db8

File tree

2 files changed

+250
-21
lines changed

2 files changed

+250
-21
lines changed

lib/SILOptimizer/IPO/ClosureSpecializer.cpp

Lines changed: 126 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757

5858
#define DEBUG_TYPE "closure-specialization"
5959
#include "swift/Basic/Range.h"
60+
#include "swift/SIL/InstructionUtils.h"
6061
#include "swift/SIL/SILCloner.h"
6162
#include "swift/SIL/SILFunction.h"
6263
#include "swift/SIL/SILInstruction.h"
@@ -123,8 +124,10 @@ class ClosureSpecCloner : public SILClonerWithScopes<ClosureSpecCloner> {
123124

124125
void populateCloned();
125126

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);
128131

129132
SILFunction *getCloned() { return &getBuilder().getFunction(); }
130133
static SILFunction *cloneFunction(const CallSiteDescriptor &CallSiteDesc,
@@ -274,7 +277,7 @@ struct ClosureInfo {
274277
ValueLifetimeAnalysis::Frontier LifetimeFrontier;
275278
llvm::SmallVector<CallSiteDescriptor, 8> CallSites;
276279

277-
ClosureInfo(SingleValueInstruction *Closure): Closure(Closure) {}
280+
ClosureInfo(SingleValueInstruction *Closure) : Closure(Closure) {}
278281

279282
ClosureInfo(ClosureInfo &&) =default;
280283
ClosureInfo &operator=(ClosureInfo &&) =default;
@@ -648,20 +651,39 @@ ClosureSpecCloner::initCloned(const CallSiteDescriptor &CallSiteDesc,
648651
}
649652

650653
// 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) {
654657
if (calleeValue == CallSiteDesc.getClosure())
655658
return NewClosure;
656659

657660
if (auto *CFI = dyn_cast<ConvertFunctionInst>(calleeValue)) {
658-
calleeValue = cloneCalleeConversion(CFI->getOperand(), NewClosure, Builder);
661+
calleeValue = cloneCalleeConversion(CFI->getOperand(), NewClosure, Builder,
662+
NeedsRelease);
659663
return Builder.createConvertFunction(CallSiteDesc.getLoc(), calleeValue,
660664
CFI->getType());
661665
}
662666

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+
663684
auto *Cvt = cast<ConvertEscapeToNoEscapeInst>(calleeValue);
664-
calleeValue = cloneCalleeConversion(Cvt->getOperand(), NewClosure, Builder);
685+
calleeValue = cloneCalleeConversion(Cvt->getOperand(), NewClosure, Builder,
686+
NeedsRelease);
665687
return Builder.createConvertEscapeToNoEscape(
666688
CallSiteDesc.getLoc(), calleeValue, Cvt->getType(), false, true);
667689
}
@@ -718,9 +740,17 @@ void ClosureSpecCloner::populateCloned() {
718740
Builder.createFunctionRef(CallSiteDesc.getLoc(), ClosedOverFun);
719741
auto *NewClosure = CallSiteDesc.createNewClosure(Builder, FnVal, NewPAIArgs);
720742

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;
722746
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+
724754
ValueMap.insert(std::make_pair(ClosureArg, ConvertedCallee));
725755

726756
BBMap.insert(std::make_pair(ClosureUserEntryBB, ClonedEntryBB));
@@ -736,10 +766,11 @@ void ClosureSpecCloner::populateCloned() {
736766

737767
// Then insert a release in all non failure exit BBs if our partial apply was
738768
// 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();
740771
if ((CallSiteDesc.isClosureGuaranteed() ||
741772
CallSiteDesc.isTrivialNoEscapeParameter()) &&
742-
CallSiteDesc.closureHasRefSemanticContext()) {
773+
(ClosureHasRefSemantics || !NeedsRelease.empty())) {
743774
for (SILBasicBlock *BB : CallSiteDesc.getNonFailureExitBBs()) {
744775
SILBasicBlock *OpBB = BBMap[BB];
745776

@@ -750,13 +781,21 @@ void ClosureSpecCloner::populateCloned() {
750781
// that it will be executed at the end of the epilogue.
751782
if (isa<ReturnInst>(TI)) {
752783
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());
755790
continue;
756791
} else if (isa<ThrowInst>(TI)) {
757792
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());
760799
continue;
761800
}
762801

@@ -772,7 +811,12 @@ void ClosureSpecCloner::populateCloned() {
772811
// value, we will retain the partial apply before we release it and
773812
// potentially eliminate it.
774813
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());
776820
}
777821
}
778822
}
@@ -839,6 +883,27 @@ void SILClosureSpecializerTransform::run() {
839883
invalidateAnalysis(SILAnalysis::InvalidationKind::Everything);
840884
}
841885

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+
842907
void SILClosureSpecializerTransform::gatherCallSites(
843908
SILFunction *Caller,
844909
llvm::SmallVectorImpl<ClosureInfo*> &ClosureCandidates,
@@ -848,6 +913,10 @@ void SILClosureSpecializerTransform::gatherCallSites(
848913
// make sure that we do not handle call sites with multiple closure arguments.
849914
llvm::DenseSet<FullApplySite> VisitedAI;
850915

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+
851920
// For each basic block BB in Caller...
852921
for (auto &BB : *Caller) {
853922

@@ -857,6 +926,8 @@ void SILClosureSpecializerTransform::gatherCallSites(
857926
if (!isSupportedClosure(&II))
858927
continue;
859928
auto ClosureInst = cast<SingleValueInstruction>(&II);
929+
if (UsedReabstractionClosure.count(ClosureInst))
930+
continue;
860931

861932
ClosureInfo *CInfo = nullptr;
862933

@@ -868,6 +939,7 @@ void SILClosureSpecializerTransform::gatherCallSites(
868939
// Live range end points.
869940
SmallVector<SILInstruction *, 8> UsePoints;
870941

942+
bool HaveUsedReabstraction = false;
871943
// Uses may grow in this loop.
872944
for (size_t UseIndex = 0; UseIndex < Uses.size(); ++UseIndex) {
873945
auto *Use = Uses[UseIndex];
@@ -883,6 +955,26 @@ void SILClosureSpecializerTransform::gatherCallSites(
883955
Uses.append(Cvt->getUses().begin(), Cvt->getUses().end());
884956
continue;
885957
}
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+
886978
// If this use is not an apply inst or an apply inst with
887979
// substitutions, there is nothing interesting for us to do, so
888980
// continue...
@@ -961,6 +1053,14 @@ void SILClosureSpecializerTransform::gatherCallSites(
9611053
auto ParamInfo = AI.getSubstCalleeType()->getParameters();
9621054
SILParameterInfo ClosureParamInfo = ParamInfo[ClosureParamIndex];
9631055

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+
9641064
// Get all non-failure exit BBs in the Apply Callee if our partial apply
9651065
// is guaranteed. If we do not understand one of the exit BBs, bail.
9661066
//
@@ -969,11 +1069,12 @@ void SILClosureSpecializerTransform::gatherCallSites(
9691069
//
9701070
// However, thin_to_thick_function closures don't have a context and
9711071
// don't need to be released.
1072+
bool OnlyHaveThinToThickClosure =
1073+
isa<ThinToThickFunctionInst>(ClosureInst) && !HaveUsedReabstraction;
1074+
9721075
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 &&
9771078
!findAllNonFailureExitBBs(ApplyCallee, NonFailureExitBBs)) {
9781079
continue;
9791080
}
@@ -983,6 +1084,10 @@ void SILClosureSpecializerTransform::gatherCallSites(
9831084
if (!CInfo)
9841085
CInfo = new ClosureInfo(ClosureInst);
9851086

1087+
// Mark the reabstraction closures as used.
1088+
if (HaveUsedReabstraction)
1089+
markReabstractionPartialApplyAsUsed(ClosureInst, Use->get(),
1090+
UsedReabstractionClosure);
9861091
// Now we know that CSDesc is profitable to specialize. Add it to our
9871092
// call site list.
9881093
CInfo->CallSites.push_back(

0 commit comments

Comments
 (0)