Skip to content

Commit 2301aed

Browse files
committed
Fix infinite recursion in ClosureSpecialize
Fixes getSpecializationLevelRecursive to handle recursive manglings caused by interleaving CapturePropagation and ClosureSpecialize passes. For some reason, only the first closure parameter was checked for recursion. We need to handle patterns like this: kind=FunctionSignatureSpecialization kind=SpecializationPassID, index=3 kind=FunctionSignatureSpecializationParam kind=FunctionSignatureSpecializationParam kind=FunctionSignatureSpecializationParamKind, index=0 kind=FunctionSignatureSpecializationParamPayload, text="$s4test10ExpressionO8contains5whereS3bXE_tFSbACXEfU_S2bXEfU_36$s4test12IndirectEnumVACycfcS2bXEfU_Tf3npf_n" I fixed the logic so we now check for recursion on all closure parameters and bail out on unrecognized mangling formats. For reference, see summary.sil in Infinitely recursive closure specialization #61955 #61955 Fixes rdar://101589190 (Swift Compiler hangs when building this code for release)
1 parent 6f78e21 commit 2301aed

File tree

1 file changed

+54
-19
lines changed

1 file changed

+54
-19
lines changed

lib/SILOptimizer/IPO/ClosureSpecializer.cpp

Lines changed: 54 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,6 +1073,8 @@ static bool canSpecializeFullApplySite(FullApplySiteKind kind) {
10731073
llvm_unreachable("covered switch");
10741074
}
10751075

1076+
const int SpecializationLevelLimit = 2;
1077+
10761078
static int getSpecializationLevelRecursive(StringRef funcName, Demangler &parent) {
10771079
using namespace Demangle;
10781080

@@ -1098,23 +1100,49 @@ static int getSpecializationLevelRecursive(StringRef funcName, Demangler &parent
10981100
return 0;
10991101
if (funcSpec->getKind() != Node::Kind::FunctionSignatureSpecialization)
11001102
return 0;
1101-
Node *param = funcSpec->getChild(1);
1102-
if (param->getKind() != Node::Kind::FunctionSignatureSpecializationParam)
1103-
return 0;
1104-
if (param->getNumChildren() < 2)
1105-
return 0;
1106-
Node *kindNd = param->getChild(0);
1107-
if (kindNd->getKind() != Node::Kind::FunctionSignatureSpecializationParamKind)
1108-
return 0;
1109-
auto kind = FunctionSigSpecializationParamKind(kindNd->getIndex());
1110-
if (kind != FunctionSigSpecializationParamKind::ConstantPropFunction)
1111-
return 0;
1112-
1113-
Node *payload = param->getChild(1);
1114-
if (payload->getKind() != Node::Kind::FunctionSignatureSpecializationParamPayload)
1115-
return 1;
1116-
// Check if the specialized function is a specialization itself.
1117-
return 1 + getSpecializationLevelRecursive(payload->getText(), demangler);
1103+
1104+
// Handle up to six parameters, otherwise assume infinite recursion
1105+
if (funcSpec->getNumChildren() > 6)
1106+
return SpecializationLevelLimit + 1;
1107+
1108+
// Match any function specialization. We check for constant propagation at the
1109+
// parameter level.
1110+
Node *param = funcSpec->getChild(0);
1111+
if (param->getKind() != Node::Kind::SpecializationPassID)
1112+
return SpecializationLevelLimit + 1; // unrecognized format
1113+
1114+
unsigned maxParamLevel = 0;
1115+
for (unsigned paramIdx = 1; paramIdx < funcSpec->getNumChildren();
1116+
++paramIdx) {
1117+
Node *param = funcSpec->getChild(paramIdx);
1118+
if (param->getKind() != Node::Kind::FunctionSignatureSpecializationParam)
1119+
return SpecializationLevelLimit + 1; // unrecognized format
1120+
1121+
// A parameter is recursive if it has a kind with index and type payload
1122+
if (param->getNumChildren() < 2)
1123+
continue;
1124+
1125+
Node *kindNd = param->getChild(0);
1126+
if (kindNd->getKind()
1127+
!= Node::Kind::FunctionSignatureSpecializationParamKind) {
1128+
return SpecializationLevelLimit + 1; // unrecognized format
1129+
}
1130+
auto kind = FunctionSigSpecializationParamKind(kindNd->getIndex());
1131+
if (kind != FunctionSigSpecializationParamKind::ConstantPropFunction)
1132+
continue;
1133+
Node *payload = param->getChild(1);
1134+
if (payload->getKind()
1135+
!= Node::Kind::FunctionSignatureSpecializationParamPayload) {
1136+
return SpecializationLevelLimit + 1; // unrecognized format
1137+
}
1138+
// Check if the specialized function is a specialization itself.
1139+
unsigned paramLevel =
1140+
1 + getSpecializationLevelRecursive(payload->getText(), demangler);
1141+
if (paramLevel > maxParamLevel)
1142+
maxParamLevel = paramLevel;
1143+
}
1144+
llvm::dbgs() << "maxParamLevel = " << maxParamLevel << "\n";
1145+
return maxParamLevel;
11181146
}
11191147

11201148
/// If \p function is a function-signature specialization for a constant-
@@ -1328,9 +1356,10 @@ bool SILClosureSpecializerTransform::gatherCallSites(
13281356
//
13291357
// A limit of 2 is good enough and will not be exceed in "regular"
13301358
// optimization scenarios.
1331-
if (getSpecializationLevel(getClosureCallee(ClosureInst)) > 2)
1359+
if (getSpecializationLevel(getClosureCallee(ClosureInst))
1360+
> SpecializationLevelLimit) {
13321361
continue;
1333-
1362+
}
13341363
// Compute the final release points of the closure. We will insert
13351364
// release of the captured arguments here.
13361365
if (!CInfo)
@@ -1395,6 +1424,8 @@ bool SILClosureSpecializerTransform::specialize(SILFunction *Caller,
13951424
if (!NewF) {
13961425
NewF = ClosureSpecCloner::cloneFunction(FuncBuilder, CSDesc, NewFName);
13971426
addFunctionToPassManagerWorklist(NewF, CSDesc.getApplyCallee());
1427+
LLVM_DEBUG(llvm::dbgs() << "\nThe rewritten callee is:\n";
1428+
NewF->dump());
13981429
}
13991430

14001431
// Rewrite the call
@@ -1404,6 +1435,10 @@ bool SILClosureSpecializerTransform::specialize(SILFunction *Caller,
14041435
Changed = true;
14051436
}
14061437
}
1438+
LLVM_DEBUG(if (Changed) {
1439+
llvm::dbgs() << "\nThe rewritten caller is:\n";
1440+
Caller->dump();
1441+
});
14071442
return Changed;
14081443
}
14091444

0 commit comments

Comments
 (0)