Skip to content

Commit b503f28

Browse files
authored
Merge pull request #68461 from kubamracek/embedded-classes-generic
[embedded] Initial support for generic classes in embedded Swift
2 parents 63a2063 + 6ad9684 commit b503f28

27 files changed

+561
-92
lines changed

include/swift/AST/DiagnosticsSIL.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,8 @@ ERROR(bad_attr_on_non_const_global,none,
358358
"global variable must be a compile-time constant to use %0 attribute", (StringRef))
359359
ERROR(global_must_be_compile_time_const,none,
360360
"global variable must be a compile-time constant", ())
361+
ERROR(non_final_generic_class_function,none,
362+
"classes cannot have non-final generic fuctions in embedded Swift", ())
361363
NOTE(performance_called_from,none,
362364
"called from here", ())
363365

include/swift/IRGen/Linking.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ inline bool isEmbedded(CanType t) {
9090
}
9191

9292
inline bool isMetadataAllowedInEmbedded(CanType t) {
93-
return isa<ClassType>(t);
93+
return isa<ClassType>(t) || isa<BoundGenericClassType>(t);
9494
}
9595

9696
inline bool isEmbedded(Decl *d) {

include/swift/SIL/SILModule.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,9 @@ class SILModule {
243243
/// Lookup table for SIL vtables from class decls.
244244
llvm::DenseMap<const ClassDecl *, SILVTable *> VTableMap;
245245

246+
/// Lookup table for specialized SIL vtables from types.
247+
llvm::DenseMap<SILType, SILVTable *> SpecializedVTableMap;
248+
246249
/// The list of SILVTables in the module.
247250
std::vector<SILVTable*> vtables;
248251

@@ -827,6 +830,9 @@ class SILModule {
827830
/// Look up the VTable mapped to the given ClassDecl. Returns null on failure.
828831
SILVTable *lookUpVTable(const ClassDecl *C, bool deserializeLazily = true);
829832

833+
/// Look up a specialized VTable
834+
SILVTable *lookUpSpecializedVTable(SILType classTy);
835+
830836
/// Attempt to lookup the function corresponding to \p Member in the class
831837
/// hierarchy of \p Class.
832838
SILFunction *lookUpFunctionInVTable(ClassDecl *Class, SILDeclRef Member);

include/swift/SIL/SILVTable.h

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ class SILVTableEntry {
8181
void setNonOverridden(bool value) { IsNonOverridden = value; }
8282

8383
SILFunction *getImplementation() const { return ImplAndKind.getPointer(); }
84+
void setImplementation(SILFunction *f);
8485

8586
void print(llvm::raw_ostream &os) const;
8687

@@ -114,6 +115,8 @@ class SILVTable final : public SILAllocated<SILVTable>,
114115
/// The ClassDecl mapped to this VTable.
115116
ClassDecl *Class;
116117

118+
SILType classType;
119+
117120
/// Whether or not this vtable is serialized, which allows
118121
/// devirtualization from another module.
119122
bool Serialized : 1;
@@ -122,11 +125,19 @@ class SILVTable final : public SILAllocated<SILVTable>,
122125
unsigned NumEntries : 31;
123126

124127
/// Private constructor. Create SILVTables by calling SILVTable::create.
125-
SILVTable(ClassDecl *c, IsSerialized_t serialized, ArrayRef<Entry> entries);
128+
SILVTable(ClassDecl *c, SILType classType, IsSerialized_t serialized,
129+
ArrayRef<Entry> entries);
126130

127-
public:
131+
public:
128132
~SILVTable();
129133

134+
/// Create a new SILVTable with the given method-to-implementation mapping.
135+
/// The SILDeclRef keys should reference the most-overridden members available
136+
/// through the class.
137+
static SILVTable *create(SILModule &M, ClassDecl *Class, SILType classType,
138+
IsSerialized_t Serialized,
139+
ArrayRef<Entry> Entries);
140+
130141
/// Create a new SILVTable with the given method-to-implementation mapping.
131142
/// The SILDeclRef keys should reference the most-overridden members available
132143
/// through the class.
@@ -137,6 +148,11 @@ class SILVTable final : public SILAllocated<SILVTable>,
137148
/// Return the class that the vtable represents.
138149
ClassDecl *getClass() const { return Class; }
139150

151+
bool isSpecialized() const {
152+
return !classType.isNull();
153+
}
154+
SILType getClassType() const { return classType; }
155+
140156
/// Returns true if this vtable is going to be (or was) serialized.
141157
IsSerialized_t isSerialized() const {
142158
return Serialized ? IsSerialized : IsNotSerialized;

include/swift/SILOptimizer/PassManager/Passes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,8 @@ SWIFT_FUNCTION_PASS(DeadStoreElimination, "dead-store-elimination",
247247
"Dead Store Elimination")
248248
PASS(GenericSpecializer, "generic-specializer",
249249
"Generic Function Specialization on Static Types")
250+
PASS(VTableSpecializer, "vtable-specializer",
251+
"Generic Specialization on VTables")
250252
PASS(ExistentialSpecializer, "existential-specializer",
251253
"Existential Specializer")
252254
PASS(SILSkippingChecker, "check-sil-skipping",

include/swift/SILOptimizer/Utils/Generics.h

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,15 +82,15 @@ class ReabstractionInfo {
8282

8383
/// If set, indirect to direct conversions should be performed by the generic
8484
/// specializer.
85-
bool ConvertIndirectToDirect;
85+
bool ConvertIndirectToDirect = true;
8686

8787
/// If true, drop metatype arguments.
8888
/// See `droppedMetatypeArgs`.
8989
bool dropMetatypeArgs = false;
9090

9191
/// The first NumResults bits in Conversions refer to formal indirect
9292
/// out-parameters.
93-
unsigned NumFormalIndirectResults;
93+
unsigned NumFormalIndirectResults = 0;
9494

9595
/// The function type after applying the substitutions used to call the
9696
/// specialized function.
@@ -101,7 +101,7 @@ class ReabstractionInfo {
101101
CanSILFunctionType SpecializedType;
102102

103103
/// The generic environment to be used by the specialization.
104-
GenericEnvironment *SpecializedGenericEnv;
104+
GenericEnvironment *SpecializedGenericEnv = nullptr;
105105

106106
/// The generic signature of the specialization.
107107
/// It is nullptr if the specialization is not polymorphic.
@@ -125,7 +125,7 @@ class ReabstractionInfo {
125125
SubstitutionMap ClonerParamSubMap;
126126

127127
// Reference to the original generic non-specialized callee function.
128-
SILFunction *Callee;
128+
SILFunction *Callee = nullptr;
129129

130130
// The module the specialization is created in.
131131
ModuleDecl *TargetModule = nullptr;
@@ -136,7 +136,7 @@ class ReabstractionInfo {
136136
ApplySite Apply;
137137

138138
// Set if a specialized function has unbound generic parameters.
139-
bool HasUnboundGenericParams;
139+
bool HasUnboundGenericParams = false;
140140

141141
// Substitutions to be used for creating a new function type
142142
// for the specialized function.
@@ -149,7 +149,7 @@ class ReabstractionInfo {
149149
bool isPrespecialization = false;
150150

151151
// Is the generated specialization going to be serialized?
152-
IsSerialized_t Serialized;
152+
IsSerialized_t Serialized = IsNotSerialized;
153153

154154
enum TypeCategory {
155155
NotLoadable,
@@ -162,7 +162,9 @@ class ReabstractionInfo {
162162
SubstitutionMap SubstMap,
163163
bool HasUnboundGenericParams);
164164

165+
public:
165166
void createSubstitutedAndSpecializedTypes();
167+
private:
166168

167169
TypeCategory getReturnTypeCategory(const SILResultInfo &RI,
168170
const SILFunctionConventions &substConv,
@@ -205,6 +207,12 @@ class ReabstractionInfo {
205207
SILFunction *Callee, GenericSignature SpecializedSig,
206208
bool isPrespecialization = false);
207209

210+
ReabstractionInfo(CanSILFunctionType substitutedType,
211+
SILModule &M) :
212+
SubstitutedType(substitutedType),
213+
isWholeModule(M.isWholeModule()) {}
214+
215+
208216
bool isPrespecialized() const { return isPrespecialization; }
209217

210218
IsSerialized_t isSerialized() const {
@@ -400,6 +408,64 @@ class GenericFuncSpecializer {
400408
/// prespecialization for -Onone support.
401409
bool isKnownPrespecialization(StringRef SpecName);
402410

411+
class TypeReplacements {
412+
private:
413+
llvm::Optional<SILType> resultType;
414+
llvm::MapVector<unsigned, CanType> indirectResultTypes;
415+
llvm::MapVector<unsigned, CanType> paramTypeReplacements;
416+
llvm::MapVector<unsigned, CanType> yieldTypeReplacements;
417+
418+
public:
419+
llvm::Optional<SILType> getResultType() const { return resultType; }
420+
421+
void setResultType(SILType type) { resultType = type; }
422+
423+
bool hasResultType() const { return resultType.has_value(); }
424+
425+
const llvm::MapVector<unsigned, CanType> &getIndirectResultTypes() const {
426+
return indirectResultTypes;
427+
}
428+
429+
void addIndirectResultType(unsigned index, CanType type) {
430+
indirectResultTypes.insert(std::make_pair(index, type));
431+
}
432+
433+
bool hasIndirectResultTypes() const { return !indirectResultTypes.empty(); }
434+
435+
const llvm::MapVector<unsigned, CanType> &getParamTypeReplacements() const {
436+
return paramTypeReplacements;
437+
}
438+
439+
void addParameterTypeReplacement(unsigned index, CanType type) {
440+
paramTypeReplacements.insert(std::make_pair(index, type));
441+
}
442+
443+
bool hasParamTypeReplacements() const {
444+
return !paramTypeReplacements.empty();
445+
}
446+
447+
const llvm::MapVector<unsigned, CanType> &getYieldTypeReplacements() const {
448+
return yieldTypeReplacements;
449+
}
450+
451+
void addYieldTypeReplacement(unsigned index, CanType type) {
452+
yieldTypeReplacements.insert(std::make_pair(index, type));
453+
}
454+
455+
bool hasYieldTypeReplacements() const {
456+
return !yieldTypeReplacements.empty();
457+
}
458+
459+
bool hasTypeReplacements() const {
460+
return hasResultType() || hasParamTypeReplacements() ||
461+
hasIndirectResultTypes() || hasYieldTypeReplacements();
462+
}
463+
};
464+
465+
ApplySite replaceWithSpecializedCallee(
466+
ApplySite applySite, SILValue callee, const ReabstractionInfo &reInfo,
467+
const TypeReplacements &typeReplacements = {});
468+
403469
/// Checks if all OnoneSupport pre-specializations are included in the module
404470
/// as public functions.
405471
///

lib/IRGen/ClassMetadataVisitor.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ template <class Impl> class ClassMetadataVisitor
6363
: super(IGM), Target(target),
6464
VTable(IGM.getSILModule().lookUpVTable(target, /*deserialize*/ false)) {}
6565

66+
ClassMetadataVisitor(IRGenModule &IGM, ClassDecl *target, SILVTable *vtable)
67+
: super(IGM), Target(target), VTable(vtable) {}
68+
6669
public:
6770
void layout() {
6871
static_assert(MetadataAdjustmentIndex::Class == 3,

lib/IRGen/GenClass.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1079,7 +1079,9 @@ void IRGenModule::emitClassDecl(ClassDecl *D) {
10791079
emitClassMetadata(*this, D, fragileLayout, resilientLayout);
10801080
emitFieldDescriptor(D);
10811081
} else {
1082-
emitEmbeddedClassMetadata(*this, D, fragileLayout);
1082+
if (!D->isGenericContext()) {
1083+
emitEmbeddedClassMetadata(*this, D, fragileLayout);
1084+
}
10831085
}
10841086

10851087
IRGen.addClassForEagerInitialization(D);

lib/IRGen/GenDecl.cpp

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1239,7 +1239,7 @@ void IRGenModule::emitGlobalLists() {
12391239
// Eagerly emit functions that are externally visible. Functions that are
12401240
// dynamic replacements must also be eagerly emitted.
12411241
static bool isLazilyEmittedFunction(SILFunction &f, SILModule &m) {
1242-
// Embedded Swift only emits specialized function, so don't emit genreic
1242+
// Embedded Swift only emits specialized function, so don't emit generic
12431243
// functions, even if they're externally visible.
12441244
if (f.getASTContext().LangOpts.hasFeature(Feature::Embedded) &&
12451245
f.getLoweredFunctionType()->getSubstGenericSignature()) {
@@ -1412,13 +1412,19 @@ deleteAndReenqueueForEmissionValuesDependentOnCanonicalPrespecializedMetadataRec
14121412
void IRGenerator::emitLazyDefinitions() {
14131413
if (SIL.getASTContext().LangOpts.hasFeature(Feature::Embedded)) {
14141414
// In embedded Swift, the compiler cannot emit any metadata, etc.
1415-
LazyTypeMetadata.clear();
1416-
LazySpecializedTypeMetadataRecords.clear();
1417-
LazyTypeContextDescriptors.clear();
1418-
LazyOpaqueTypeDescriptors.clear();
1419-
LazyCanonicalSpecializedMetadataAccessors.clear();
1420-
LazyMetadataAccessors.clear();
1421-
LazyWitnessTables.clear();
1415+
assert(LazyTypeMetadata.empty());
1416+
assert(LazySpecializedTypeMetadataRecords.empty());
1417+
assert(LazyTypeContextDescriptors.empty());
1418+
assert(LazyOpaqueTypeDescriptors.empty());
1419+
assert(LazyFieldDescriptors.empty());
1420+
// LazyFunctionDefinitions are allowed, but they must not be generic
1421+
for (SILFunction *f : LazyFunctionDefinitions) {
1422+
assert(!f->getLoweredFunctionType()->getSubstGenericSignature());
1423+
}
1424+
assert(LazyWitnessTables.empty());
1425+
assert(LazyCanonicalSpecializedMetadataAccessors.empty());
1426+
assert(LazyMetadataAccessors.empty());
1427+
// LazySpecializedClassMetadata is allowed
14221428
}
14231429

14241430
while (!LazyTypeMetadata.empty() ||
@@ -1427,7 +1433,8 @@ void IRGenerator::emitLazyDefinitions() {
14271433
!LazyOpaqueTypeDescriptors.empty() || !LazyFieldDescriptors.empty() ||
14281434
!LazyFunctionDefinitions.empty() || !LazyWitnessTables.empty() ||
14291435
!LazyCanonicalSpecializedMetadataAccessors.empty() ||
1430-
!LazyMetadataAccessors.empty()) {
1436+
!LazyMetadataAccessors.empty() ||
1437+
!LazySpecializedClassMetadata.empty()) {
14311438
// Emit any lazy type metadata we require.
14321439
while (!LazyTypeMetadata.empty()) {
14331440
NominalTypeDecl *type = LazyTypeMetadata.pop_back_val();
@@ -1519,6 +1526,12 @@ void IRGenerator::emitLazyDefinitions() {
15191526
CurrentIGMPtr IGM = getGenModule(nominal->getDeclContext());
15201527
emitLazyMetadataAccessor(*IGM.get(), nominal);
15211528
}
1529+
1530+
while (!LazySpecializedClassMetadata.empty()) {
1531+
CanType classType = LazySpecializedClassMetadata.pop_back_val();
1532+
CurrentIGMPtr IGM = getGenModule(classType->getClassOrBoundGenericClass());
1533+
emitLazySpecializedClassMetadata(*IGM.get(), classType);
1534+
}
15221535
}
15231536

15241537
FinishedEmittingLazyDefinitions = true;
@@ -1528,6 +1541,10 @@ void IRGenerator::addLazyFunction(SILFunction *f) {
15281541
// Add it to the queue if it hasn't already been put there.
15291542
if (!LazilyEmittedFunctions.insert(f).second)
15301543
return;
1544+
1545+
if (SIL.getASTContext().LangOpts.hasFeature(Feature::Embedded)) {
1546+
assert(!f->getLoweredFunctionType()->getSubstGenericSignature());
1547+
}
15311548

15321549
assert(!FinishedEmittingLazyDefinitions);
15331550
LazyFunctionDefinitions.push_back(f);
@@ -1601,6 +1618,12 @@ bool IRGenerator::hasLazyMetadata(TypeDecl *type) {
16011618
return isLazy;
16021619
}
16031620

1621+
void IRGenerator::noteUseOfSpecializedClassMetadata(CanType classType) {
1622+
if (LazilyEmittedSpecializedClassMetadata.insert(classType.getPointer()).second) {
1623+
LazySpecializedClassMetadata.push_back(classType);
1624+
}
1625+
}
1626+
16041627
void IRGenerator::noteUseOfTypeGlobals(NominalTypeDecl *type,
16051628
bool isUseOfMetadata,
16061629
RequireMetadata_t requireMetadata) {
@@ -5061,8 +5084,9 @@ IRGenModule::getAddrOfTypeMetadata(CanType concreteType,
50615084
// Foreign classes and prespecialized generic types do not use an alias into
50625085
// the full metadata and therefore require a GEP.
50635086
bool fullMetadata =
5064-
foreign || (concreteType->getAnyGeneric() &&
5065-
concreteType->getAnyGeneric()->isGenericContext());
5087+
!Context.LangOpts.hasFeature(Feature::Embedded) &&
5088+
(foreign || (concreteType->getAnyGeneric() &&
5089+
concreteType->getAnyGeneric()->isGenericContext()));
50665090

50675091
llvm::Type *defaultVarTy;
50685092
unsigned adjustmentIndex;
@@ -5099,6 +5123,14 @@ IRGenModule::getAddrOfTypeMetadata(CanType concreteType,
50995123
// trigger lazy emission of the metadata.
51005124
if (NominalTypeDecl *nominal = concreteType->getAnyNominal()) {
51015125
IRGen.noteUseOfTypeMetadata(nominal);
5126+
5127+
if (Context.LangOpts.hasFeature(Feature::Embedded)) {
5128+
if (auto *classDecl = dyn_cast<ClassDecl>(nominal)) {
5129+
if (classDecl->isGenericContext()) {
5130+
IRGen.noteUseOfSpecializedClassMetadata(concreteType);
5131+
}
5132+
}
5133+
}
51025134
}
51035135

51045136
if (shouldPrespecializeGenericMetadata()) {

0 commit comments

Comments
 (0)