5757
5858#define DEBUG_TYPE " closure-specialization"
5959#include " swift/Basic/Range.h"
60+ #include " swift/Demangling/Demangler.h"
6061#include " swift/SIL/InstructionUtils.h"
6162#include " swift/SIL/SILCloner.h"
6263#include " swift/SIL/SILFunction.h"
@@ -162,6 +163,14 @@ class ClosureSpecCloner : public SILClonerWithScopes<ClosureSpecCloner> {
162163namespace {
163164struct ClosureInfo ;
164165
166+ static SILFunction *getClosureCallee (SILInstruction *inst) {
167+ if (auto *PAI = dyn_cast<PartialApplyInst>(inst))
168+ return cast<FunctionRefInst>(PAI->getCallee ())->getReferencedFunction ();
169+
170+ auto *TTTFI = cast<ThinToThickFunctionInst>(inst);
171+ return cast<FunctionRefInst>(TTTFI->getCallee ())->getReferencedFunction ();
172+ }
173+
165174class CallSiteDescriptor {
166175 ClosureInfo *CInfo;
167176 FullApplySite AI;
@@ -188,11 +197,7 @@ class CallSiteDescriptor {
188197 }
189198
190199 SILFunction *getClosureCallee () const {
191- if (auto *PAI = dyn_cast<PartialApplyInst>(getClosure ()))
192- return cast<FunctionRefInst>(PAI->getCallee ())->getReferencedFunction ();
193-
194- auto *TTTFI = cast<ThinToThickFunctionInst>(getClosure ());
195- return cast<FunctionRefInst>(TTTFI->getCallee ())->getReferencedFunction ();
200+ return ::getClosureCallee (getClosure ());
196201 }
197202
198203 bool closureHasRefSemanticContext () const {
@@ -1065,6 +1070,59 @@ static bool canSpecializeFullApplySite(FullApplySiteKind kind) {
10651070 llvm_unreachable (" covered switch" );
10661071}
10671072
1073+ static int getSpecializationLevelRecursive (StringRef funcName, Demangler &parent) {
1074+ using namespace Demangle ;
1075+
1076+ Demangler demangler;
1077+ demangler.providePreallocatedMemory (parent);
1078+
1079+ // Check for this kind of node tree:
1080+ //
1081+ // kind=Global
1082+ // kind=FunctionSignatureSpecialization
1083+ // kind=SpecializationPassID, index=1
1084+ // kind=FunctionSignatureSpecializationParam
1085+ // kind=FunctionSignatureSpecializationParamKind, index=5
1086+ // kind=FunctionSignatureSpecializationParamPayload, text="..."
1087+ //
1088+ Node *root = demangler.demangleSymbol (funcName);
1089+ if (!root)
1090+ return 0 ;
1091+ if (root->getKind () != Node::Kind::Global)
1092+ return 0 ;
1093+ Node *funcSpec = root->getFirstChild ();
1094+ if (!funcSpec || funcSpec->getNumChildren () < 2 )
1095+ return 0 ;
1096+ if (funcSpec->getKind () != Node::Kind::FunctionSignatureSpecialization)
1097+ return 0 ;
1098+ Node *param = funcSpec->getChild (1 );
1099+ if (param->getKind () != Node::Kind::FunctionSignatureSpecializationParam)
1100+ return 0 ;
1101+ if (param->getNumChildren () < 2 )
1102+ return 0 ;
1103+ Node *kindNd = param->getChild (0 );
1104+ if (kindNd->getKind () != Node::Kind::FunctionSignatureSpecializationParamKind)
1105+ return 0 ;
1106+ auto kind = FunctionSigSpecializationParamKind (kindNd->getIndex ());
1107+ if (kind != FunctionSigSpecializationParamKind::ConstantPropFunction)
1108+ return 0 ;
1109+
1110+ Node *payload = param->getChild (1 );
1111+ if (payload->getKind () != Node::Kind::FunctionSignatureSpecializationParamPayload)
1112+ return 1 ;
1113+ // Check if the specialized function is a specialization itself.
1114+ return 1 + getSpecializationLevelRecursive (payload->getText (), demangler);
1115+ }
1116+
1117+ // / If \p function is a function-signature specialization for a constant-
1118+ // / propagated function argument, returns 1.
1119+ // / If \p function is a specialization of such a specialization, returns 2.
1120+ // / And so on.
1121+ static int getSpecializationLevel (SILFunction *f) {
1122+ Demangle::StackAllocatedDemangler<1024 > demangler;
1123+ return getSpecializationLevelRecursive (f->getName (), demangler);
1124+ }
1125+
10681126bool SILClosureSpecializerTransform::gatherCallSites (
10691127 SILFunction *Caller,
10701128 llvm::SmallVectorImpl<std::unique_ptr<ClosureInfo>> &ClosureCandidates,
@@ -1252,6 +1310,24 @@ bool SILClosureSpecializerTransform::gatherCallSites(
12521310 continue ;
12531311 }
12541312
1313+ // Avoid an infinite specialization loop caused by repeated runs of
1314+ // ClosureSpecializer and CapturePropagation.
1315+ // CapturePropagation propagates constant function-literals. Such
1316+ // function specializations can then be optimized again by the
1317+ // ClosureSpecializer and so on.
1318+ // This happens if a closure argument is called _and_ referenced in
1319+ // another closure, which is passed to a recursive call. E.g.
1320+ //
1321+ // func foo(_ c: @escaping () -> ()) {
1322+ // c()
1323+ // foo({ c() })
1324+ // }
1325+ //
1326+ // A limit of 2 is good enough and will not be exceed in "regular"
1327+ // optimization scenarios.
1328+ if (getSpecializationLevel (getClosureCallee (ClosureInst)) > 2 )
1329+ continue ;
1330+
12551331 // Compute the final release points of the closure. We will insert
12561332 // release of the captured arguments here.
12571333 if (!CInfo)
0 commit comments