Skip to content

Commit b798936

Browse files
authored
Merge pull request swiftlang#20449 from DougGregor/get-assoc-conformance-witness-runtime
[ABI] Retrieve all associated conformances via a runtime function.
2 parents e7dd1c1 + f7b2522 commit b798936

File tree

9 files changed

+78
-54
lines changed

9 files changed

+78
-54
lines changed

include/swift/Runtime/Metadata.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,24 @@ MetadataResponse swift_getAssociatedTypeWitness(
393393
const ProtocolRequirement *reqBase,
394394
const ProtocolRequirement *assocType);
395395

396+
/// Retrieve an associated conformance witness table from the given witness
397+
/// table.
398+
///
399+
/// \param wtable The witness table.
400+
/// \param conformingType Metadata for the conforming type.
401+
/// \param assocType Metadata for the sasociated type.
402+
/// \param reqBase "Base" requirement used to compute the witness index
403+
/// \param assocConformance Associated conformance descriptor.
404+
///
405+
/// \returns corresponding witness table.
406+
SWIFT_RUNTIME_EXPORT SWIFT_CC(swift)
407+
const WitnessTable *swift_getAssociatedConformanceWitness(
408+
WitnessTable *wtable,
409+
const Metadata *conformingType,
410+
const Metadata *assocType,
411+
const ProtocolRequirement *reqBase,
412+
const ProtocolRequirement *assocConformance);
413+
396414
/// \brief Fetch a uniqued metadata for a function type.
397415
SWIFT_RUNTIME_EXPORT
398416
const FunctionTypeMetadata *

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,23 @@ FUNCTION(GetAssociatedTypeWitness, swift_getAssociatedTypeWitness, SwiftCC,
650650
ProtocolRequirementStructTy->getPointerTo()),
651651
ATTRS(NoUnwind, ReadNone))
652652

