Skip to content

Commit 5e0d0fb

Browse files
Merge pull request #36765 from nate-chandler/generic-metadata-prespecialization-components/generic-value-witnesses
[IRGen] Use generic value witnesses for prespecialized types.
2 parents 9da7665 + 02a63e5 commit 5e0d0fb

20 files changed

+469
-307
lines changed

include/swift/AST/ASTContext.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -744,6 +744,10 @@ class ASTContext final {
744744
/// Get the runtime availability of support for differentiation.
745745
AvailabilityContext getDifferentiationAvailability();
746746

747+
/// Get the runtime availability of getters and setters of multi payload enum
748+
/// tag single payloads.
749+
AvailabilityContext getMultiPayloadEnumTagSinglePayload();
750+
747751
/// Get the runtime availability of features introduced in the Swift 5.2
748752
/// compiler for the target platform.
749753
AvailabilityContext getSwift52Availability();
@@ -760,6 +764,10 @@ class ASTContext final {
760764
/// compiler for the target platform.
761765
AvailabilityContext getSwift55Availability();
762766

767+
/// Get the runtime availability of features introduced in the Swift 5.6
768+
/// compiler for the target platform.
769+
AvailabilityContext getSwift56Availability();
770+
763771
/// Get the runtime availability of features that have been introduced in the
764772
/// Swift compiler for future versions of the target platform.
765773
AvailabilityContext getSwiftFutureAvailability();

include/swift/Runtime/Enum.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,24 @@ void swift_storeEnumTagMultiPayload(OpaqueValue *value,
129129
const EnumMetadata *enumType,
130130
unsigned whichCase);
131131

132+
/// The unspecialized getEnumTagSinglePayload value witness to be used by the
133+
/// VWTs for for specialized generic enums that are multi-payload.
134+
///
135+
/// Runtime availability: Swift 5.6
136+
SWIFT_RUNTIME_EXPORT
137+
unsigned swift_getMultiPayloadEnumTagSinglePayload(const OpaqueValue *value,
138+
uint32_t numExtraCases,
139+
const Metadata *enumType);
140+
141+
/// The unspecialized storeEnumTagSinglePayload value witness to be used by the
142+
/// VWTs for for specialized generic enums that are multi-payload.
143+
///
144+
/// Runtime availability: Swift 5.6
145+
SWIFT_RUNTIME_EXPORT
146+
void swift_storeMultiPayloadEnumTagSinglePayload(OpaqueValue *value,
147+
uint32_t index,
148+
uint32_t numExtraCases,
149+
const Metadata *enumType);
132150
}
133151

134152
#endif

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1738,6 +1738,29 @@ FUNCTION(AutoDiffAllocateSubcontext,
17381738
ARGS(RefCountedPtrTy, SizeTy),
17391739
ATTRS(NoUnwind, ArgMemOnly))
17401740

1741+
// SWIFT_RUNTIME_EXPORT
1742+
// unsigned swift_getMultiPayloadEnumTagSinglePayload(const OpaqueValue *value,
1743+
// uint32_t numExtraCases,
1744+
// const Metadata *enumType)
1745+
FUNCTION(GetMultiPayloadEnumTagSinglePayload,
1746+
swift_getMultiPayloadEnumTagSinglePayload, C_CC,
1747+
MultiPayloadEnumTagSinglePayloadAvailability,
1748+
RETURNS(Int32Ty),
1749+
ARGS(OpaquePtrTy, Int32Ty, TypeMetadataPtrTy),
1750+
ATTRS(NoUnwind))
1751+
1752+
// SWIFT_RUNTIME_EXPORT
1753+
// void swift_storeMultiPayloadEnumTagSinglePayload(OpaqueValue *value,
1754+
// uint32_t index,
1755+
// uint32_t numExtraCases,
1756+
// const Metadata *enumType);
1757+
FUNCTION(StoreMultiPayloadEnumTagSinglePayload,
1758+
swift_storeMultiPayloadEnumTagSinglePayload, C_CC,
1759+
MultiPayloadEnumTagSinglePayloadAvailability,
1760+
RETURNS(VoidTy),
1761+
ARGS(OpaquePtrTy, Int32Ty, Int32Ty, TypeMetadataPtrTy),
1762+
ATTRS(NoUnwind))
1763+
17411764
#undef RETURNS
17421765
#undef ARGS
17431766
#undef ATTRS

lib/AST/Availability.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,10 @@ AvailabilityContext ASTContext::getDifferentiationAvailability() {
334334
return getSwiftFutureAvailability();
335335
}
336336

337+
AvailabilityContext ASTContext::getMultiPayloadEnumTagSinglePayload() {
338+
return getSwift56Availability();
339+
}
340+
337341
AvailabilityContext ASTContext::getSwift52Availability() {
338342
auto target = LangOpts.Target;
339343

@@ -429,6 +433,9 @@ AvailabilityContext ASTContext::getSwift55Availability() {
429433
}
430434
}
431435

436+
AvailabilityContext ASTContext::getSwift56Availability() {
437+
return getSwiftFutureAvailability();
438+
}
432439

433440
AvailabilityContext ASTContext::getSwiftFutureAvailability() {
434441
auto target = LangOpts.Target;

lib/IRGen/GenValueWitness.cpp

Lines changed: 126 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include "IRGenDebugInfo.h"
4242
#include "IRGenFunction.h"
4343
#include "IRGenModule.h"
44+
#include "MetadataLayout.h"
4445
#include "StructLayout.h"
4546
#include "TypeInfo.h"
4647

@@ -815,15 +816,72 @@ static llvm::Constant *getMemCpyFunction(IRGenModule &IGM,
815816
});
816817
}
817818

