Skip to content

Commit 88c2f55

Browse files
committed
[PackageCMO] Use InstructionVisitor to remap types during canSerialize checks.
In the `canSerialize*` checks, the `InstructionVisitor` is not utilized, which can result in skipping certain types during analysis. This creates an inconsistency with the subsequent serialization pass, where the `InstructionVisitor` is used; it remaps types, particularly when handling protocol conformance substitutions. Resolves rdar://130788545
1 parent 3442fba commit 88c2f55

File tree

1 file changed

+76
-43
lines changed

1 file changed

+76
-43
lines changed

lib/SILOptimizer/IPO/CrossModuleOptimization.cpp

Lines changed: 76 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ class CrossModuleOptimization {
5454
friend class InstructionVisitor;
5555

5656
llvm::DenseMap<SILType, bool> typesChecked;
57+
llvm::DenseMap<CanType, bool> canTypesChecked;
5758
llvm::SmallPtrSet<TypeBase *, 16> typesHandled;
5859

5960
SILModule &M;
@@ -98,6 +99,8 @@ class CrossModuleOptimization {
9899
bool canSerializeGlobal(SILGlobalVariable *global);
99100

100101
bool canSerializeType(SILType type);
102+
bool canSerializeType(CanType type);
103+
bool canSerializeDecl(NominalTypeDecl *decl);
101104

102105
bool canUseFromInline(DeclContext *declCtxt);
103106

@@ -120,8 +123,6 @@ class CrossModuleOptimization {
120123
void makeDeclUsableFromInline(ValueDecl *decl);
121124

122125
void makeTypeUsableFromInline(CanType type);
123-
124-
void makeSubstUsableFromInline(const SubstitutionMap &substs);
125126
};
126127

127128
/// Visitor for making used types of an instruction inlinable.
@@ -138,10 +139,10 @@ class InstructionVisitor : public SILCloner<InstructionVisitor> {
138139

139140
private:
140141
CrossModuleOptimization &CMS;
141-
142+
bool checkSerializableInst;
142143
public:
143-
InstructionVisitor(SILFunction &F, CrossModuleOptimization &CMS) :
144-
SILCloner(F), CMS(CMS) {}
144+
InstructionVisitor(SILFunction &F, CrossModuleOptimization &CMS, bool checkSerializableInst) :
145+
SILCloner(F), CMS(CMS), checkSerializableInst(checkSerializableInst) {}
145146

146147
SILType remapType(SILType Ty) {
147148
if (Ty.hasLocalArchetype()) {
@@ -151,7 +152,10 @@ class InstructionVisitor : public SILCloner<InstructionVisitor> {
151152
SubstFlags::SubstituteLocalArchetypes);
152153
}
153154

154-
CMS.makeTypeUsableFromInline(Ty.getASTType());
155+
if (checkSerializableInst)
156+
CMS.canSerializeType(Ty);
157+
else
158+
CMS.makeTypeUsableFromInline(Ty.getASTType());
155159
return Ty;
156160
}
157161

@@ -162,7 +166,10 @@ class InstructionVisitor : public SILCloner<InstructionVisitor> {
162166
SubstFlags::SubstituteLocalArchetypes)->getCanonicalType();
163167
}
164168

165-
CMS.makeTypeUsableFromInline(Ty);
169+
if (checkSerializableInst)
170+
CMS.canSerializeType(Ty);
171+
else
172+
CMS.makeTypeUsableFromInline(Ty);
166173
return Ty;
167174
}
168175

@@ -173,7 +180,23 @@ class InstructionVisitor : public SILCloner<InstructionVisitor> {
173180
SubstFlags::SubstituteLocalArchetypes);
174181
}
175182

176-
CMS.makeSubstUsableFromInline(Subs);
183+
for (Type replType : Subs.getReplacementTypes()) {
184+
if (checkSerializableInst)
185+
CMS.canSerializeType(replType->getCanonicalType());
186+
else
187+
/// Ensure that all replacement types of \p Subs are usable from serialized
188+
/// functions.
189+
CMS.makeTypeUsableFromInline(replType->getCanonicalType());
190+
}
191+
for (ProtocolConformanceRef pref : Subs.getConformances()) {
192+
if (pref.isConcrete()) {
193+
ProtocolConformance *concrete = pref.getConcrete();
194+
if (checkSerializableInst)
195+
CMS.canSerializeDecl(concrete->getProtocol());
196+
else
197+
CMS.makeDeclUsableFromInline(concrete->getProtocol());
198+
}
199+
}
177200
return Subs;
178201
}
179202

