Skip to content

Commit

Permalink
[ABI] Pass requirement base descriptor to swift_getAssociatedTypeWitn…
Browse files Browse the repository at this point in the history
…ess().

Have clients pass the requirement base descriptor to
swift_getAssociatedTypeWitness(), so that the witness index is just one
subtraction away, avoiding several dependent loads (witness table ->
conformance descriptor -> protocol descriptor -> requirement offset)
in the hot path.
  • Loading branch information
DougGregor committed Oct 11, 2018
1 parent 1fc57ad commit aba018c
Show file tree
Hide file tree
Showing 11 changed files with 47 additions and 18 deletions.
6 changes: 6 additions & 0 deletions include/swift/ABI/Metadata.h
Expand Up @@ -2943,6 +2943,12 @@ struct TargetProtocolDescriptor final
NumRequirements};
}

/// Retrieve the requirement base descriptor address.
ConstTargetPointer<Runtime, TargetProtocolRequirement<Runtime>>
getRequirementBaseDescriptor() const {
return getRequirements().data() - WitnessTableFirstRequirementOffset;
}

#ifndef NDEBUG
LLVM_ATTRIBUTE_DEPRECATED(void dump() const LLVM_ATTRIBUTE_USED,
"only for use in the debugger");
Expand Down
2 changes: 2 additions & 0 deletions include/swift/Runtime/Metadata.h
Expand Up @@ -414,6 +414,7 @@ swift_getGenericWitnessTable(GenericWitnessTable *genericTable,
///
/// \param wtable The witness table.
/// \param conformingType Metadata for the conforming type.
/// \param reqBase "Base" requirement used to compute the witness index
/// \param assocType Associated type descriptor.
///
/// \returns metadata for the associated type witness.
Expand All @@ -422,6 +423,7 @@ MetadataResponse swift_getAssociatedTypeWitness(
MetadataRequest request,
WitnessTable *wtable,
const Metadata *conformingType,
const ProtocolRequirement *reqBase,
const ProtocolRequirement *assocType);

/// \brief Fetch a uniqued metadata for a function type.
Expand Down
2 changes: 2 additions & 0 deletions include/swift/Runtime/RuntimeFunctions.def
Expand Up @@ -649,12 +649,14 @@ FUNCTION(GetGenericWitnessTable, swift_getGenericWitnessTable, C_CC,
// MetadataRequest request,
// WitnessTable *wtable,
// const Metadata *conformingType,
// ProtocolRequirement *reqBase,
// ProtocolRequirement *assocType);
FUNCTION(GetAssociatedTypeWitness, swift_getAssociatedTypeWitness, C_CC,
RETURNS(TypeMetadataResponseTy),
ARGS(SizeTy,
WitnessTablePtrTy,
TypeMetadataPtrTy,
ProtocolRequirementStructTy->getPointerTo(),
ProtocolRequirementStructTy->getPointerTo()),
ATTRS(NoUnwind, ReadNone))

Expand Down
6 changes: 6 additions & 0 deletions lib/IRGen/GenProto.cpp
Expand Up @@ -3554,6 +3554,11 @@ irgen::emitAssociatedTypeMetadataRef(IRGenFunction &IGF,
DynamicMetadataRequest request) {
auto &IGM = IGF.IGM;

// Extract the requirements base descriptor.
auto reqBaseDescriptor =
IGM.getAddrOfProtocolRequirementsBaseDescriptor(
associatedType.getSourceProtocol());

// Extract the associated type descriptor.
auto assocTypeDescriptor =
IGM.getAddrOfAssociatedTypeDescriptor(associatedType.getAssociation());
Expand All @@ -3563,6 +3568,7 @@ irgen::emitAssociatedTypeMetadataRef(IRGenFunction &IGF,
{ request.get(IGF),
wtable,
parentMetadata,
reqBaseDescriptor,
assocTypeDescriptor });
call->setDoesNotThrow();
call->setDoesNotAccessMemory();
Expand Down
6 changes: 4 additions & 2 deletions stdlib/public/runtime/Casting.cpp
Expand Up @@ -2550,8 +2550,10 @@ MetadataResponse _getBridgedObjectiveCType(
assert(assocTypeRequirement->Flags.getKind() ==
ProtocolRequirementFlags::Kind::AssociatedTypeAccessFunction);
auto mutableWTable = (WitnessTable *)wtable;
return swift_getAssociatedTypeWitness(request, mutableWTable, conformingType,
assocTypeRequirement);
return swift_getAssociatedTypeWitness(
request, mutableWTable, conformingType,
protocol->getRequirementBaseDescriptor(),
assocTypeRequirement);
}

} // unnamed namespace
Expand Down
27 changes: 17 additions & 10 deletions stdlib/public/runtime/Metadata.cpp
Expand Up @@ -3998,21 +3998,24 @@ MetadataResponse
swift::swift_getAssociatedTypeWitness(MetadataRequest request,
WitnessTable *wtable,
const Metadata *conformingType,
const ProtocolRequirement *reqBase,
const ProtocolRequirement *assocType) {
const ProtocolConformanceDescriptor *conformance = wtable->Description;
const ProtocolDescriptor *protocol = conformance->getProtocol();

auto requirements = protocol->getRequirements();
assert(assocType >= requirements.begin() &&
assocType < requirements.end());
const auto &req = *assocType;
(void)req;
assert(req.Flags.getKind() ==
#ifndef NDEBUG
{
const ProtocolConformanceDescriptor *conformance = wtable->Description;
const ProtocolDescriptor *protocol = conformance->getProtocol();
auto requirements = protocol->getRequirements();
assert(assocType >= requirements.begin() &&
assocType < requirements.end());
assert(reqBase == requirements.data() - WitnessTableFirstRequirementOffset);
assert(assocType->Flags.getKind() ==
ProtocolRequirementFlags::Kind::AssociatedTypeAccessFunction);
}
#endif

// If the low bit of the witness is clear, it's already a metadata pointer.
unsigned witnessIndex = (assocType - requirements.begin()) +
WitnessTableFirstRequirementOffset;
unsigned witnessIndex = assocType - reqBase;
auto witness = ((const void* const *)wtable)[witnessIndex];
if (LLVM_LIKELY((uintptr_t(witness) &
ProtocolRequirementFlags::AssociatedTypeMangledNameBit) == 0)) {
Expand All @@ -4034,6 +4037,10 @@ swift::swift_getAssociatedTypeWitness(MetadataRequest request,
++mangledNameBase;
}

// Dig out the protocol.
const ProtocolConformanceDescriptor *conformance = wtable->Description;
const ProtocolDescriptor *protocol = conformance->getProtocol();

// Extract the mangled name itself.
StringRef mangledName =
Demangle::makeSymbolicMangledNameStringRef(mangledNameBase);
Expand Down
1 change: 1 addition & 0 deletions stdlib/public/runtime/MetadataLookup.cpp
Expand Up @@ -1200,6 +1200,7 @@ swift::_getTypeByMangledName(StringRef typeName,
MetadataState::Abstract,
const_cast<WitnessTable *>(witnessTable),
base,
protocol->getRequirementBaseDescriptor(),
*assocTypeReq).Value;
});

Expand Down
5 changes: 4 additions & 1 deletion stdlib/public/runtime/ProtocolConformance.cpp
Expand Up @@ -671,7 +671,10 @@ static const Metadata *resolveGenericParamRef(
current = swift_getAssociatedTypeWitness(
MetadataState::Abstract,
const_cast<WitnessTable *>(witnessTable),
current, assocTypeReq).Value;
current,
assocTypeRef.Protocol
->getRequirementBaseDescriptor(),
assocTypeReq).Value;
if (!current) return nullptr;
}

Expand Down
4 changes: 2 additions & 2 deletions test/IRGen/associated_types.swift
Expand Up @@ -75,7 +75,7 @@ func testFastRuncible<T: Runcible, U: FastRuncible>(_ t: T, u: U)
// 1. Get the type metadata for U.RuncerType.Runcee.
// 1a. Get the type metadata for U.RuncerType.
// Note that we actually look things up in T, which is going to prove unfortunate.
// CHECK: [[T2:%.*]] = call %swift.metadata_response @swift_getAssociatedTypeWitness([[INT]] 0, i8** %T.Runcible, %swift.type* %T, %swift.protocol_requirement* getelementptr inbounds (<{{.*}}>, <{{.*}}>* @"$s16associated_types8RuncibleMp", i32 0, i32 14)) [[NOUNWIND_READNONE:#.*]]
// CHECK: [[T2:%.*]] = call %swift.metadata_response @swift_getAssociatedTypeWitness([[INT]] 0, i8** %T.Runcible, %swift.type* %T, %swift.protocol_requirement* getelementptr{{.*}}i32 12), i32 -1), %swift.protocol_requirement* getelementptr inbounds (<{{.*}}>, <{{.*}}>* @"$s16associated_types8RuncibleMp", i32 0, i32 14)) [[NOUNWIND_READNONE:#.*]]
// CHECK-NEXT: %T.RuncerType = extractvalue %swift.metadata_response [[T2]], 0
// CHECK-NEXT: store %swift.type*
// 2. Get the witness table for U.RuncerType.Runcee : Speedy
Expand All @@ -85,7 +85,7 @@ func testFastRuncible<T: Runcible, U: FastRuncible>(_ t: T, u: U)
// CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to i8** (%swift.type*, %swift.type*, i8**)*
// CHECK-NEXT: %T.RuncerType.FastRuncer = call swiftcc i8** [[T2]](%swift.type* %T.RuncerType, %swift.type* %U, i8** %U.FastRuncible)
// 1c. Get the type metadata for U.RuncerType.Runcee.
// CHECK-NEXT: [[T2:%.*]] = call %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))
// CHECK-NEXT: [[T2:%.*]] = call %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))
// CHECK-NEXT: %T.RuncerType.Runcee = extractvalue %swift.metadata_response [[T2]], 0
// CHECK-NEXT: store %swift.type*
// 2b. Get the witness table for U.RuncerType.Runcee : Speedy.
Expand Down
4 changes: 2 additions & 2 deletions test/IRGen/generic_structs.sil
Expand Up @@ -256,7 +256,7 @@ struct GenericLayoutWithAssocType<T: ParentHasAssociatedType> {
// CHECK: [[T0_GEP:%.*]] = getelementptr inbounds i8*, i8** %T.ParentHasAssociatedType, i32 1
// CHECK: [[T0:%.*]] = load i8*, i8** [[T0_GEP]]
// CHECK: [[T1:%.*]] = bitcast i8* [[T0]] to i8**
// CHECK: [[T4:%.*]] = call %swift.metadata_response @swift_getAssociatedTypeWitness(i64 0, i8** %T.HasAssociatedType, %swift.type* %T, %swift.protocol_requirement* @"$s5Assoc15generic_structs17HasAssociatedTypePTl")
// CHECK: [[T4:%.*]] = call %swift.metadata_response @swift_getAssociatedTypeWitness(i64 0, i8** %T.HasAssociatedType, %swift.type* %T, %swift.protocol_requirement* @"$s15generic_structs17HasAssociatedTypeTL", %swift.protocol_requirement* @"$s5Assoc15generic_structs17HasAssociatedTypePTl")

// CHECK: %T.Assoc = extractvalue %swift.metadata_response [[T4]], 0

Expand All @@ -265,5 +265,5 @@ struct GenericLayoutWithAssocType<T: ParentHasAssociatedType> {
// CHECK: [[T2:%.*]] = bitcast i8* [[T1]] to i8** (%swift.type*, %swift.type*, i8**)*
// CHECK: %T.Assoc.HasAssociatedType = call swiftcc i8** [[T2]](%swift.type* %T.Assoc, %swift.type* %T, i8** %T.ParentHasAssociatedType)

// CHECK: [[T2:%.*]] = call %swift.metadata_response @swift_getAssociatedTypeWitness(i64 0, i8** %T.Assoc.HasAssociatedType, %swift.type* %T.Assoc, %swift.protocol_requirement* @"$s5Assoc15generic_structs17HasAssociatedTypePTl")
// CHECK: [[T2:%.*]] = call %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")
// CHECK: %T.Assoc.Assoc = extractvalue %swift.metadata_response [[T2]], 0
2 changes: 1 addition & 1 deletion test/IRGen/protocol_resilience_descriptors.swift
Expand Up @@ -82,7 +82,7 @@ where Element: ProtocolWithRequirements, Element.T == Y {

// CHECK-USAGE: define{{( dllexport)?}}{{( protected)?}} swiftcc %swift.type* @"$s31protocol_resilience_descriptors17assocTypeMetadatay1TQzmxm010resilient_A024ProtocolWithRequirementsRzlF"(%swift.type*, %swift.type* [[PWD:%.*]], i8** [[WTABLE:%.*]])
public func assocTypeMetadata<PWR: ProtocolWithRequirements>(_: PWR.Type) -> PWR.T.Type {
// CHECK-USAGE: call %swift.metadata_response @swift_getAssociatedTypeWitness([[INT]] 0, i8** %PWR.ProtocolWithRequirements, %swift.type* %PWR, %swift.protocol_requirement* @"$s1T18resilient_protocol24ProtocolWithRequirementsPTl")
// CHECK-USAGE: call %swift.metadata_response @swift_getAssociatedTypeWitness([[INT]] 0, i8** %PWR.ProtocolWithRequirements, %swift.type* %PWR, %swift.protocol_requirement* @"$s18resilient_protocol24ProtocolWithRequirementsTL", %swift.protocol_requirement* @"$s1T18resilient_protocol24ProtocolWithRequirementsPTl")
return PWR.T.self
}

Expand Down

0 comments on commit aba018c

Please sign in to comment.