819+
namespace {
820+
struct BoundGenericTypeCharacteristics {
821+
SILType concreteType;
822+
const TypeInfo *TI;
823+
FixedPacking packing;
824+
};
825+
826+
ValueWitnessFlags getValueWitnessFlags(const TypeInfo *TI, SILType concreteType,
827+
FixedPacking packing) {
828+
ValueWitnessFlags flags;
829+
830+
// If we locally know that the type has fixed layout, we can emit
831+
// meaningful flags for it.
832+
if (auto *fixedTI = dyn_cast<FixedTypeInfo>(TI)) {
833+
assert(packing == FixedPacking::OffsetZero ||
834+
packing == FixedPacking::Allocate);
835+
bool isInline = packing == FixedPacking::OffsetZero;
836+
bool isBitwiseTakable =
837+
fixedTI->isBitwiseTakable(ResilienceExpansion::Maximal);
838+
assert(isBitwiseTakable || !isInline);
839+
flags = flags.withAlignment(fixedTI->getFixedAlignment().getValue())
840+
.withPOD(fixedTI->isPOD(ResilienceExpansion::Maximal))
841+
.withInlineStorage(isInline)
842+
.withBitwiseTakable(isBitwiseTakable);
843+
} else {
844+
flags = flags.withIncomplete(true);
845+
}
846+
847+
if (concreteType.getEnumOrBoundGenericEnum())
848+
flags = flags.withEnumWitnesses(true);
849+
850+
return flags;
851+
}
852+
853+
unsigned getExtraInhabitantCount(const TypeInfo *TI, IRGenModule &IGM) {
854+
unsigned value = 0;
855+
if (auto *fixedTI = dyn_cast<FixedTypeInfo>(TI)) {
856+
value = fixedTI->getFixedExtraInhabitantCount(IGM);
857+
}
858+
return value;
859+
}
860+
861+
void addSize(ConstantStructBuilder &B, const TypeInfo *TI, IRGenModule &IGM) {
862+
if (auto staticSize = TI->getStaticSize(IGM))
863+
return B.add(staticSize);
864+
// Just fill in 0 here if the type can't be statically laid out.
865+
return B.addSize(Size(0));
866+
}
867+
868+
void addStride(ConstantStructBuilder &B, const TypeInfo *TI, IRGenModule &IGM) {
869+
if (auto value = TI->getStaticStride(IGM))
870+
return B.add(value);
871+
872+
// Just fill in null here if the type can't be statically laid out.
873+
return B.addSize(Size(0));
874+
}
875+
} // end anonymous namespace
876+
818877
/// Find a witness to the fact that a type is a value type.
819878
/// Always adds an i8*.
820-
static void addValueWitness(IRGenModule &IGM,
821-
ConstantStructBuilder &B,
822-
ValueWitness index,
823-
FixedPacking packing,
824-
CanType abstractType,
825-
SILType concreteType,
826-
const TypeInfo &concreteTI) {
879+
static void addValueWitness(IRGenModule &IGM, ConstantStructBuilder &B,
880+
ValueWitness index, FixedPacking packing,
881+
CanType abstractType, SILType concreteType,
882+
const TypeInfo &concreteTI,
883+
const Optional<BoundGenericTypeCharacteristics>
884+
boundGenericCharacteristics = llvm::None) {
827885
auto addFunction = [&](llvm::Constant *fn) {
828886
fn = llvm::ConstantExpr::getBitCast(fn, IGM.Int8PtrTy);
829887
B.addSignedPointer(fn, IGM.getOptions().PointerAuth.ValueWitnesses, index);
@@ -880,57 +938,51 @@ static void addValueWitness(IRGenModule &IGM,
880938
goto standard;
881939

882940
case ValueWitness::Size: {
883-
if (auto value = concreteTI.getStaticSize(IGM))
884-
return B.add(value);
885-
886-
// Just fill in 0 here if the type can't be statically laid out.
887-
return B.addSize(Size(0));
941+
if (boundGenericCharacteristics)
942+
return addSize(B, boundGenericCharacteristics->TI, IGM);
943+
return addSize(B, &concreteTI, IGM);
888944
}
889945

890946
case ValueWitness::Flags: {
891-
ValueWitnessFlags flags;
892-
893-
// If we locally know that the type has fixed layout, we can emit
894-
// meaningful flags for it.
895-
if (auto *fixedTI = dyn_cast<FixedTypeInfo>(&concreteTI)) {
896-
assert(packing == FixedPacking::OffsetZero ||
897-
packing == FixedPacking::Allocate);
898-
bool isInline = packing == FixedPacking::OffsetZero;
899-
bool isBitwiseTakable =
900-
fixedTI->isBitwiseTakable(ResilienceExpansion::Maximal);
901-
assert(isBitwiseTakable || !isInline);
902-
flags = flags.withAlignment(fixedTI->getFixedAlignment().getValue())
903-
.withPOD(fixedTI->isPOD(ResilienceExpansion::Maximal))
904-
.withInlineStorage(isInline)
905-
.withBitwiseTakable(isBitwiseTakable);
906-
} else {
907-
flags = flags.withIncomplete(true);
908-
}
909-
910-
if (concreteType.getEnumOrBoundGenericEnum())
911-
flags = flags.withEnumWitnesses(true);
912-
913-
return B.addInt32(flags.getOpaqueValue());
947+
if (boundGenericCharacteristics)
948+
return B.addInt32(
949+
getValueWitnessFlags(boundGenericCharacteristics->TI,
950+
boundGenericCharacteristics->concreteType,
951+
boundGenericCharacteristics->packing)
952+
.getOpaqueValue());
953+
return B.addInt32(getValueWitnessFlags(&concreteTI, concreteType, packing)
954+
.getOpaqueValue());
914955
}
915956

916957
case ValueWitness::ExtraInhabitantCount: {
917-
unsigned value = 0;
918-
if (auto *fixedTI = dyn_cast<FixedTypeInfo>(&concreteTI)) {
919-
value = fixedTI->getFixedExtraInhabitantCount(IGM);
920-
}
921-
return B.addInt32(value);
958+
if (boundGenericCharacteristics)
959+
return B.addInt32(
960+
getExtraInhabitantCount(boundGenericCharacteristics->TI, IGM));
961+
return B.addInt32(getExtraInhabitantCount(&concreteTI, IGM));
922962
}
923963

924964
case ValueWitness::Stride: {
925-
if (auto value = concreteTI.getStaticStride(IGM))
926-
return B.add(value);
927-
928-
// Just fill in null here if the type can't be statically laid out.
929-
return B.addSize(Size(0));
965+
if (boundGenericCharacteristics)
966+
return addStride(B, boundGenericCharacteristics->TI, IGM);
967+
return addStride(B, &concreteTI, IGM);
930968
}
931969

932-
case ValueWitness::GetEnumTagSinglePayload:
970+
case ValueWitness::GetEnumTagSinglePayload: {
971+
if (boundGenericCharacteristics)
972+
if (auto *enumDecl = boundGenericCharacteristics->concreteType
973+
.getEnumOrBoundGenericEnum())
974+
if (IGM.getMetadataLayout(enumDecl).hasPayloadSizeOffset())
975+
return B.add(llvm::ConstantExpr::getBitCast(
976+
IGM.getGetMultiPayloadEnumTagSinglePayloadFn(), IGM.Int8PtrTy));
977+
goto standard;
978+
}
933979
case ValueWitness::StoreEnumTagSinglePayload: {
980+
if (boundGenericCharacteristics)
981+
if (auto *enumDecl = boundGenericCharacteristics->concreteType
982+
.getEnumOrBoundGenericEnum())
983+
if (IGM.getMetadataLayout(enumDecl).hasPayloadSizeOffset())
984+
return B.add(llvm::ConstantExpr::getBitCast(
985+
IGM.getStoreMultiPayloadEnumTagSinglePayloadFn(), IGM.Int8PtrTy));
934986
goto standard;
935987
}
936988

@@ -949,7 +1001,7 @@ static void addValueWitness(IRGenModule &IGM,
9491001
buildValueWitnessFunction(IGM, fn, index, packing, abstractType,
9501002
concreteType, concreteTI);
9511003
addFunction(fn);
952-
}
1004+
}
9531005

9541006
static bool shouldAddEnumWitnesses(CanType abstractType) {
9551007
// Needs to handle UnboundGenericType.
@@ -964,22 +1016,21 @@ static llvm::StructType *getValueWitnessTableType(IRGenModule &IGM,
9641016
}
9651017

9661018
/// Collect the value witnesses for a particular type.
967-
static void addValueWitnesses(IRGenModule &IGM,
968-
ConstantStructBuilder &B,
969-
FixedPacking packing,
970-
CanType abstractType,
971-
SILType concreteType,
972-
const TypeInfo &concreteTI) {
1019+
static void addValueWitnesses(IRGenModule &IGM, ConstantStructBuilder &B,
1020+
FixedPacking packing, CanType abstractType,
1021+
SILType concreteType, const TypeInfo &concreteTI,
1022+
const Optional<BoundGenericTypeCharacteristics>
1023+
boundGenericCharacteristics = llvm::None) {
9731024
for (unsigned i = 0; i != NumRequiredValueWitnesses; ++i) {
974-
addValueWitness(IGM, B, ValueWitness(i), packing,
975-
abstractType, concreteType, concreteTI);
1025+
addValueWitness(IGM, B, ValueWitness(i), packing, abstractType,
1026+
concreteType, concreteTI, boundGenericCharacteristics);
9761027
}
9771028
if (shouldAddEnumWitnesses(abstractType)) {
9781029
for (auto i = unsigned(ValueWitness::First_EnumValueWitness);
9791030
i <= unsigned(ValueWitness::Last_EnumValueWitness);
9801031
++i) {
981-
addValueWitness(IGM, B, ValueWitness(i), packing,
982-
abstractType, concreteType, concreteTI);
1032+
addValueWitness(IGM, B, ValueWitness(i), packing, abstractType,
1033+
concreteType, concreteTI, boundGenericCharacteristics);
9831034
}
9841035
}
9851036
}
@@ -995,6 +1046,19 @@ static void addValueWitnessesForAbstractType(IRGenModule &IGM,
9951046
ConstantStructBuilder &B,
9961047
CanType abstractType,
9971048
bool &canBeConstant) {
1049+
Optional<BoundGenericTypeCharacteristics> boundGenericCharacteristics;
1050+
if (auto boundGenericType = dyn_cast<BoundGenericType>(abstractType)) {
1051+
CanType concreteFormalType = getFormalTypeInContext(abstractType);
1052+
1053+
auto concreteLoweredType = IGM.getLoweredType(concreteFormalType);
1054+
const auto *boundConcreteTI = &IGM.getTypeInfo(concreteLoweredType);
1055+
auto packing = boundConcreteTI->getFixedPacking(IGM);
1056+
boundGenericCharacteristics = {concreteLoweredType, boundConcreteTI,
1057+
packing};
1058+
1059+
abstractType =
1060+
boundGenericType->getDecl()->getDeclaredType()->getCanonicalType();
1061+
}
9981062
CanType concreteFormalType = getFormalTypeInContext(abstractType);
9991063

10001064
auto concreteLoweredType = IGM.getLoweredType(concreteFormalType);
@@ -1003,10 +1067,12 @@ static void addValueWitnessesForAbstractType(IRGenModule &IGM,
10031067

10041068
// For now, assume that we never have any interest in dynamically
10051069
// changing the value witnesses for something that's fixed-layout.
1006-
canBeConstant = concreteTI.isFixedSize();
1070+
canBeConstant = boundGenericCharacteristics
1071+
? boundGenericCharacteristics->TI->isFixedSize()
1072+
: concreteTI.isFixedSize();
10071073

1008-
addValueWitnesses(IGM, B, packing, abstractType,
1009-
concreteLoweredType, concreteTI);
1074+
addValueWitnesses(IGM, B, packing, abstractType, concreteLoweredType,
1075+
concreteTI, boundGenericCharacteristics);
10101076
}
10111077

10121078
static constexpr uint64_t sizeAndAlignment(Size size, Alignment alignment) {

lib/IRGen/IRGenModule.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -793,6 +793,15 @@ namespace RuntimeConstants {
793793
}
794794
return RuntimeAvailability::AlwaysAvailable;
795795
}
796+
797+
RuntimeAvailability
798+
MultiPayloadEnumTagSinglePayloadAvailability(ASTContext &context) {
799+
auto featureAvailability = context.getMultiPayloadEnumTagSinglePayload();
800+
if (!isDeploymentAvailabilityContainedIn(context, featureAvailability)) {
801+
return RuntimeAvailability::ConditionallyAvailable;
802+
}
803+
return RuntimeAvailability::AlwaysAvailable;
804+
}
796805
} // namespace RuntimeConstants
797806

798807
// We don't use enough attributes to justify generalizing the
@@ -1679,7 +1688,7 @@ bool IRGenModule::useDllStorage() { return ::useDllStorage(Triple); }
16791688

16801689
bool IRGenModule::shouldPrespecializeGenericMetadata() {
16811690
auto canPrespecializeTarget =
1682-
(Triple.isOSDarwin() || Triple.isTvOS() ||
1691+
(Triple.isOSDarwin() ||
16831692
(Triple.isOSLinux() && !(Triple.isARM() && Triple.isArch32Bit())));
16841693
if (canPrespecializeTarget && isStandardLibrary()) {
16851694
return true;

0 commit comments

Comments
 (0)