Skip to content

Commit 9ea71d1

Browse files
committed
[IRGen] Prepare to refer to prespecializations.
When emitting a reference to the metadata for a generic type, prepare to, rather than always inserting calls to the type metadata access function, emit direct references to static specializations when possible and emit calls to the forthcoming swift_getCanonicalSpecializedMetadata when not possible. For now, the metadata access function is always called.
1 parent 89278f8 commit 9ea71d1

File tree

2 files changed

+89
-3
lines changed

2 files changed

+89
-3
lines changed

lib/IRGen/MetadataRequest.cpp

Lines changed: 85 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,76 @@ static MetadataResponse emitNominalMetadataRef(IRGenFunction &IGF,
692692
return response;
693693
}
694694

695+
bool irgen::isNominalGenericContextTypeMetadataAccessTrivial(
696+
IRGenModule &IGM, NominalTypeDecl &nominal, CanType type) {
697+
// TODO: Once prespecialized generic metadata can be lazily emitted, eliminate
698+
// this early return.
699+
return false;
700+
701+
assert(nominal.isGenericContext());
702+
703+
if (!IGM.shouldPrespecializeGenericMetadata()) {
704+
return false;
705+
}
706+
707+
if (type->hasArchetype()) {
708+
return false;
709+
}
710+
711+
if (nominal.getModuleContext() != IGM.getSwiftModule() ||
712+
nominal.isResilient(IGM.getSwiftModule(), ResilienceExpansion::Minimal)) {
713+
return false;
714+
}
715+
716+
if (isa<EnumType>(type) || isa<BoundGenericEnumType>(type)) {
717+
// TODO: Support enums.
718+
return false;
719+
}
720+
721+
if (isa<ClassType>(type) || isa<BoundGenericClassType>(type)) {
722+
// TODO: Support classes.
723+
return false;
724+
}
725+
726+
auto *generic = type.getAnyGeneric();
727+
assert(generic);
728+
auto *environment = generic->getGenericEnvironment();
729+
assert(environment);
730+
auto substitutions =
731+
type->getContextSubstitutionMap(IGM.getSwiftModule(), &nominal);
732+
733+
return llvm::all_of(environment->getGenericParams(), [&](auto parameter) {
734+
auto conformances =
735+
environment->getGenericSignature()->getConformsTo(parameter);
736+
auto witnessTablesAreReferenceable =
737+
llvm::all_of(conformances, [&](ProtocolDecl *conformance) {
738+
return conformance->getModuleContext() == IGM.getSwiftModule() &&
739+
!conformance->isResilient(IGM.getSwiftModule(),
740+
ResilienceExpansion::Minimal);
741+
});
742+
auto argument = ((Type *)parameter)->subst(substitutions);
743+
auto genericArgument = argument->getAnyGeneric();
744+
// For now, to avoid statically specializing generic protocol witness
745+
// tables, don't statically specialize metadata for types any of whose
746+
// arguments are generic.
747+
//
748+
// TODO: This is more pessimistic than necessary. Specialize even in
749+
// the face of generic arguments so long as those arguments
750+
// aren't required to conform to any protocols.
751+
//
752+
// TODO: Once witness tables are statically specialized, check whether the
753+
// ConformanceInfo returns nullptr from tryGetConstantTable.
754+
// early return.
755+
auto isGeneric = genericArgument && genericArgument->isGenericContext();
756+
auto isNominal = argument->getNominalOrBoundGenericNominal();
757+
auto isExistential = argument->isExistentialType();
758+
return isNominal && !isGeneric && !isExistential &&
759+
witnessTablesAreReferenceable &&
760+
irgen::isTypeMetadataAccessTrivial(IGM,
761+
argument->getCanonicalType());
762+
}) && IGM.getTypeInfoForUnlowered(type).isFixedSize(ResilienceExpansion::Maximal);
763+
}
764+
695765
/// Is it basically trivial to access the given metadata? If so, we don't
696766
/// need a cache variable in its accessor.
697767
bool irgen::isTypeMetadataAccessTrivial(IRGenModule &IGM, CanType type) {
@@ -707,14 +777,14 @@ bool irgen::isTypeMetadataAccessTrivial(IRGenModule &IGM, CanType type) {
707777
if (isa<ClangModuleUnit>(nominalDecl->getModuleScopeContext()))
708778
return false;
709779

710-
// Generic type metadata always requires an accessor.
711780
if (nominalDecl->isGenericContext())
712-
return false;
781+
return isNominalGenericContextTypeMetadataAccessTrivial(IGM, *nominalDecl,
782+
type);
713783

714784
auto expansion = ResilienceExpansion::Maximal;
715785

716786
// Resiliently-sized metadata access always requires an accessor.
717-
return (IGM.getTypeInfoForUnlowered(type).isFixedSize(expansion));
787+
return IGM.getTypeInfoForUnlowered(type).isFixedSize(expansion);
718788
}
719789

720790
// The empty tuple type has a singleton metadata.
@@ -739,6 +809,18 @@ bool irgen::isTypeMetadataAccessTrivial(IRGenModule &IGM, CanType type) {
739809
if (type->hasDynamicSelfType())
740810
return true;
741811

812+
if (isa<BoundGenericStructType>(type) || isa<BoundGenericEnumType>(type)) {
813+
auto nominalType = cast<BoundGenericType>(type);
814+
auto *nominalDecl = nominalType->getDecl();
815+
816+
// Imported type metadata always requires an accessor.
817+
if (isa<ClangModuleUnit>(nominalDecl->getModuleScopeContext()))
818+
return false;
819+
820+
return isNominalGenericContextTypeMetadataAccessTrivial(IGM, *nominalDecl,
821+
type);
822+
}
823+
742824
return false;
743825
}
744826

lib/IRGen/MetadataRequest.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,10 @@ static inline bool isAccessorLazilyGenerated(MetadataAccessStrategy strategy) {
503503
/// need a cache variable in its accessor.
504504
bool isTypeMetadataAccessTrivial(IRGenModule &IGM, CanType type);
505505

506+
bool isNominalGenericContextTypeMetadataAccessTrivial(IRGenModule &IGM,
507+
NominalTypeDecl &nominal,
508+
CanType type);
509+
506510
/// Determine how the given type metadata should be accessed.
507511
MetadataAccessStrategy getTypeMetadataAccessStrategy(CanType type);
508512

0 commit comments

Comments
 (0)