Skip to content

Commit 5114f22

Browse files
committed
[metadata prespecialization] Reemit dependent values.
The metadata accessor and type context descriptor for a nominal type both depend on canonical metadata--the former because it returns those metadata, the latter because it has them as trailing objects. Here, the work is done to reemit those values when new canonical prespecialized metadata are encountered.
1 parent 00e143c commit 5114f22

13 files changed

+669
-75
lines changed

lib/IRGen/GenDecl.cpp

Lines changed: 73 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1164,18 +1164,42 @@ void IRGenerator::emitTypeMetadataRecords() {
11641164
}
11651165
}
11661166

1167+
void IRGenerator::
1168+
deleteAndReenqueueForEmissionValuesDependentOnCanonicalPrespecializedMetadataRecords(
1169+
IRGenModule &IGM, CanType typeWithCanonicalMetadataPrespecialization,
1170+
NominalTypeDecl &decl) {
1171+
// The accessor depends on canonical metadata records because they are
1172+
// returned from the function when the arguments match.
1173+
//
1174+
// TODO: Once work of looking through canonical prespecialized metadata has
1175+
// been moved into getGenericMetadata, this reemission will no longer
1176+
// be necessary.
1177+
auto *accessor = IGM.getAddrOfTypeMetadataAccessFunction(
1178+
decl.getDeclaredType()->getCanonicalType(), NotForDefinition);
1179+
accessor->deleteBody();
1180+
IGM.IRGen.noteUseOfMetadataAccessor(&decl);
1181+
1182+
// The type context descriptor depends on canonical metadata records because
1183+
// pointers to them are attached as trailing objects to it.
1184+
//
1185+
// Don't call
1186+
//
1187+
// noteUseOfTypeContextDescriptor
1188+
//
1189+
// here because we don't want to reemit metadata.
1190+
emitLazyTypeContextDescriptor(IGM, &decl, RequireMetadata);
1191+
}
1192+
11671193
/// Emit any lazy definitions (of globals or functions or whatever
11681194
/// else) that we require.
11691195
void IRGenerator::emitLazyDefinitions() {
11701196
while (!LazyTypeMetadata.empty() ||
11711197
!LazySpecializedTypeMetadataRecords.empty() ||
11721198
!LazyTypeContextDescriptors.empty() ||
1173-
!LazyOpaqueTypeDescriptors.empty() ||
1174-
!LazyFieldDescriptors.empty() ||
1175-
!LazyFunctionDefinitions.empty() ||
1176-
!LazyWitnessTables.empty() ||
1177-
!LazyCanonicalSpecializedMetadataAccessors.empty()) {
1178-
1199+
!LazyOpaqueTypeDescriptors.empty() || !LazyFieldDescriptors.empty() ||
1200+
!LazyFunctionDefinitions.empty() || !LazyWitnessTables.empty() ||
1201+
!LazyCanonicalSpecializedMetadataAccessors.empty() ||
1202+
!LazyMetadataAccessors.empty()) {
11791203
// Emit any lazy type metadata we require.
11801204
while (!LazyTypeMetadata.empty()) {
11811205
NominalTypeDecl *type = LazyTypeMetadata.pop_back_val();
@@ -1187,10 +1211,23 @@ void IRGenerator::emitLazyDefinitions() {
11871211
emitLazyTypeMetadata(*IGM.get(), type);
11881212
}
11891213
while (!LazySpecializedTypeMetadataRecords.empty()) {
1190-
CanType type = LazySpecializedTypeMetadataRecords.pop_back_val();
1191-
auto *nominal = type->getNominalOrBoundGenericNominal();
1192-
CurrentIGMPtr IGM = getGenModule(nominal->getDeclContext());
1193-
emitLazySpecializedGenericTypeMetadata(*IGM.get(), type);
1214+
CanType theType;
1215+
TypeMetadataCanonicality canonicality;
1216+
std::tie(theType, canonicality) =
1217+
LazySpecializedTypeMetadataRecords.pop_back_val();
1218+
auto *nominal = theType->getNominalOrBoundGenericNominal();
1219+
CurrentIGMPtr IGMPtr = getGenModule(nominal->getDeclContext());
1220+
auto &IGM = *IGMPtr.get();
1221+
// A new canonical prespecialized metadata changes both the type
1222+
// descriptor (adding a new entry to the trailing list of metadata) and
1223+
// the metadata accessor (adding a new list of generic arguments against
1224+
// which to compare the arguments to the function). Consequently, it is
1225+
// necessary to force these to be reemitted.
1226+
if (canonicality == TypeMetadataCanonicality::Canonical) {
1227+
deleteAndReenqueueForEmissionValuesDependentOnCanonicalPrespecializedMetadataRecords(
1228+
IGM, theType, *nominal);
1229+
}
1230+
emitLazySpecializedGenericTypeMetadata(IGM, theType);
11941231
}
11951232
while (!LazyTypeContextDescriptors.empty()) {
11961233
NominalTypeDecl *type = LazyTypeContextDescriptors.pop_back_val();
@@ -1236,17 +1273,25 @@ void IRGenerator::emitLazyDefinitions() {
12361273
LazyCanonicalSpecializedMetadataAccessors.pop_back_val();
12371274
auto *nominal = theType->getAnyNominal();
12381275
assert(nominal);
1276+
CurrentIGMPtr IGMPtr = getGenModule(nominal->getDeclContext());
1277+
auto &IGM = *IGMPtr.get();
1278+
// TODO: Once non-canonical accessors are available, this variable should
1279+
// reflect the canonicality of the accessor rather than always being
1280+
// canonical.
1281+
auto canonicality = TypeMetadataCanonicality::Canonical;
1282+
if (canonicality == TypeMetadataCanonicality::Canonical) {
1283+
deleteAndReenqueueForEmissionValuesDependentOnCanonicalPrespecializedMetadataRecords(
1284+
IGM, theType, *nominal);
1285+
}
1286+
emitLazyCanonicalSpecializedMetadataAccessor(IGM, theType);
1287+
}
1288+
while (!LazyMetadataAccessors.empty()) {
1289+
NominalTypeDecl *nominal = LazyMetadataAccessors.pop_back_val();
12391290
CurrentIGMPtr IGM = getGenModule(nominal->getDeclContext());
1240-
emitLazyCanonicalSpecializedMetadataAccessor(*IGM.get(), theType);
1291+
emitLazyMetadataAccessor(*IGM.get(), nominal);
12411292
}
12421293
}
12431294

1244-
while (!LazyMetadataAccessors.empty()) {
1245-
NominalTypeDecl *nominal = LazyMetadataAccessors.pop_back_val();
1246-
CurrentIGMPtr IGM = getGenModule(nominal->getDeclContext());
1247-
emitLazyMetadataAccessor(*IGM.get(), nominal);
1248-
}
1249-
12501295
FinishedEmittingLazyDefinitions = true;
12511296
}
12521297

@@ -1442,17 +1487,19 @@ static bool typeKindCanBePrespecialized(TypeKind theKind) {
14421487
}
14431488
}
14441489

1445-
void IRGenerator::noteUseOfSpecializedGenericTypeMetadata(CanType type) {
1446-
assert(typeKindCanBePrespecialized(type->getKind()));
1447-
auto key = type->getAnyNominal();
1490+
void IRGenerator::noteUseOfSpecializedGenericTypeMetadata(
1491+
IRGenModule &IGM, CanType theType, TypeMetadataCanonicality canonicality) {
1492+
assert(typeKindCanBePrespecialized(theType->getKind()));
1493+
auto key = theType->getAnyNominal();
14481494
assert(key);
14491495
assert(key->isGenericContext());
1450-
auto &enqueuedSpecializedTypes = CanonicalSpecializationsForGenericTypes[key];
1496+
auto &enqueuedSpecializedTypes =
1497+
MetadataPrespecializationsForGenericTypes[key];
14511498
if (llvm::all_of(enqueuedSpecializedTypes,
1452-
[&](CanType enqueued) { return enqueued != type; })) {
1499+
[&](auto enqueued) { return enqueued.first != theType; })) {
14531500
assert(!FinishedEmittingLazyDefinitions);
1454-
LazySpecializedTypeMetadataRecords.push_back(type);
1455-
enqueuedSpecializedTypes.push_back(type);
1501+
LazySpecializedTypeMetadataRecords.push_back({theType, canonicality});
1502+
enqueuedSpecializedTypes.push_back({theType, canonicality});
14561503
}
14571504
}
14581505

@@ -4032,7 +4079,8 @@ IRGenModule::getAddrOfTypeMetadata(CanType concreteType,
40324079
if (shouldPrespecializeGenericMetadata()) {
40334080
if (auto nominal = concreteType->getAnyNominal()) {
40344081
if (nominal->isGenericContext()) {
4035-
IRGen.noteUseOfSpecializedGenericTypeMetadata(concreteType);
4082+
IRGen.noteUseOfSpecializedGenericTypeMetadata(*this, concreteType,
4083+
canonicality);
40364084
}
40374085
}
40384086
}

lib/IRGen/GenMeta.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1218,6 +1218,7 @@ namespace {
12181218
void setCommonFlags(TypeContextDescriptorFlags &flags) {
12191219
setClangImportedFlags(flags);
12201220
setMetadataInitializationKind(flags);
1221+
setHasCanonicalMetadataPrespecializations(flags);
12211222
}
12221223

12231224
void setClangImportedFlags(TypeContextDescriptorFlags &flags) {
@@ -1251,6 +1252,19 @@ namespace {
12511252
flags.setMetadataInitialization(MetadataInitialization);
12521253
}
12531254

1255+
void setHasCanonicalMetadataPrespecializations(TypeContextDescriptorFlags &flags) {
1256+
flags.setHasCanonicalMetadataPrespecializations(hasCanonicalMetadataPrespecializations());
1257+
}
1258+
1259+
bool hasCanonicalMetadataPrespecializations() {
1260+
return IGM.shouldPrespecializeGenericMetadata() &&
1261+
llvm::any_of(IGM.IRGen.metadataPrespecializationsForType(Type),
1262+
[](auto pair) {
1263+
return pair.second ==
1264+
TypeMetadataCanonicality::Canonical;
1265+
});
1266+
}
1267+
12541268
void maybeAddMetadataInitialization() {
12551269
switch (MetadataInitialization) {
12561270
case TypeContextDescriptorFlags::NoMetadataInitialization:
@@ -1310,6 +1324,28 @@ namespace {
13101324
addIncompleteMetadata();
13111325
}
13121326

1327+
void maybeAddCanonicalMetadataPrespecializations() {
1328+
if (Type->isGenericContext() && hasCanonicalMetadataPrespecializations()) {
1329+
asImpl().addCanonicalMetadataPrespecializations();
1330+
}
1331+
}
1332+
1333+
void addCanonicalMetadataPrespecializations() {
1334+
auto specializations = IGM.IRGen.metadataPrespecializationsForType(Type);
1335+
auto count = llvm::count_if(specializations, [](auto pair) {
1336+
return pair.second == TypeMetadataCanonicality::Canonical;
1337+
});
1338+
B.addInt32(count);
1339+
for (auto pair : specializations) {
1340+
if (pair.second != TypeMetadataCanonicality::Canonical) {
1341+
continue;
1342+
}
1343+
auto specialization = pair.first;
1344+
auto *metadata = IGM.getAddrOfTypeMetadata(specialization);
1345+
B.addRelativeAddress(metadata);
1346+
}
1347+
}
1348+
13131349
// Subclasses should provide:
13141350
// ContextDescriptorKind getContextKind();
13151351
// void addLayoutInfo();
@@ -1337,6 +1373,11 @@ namespace {
13371373
FieldVectorOffset = layout.getFieldOffsetVectorOffset().getStatic();
13381374
}
13391375

1376+
void layout() {
1377+
super::layout();
1378+
maybeAddCanonicalMetadataPrespecializations();
1379+
}
1380+
13401381
ContextDescriptorKind getContextKind() {
13411382
return ContextDescriptorKind::Struct;
13421383
}
@@ -1397,6 +1438,11 @@ namespace {
13971438
if (layout.hasPayloadSizeOffset())
13981439
PayloadSizeOffset = layout.getPayloadSizeOffset().getStatic();
13991440
}
1441+
1442+
void layout() {
1443+
super::layout();
1444+
maybeAddCanonicalMetadataPrespecializations();
1445+
}
14001446

14011447
ContextDescriptorKind getContextKind() {
14021448
return ContextDescriptorKind::Enum;
@@ -1511,6 +1557,7 @@ namespace {
15111557
addVTable();
15121558
addOverrideTable();
15131559
addObjCResilientClassStubInfo();
1560+
maybeAddCanonicalMetadataPrespecializations();
15141561
}
15151562

15161563
void addIncompleteMetadataOrRelocationFunction() {
@@ -1783,6 +1830,19 @@ namespace {
17831830
getType(), NotForDefinition,
17841831
TypeMetadataAddress::AddressPoint));
17851832
}
1833+
1834+
void addCanonicalMetadataPrespecializations() {
1835+
super::addCanonicalMetadataPrespecializations();
1836+
auto specializations = IGM.IRGen.metadataPrespecializationsForType(Type);
1837+
for (auto pair : specializations) {
1838+
if (pair.second != TypeMetadataCanonicality::Canonical) {
1839+
continue;
1840+
}
1841+
auto specialization = pair.first;
1842+
auto *function = IGM.getAddrOfCanonicalSpecializedGenericTypeMetadataAccessFunction(specialization, NotForDefinition);
1843+
B.addRelativeAddress(function);
1844+
}
1845+
}
17861846
};
17871847

17881848
class OpaqueTypeDescriptorBuilder

lib/IRGen/IRGenModule.h

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,11 @@ enum RequireMetadata_t : bool {
192192
RequireMetadata = true
193193
};
194194

195+
enum class TypeMetadataCanonicality : bool {
196+
Noncanonical,
197+
Canonical,
198+
};
199+
195200
/// The principal singleton which manages all of IR generation.
196201
///
197202
/// The IRGenerator delegates the emission of different top-level entities
@@ -259,17 +264,20 @@ class IRGenerator {
259264
/// queued up.
260265
llvm::SmallPtrSet<NominalTypeDecl *, 4> LazilyEmittedFieldMetadata;
261266

262-
/// Maps every generic type that is specialized within the module to its
263-
/// specializations.
264-
llvm::DenseMap<NominalTypeDecl *, llvm::SmallVector<CanType, 4>>
265-
CanonicalSpecializationsForGenericTypes;
267+
/// Maps every generic type whose metadata is specialized within the module
268+
/// to its specializations.
269+
llvm::DenseMap<
270+
NominalTypeDecl *,
271+
llvm::SmallVector<std::pair<CanType, TypeMetadataCanonicality>, 4>>
272+
MetadataPrespecializationsForGenericTypes;
266273

267274
llvm::DenseMap<NominalTypeDecl *, llvm::SmallVector<CanType, 4>>
268275
CanonicalSpecializedAccessorsForGenericTypes;
269276

270277
/// The queue of specialized generic types whose prespecialized metadata to
271278
/// emit.
272-
llvm::SmallVector<CanType, 4> LazySpecializedTypeMetadataRecords;
279+
llvm::SmallVector<std::pair<CanType, TypeMetadataCanonicality>, 4>
280+
LazySpecializedTypeMetadataRecords;
273281

274282
/// The queue of metadata accessors to emit.
275283
///
@@ -423,11 +431,16 @@ class IRGenerator {
423431

424432
void ensureRelativeSymbolCollocation(SILDefaultWitnessTable &wt);
425433

426-
llvm::SmallVector<CanType, 4>
427-
canonicalSpecializationsForType(NominalTypeDecl *type) {
428-
return CanonicalSpecializationsForGenericTypes.lookup(type);
434+
llvm::SmallVector<std::pair<CanType, TypeMetadataCanonicality>, 4>
435+
metadataPrespecializationsForType(NominalTypeDecl *type) {
436+
return MetadataPrespecializationsForGenericTypes.lookup(type);
429437
}
430438

439+
void
440+
deleteAndReenqueueForEmissionValuesDependentOnCanonicalPrespecializedMetadataRecords(
441+
IRGenModule &IGM, CanType typeWithCanonicalMetadataPrespecialization,
442+
NominalTypeDecl &decl);
443+
431444
void noteUseOfMetadataAccessor(NominalTypeDecl *decl) {
432445
if (LazyMetadataAccessors.count(decl) == 0) {
433446
LazyMetadataAccessors.insert(decl);
@@ -438,7 +451,8 @@ class IRGenerator {
438451
noteUseOfTypeGlobals(type, true, RequireMetadata);
439452
}
440453

441-
void noteUseOfSpecializedGenericTypeMetadata(CanType type);
454+
void noteUseOfSpecializedGenericTypeMetadata(
455+
IRGenModule &IGM, CanType theType, TypeMetadataCanonicality canonicality);
442456
void noteUseOfCanonicalSpecializedMetadataAccessor(CanType forType);
443457

444458
void noteUseOfTypeMetadata(CanType type) {
@@ -547,11 +561,6 @@ enum class MangledTypeRefRole {
547561
DefaultAssociatedTypeWitness,
548562
};
549563

550-
enum class TypeMetadataCanonicality : bool {
551-
Noncanonical,
552-
Canonical,
553-
};
554-
555564
/// IRGenModule - Primary class for emitting IR for global declarations.
556565
///
557566
class IRGenModule {

0 commit comments

Comments
 (0)