@@ -53,7 +53,7 @@ namespace {
53
53
class CrossModuleOptimization {
54
54
friend class InstructionVisitor ;
55
55
56
- llvm::DenseMap<CanType , bool > canTypesChecked ;
56
+ llvm::DenseMap<SILType , bool > typesChecked ;
57
57
llvm::SmallPtrSet<TypeBase *, 16 > typesHandled;
58
58
59
59
SILModule &M;
@@ -90,18 +90,14 @@ class CrossModuleOptimization {
90
90
void trySerializeFunctions (ArrayRef<SILFunction *> functions);
91
91
92
92
bool canSerializeFunction (SILFunction *function,
93
- FunctionFlags &canSerializeFlags,
94
- int maxDepth);
93
+ FunctionFlags &canSerializeFlags, int maxDepth);
95
94
96
- bool canSerializeFieldsByInstructionKind (SILInstruction *inst,
97
- FunctionFlags &canSerializeFlags,
98
- int maxDepth);
95
+ bool canSerializeInstruction (SILInstruction *inst,
96
+ FunctionFlags &canSerializeFlags, int maxDepth);
99
97
100
98
bool canSerializeGlobal (SILGlobalVariable *global);
101
99
102
100
bool canSerializeType (SILType type);
103
- bool canSerializeType (CanType type);
104
- bool canSerializeDecl (NominalTypeDecl *decl);
105
101
106
102
bool canUseFromInline (DeclContext *declCtxt);
107
103
@@ -122,10 +118,11 @@ class CrossModuleOptimization {
122
118
void makeDeclUsableFromInline (ValueDecl *decl);
123
119
124
120
void makeTypeUsableFromInline (CanType type);
121
+
122
+ void makeSubstUsableFromInline (const SubstitutionMap &substs);
125
123
};
126
124
127
- // / Visitor for detecting if an instruction can be serialized and also making used
128
- // / types of an instruction inlinable if so.
125
+ // / Visitor for making used types of an instruction inlinable.
129
126
// /
130
127
// / We use the SILCloner for visiting types, though it sucks that we allocate
131
128
// / instructions just to delete them immediately. But it's better than to
@@ -137,22 +134,12 @@ class InstructionVisitor : public SILCloner<InstructionVisitor> {
137
134
friend class SILInstructionVisitor <InstructionVisitor>;
138
135
friend class CrossModuleOptimization ;
139
136
140
- public:
141
- // / This visitor is used for 2 passes, 1st pass that detects whether the instruction
142
- // / visited can be serialized, and 2nd pass that does the serializing.
143
- enum class VisitMode {
144
- DetectSerializableInst,
145
- SerializeInst
146
- };
147
-
148
137
private:
149
138
CrossModuleOptimization &CMS;
150
- VisitMode mode;
151
- bool isInstSerializable = true ;
152
139
153
140
public:
154
- InstructionVisitor (SILFunction &F, CrossModuleOptimization &CMS, VisitMode visitMode ) :
155
- SILCloner (F), CMS(CMS), mode(visitMode) {}
141
+ InstructionVisitor (SILFunction &F, CrossModuleOptimization &CMS) :
142
+ SILCloner (F), CMS(CMS) {}
156
143
157
144
SILType remapType (SILType Ty) {
158
145
if (Ty.hasLocalArchetype ()) {
@@ -162,15 +149,7 @@ class InstructionVisitor : public SILCloner<InstructionVisitor> {
162
149
SubstFlags::SubstituteLocalArchetypes);
163
150
}
164
151
165
- switch (mode) {
166
- case VisitMode::DetectSerializableInst:
167
- if (!CMS.canSerializeType (Ty))
168
- isInstSerializable = false ;
169
- break ;
170
- case VisitMode::SerializeInst:
171
- CMS.makeTypeUsableFromInline (Ty.getASTType ());
172
- break ;
173
- }
152
+ CMS.makeTypeUsableFromInline (Ty.getASTType ());
174
153
return Ty;
175
154
}
176
155
@@ -181,15 +160,7 @@ class InstructionVisitor : public SILCloner<InstructionVisitor> {
181
160
SubstFlags::SubstituteLocalArchetypes)->getCanonicalType ();
182
161
}
183
162
184
- switch (mode) {
185
- case VisitMode::DetectSerializableInst:
186
- if (!CMS.canSerializeType (Ty))
187
- isInstSerializable = false ;
188
- break ;
189
- case VisitMode::SerializeInst:
190
- CMS.makeTypeUsableFromInline (Ty);
191
- break ;
192
- }
163
+ CMS.makeTypeUsableFromInline (Ty);
193
164
return Ty;
194
165
}
195
166
@@ -200,32 +171,7 @@ class InstructionVisitor : public SILCloner<InstructionVisitor> {
200
171
SubstFlags::SubstituteLocalArchetypes);
201
172
}
202
173
203
- for (Type replType : Subs.getReplacementTypes ()) {
204
- switch (mode) {
205
- case VisitMode::DetectSerializableInst:
206
- CMS.canSerializeType (replType->getCanonicalType ());
207
- break ;
208
- case VisitMode::SerializeInst:
209
- // / Ensure that all replacement types of \p Subs are usable from serialized
210
- // / functions.
211
- CMS.makeTypeUsableFromInline (replType->getCanonicalType ());
212
- break ;
213
- }
214
- }
215
- for (ProtocolConformanceRef pref : Subs.getConformances ()) {
216
- if (pref.isConcrete ()) {
217
- ProtocolConformance *concrete = pref.getConcrete ();
218
- switch (mode) {
219
- case VisitMode::DetectSerializableInst:
220
- if (!CMS.canSerializeDecl (concrete->getProtocol ()))
221
- isInstSerializable = false ;
222
- break ;
223
- case VisitMode::SerializeInst:
224
- CMS.makeDeclUsableFromInline (concrete->getProtocol ());
225
- break ;
226
- }
227
- }
228
- }
174
+ CMS.makeSubstUsableFromInline (Subs);
229
175
return Subs;
230
176
}
231
177
@@ -234,36 +180,9 @@ class InstructionVisitor : public SILCloner<InstructionVisitor> {
234
180
Cloned->eraseFromParent ();
235
181
}
236
182
237
- // This method retrieves the operand passed as \p Value as mapped
238
- // in a previous instruction.
239
- SILValue getMappedValue (SILValue Value) {
240
- switch (mode) {
241
- case VisitMode::DetectSerializableInst:
242
- // Typically, the type of the operand (\p Value) is already checked
243
- // and remapped as the resulting type of a previous instruction, so
244
- // rechecking the type isn't necessary. However, certain instructions
245
- // have operands that weren’t previously mapped, such as:
246
- //
247
- // ```
248
- // bb0(%0 : $*Foo):
249
- // %1 = struct_element_addr %0 : $*Foo, #Foo.bar
250
- // ```
251
- // where the operand of the first instruction is the argument of the
252
- // basic block. In such case, an explicit check for the operand's type
253
- // is required to ensure serializability.
254
- remapType (Value->getType ());
255
- break ;
256
- case VisitMode::SerializeInst:
257
- break ;
258
- }
259
- return Value;
260
- }
183
+ SILValue getMappedValue (SILValue Value) { return Value; }
261
184
262
185
SILBasicBlock *remapBasicBlock (SILBasicBlock *BB) { return BB; }
263
-
264
- bool canSerializeTypesInInst (SILInstruction *inst) {
265
- return isInstSerializable;
266
- }
267
186
};
268
187
269
188
static bool isPackageCMOEnabled (ModuleDecl *mod) {
@@ -537,36 +456,32 @@ bool CrossModuleOptimization::canSerializeFunction(
537
456
}
538
457
539
458
// Check if any instruction prevents serializing the function.
540
- InstructionVisitor visitor (*function, *this , InstructionVisitor::VisitMode::DetectSerializableInst);
541
-
542
459
for (SILBasicBlock &block : *function) {
543
460
for (SILInstruction &inst : block) {
544
- visitor.getBuilder ().setInsertionPoint (&inst);
545
- // First, visit each instruction and see if its
546
- // canonical or substituted types are serializalbe.
547
- visitor.visit (&inst);
548
- if (!visitor.canSerializeTypesInInst (&inst)) {
549
- M.reclaimUnresolvedLocalArchetypeDefinitions ();
550
- return false ;
551
- }
552
- // Next, check for any fields that weren't visited.
553
- if (!canSerializeFieldsByInstructionKind (&inst, canSerializeFlags, maxDepth)) {
554
- M.reclaimUnresolvedLocalArchetypeDefinitions ();
461
+ if (!canSerializeInstruction (&inst, canSerializeFlags, maxDepth)) {
555
462
return false ;
556
463
}
557
464
}
558
465
}
559
- M.reclaimUnresolvedLocalArchetypeDefinitions ();
560
-
561
466
canSerializeFlags[function] = true ;
562
467
return true ;
563
468
}
564
469
565
- // / Returns true if \p inst can be serialized by checking its fields per instruction kind .
470
+ // / Returns true if \p inst can be serialized.
566
471
// /
567
472
// / If \p inst is a function_ref, recursively visits the referenced function.
568
- bool CrossModuleOptimization::canSerializeFieldsByInstructionKind (
473
+ bool CrossModuleOptimization::canSerializeInstruction (
569
474
SILInstruction *inst, FunctionFlags &canSerializeFlags, int maxDepth) {
475
+ // First check if any result or operand types prevent serialization.
476
+ for (SILValue result : inst->getResults ()) {
477
+ if (!canSerializeType (result->getType ()))
478
+ return false ;
479
+ }
480
+ for (Operand &op : inst->getAllOperands ()) {
481
+ if (!canSerializeType (op.get ()->getType ()))
482
+ return false ;
483
+ }
484
+
570
485
if (auto *FRI = dyn_cast<FunctionRefBaseInst>(inst)) {
571
486
SILFunction *callee = FRI->getReferencedFunctionOrNull ();
572
487
if (!callee)
@@ -658,45 +573,6 @@ bool CrossModuleOptimization::canSerializeFieldsByInstructionKind(
658
573
return true ;
659
574
}
660
575
661
- bool CrossModuleOptimization::canSerializeType (SILType type) {
662
- return canSerializeType (type.getASTType ());
663
- }
664
-
665
- bool CrossModuleOptimization::canSerializeType (CanType type) {
666
- auto iter = canTypesChecked.find (type);
667
- if (iter != canTypesChecked.end ())
668
- return iter->getSecond ();
669
-
670
- bool success = type.findIf (
671
- [this ](Type rawSubType) {
672
- CanType subType = rawSubType->getCanonicalType ();
673
- if (auto nominal = subType->getNominalOrBoundGenericNominal ()) {
674
- return canSerializeDecl (nominal);
675
- }
676
- // If reached here, the type is a Builtin type or similar,
677
- // e.g. Builtin.Int64, Builtin.Word, Builtin.NativeObject, etc.
678
- return true ;
679
- });
680
-
681
- canTypesChecked[type] = success;
682
- return success;
683
- }
684
-
685
- bool CrossModuleOptimization::canSerializeDecl (NominalTypeDecl *decl) {
686
- assert (decl && " Decl should not be null when checking if it can be serialized" );
687
-
688
- // In conservative mode we don't want to change the access level of types.
689
- if (conservative && decl->getEffectiveAccess () < AccessLevel::Package) {
690
- return false ;
691
- }
692
- // Exclude types which are defined in an @_implementationOnly imported
693
- // module. Such modules are not transitively available.
694
- if (!canUseFromInline (decl)) {
695
- return false ;
696
- }
697
- return true ;
698
- }
699
-
700
576
bool CrossModuleOptimization::canSerializeGlobal (SILGlobalVariable *global) {
701
577
// Check for referenced functions in the initializer.
702
578
for (const SILInstruction &initInst : *global) {
@@ -718,6 +594,32 @@ bool CrossModuleOptimization::canSerializeGlobal(SILGlobalVariable *global) {
718
594
return true ;
719
595
}
720
596
597
+ bool CrossModuleOptimization::canSerializeType (SILType type) {
598
+ auto iter = typesChecked.find (type);
599
+ if (iter != typesChecked.end ())
600
+ return iter->getSecond ();
601
+
602
+ bool success = !type.getASTType ().findIf (
603
+ [this ](Type rawSubType) {
604
+ CanType subType = rawSubType->getCanonicalType ();
605
+ if (NominalTypeDecl *subNT = subType->getNominalOrBoundGenericNominal ()) {
606
+
607
+ if (conservative && subNT->getEffectiveAccess () < AccessLevel::Package) {
608
+ return true ;
609
+ }
610
+
611
+ // Exclude types which are defined in an @_implementationOnly imported
612
+ // module. Such modules are not transitively available.
613
+ if (!canUseFromInline (subNT)) {
614
+ return true ;
615
+ }
616
+ }
617
+ return false ;
618
+ });
619
+ typesChecked[type] = success;
620
+ return success;
621
+ }
622
+
721
623
// / Returns true if the function in \p funcCtxt could be linked statically to
722
624
// / this module.
723
625
static bool couldBeLinkedStatically (DeclContext *funcCtxt, SILModule &module ) {
@@ -811,7 +713,7 @@ void CrossModuleOptimization::serializeFunction(SILFunction *function,
811
713
}
812
714
function->setSerializedKind (getRightSerializedKind (M));
813
715
814
- InstructionVisitor visitor (*function, *this , InstructionVisitor::VisitMode::SerializeInst );
716
+ InstructionVisitor visitor (*function, *this );
815
717
for (SILBasicBlock &block : *function) {
816
718
for (SILInstruction &inst : block) {
817
719
visitor.getBuilder ().setInsertionPoint (&inst);
@@ -1010,6 +912,21 @@ void CrossModuleOptimization::makeTypeUsableFromInline(CanType type) {
1010
912
});
1011
913
}
1012
914
915
+ // / Ensure that all replacement types of \p substs are usable from serialized
916
+ // / functions.
917
+ void CrossModuleOptimization::makeSubstUsableFromInline (
918
+ const SubstitutionMap &substs) {
919
+ for (Type replType : substs.getReplacementTypes ()) {
920
+ makeTypeUsableFromInline (replType->getCanonicalType ());
921
+ }
922
+ for (ProtocolConformanceRef pref : substs.getConformances ()) {
923
+ if (pref.isConcrete ()) {
924
+ ProtocolConformance *concrete = pref.getConcrete ();
925
+ makeDeclUsableFromInline (concrete->getProtocol ());
926
+ }
927
+ }
928
+ }
929
+
1013
930
class CrossModuleOptimizationPass : public SILModuleTransform {
1014
931
void run () override {
1015
932
auto &M = *getModule ();
0 commit comments