@@ -434,13 +457,18 @@ bool CrossModuleOptimization::canSerializeFunction(
434457
return false;
435458

436459
// Check if any instruction prevents serializing the function.
460+
InstructionVisitor visitor(*function, *this, true);
437461
for (SILBasicBlock &block : *function) {
438462
for (SILInstruction &inst : block) {
463+
visitor.getBuilder().setInsertionPoint(&inst);
464+
visitor.visit(&inst);
439465
if (!canSerializeInstruction(&inst, canSerializeFlags, maxDepth)) {
440466
return false;
441467
}
442468
}
443469
}
470+
M.reclaimUnresolvedLocalArchetypeDefinitions();
471+
444472
canSerializeFlags[function] = true;
445473
return true;
446474
}
@@ -572,32 +600,52 @@ bool CrossModuleOptimization::canSerializeGlobal(SILGlobalVariable *global) {
572600
return true;
573601
}
574602

575-
bool CrossModuleOptimization::canSerializeType(SILType type) {
576-
auto iter = typesChecked.find(type);
577-
if (iter != typesChecked.end())
578-
return iter->getSecond();
603+
bool CrossModuleOptimization::canSerializeDecl(NominalTypeDecl *decl) {
604+
if (!decl)
605+
return true;
579606

580-
bool success = !type.getASTType().findIf(
581-
[this](Type rawSubType) {
582-
CanType subType = rawSubType->getCanonicalType();
583-
if (NominalTypeDecl *subNT = subType->getNominalOrBoundGenericNominal()) {
607+
// In conservative mode we don't want to change the access level of types.
608+
if (conservative && decl->getEffectiveAccess() < AccessLevel::Package) {
609+
return false;
610+
}
584611

585-
if (conservative && subNT->getEffectiveAccess() < AccessLevel::Package) {
586-
return true;
587-
}
612+
// Exclude types which are defined in an @_implementationOnly imported
613+
// module. Such modules are not transitively available.
614+
if (!canUseFromInline(decl)) {
615+
return false;
616+
}
588617

589-
// Exclude types which are defined in an @_implementationOnly imported
590-
// module. Such modules are not transitively available.
591-
if (!canUseFromInline(subNT)) {
592-
return true;
593-
}
594-
}
618+
if (auto *nominalCtx = dyn_cast<NominalTypeDecl>(decl->getDeclContext())) {
619+
if (!canSerializeDecl(nominalCtx))
595620
return false;
596-
});
597-
typesChecked[type] = success;
621+
} else if (auto *extCtx = dyn_cast<ExtensionDecl>(decl->getDeclContext())) {
622+
if (auto *extendedNominal = extCtx->getExtendedNominal()) {
623+
if (!canSerializeDecl(extendedNominal))
624+
return false;
625+
}
626+
}
627+
return true;
628+
}
629+
630+
bool CrossModuleOptimization::canSerializeType(CanType type) {
631+
auto iter = canTypesChecked.find(type);
632+
if (iter != canTypesChecked.end())
633+
return iter->getSecond();
634+
635+
bool success = type.findIf(
636+
[this](Type rawSubType) {
637+
CanType subType = rawSubType->getCanonicalType();
638+
return canSerializeDecl(subType->getNominalOrBoundGenericNominal());
639+
});
640+
641+
canTypesChecked[type] = success;
598642
return success;
599643
}
600644

645+
bool CrossModuleOptimization::canSerializeType(SILType type) {
646+
return canSerializeType(type.getASTType());
647+
}
648+
601649
/// Returns true if the function in \p funcCtxt could be linked statically to
602650
/// this module.
603651
static bool couldBeLinkedStatically(DeclContext *funcCtxt, SILModule &module) {
@@ -730,7 +778,7 @@ void CrossModuleOptimization::serializeFunction(SILFunction *function,
730778
}
731779
function->setSerializedKind(getRightSerializedKind(M));
732780

733-
InstructionVisitor visitor(*function, *this);
781+
InstructionVisitor visitor(*function, *this, false);
734782
for (SILBasicBlock &block : *function) {
735783
for (SILInstruction &inst : block) {
736784
visitor.getBuilder().setInsertionPoint(&inst);
@@ -929,21 +977,6 @@ void CrossModuleOptimization::makeTypeUsableFromInline(CanType type) {
929977
});
930978
}
931979

932-
/// Ensure that all replacement types of \p substs are usable from serialized
933-
/// functions.
934-
void CrossModuleOptimization::makeSubstUsableFromInline(
935-
const SubstitutionMap &substs) {
936-
for (Type replType : substs.getReplacementTypes()) {
937-
makeTypeUsableFromInline(replType->getCanonicalType());
938-
}
939-
for (ProtocolConformanceRef pref : substs.getConformances()) {
940-
if (pref.isConcrete()) {
941-
ProtocolConformance *concrete = pref.getConcrete();
942-
makeDeclUsableFromInline(concrete->getProtocol());
943-
}
944-
}
945-
}
946-
947980
class CrossModuleOptimizationPass: public SILModuleTransform {
948981
void run() override {
949982
auto &M = *getModule();

0 commit comments

Comments
 (0)