Skip to content

Commit f7b2522

Browse files
committed
[ABI] Retrieve all associated conformances via a runtime function.
Introduce a new runtime entry point, swift_getAssociatedConformanceWitness(), which extracts an associated conformance witness from a witness table. Teach IRGen to use this entry point rather than loading the witness from the witness table and calling it directly. There’s no advantage to doing this now, but it is staging for changing the representation of associated conformances in witness tables.
1 parent 5758cdc commit f7b2522

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)