653+
// SWIFT_RUNTIME_EXPORT SWIFT_CC(swift)
654+
// const WitnessTable *swift_getAssociatedConformanceWitness(
655+
// WitnessTable *wtable,
656+
// const Metadata *conformingType,
657+
// const Metadata *assocType,
658+
// const ProtocolRequirement *reqBase,
659+
// const ProtocolRequirement *assocConformance);
660+
FUNCTION(GetAssociatedConformanceWitness,
661+
swift_getAssociatedConformanceWitness, SwiftCC,
662+
RETURNS(WitnessTablePtrTy),
663+
ARGS(WitnessTablePtrTy,
664+
TypeMetadataPtrTy,
665+
TypeMetadataPtrTy,
666+
ProtocolRequirementStructTy->getPointerTo(),
667+
ProtocolRequirementStructTy->getPointerTo()),
668+
ATTRS(NoUnwind, ReadNone))
669+
653670
// Metadata *swift_getMetatypeMetadata(Metadata *instanceTy);
654671
FUNCTION(GetMetatypeMetadata, swift_getMetatypeMetadata, C_CC,
655672
RETURNS(TypeMetadataPtrTy),

lib/IRGen/GenProto.cpp

Lines changed: 11 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2505,40 +2505,17 @@ emitAssociatedTypeWitnessTableRef(IRGenFunction &IGF,
25052505
AssociatedConformance conformance,
25062506
llvm::Value *associatedTypeMetadata) {
25072507
auto sourceProtocol = conformance.getSourceProtocol();
2508-
llvm::Value *witness;
2509-
if (IGF.IGM.isResilient(sourceProtocol, ResilienceExpansion::Maximal)) {
2510-
// For resilient protocols, use the associated conformance descriptor to
2511-
// determine the index.
2512-
auto assocConformanceDescriptor =
2513-
IGF.IGM.getAddrOfAssociatedConformanceDescriptor(conformance);
2514-
2515-
auto index =
2516-
computeResilientWitnessTableIndex(IGF, sourceProtocol,
2517-
assocConformanceDescriptor);
2518-
2519-
witness = emitInvariantLoadOfOpaqueWitness(IGF, wtable, index);
2520-
} else {
2521-
// For non-resilient protocols, the index is a constant.
2522-
auto &pi = IGF.IGM.getProtocolInfo(sourceProtocol,
2523-
ProtocolInfoKind::RequirementSignature);
2524-
2525-
auto index = pi.getAssociatedConformanceIndex(conformance);
2526-
witness = emitInvariantLoadOfOpaqueWitness(IGF, wtable,
2527-
index.forProtocolWitnessTable());
2528-
}
2529-
2530-
// Cast the witness to the appropriate function type.
2531-
auto sig = IGF.IGM.getAssociatedTypeWitnessTableAccessFunctionSignature();
2532-
auto witnessTy = sig.getType();
2533-
witness = IGF.Builder.CreateBitCast(witness, witnessTy->getPointerTo());
2534-
2535-
FunctionPointer witnessFnPtr(witness, sig);
2536-
2537-
// Call the accessor.
2538-
auto call = IGF.Builder.CreateCall(witnessFnPtr,
2539-
{ associatedTypeMetadata, parentMetadata, wtable });
2540-
2541-
return call;
2508+
auto assocConformanceDescriptor =
2509+
IGF.IGM.getAddrOfAssociatedConformanceDescriptor(conformance);
2510+
auto baseDescriptor =
2511+
IGF.IGM.getAddrOfProtocolRequirementsBaseDescriptor(sourceProtocol);
2512+
2513+
return IGF.Builder.CreateCall(IGF.IGM.getGetAssociatedConformanceWitnessFn(),
2514+
{
2515+
wtable, parentMetadata,
2516+
associatedTypeMetadata,
2517+
baseDescriptor, assocConformanceDescriptor
2518+
});
25422519
}
25432520

25442521
/// Drill down on a single stage of component.

stdlib/public/runtime/Metadata.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4151,6 +4151,32 @@ swift::swift_getAssociatedTypeWitness(MetadataRequest request,
41514151
return response;
41524152
}
41534153

4154+
const WitnessTable *swift::swift_getAssociatedConformanceWitness(
4155+
WitnessTable *wtable,
4156+
const Metadata *conformingType,
4157+
const Metadata *assocType,
4158+
const ProtocolRequirement *reqBase,
4159+
const ProtocolRequirement *assocConformance) {
4160+
#ifndef NDEBUG
4161+
{
4162+
const ProtocolConformanceDescriptor *conformance = wtable->Description;
4163+
const ProtocolDescriptor *protocol = conformance->getProtocol();
4164+
auto requirements = protocol->getRequirements();
4165+
assert(assocConformance >= requirements.begin() &&
4166+
assocConformance < requirements.end());
4167+
assert(reqBase == requirements.data() - WitnessTableFirstRequirementOffset);
4168+
assert(assocConformance->Flags.getKind() ==
4169+
ProtocolRequirementFlags::Kind::AssociatedConformanceAccessFunction);
4170+
}
4171+
#endif
4172+
4173+
// Call the access function.
4174+
unsigned witnessIndex = assocConformance - reqBase;
4175+
auto witness =
4176+
((AssociatedWitnessTableAccessFunction* const *)wtable)[witnessIndex];
4177+
return witness(assocType, conformingType, wtable);
4178+
}
4179+
41544180
/***************************************************************************/
41554181
/*** Recursive metadata dependencies ***************************************/
41564182
/***************************************************************************/

test/IRGen/associated_types.swift

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -80,19 +80,13 @@ func testFastRuncible<T: Runcible, U: FastRuncible>(_ t: T, u: U)
8080
// CHECK-NEXT: store %swift.type*
8181
// 2. Get the witness table for U.RuncerType.Runcee : Speedy
8282
// 2a. Get the protocol witness table for U.RuncerType : FastRuncer.
83-
// CHECK: [[T0:%.*]] = getelementptr inbounds i8*, i8** %U.FastRuncible, i32 1
84-
// CHECK-NEXT: [[T1:%.*]] = load i8*, i8** [[T0]],
85-
// CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to i8** (%swift.type*, %swift.type*, i8**)*
86-
// CHECK-NEXT: %T.RuncerType.FastRuncer = call swiftcc i8** [[T2]](%swift.type* %T.RuncerType, %swift.type* %U, i8** %U.FastRuncible)
83+
// CHECK-NEXT: %T.RuncerType.FastRuncer = call swiftcc i8** @swift_getAssociatedConformanceWitness(i8** %U.FastRuncible, %swift.type* %U, %swift.type* %T.RuncerType
8784
// 1c. Get the type metadata for U.RuncerType.Runcee.
8885
// CHECK-NEXT: [[T2:%.*]] = call swiftcc %swift.metadata_response @swift_getAssociatedTypeWitness([[INT]] 0, i8** %T.RuncerType.FastRuncer, %swift.type* %T.RuncerType, {{.*}}, %swift.protocol_requirement* getelementptr inbounds (<{{.*}}>, <{{.*}}>* @"$s16associated_types10FastRuncerMp", i32 0, i32 10))
8986
// CHECK-NEXT: %T.RuncerType.Runcee = extractvalue %swift.metadata_response [[T2]], 0
9087
// CHECK-NEXT: store %swift.type*
9188
// 2b. Get the witness table for U.RuncerType.Runcee : Speedy.
92-
// CHECK: [[T0:%.*]] = getelementptr inbounds i8*, i8** %T.RuncerType.FastRuncer, i32 1
93-
// CHECK-NEXT: [[T1:%.*]] = load i8*, i8** [[T0]],
94-
// CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to i8** (%swift.type*, %swift.type*, i8**)*
95-
// CHECK-NEXT: %T.RuncerType.Runcee.Speedy = call swiftcc i8** [[T2]](%swift.type* %T.RuncerType.Runcee, %swift.type* %T.RuncerType, i8** %T.RuncerType.FastRuncer)
89+
// CHECK-NEXT: %T.RuncerType.Runcee.Speedy = call swiftcc i8** @swift_getAssociatedConformanceWitness(i8** %T.RuncerType.FastRuncer, %swift.type* %T.RuncerType, %swift.type* %T.RuncerType.Runcee
9690
// 3. Perform the actual call.
9791
// CHECK-NEXT: [[T0_GEP:%.*]] = getelementptr inbounds i8*, i8** %T.RuncerType.Runcee.Speedy, i32 1
9892
// CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[T0_GEP]]

test/IRGen/conformance_access_path.swift

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,7 @@ extension Validatable {
1818
// CHECK: [[S_AS_VALIDATION_SUITE_GEP:%[0-9]+]] = getelementptr inbounds i8*, i8** %S.ValidationSuite, i32 1
1919
// CHECK: [[S_AS_VALIDATION_SUITE:%[0-9]+]] = load i8*, i8** [[S_AS_VALIDATION_SUITE_GEP]]
2020
// CHECK-NEXT: [[S_VALIDATOR_BASE:%.*]] = bitcast i8* [[S_AS_VALIDATION_SUITE]] to i8**
21-
// CHECK-NEXT: [[S_VALIDATABLE_ADDR:%[0-9]+]] = getelementptr inbounds i8*, i8** [[S_VALIDATOR_BASE]], i32 1
22-
// CHECK-NEXT: [[S_VALIDATABLE_FN_RAW:%[0-9]+]] = load i8*, i8** [[S_VALIDATABLE_ADDR]]
23-
// CHECK-NEXT: [[S_VALIDATABLE_FN:%[0-9]+]] = bitcast i8* [[S_VALIDATABLE_FN_RAW]] to i8** (%swift.type*, %swift.type*, i8**)*
24-
// CHECK-NEXT: call swiftcc i8** [[S_VALIDATABLE_FN]](%swift.type* %Self, %swift.type* %S, i8** %S.Validator)
21+
// CHECK-NEXT: call swiftcc i8** @swift_getAssociatedConformanceWitness(i8** %S.Validator, %swift.type* %S, %swift.type* %Self,
2522
tested()
2623
}
2724
}

