Skip to content

Commit cfb065d

Browse files
authored
Merge pull request #3437 from swiftwasm/release/5.5
[pull] swiftwasm-release/5.5 from release/5.5
2 parents 7219d74 + 159c946 commit cfb065d

19 files changed

+235
-24
lines changed

include/swift/AST/Module.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -645,9 +645,10 @@ class ModuleDecl : public DeclContext, public TypeDecl {
645645
/// This assumes that \p module was imported.
646646
bool isImportedImplementationOnly(const ModuleDecl *module) const;
647647

648-
/// Returns true if a function, which is using \p nominal, can be serialized
649-
/// by cross-module-optimization.
650-
bool canBeUsedForCrossModuleOptimization(NominalTypeDecl *nominal) const;
648+
/// Returns true if decl context or its content can be serialized by
649+
/// cross-module-optimization.
650+
/// The \p ctxt can e.g. be a NominalType or the context of a function.
651+
bool canBeUsedForCrossModuleOptimization(DeclContext *ctxt) const;
651652

652653
/// Finds all top-level decls of this module.
653654
///

lib/AST/Module.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2179,14 +2179,15 @@ bool ModuleDecl::isImportedImplementationOnly(const ModuleDecl *module) const {
21792179
}
21802180

21812181
bool ModuleDecl::
2182-
canBeUsedForCrossModuleOptimization(NominalTypeDecl *nominal) const {
2183-
ModuleDecl *moduleOfNominal = nominal->getParentModule();
2182+
canBeUsedForCrossModuleOptimization(DeclContext *ctxt) const {
2183+
ModuleDecl *moduleOfCtxt = ctxt->getParentModule();
21842184

2185-
// If the nominal is defined in the same module, it's fine.
2186-
if (moduleOfNominal == this)
2185+
// If the context defined in the same module - or is the same module, it's
2186+
// fine.
2187+
if (moduleOfCtxt == this)
21872188
return true;
21882189

2189-
// See if nominal is imported in a "regular" way, i.e. not with
2190+
// See if context is imported in a "regular" way, i.e. not with
21902191
// @_implementationOnly or @_spi.
21912192
ModuleDecl::ImportFilter filter = {
21922193
ModuleDecl::ImportFilterKind::Exported,
@@ -2196,7 +2197,7 @@ canBeUsedForCrossModuleOptimization(NominalTypeDecl *nominal) const {
21962197

21972198
auto &imports = getASTContext().getImportCache();
21982199
for (auto &desc : results) {
2199-
if (imports.isImportedBy(moduleOfNominal, desc.importedModule))
2200+
if (imports.isImportedBy(moduleOfCtxt, desc.importedModule))
22002201
return true;
22012202
}
22022203
return false;

lib/SILOptimizer/IPO/ClosureSpecializer.cpp

Lines changed: 81 additions & 5 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/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> {
162163
namespace {
163164
struct 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+
165174
class 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+
10681126
bool 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)

lib/SILOptimizer/IPO/CrossModuleSerializationSetup.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,11 @@ bool CrossModuleSerializationSetup::canUseFromInline(SILFunction *func,
386386
if (!func)
387387
return false;
388388

389+
if (DeclContext *funcCtxt = func->getDeclContext()) {
390+
if (!M.getSwiftModule()->canBeUsedForCrossModuleOptimization(funcCtxt))
391+
return false;
392+
}
393+
389394
switch (func->getLinkage()) {
390395
case SILLinkage::PublicNonABI:
391396
return func->isSerialized() != IsNotSerialized;

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -873,6 +873,25 @@ void TypeChecker::buildTypeRefinementContextHierarchy(SourceFile &SF) {
873873
}
874874
}
875875

876+
void TypeChecker::buildTypeRefinementContextHierarchyDelayed(SourceFile &SF, AbstractFunctionDecl *AFD) {
877+
// If there's no TRC for the file, we likely don't want this one either.
878+
// RootTRC is not set when availability checking is disabled.
879+
TypeRefinementContext *RootTRC = SF.getTypeRefinementContext();
880+
if(!RootTRC)
881+
return;
882+
883+
if (AFD->getBodyKind() != AbstractFunctionDecl::BodyKind::Unparsed)
884+
return;
885+
886+
// Parse the function body.
887+
AFD->getBody(/*canSynthesize=*/true);
888+
889+
// Build the refinement context for the function body.
890+
ASTContext &Context = SF.getASTContext();
891+
TypeRefinementContextBuilder Builder(RootTRC, Context);
892+
Builder.build(AFD);
893+
}
894+
876895
TypeRefinementContext *
877896
TypeChecker::getOrBuildTypeRefinementContext(SourceFile *SF) {
878897
TypeRefinementContext *TRC = SF->getTypeRefinementContext();

lib/Sema/TypeChecker.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ static void typeCheckDelayedFunctions(SourceFile &SF) {
256256
++currentFunctionIdx) {
257257
auto *AFD = SF.DelayedFunctions[currentFunctionIdx];
258258
assert(!AFD->getDeclContext()->isLocalContext());
259+
TypeChecker::buildTypeRefinementContextHierarchyDelayed(SF, AFD);
259260
(void)AFD->getTypecheckedBody();
260261
}
261262

lib/Sema/TypeChecker.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -958,6 +958,10 @@ AvailabilityContext overApproximateAvailabilityAtLocation(
958958
/// Walk the AST to build the hierarchy of TypeRefinementContexts
959959
void buildTypeRefinementContextHierarchy(SourceFile &SF);
960960

961+
/// Walk the AST to complete the hierarchy of TypeRefinementContexts for
962+
/// the delayed function body of \p AFD.
963+
void buildTypeRefinementContextHierarchyDelayed(SourceFile &SF, AbstractFunctionDecl *AFD);
964+
961965
/// Build the hierarchy of TypeRefinementContexts for the entire
962966
/// source file, if it has not already been built. Returns the root
963967
/// TypeRefinementContext for the source file.

lib/Serialization/DeserializeSIL.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,14 @@ SILFunction *SILDeserializer::getFuncForReference(StringRef name,
406406
// SIL.
407407
SourceLoc sourceLoc;
408408
SILSerializationFunctionBuilder builder(SILMod);
409-
return builder.createDeclaration(name, type, RegularLocation(sourceLoc));
409+
fn = builder.createDeclaration(name, type,
410+
RegularLocation(sourceLoc));
411+
// The function is not really de-serialized, but it's important to call
412+
// `didDeserialize` on every new function. Otherwise some Analysis might miss
413+
// `notifyAddedOrModifiedFunction` notifications.
414+
if (Callback)
415+
Callback->didDeserialize(MF->getAssociatedModule(), fn);
416+
return fn;
410417
}
411418

412419
/// Helper function to find a SILFunction, given its name and type.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
#include "c-module.h"
3+
4+
long privateCFunc() {
5+
return 123;
6+
}
7+
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
2+
long privateCFunc();
3+

0 commit comments

Comments
 (0)