@@ -54,6 +54,7 @@ class CrossModuleOptimization {
54
54
friend class InstructionVisitor ;
55
55
56
56
llvm::DenseMap<SILType, bool > typesChecked;
57
+ llvm::DenseMap<CanType, bool > canTypesChecked;
57
58
llvm::SmallPtrSet<TypeBase *, 16 > typesHandled;
58
59
59
60
SILModule &M;
@@ -98,6 +99,8 @@ class CrossModuleOptimization {
98
99
bool canSerializeGlobal (SILGlobalVariable *global);
99
100
100
101
bool canSerializeType (SILType type);
102
+ bool canSerializeType (CanType type);
103
+ bool canSerializeDecl (NominalTypeDecl *decl);
101
104
102
105
bool canUseFromInline (DeclContext *declCtxt);
103
106
@@ -120,8 +123,6 @@ class CrossModuleOptimization {
120
123
void makeDeclUsableFromInline (ValueDecl *decl);
121
124
122
125
void makeTypeUsableFromInline (CanType type);
123
-
124
- void makeSubstUsableFromInline (const SubstitutionMap &substs);
125
126
};
126
127
127
128
// / Visitor for making used types of an instruction inlinable.
@@ -138,10 +139,10 @@ class InstructionVisitor : public SILCloner<InstructionVisitor> {
138
139
139
140
private:
140
141
CrossModuleOptimization &CMS;
141
-
142
+ bool checkSerializableInst;
142
143
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) {}
145
146
146
147
SILType remapType (SILType Ty) {
147
148
if (Ty.hasLocalArchetype ()) {
@@ -151,7 +152,10 @@ class InstructionVisitor : public SILCloner<InstructionVisitor> {
151
152
SubstFlags::SubstituteLocalArchetypes);
152
153
}
153
154
154
- CMS.makeTypeUsableFromInline (Ty.getASTType ());
155
+ if (checkSerializableInst)
156
+ CMS.canSerializeType (Ty);
157
+ else
158
+ CMS.makeTypeUsableFromInline (Ty.getASTType ());
155
159
return Ty;
156
160
}
157
161
@@ -162,7 +166,10 @@ class InstructionVisitor : public SILCloner<InstructionVisitor> {
162
166
SubstFlags::SubstituteLocalArchetypes)->getCanonicalType ();
163
167
}
164
168
165
- CMS.makeTypeUsableFromInline (Ty);
169
+ if (checkSerializableInst)
170
+ CMS.canSerializeType (Ty);
171
+ else
172
+ CMS.makeTypeUsableFromInline (Ty);
166
173
return Ty;
167
174
}
168
175
@@ -173,7 +180,23 @@ class InstructionVisitor : public SILCloner<InstructionVisitor> {
173
180
SubstFlags::SubstituteLocalArchetypes);
174
181
}
175
182
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
+ }
177
200
return Subs;
178
201
}
179
202
@@ -434,13 +457,18 @@ bool CrossModuleOptimization::canSerializeFunction(
434
457
return false ;
435
458
436
459
// Check if any instruction prevents serializing the function.
460
+ InstructionVisitor visitor (*function, *this , true );
437
461
for (SILBasicBlock &block : *function) {
438
462
for (SILInstruction &inst : block) {
463
+ visitor.getBuilder ().setInsertionPoint (&inst);
464
+ visitor.visit (&inst);
439
465
if (!canSerializeInstruction (&inst, canSerializeFlags, maxDepth)) {
440
466
return false ;
441
467
}
442
468
}
443
469
}
470
+ M.reclaimUnresolvedLocalArchetypeDefinitions ();
471
+
444
472
canSerializeFlags[function] = true ;
445
473
return true ;
446
474
}
@@ -572,32 +600,52 @@ bool CrossModuleOptimization::canSerializeGlobal(SILGlobalVariable *global) {
572
600
return true ;
573
601
}
574
602
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 ;
579
606
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
+ }
584
611
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
+ }
588
617
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))
595
620
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;
598
642
return success;
599
643
}
600
644
645
+ bool CrossModuleOptimization::canSerializeType (SILType type) {
646
+ return canSerializeType (type.getASTType ());
647
+ }
648
+
601
649
// / Returns true if the function in \p funcCtxt could be linked statically to
602
650
// / this module.
603
651
static bool couldBeLinkedStatically (DeclContext *funcCtxt, SILModule &module ) {
@@ -730,7 +778,7 @@ void CrossModuleOptimization::serializeFunction(SILFunction *function,
730
778
}
731
779
function->setSerializedKind (getRightSerializedKind (M));
732
780
733
- InstructionVisitor visitor (*function, *this );
781
+ InstructionVisitor visitor (*function, *this , false );
734
782
for (SILBasicBlock &block : *function) {
735
783
for (SILInstruction &inst : block) {
736
784
visitor.getBuilder ().setInsertionPoint (&inst);
@@ -929,21 +977,6 @@ void CrossModuleOptimization::makeTypeUsableFromInline(CanType type) {
929
977
});
930
978
}
931
979
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
-
947
980
class CrossModuleOptimizationPass : public SILModuleTransform {
948
981
void run () override {
949
982
auto &M = *getModule ();
0 commit comments