Skip to content

Commit 1430c04

Browse files
Merge pull request #28610 from nate-chandler/generic-metadata-prespecialization
Generic metadata prespecialization, part 1
2 parents f34c970 + d78dc03 commit 1430c04

File tree

55 files changed

+2206
-122
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+2206
-122
lines changed

include/swift/ABI/Metadata.h

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,8 @@ struct TargetMetadata {
697697

698698
bool satisfiesClassConstraint() const;
699699

700+
bool isCanonicalStaticallySpecializedGenericMetadata() const;
701+
700702
#if SWIFT_OBJC_INTEROP
701703
/// Get the ObjC class object for this type if it has one, or return null if
702704
/// the type is not a class (or not a class with a class object).
@@ -1348,6 +1350,34 @@ struct TargetStructMetadata : public TargetValueMetadata<Runtime> {
13481350
return reinterpret_cast<const uint32_t *>(asWords + offset);
13491351
}
13501352

1353+
bool isCanonicalStaticallySpecializedGenericMetadata() const {
1354+
auto *description = getDescription();
1355+
if (!description->isGeneric())
1356+
return false;
1357+
1358+
auto *trailingFlags = getTrailingFlags();
1359+
if (trailingFlags == nullptr)
1360+
return false;
1361+
1362+
return trailingFlags->isCanonicalStaticSpecialization();
1363+
}
1364+
1365+
const MetadataTrailingFlags *getTrailingFlags() const {
1366+
auto description = getDescription();
1367+
auto flags = description->getFullGenericContextHeader()
1368+
.DefaultInstantiationPattern->PatternFlags;
1369+
if (!flags.hasTrailingFlags())
1370+
return nullptr;
1371+
auto fieldOffset = description->FieldOffsetVectorOffset;
1372+
auto offset =
1373+
fieldOffset +
1374+
// Pad to the nearest pointer.
1375+
((description->NumFields * sizeof(uint32_t) + sizeof(void *) - 1) /
1376+
sizeof(void *));
1377+
auto asWords = reinterpret_cast<const void *const *>(this);
1378+
return reinterpret_cast<const MetadataTrailingFlags *>(asWords + offset);
1379+
}
1380+
13511381
static constexpr int32_t getGenericArgumentOffset() {
13521382
return sizeof(TargetStructMetadata<Runtime>) / sizeof(StoredPointer);
13531383
}
@@ -3575,7 +3605,7 @@ struct TargetSingletonMetadataInitialization {
35753605
}
35763606

35773607
/// This method can only be called from the runtime itself. It is defined
3578-
/// in MetadataCache.h.
3608+
/// in Metadata.cpp.
35793609
TargetMetadata<Runtime> *allocate(
35803610
const TargetTypeContextDescriptor<Runtime> *description) const;
35813611
};