test/IRGen/generic_structs.sil

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -259,11 +259,7 @@ struct GenericLayoutWithAssocType<T: ParentHasAssociatedType> {
259259
// CHECK: [[T4:%.*]] = call swiftcc %swift.metadata_response @swift_getAssociatedTypeWitness(i64 0, i8** %T.HasAssociatedType, %swift.type* %T, %swift.protocol_requirement* @"$s15generic_structs17HasAssociatedTypeTL", %swift.protocol_requirement* @"$s5Assoc15generic_structs17HasAssociatedTypePTl")
260260

261261
// CHECK: %T.Assoc = extractvalue %swift.metadata_response [[T4]], 0
262-
263-
// CHECK: [[T0:%.*]] = getelementptr inbounds i8*, i8** %T.ParentHasAssociatedType, i32 2
264-
// CHECK: [[T1:%.*]] = load i8*, i8** [[T0]],
265-
// CHECK: [[T2:%.*]] = bitcast i8* [[T1]] to i8** (%swift.type*, %swift.type*, i8**)*
266-
// CHECK: %T.Assoc.HasAssociatedType = call swiftcc i8** [[T2]](%swift.type* %T.Assoc, %swift.type* %T, i8** %T.ParentHasAssociatedType)
262+
// CHECK: %T.Assoc.HasAssociatedType = call swiftcc i8** @swift_getAssociatedConformanceWitness(i8** %T.ParentHasAssociatedType, %swift.type* %T, %swift.type* %T.Assoc,
267263

268264
// CHECK: [[T2:%.*]] = call swiftcc %swift.metadata_response @swift_getAssociatedTypeWitness(i64 0, i8** %T.Assoc.HasAssociatedType, %swift.type* %T.Assoc, %swift.protocol_requirement* @"$s15generic_structs17HasAssociatedTypeTL", %swift.protocol_requirement* @"$s5Assoc15generic_structs17HasAssociatedTypePTl")
269265
// CHECK: %T.Assoc.Assoc = extractvalue %swift.metadata_response [[T2]], 0

test/IRGen/protocol_resilience_descriptors.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@ func useOtherResilientProtocol<T: OtherResilientProtocol>(_: T.Type) { }
9090

9191
// CHECK-USAGE: define{{( dllexport)?}}{{( protected)?}} swiftcc void @"$s31protocol_resilience_descriptors23extractAssocConformanceyyx010resilient_A0012ProtocolWithE12TypeDefaultsRzlF"
9292
public func extractAssocConformance<T: ProtocolWithAssocTypeDefaults>(_: T) {
93-
// CHECK-USAGE: [[WITNESS_ADDR:%.*]] = getelementptr inbounds i8*, i8** %T.ProtocolWithAssocTypeDefaults, [[INT]] udiv ([[INT]] sub ([[INT]] ptrtoint (%swift.protocol_requirement* @"$s18resilient_protocol29ProtocolWithAssocTypeDefaultsP2T2AC_AA014OtherResilientC0Tn" to [[INT]]), [[INT]] ptrtoint (%swift.protocol_requirement* @"$s18resilient_protocol29ProtocolWithAssocTypeDefaultsTL" to [[INT]])), [[INT]] 8)
94-
// CHECK-USAGE: load i8*, i8** [[WITNESS_ADDR]]
93+
// CHECK-USAGE: swift_getAssociatedConformanceWitness
9594
useOtherResilientProtocol(T.T2.self)
9695
}

test/Inputs/conditional_conformance_with_assoc.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,6 @@ extension X: Sub where T: Sub, T.S == T {
268268
// CHECK: [[XT_TYPE:%.*]] = bitcast %swift.type* %"X<T>" to %swift.type**
269269
// CHECK: [[ADDR:%.*]] = getelementptr inbounds %swift.type*, %swift.type** [[XT_TYPE]], i64 2
270270
// CHECK: [[T:%.*]] = load %swift.type*, %swift.type** [[ADDR]]
271-
// CHECK: %T.Base = call swiftcc i8** {{.*}}(%swift.type* %T, %swift.type* %T, i8** {{.*}})
271+
// CHECK: %T.Base = call swiftcc i8** @swift_getAssociatedConformanceWitness(i8** {{.*}}, %swift.type* %T, %swift.type* %T
272272
// CHECK: ret void
273273
// CHECK: }

0 commit comments

Comments
 (0)