57
57
58
58
#define DEBUG_TYPE " closure-specialization"
59
59
#include " swift/Basic/Range.h"
60
+ #include " swift/Demangling/Demangler.h"
60
61
#include " swift/SIL/InstructionUtils.h"
61
62
#include " swift/SIL/SILCloner.h"
62
63
#include " swift/SIL/SILFunction.h"
@@ -162,6 +163,14 @@ class ClosureSpecCloner : public SILClonerWithScopes<ClosureSpecCloner> {
162
163
namespace {
163
164
struct ClosureInfo ;
164
165
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
+
165
174
class CallSiteDescriptor {
166
175
ClosureInfo *CInfo;
167
176
FullApplySite AI;
@@ -188,11 +197,7 @@ class CallSiteDescriptor {
188
197
}
189
198
190
199
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 ());
196
201
}
197
202
198
203
bool closureHasRefSemanticContext () const {
@@ -1065,6 +1070,59 @@ static bool canSpecializeFullApplySite(FullApplySiteKind kind) {
1065
1070
llvm_unreachable (" covered switch" );
1066
1071
}
1067
1072
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
+
1068
1126
bool SILClosureSpecializerTransform::gatherCallSites (
1069
1127
SILFunction *Caller,
1070
1128
llvm::SmallVectorImpl<std::unique_ptr<ClosureInfo>> &ClosureCandidates,
@@ -1252,6 +1310,24 @@ bool SILClosureSpecializerTransform::gatherCallSites(
1252
1310
continue ;
1253
1311
}
1254
1312
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
+
1255
1331
// Compute the final release points of the closure. We will insert
1256
1332
// release of the captured arguments here.
1257
1333
if (!CInfo)
0 commit comments