include/swift/ABI/MetadataValues.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1511,6 +1511,10 @@ class GenericMetadataPatternFlags : public FlagSet<uint32_t> {
15111511
/// Does this pattern have an extra-data pattern?
15121512
HasExtraDataPattern = 0,
15131513

1514+
/// Do instances of this pattern have a bitset of flags that occur at the
1515+
/// end of the metadata, after the extra data if there is any?
1516+
HasTrailingFlags = 1,
1517+
15141518
// Class-specific flags.
15151519

15161520
/// Does this pattern have an immediate-members pattern?
@@ -1535,6 +1539,10 @@ class GenericMetadataPatternFlags : public FlagSet<uint32_t> {
15351539
hasExtraDataPattern,
15361540
setHasExtraDataPattern)
15371541

1542+
FLAGSET_DEFINE_FLAG_ACCESSORS(HasTrailingFlags,
1543+
hasTrailingFlags,
1544+
setHasTrailingFlags)
1545+
15381546
FLAGSET_DEFINE_FIELD_ACCESSORS(Value_MetadataKind,
15391547
Value_MetadataKind_width,
15401548
MetadataKind,
@@ -1667,6 +1675,30 @@ class MetadataRequest : public FlagSet<size_t> {
16671675
}
16681676
};
16691677

1678+
struct MetadataTrailingFlags : public FlagSet<uint64_t> {
1679+
enum {
1680+
/// Whether this metadata is a specialization of a generic metadata pattern
1681+
/// which was created during compilation.
1682+
IsStaticSpecialization = 0,
1683+
1684+
/// Whether this metadata is a specialization of a generic metadata pattern
1685+
/// which was created during compilation and made to be canonical by
1686+
/// modifying the metadata accessor.
1687+
IsCanonicalStaticSpecialization = 1,
1688+
};
1689+
1690+
explicit MetadataTrailingFlags(uint64_t bits) : FlagSet(bits) {}
1691+
constexpr MetadataTrailingFlags() {}
1692+
1693+
FLAGSET_DEFINE_FLAG_ACCESSORS(IsStaticSpecialization,
1694+
isStaticSpecialization,
1695+
setIsStaticSpecialization)
1696+
1697+
FLAGSET_DEFINE_FLAG_ACCESSORS(IsCanonicalStaticSpecialization,
1698+
isCanonicalStaticSpecialization,
1699+
setIsCanonicalStaticSpecialization)
1700+
};
1701+
16701702
/// Flags for Builtin.IntegerLiteral values.
16711703
class IntegerLiteralFlags {
16721704
public:

include/swift/AST/ASTContext.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,14 @@ class ASTContext final {
614614
/// swift_getTypeByMangledNameInContextInMetadataState.
615615
AvailabilityContext getTypesInAbstractMetadataStateAvailability();
616616

617+
/// Get the runtime availability of support for prespecialized generic
618+
/// metadata.
619+
AvailabilityContext getPrespecializedGenericMetadataAvailability();
620+
621+
/// Get the runtime availability of features introduced in the Swift 5.2
622+
/// compiler for the target platform.
623+
AvailabilityContext getSwift52Availability();
624+
617625

618626
//===--------------------------------------------------------------------===//
619627
// Diagnostics Helper functions

include/swift/AST/Decl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2864,7 +2864,7 @@ class GenericTypeDecl : public GenericContext, public TypeDecl {
28642864
/// code. One is formed implicitly when a declaration is written with an opaque
28652865
/// result type, as in:
28662866
///
2867-
/// func foo() -> opaque SignedInteger { return 1 }
2867+
/// func foo() -> some SignedInteger { return 1 }
28682868
///
28692869
/// The declared type is a special kind of ArchetypeType representing the
28702870
/// abstracted underlying type.

include/swift/AST/IRGenOptions.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,10 @@ class IRGenOptions {
190190
/// Passing this flag completely disables this behavior.
191191
unsigned DisableLegacyTypeInfo : 1;
192192

193+
/// Create metadata specializations for generic types at statically known type
194+
/// arguments.
195+
unsigned PrespecializeGenericMetadata : 1;
196+
193197
/// The path to load legacy type layouts from.
194198
StringRef ReadLegacyTypeInfoPath;
195199

@@ -255,8 +259,9 @@ class IRGenOptions {
255259
EnableAnonymousContextMangledNames(false), ForcePublicLinkage(false),
256260
LazyInitializeClassMetadata(false),
257261
LazyInitializeProtocolConformances(false), DisableLegacyTypeInfo(false),
258-
UseIncrementalLLVMCodeGen(true), UseSwiftCall(false),
259-
GenerateProfile(false), EnableDynamicReplacementChaining(false),
262+
PrespecializeGenericMetadata(false), UseIncrementalLLVMCodeGen(true),
263+
UseSwiftCall(false), GenerateProfile(false),
264+
EnableDynamicReplacementChaining(false),
260265
DisableRoundTripDebugTypes(false), DisableDebuggerShadowCopies(false),
261266
CmdArgs(), SanitizeCoverage(llvm::SanitizerCoverageOptions()),
262267
TypeInfoFilter(TypeInfoDumpFilter::All) {}

include/swift/IRGen/Linking.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ class UniversalLinkageInfo {
6565
bool shouldAllPrivateDeclsBeVisibleFromOtherFiles() const {
6666
return HasMultipleIGMs;
6767
}
68-
/// In case of multipe llvm modules, private lazy protocol
68+
/// In case of multiple llvm modules, private lazy protocol
6969
/// witness table accessors could be emitted by two different IGMs during
7070
/// IRGen into different object files and the linker would complain about
7171
/// duplicate symbols.

include/swift/Option/FrontendOptions.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,10 @@ def disable_verify_exclusivity : Flag<["-"], "disable-verify-exclusivity">,
644644
def disable_legacy_type_info : Flag<["-"], "disable-legacy-type-info">,
645645
HelpText<"Completely disable legacy type layout">;
646646

647+
def prespecialize_generic_metadata : Flag<["-"], "prespecialize-generic-metadata">,
648+
HelpText<"Statically specialize metadata for generic types at types that "
649+
"are known to be used in source.">;
650+
647651
def read_legacy_type_info_path_EQ : Joined<["-"], "read-legacy-type-info-path=">,
648652
HelpText<"Read legacy type layout from the given path instead of default path">;
649653

lib/AST/Availability.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,14 +239,25 @@ AvailabilityContext ASTContext::getSwift51Availability() {
239239
}
240240

241241
AvailabilityContext ASTContext::getTypesInAbstractMetadataStateAvailability() {
242+
return getSwift52Availability();
243+
}
244+
245+
AvailabilityContext ASTContext::getPrespecializedGenericMetadataAvailability() {
246+
return getSwift52Availability();
247+
}
248+
249+
AvailabilityContext ASTContext::getSwift52Availability() {
242250
auto target = LangOpts.Target;
243251

244252
if (target.isMacOSX() ) {
245253
return AvailabilityContext(
246254
VersionRange::allGTE(llvm::VersionTuple(10, 99, 0)));
247-
} else if (target.isiOS() || target.isWatchOS()) {
255+
} else if (target.isiOS()) {
256+
return AvailabilityContext(
257+
VersionRange::allGTE(llvm::VersionTuple(99, 0, 0)));
258+
} else if (target.isWatchOS()) {
248259
return AvailabilityContext(
249-
VersionRange::allGTE(llvm::VersionTuple(9999, 0, 0)));
260+
VersionRange::allGTE(llvm::VersionTuple(9, 99, 0)));
250261
} else {
251262
return AvailabilityContext::alwaysAvailable();
252263
}

lib/Frontend/CompilerInvocation.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1245,6 +1245,10 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args,
12451245
Opts.DisableLegacyTypeInfo = true;
12461246
}
12471247

1248+
if (Args.hasArg(OPT_prespecialize_generic_metadata)) {
1249+
Opts.PrespecializeGenericMetadata = true;
1250+
}
1251+
12481252
if (const Arg *A = Args.getLastArg(OPT_read_legacy_type_info_path_EQ)) {
12491253
Opts.ReadLegacyTypeInfoPath = A->getValue();
12501254
}

lib/IRGen/ClassMetadataVisitor.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,8 +204,13 @@ class ClassMetadataScanner : public ClassMetadataVisitor<Impl> {
204204
addPointer();
205205
}
206206
}
207-
void addGenericArgument(ClassDecl *forClass) { addPointer(); }
208-
void addGenericWitnessTable(ClassDecl *forClass) { addPointer(); }
207+
void addGenericArgument(GenericRequirement requirement, ClassDecl *forClass) {
208+
addPointer();
209+
}
210+
void addGenericWitnessTable(GenericRequirement requirement,
211+
ClassDecl *forClass) {
212+
addPointer();
213+
}
209214
void addPlaceholder(MissingMemberDecl *MMD) {
210215
for (auto i : range(MMD->getNumberOfVTableEntries())) {
211216
(void)i;

lib/IRGen/EnumMetadataVisitor.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ class EnumMetadataScanner : public EnumMetadataVisitor<Impl> {
8282
void addMetadataFlags() { addPointer(); }
8383
void addValueWitnessTable() { addPointer(); }
8484
void addNominalTypeDescriptor() { addPointer(); }
85-
void addGenericArgument() { addPointer(); }
86-
void addGenericWitnessTable() { addPointer(); }
85+
void addGenericArgument(GenericRequirement requirement) { addPointer(); }
86+
void addGenericWitnessTable(GenericRequirement requirement) { addPointer(); }
8787
void addPayloadSize() { addPointer(); }
8888
void noteStartOfTypeSpecificMembers() {}
8989

lib/IRGen/GenDecl.cpp

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1129,6 +1129,7 @@ void IRGenerator::emitTypeMetadataRecords() {
11291129
/// else) that we require.
11301130
void IRGenerator::emitLazyDefinitions() {
11311131
while (!LazyTypeMetadata.empty() ||
1132+
!LazySpecializedTypeMetadataRecords.empty() ||
11321133
!LazyTypeContextDescriptors.empty() ||
11331134
!LazyOpaqueTypeDescriptors.empty() ||
11341135
!LazyFieldDescriptors.empty() ||
@@ -1145,6 +1146,12 @@ void IRGenerator::emitLazyDefinitions() {
11451146
CurrentIGMPtr IGM = getGenModule(type->getDeclContext());
11461147
emitLazyTypeMetadata(*IGM.get(), type);
11471148
}
1149+
while (!LazySpecializedTypeMetadataRecords.empty()) {
1150+
CanType type = LazySpecializedTypeMetadataRecords.pop_back_val();
1151+
auto *nominal = type->getNominalOrBoundGenericNominal();
1152+
CurrentIGMPtr IGM = getGenModule(nominal->getDeclContext());
1153+
emitLazySpecializedGenericTypeMetadata(*IGM.get(), type);
1154+
}
11481155
while (!LazyTypeContextDescriptors.empty()) {
11491156
NominalTypeDecl *type = LazyTypeContextDescriptors.pop_back_val();
11501157
auto &entry = LazyTypeGlobals.find(type)->second;
@@ -1185,6 +1192,12 @@ void IRGenerator::emitLazyDefinitions() {
11851192
}
11861193
}
11871194

1195+
while (!LazyMetadataAccessors.empty()) {
1196+
NominalTypeDecl *nominal = LazyMetadataAccessors.pop_back_val();
1197+
CurrentIGMPtr IGM = getGenModule(nominal->getDeclContext());
1198+
emitLazyMetadataAccessor(*IGM.get(), nominal);
1199+
}
1200+
11881201
FinishedEmittingLazyDefinitions = true;
11891202
}
11901203

@@ -1362,6 +1375,18 @@ void IRGenerator::noteUseOfFieldDescriptor(NominalTypeDecl *type) {
13621375
LazyFieldDescriptors.push_back(type);
13631376
}
13641377

1378+
void IRGenerator::noteUseOfSpecializedGenericTypeMetadata(CanType type) {
1379+
auto key = type->getAnyNominal();
1380+
assert(key);
1381+
auto &enqueuedSpecializedTypes = this->SpecializationsForGenericTypes[key];
1382+
if (llvm::all_of(enqueuedSpecializedTypes,
1383+
[&](CanType enqueued) { return enqueued != type; })) {
1384+
assert(!FinishedEmittingLazyDefinitions);
1385+
this->LazySpecializedTypeMetadataRecords.push_back(type);
1386+
enqueuedSpecializedTypes.push_back(type);
1387+
}
1388+
}
1389+
13651390
void IRGenerator::noteUseOfOpaqueTypeDescriptor(OpaqueTypeDecl *opaque) {
13661391
if (!opaque)
13671392
return;
@@ -3646,8 +3671,11 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata(CanType concreteType,
36463671
if (nominal)
36473672
addRuntimeResolvableType(nominal);
36483673

3649-
// Don't define the alias for foreign type metadata, since it's not ABI.
3650-
if (nominal && requiresForeignTypeMetadata(nominal))
3674+
// Don't define the alias for foreign type metadata or prespecialized generic
3675+
// metadata, since neither is ABI.
3676+
if ((nominal && requiresForeignTypeMetadata(nominal)) ||
3677+
(concreteType->getAnyGeneric() &&
3678+
concreteType->getAnyGeneric()->isGenericContext()))
36513679
return var;
36523680

36533681
// For concrete metadata, declare the alias to its address point.
@@ -3682,9 +3710,13 @@ ConstantReference IRGenModule::getAddrOfTypeMetadata(CanType concreteType,
36823710

36833711
llvm::Type *defaultVarTy;
36843712
unsigned adjustmentIndex;
3685-
3713+
3714+
bool fullMetadata = (nominal && requiresForeignTypeMetadata(nominal)) ||
3715+
(concreteType->getAnyGeneric() &&
3716+
concreteType->getAnyGeneric()->isGenericContext());
3717+
36863718
// Foreign classes reference the full metadata with a GEP.
3687-
if (nominal && requiresForeignTypeMetadata(nominal)) {
3719+
if (fullMetadata) {
36883720
defaultVarTy = FullTypeMetadataStructTy;
36893721
adjustmentIndex = MetadataAdjustmentIndex::ValueType;
36903722
// The symbol for other nominal type metadata is generated at the address
@@ -3709,10 +3741,18 @@ ConstantReference IRGenModule::getAddrOfTypeMetadata(CanType concreteType,
37093741
IRGen.noteUseOfTypeMetadata(nominal);
37103742
}
37113743

3744+
if (shouldPrespecializeGenericMetadata()) {
3745+
if (auto nominal = concreteType->getAnyNominal()) {
3746+
if (nominal->isGenericContext()) {
3747+
IRGen.noteUseOfSpecializedGenericTypeMetadata(concreteType);
3748+
}
3749+
}
3750+
}
3751+
37123752
Optional<LinkEntity> entity;
37133753
DebugTypeInfo DbgTy;
37143754

3715-
if (nominal && requiresForeignTypeMetadata(nominal)) {
3755+
if (fullMetadata) {
37163756
entity = LinkEntity::forTypeMetadata(concreteType,
37173757
TypeMetadataAddress::FullMetadata);
37183758
DbgTy = DebugTypeInfo::getMetadata(MetatypeType::get(concreteType),
@@ -4029,10 +4069,6 @@ Optional<llvm::Function*> IRGenModule::getAddrOfIVarInitDestroy(
40294069
llvm::Function *IRGenModule::getAddrOfValueWitness(CanType abstractType,
40304070
ValueWitness index,
40314071
ForDefinition_t forDefinition) {
4032-
// We shouldn't emit value witness symbols for generic type instances.
4033-
assert(!isa<BoundGenericType>(abstractType) &&
4034-
"emitting value witness for generic type instance?!");
4035-
40364072
LinkEntity entity = LinkEntity::forValueWitness(abstractType, index);
40374073

40384074
llvm::Function *&entry = GlobalFuncs[entity];

0 commit comments

Comments
 (0)