Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 4 additions & 15 deletions lib/IRGen/GenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1164,21 +1164,10 @@ void IRGenerator::emitTypeMetadataRecords() {
}
}

void IRGenerator::
deleteAndReenqueueForEmissionValuesDependentOnCanonicalPrespecializedMetadataRecords(
IRGenModule &IGM, CanType typeWithCanonicalMetadataPrespecialization,
NominalTypeDecl &decl) {
// The accessor depends on canonical metadata records because they are
// returned from the function when the arguments match.
//
// TODO: Once work of looking through canonical prespecialized metadata has
// been moved into getGenericMetadata, this reemission will no longer
// be necessary.
auto *accessor = IGM.getAddrOfTypeMetadataAccessFunction(
decl.getDeclaredType()->getCanonicalType(), NotForDefinition);
accessor->deleteBody();
IGM.IRGen.noteUseOfMetadataAccessor(&decl);

static void
deleteAndReenqueueForEmissionValuesDependentOnCanonicalPrespecializedMetadataRecords(
IRGenModule &IGM, CanType typeWithCanonicalMetadataPrespecialization,
NominalTypeDecl &decl) {
// The type context descriptor depends on canonical metadata records because
// pointers to them are attached as trailing objects to it.
//
Expand Down
5 changes: 0 additions & 5 deletions lib/IRGen/IRGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -436,11 +436,6 @@ class IRGenerator {
return MetadataPrespecializationsForGenericTypes.lookup(type);
}

void
deleteAndReenqueueForEmissionValuesDependentOnCanonicalPrespecializedMetadataRecords(
IRGenModule &IGM, CanType typeWithCanonicalMetadataPrespecialization,
NominalTypeDecl &decl);

void noteUseOfMetadataAccessor(NominalTypeDecl *decl) {
if (LazyMetadataAccessors.count(decl) == 0) {
LazyMetadataAccessors.insert(decl);
Expand Down
190 changes: 0 additions & 190 deletions lib/IRGen/MetadataRequest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1986,176 +1986,6 @@ IRGenFunction::emitGenericTypeMetadataAccessFunctionCall(
return MetadataResponse::handle(*this, request, call);
}

static void emitCanonicalSpecializationsForGenericTypeMetadataAccessFunction(
IRGenFunction &IGF, llvm::Value *request, NominalTypeDecl *nominal,
GenericArguments &genericArgs,
std::function<llvm::Value *(int)> valueAtIndex) {
auto &IGM = IGF.IGM;
auto specializations = IGM.IRGen.metadataPrespecializationsForType(nominal);
auto canonicalCount = llvm::count_if(specializations, [](auto pair) {
return pair.second == TypeMetadataCanonicality::Canonical;
});

if (canonicalCount > 0) {
SmallVector<llvm::BasicBlock *, 4> conditionBlocks;
for (size_t index = 0; index < specializations.size(); ++index) {
conditionBlocks.push_back(llvm::BasicBlock::Create(IGM.getLLVMContext()));
}

IGF.Builder.CreateBr(conditionBlocks[0]);

SmallVector<std::tuple<llvm::BasicBlock *, CanType,
std::function<llvm::Value *(llvm::Value *, CanType,
IRGenFunction &,
IRGenModule &)>>,
4>
specializationBlocks;
auto switchDestination = llvm::BasicBlock::Create(IGM.getLLVMContext());
unsigned long blockIndex = 0;
for (auto pair : specializations) {
if (pair.second != TypeMetadataCanonicality::Canonical) {
continue;
}
auto specialization = pair.first;
auto conditionBlock = conditionBlocks[blockIndex];
IGF.Builder.emitBlock(conditionBlock);
auto successorBlock = blockIndex < conditionBlocks.size() - 1
? conditionBlocks[blockIndex + 1]
: switchDestination;
auto specializationBlock = llvm::BasicBlock::Create(IGM.getLLVMContext());
auto substitutions = specialization->getContextSubstitutionMap(
IGM.getSwiftModule(), nominal);

llvm::Value *condition = llvm::ConstantInt::get(IGM.Int1Ty, 1);
auto nominal = specialization->getAnyNominal();
auto requirements = GenericTypeRequirements(IGM, nominal);
int requirementIndex = 0;
for (auto requirement : requirements.getRequirements()) {
auto parameter = requirement.TypeParameter;
auto argument = parameter.subst(substitutions);
if (requirement.Protocol) {
auto conformance = substitutions.lookupConformance(
requirement.TypeParameter->getCanonicalType(),
requirement.Protocol);
ProtocolConformance *concreteConformance = conformance.getConcrete();
auto argumentNominal = argument->getAnyNominal();
if (argumentNominal && argumentNominal->isGenericContext()) {
// TODO: Statically specialize the witness table pattern for t's
// conformance.
llvm_unreachable(
"Statically specializing metadata at generic types is "
"not supported.");
} else {
RootProtocolConformance *rootConformance =
concreteConformance->getRootConformance();
llvm::Value *expectedDescriptor =
IGM.getAddrOfProtocolConformanceDescriptor(rootConformance);
auto *witnessTable = valueAtIndex(requirementIndex);
auto *witnessBuffer =
IGF.Builder.CreateBitCast(witnessTable, IGM.Int8PtrPtrTy);
auto *uncastProvidedDescriptor =
IGF.Builder.CreateLoad(witnessBuffer, Alignment());
auto *providedDescriptor = IGF.Builder.CreateBitCast(
uncastProvidedDescriptor,
IGM.ProtocolConformanceDescriptorPtrTy);

// Auth the stored descriptor.
auto storedScheme =
IGM.getOptions().PointerAuth.ProtocolConformanceDescriptors;
if (storedScheme) {
auto authInfo = PointerAuthInfo::emit(
IGF, storedScheme, witnessTable,
PointerAuthEntity::Special::ProtocolConformanceDescriptor);
providedDescriptor =
emitPointerAuthAuth(IGF, providedDescriptor, authInfo);
}

// Sign the descriptors.
auto argScheme =
IGM.getOptions()
.PointerAuth.ProtocolConformanceDescriptorsAsArguments;
if (argScheme) {
auto authInfo = PointerAuthInfo::emit(
IGF, argScheme, nullptr,
PointerAuthEntity::Special::
ProtocolConformanceDescriptorAsArgument);
expectedDescriptor =
emitPointerAuthSign(IGF, expectedDescriptor, authInfo);
providedDescriptor =
emitPointerAuthSign(IGF, providedDescriptor, authInfo);
}

auto *call = IGF.Builder.CreateCall(
IGM.getCompareProtocolConformanceDescriptorsFn(),
{providedDescriptor, expectedDescriptor});
call->setDoesNotThrow();
call->setCallingConv(IGM.SwiftCC);
call->addAttribute(llvm::AttributeList::FunctionIndex,
llvm::Attribute::ReadNone);
condition = IGF.Builder.CreateAnd(condition, call);
}
} else {
llvm::Constant *addr =
IGM.getAddrOfTypeMetadata(argument->getCanonicalType());
auto addrInt = IGF.Builder.CreateBitCast(addr, IGM.Int8PtrTy);
condition = IGF.Builder.CreateAnd(
condition, IGF.Builder.CreateICmpEQ(
addrInt, valueAtIndex(requirementIndex)));
}
++requirementIndex;
}
IGF.Builder.CreateCondBr(condition, specializationBlock, successorBlock);

auto responseBuilder = [](llvm::Value *request, CanType specialization,
IRGenFunction &IGF, IRGenModule &IGM) {
auto nominal = specialization->getAnyNominal();
llvm::Value *specializedMetadata;
if (isa<ClassDecl>(nominal)) {
llvm::Function *accessor =
IGM
.getAddrOfCanonicalSpecializedGenericTypeMetadataAccessFunction(
specialization, NotForDefinition);

specializedMetadata =
IGF.emitGenericTypeMetadataAccessFunctionCall(
accessor, {}, DynamicMetadataRequest(request))
.getMetadata();
} else {
specializedMetadata = IGM.getAddrOfTypeMetadata(specialization);
}
// Construct a MetadataResponse. It has three fields in the following
// order:
// - const Metadata *Metadata;
// - MetadataState (i32) StaticState;
llvm::Value *response =
llvm::UndefValue::get(IGM.TypeMetadataResponseTy);
response = IGF.Builder.CreateInsertValue(
response, specializedMetadata, 0,
"insert metadata address into response");
auto state = MetadataResponse::getCompletedState(IGM);
response = IGF.Builder.CreateInsertValue(
response, state, 1, "insert metadata state into response");
return response;
};
specializationBlocks.push_back(std::make_tuple(
specializationBlock, specialization, responseBuilder));
++blockIndex;
}

for (auto tuple : specializationBlocks) {
llvm::BasicBlock *block;
CanType type;
std::function<llvm::Value *(llvm::Value *, CanType, IRGenFunction &,
IRGenModule &)>
builder;
std::tie(block, type, builder) = tuple;
IGF.Builder.emitBlock(block);
IGF.Builder.CreateRet(builder(request, type, IGF, IGM));
}
IGF.Builder.emitBlock(switchDestination);
}
}

MetadataResponse irgen::emitGenericTypeMetadataAccessFunction(
IRGenFunction &IGF, Explosion &params, NominalTypeDecl *nominal,
GenericArguments &genericArgs) {
Expand Down Expand Up @@ -2186,20 +2016,6 @@ MetadataResponse irgen::emitGenericTypeMetadataAccessFunction(
llvm::Value *arguments =
IGF.Builder.CreateBitCast(argsBuffer.getAddress(), IGM.Int8PtrTy);

llvm::Value *argumentsBuffer =
IGF.Builder.CreateBitCast(argsBuffer.getAddress(), IGM.Int8PtrPtrTy);

emitCanonicalSpecializationsForGenericTypeMetadataAccessFunction(
IGF, request, nominal, genericArgs, [&](int index) {
llvm::Value *indexValue = llvm::ConstantInt::get(IGM.Int64Ty, index);
llvm::Value *elementPointer =
IGF.Builder.CreateGEP(argumentsBuffer, indexValue);
llvm::LoadInst *retval = IGF.Builder.CreateLoad(
elementPointer, Alignment(),
llvm::formatv("load argument at index {0} from buffer", index));
return retval;
});

// Make the call.
auto call = IGF.Builder.CreateCall(IGM.getGetGenericMetadataFn(),
{request, arguments, descriptor});
Expand Down Expand Up @@ -2278,12 +2094,6 @@ MetadataResponse irgen::emitGenericTypeMetadataAccessFunction(
? IGF.Builder.CreateBitCast(params.claimNext(), IGM.Int8PtrTy)
: llvm::UndefValue::get(IGM.Int8PtrTy);

std::array<llvm::Value *, 3> argValues = {arg0, arg1, arg2};

emitCanonicalSpecializationsForGenericTypeMetadataAccessFunction(
IGF, request, nominal, genericArgs,
[&](int index) { return argValues[index]; });

auto call = IGF.Builder.CreateCall(thunkFn,
{request, arg0, arg1, arg2, descriptor});
call->setDoesNotAccessMemory();
Expand Down
41 changes: 41 additions & 0 deletions stdlib/public/runtime/Metadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -756,12 +756,53 @@ MetadataResponse swift::swift_getCanonicalSpecializedMetadata(
return result.second;
}

// Look into the canonical prespecialized metadata attached to the type
// descriptor and return matching records, if any.
static Metadata *
findCanonicalSpecializedMetadata(MetadataRequest request,
const void *const *arguments,
const TypeContextDescriptor *description) {
auto &cache = getCache(*description);
auto key = MetadataCacheKey(cache.NumKeyParameters, cache.NumWitnessTables,
arguments);
auto prespecializedMetadatas =
description->getCanonicicalMetadataPrespecializations();
int index = 0;
for (auto &prespecializedMetadataPtr : prespecializedMetadatas) {
Metadata *prespecializationMetadata = prespecializedMetadataPtr.get();
const void *const *prespecializationArguments =
reinterpret_cast<const void *const *>(
prespecializationMetadata->getGenericArgs());
auto prespecializationKey =
MetadataCacheKey(cache.NumKeyParameters, cache.NumWitnessTables,
prespecializationArguments);
if (key == prespecializationKey) {
if (auto *classDescription = dyn_cast<ClassDescriptor>(description)) {
auto canonicalMetadataAccessors =
classDescription->getCanonicalMetadataPrespecializationAccessors();
auto &canonicalMetadataAccessorPtr = canonicalMetadataAccessors[index];
auto *canonicalMetadataAccessor = canonicalMetadataAccessorPtr.get();
auto response = canonicalMetadataAccessor(request);
return const_cast<Metadata *>(response.Value);
} else {
return prespecializationMetadata;
}
}
++index;
}
return nullptr;
}

/// The primary entrypoint.
MetadataResponse
swift::swift_getGenericMetadata(MetadataRequest request,
const void * const *arguments,
const TypeContextDescriptor *description) {
description = swift_auth_data_non_address(description, SpecialPointerAuthDiscriminators::TypeDescriptor);
if (auto *prespecialization =
findCanonicalSpecializedMetadata(request, arguments, description)) {
return {prespecialization, MetadataState::Complete};
}
auto &cache = getCache(*description);
assert(description->getFullGenericContextHeader().Base.NumKeyArguments ==
cache.NumKeyParameters + cache.NumWitnessTables);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -238,90 +238,6 @@ doit()
// CHECK: entry:
// CHECK: [[ERASED_ARGUMENT1:%[0-9]+]] = bitcast %swift.type* [[ARGUMENT1_METADATA]] to i8*
// CHECK: [[ERASED_ARGUMENT2:%[0-9]+]] = bitcast %swift.type* [[ARGUMENT2_METADATA]] to i8*
// CHECK: br label %[[TYPE_COMPARISON_LABEL:[0-9]+]]
// CHECK: [[TYPE_COMPARISON_LABEL]]:
// CHECK: [[EQUAL_TYPE_1:%[0-9]+]] = icmp eq i8* bitcast (
// : %swift.type* getelementptr inbounds (
// : %swift.full_heapmetadata,
// : %swift.full_heapmetadata* bitcast (
// : <{
// : void (
// : %T4main9Argument1[[UNIQUE_ID_1]]LLC*
// : )*,
// : i8**,
// : [[INT]],
// : %objc_class*,
// : %swift.opaque*,
// : %swift.opaque*,
// : [[INT]],
// : i32,
// : i32,
// : i32,
// : i16,
// : i16,
// : i32,
// : i32,
// : %swift.type_descriptor*,
// : i8*,
// : %swift.type*,
// : [[INT]],
// : %T4main9Argument1[[UNIQUE_ID_1]]LLC* (
// : %swift.opaque*,
// : %swift.type*
// : )*
// : }>*
// CHECK-SAME: @"$s4main9Argument1[[UNIQUE_ID_1]]LLCySiGMf"
// : to %swift.full_heapmetadata*
// : ),
// : i32 0,
// : i32 2
// : ) to i8*
// CHECK-SAME: ), [[ERASED_ARGUMENT1]]
// CHECK: [[EQUAL_TYPES_1:%[0-9]+]] = and i1 true, [[EQUAL_TYPE_1]]
// CHECK: [[EQUAL_TYPE_2:%[0-9]+]] = icmp eq i8* bitcast (
// : %swift.type* getelementptr inbounds (
// : %swift.full_heapmetadata,
// : %swift.full_heapmetadata* bitcast (
// : <{
// : void (
// : %T4main9Argument2[[UNIQUE_ID_1]]LLC*
// : )*,
// : i8**,
// : [[INT]],
// : %objc_class*,
// : %swift.opaque*,
// : %swift.opaque*,
// : [[INT]],
// : i32,
// : i32,
// : i32,
// : i16,
// : i16,
// : i32,
// : i32,
// : %swift.type_descriptor*,
// : i8*,
// : %swift.type*,
// : [[INT]],
// : %T4main9Argument2[[UNIQUE_ID_1]]LLC* (
// : %swift.opaque*,
// : %swift.type*
// : )*
// CHECK-SAME: }>* @"$s4main9Argument2[[UNIQUE_ID_1]]LLCySSGMf" to %swift.full_heapmetadata*
// : ),
// : i32 0,
// : i32 2
// : ) to i8*
// : ), [[ERASED_ARGUMENT2]]
// CHECK: [[EQUAL_TYPES_2:%[0-9]+]] = and i1 [[EQUAL_TYPES_1]], [[EQUAL_TYPE_2]]
// CHECK: br i1 [[EQUAL_TYPES_2]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]]
// CHECK: [[EXIT_PRESPECIALIZED]]:
// CHECK-NEXT: [[METADATA_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$s4main5Value[[UNIQUE_ID_3:[0-9A-Z_]+]]LLCyAA9Argument1ACLLCySiGAA9Argument2ACLLCySSGGMb"([[INT]] [[METADATA_REQUEST]])
// CHECK: [[METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0
// CHECK: [[PARTIAL_RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response undef, %swift.type* [[METADATA]], 0
// CHECK: [[RESULT_METADATA:%[\" a-zA-Z0-9]+]] = insertvalue %swift.metadata_response [[PARTIAL_RESULT_METADATA]], [[INT]] 0, 1
// CHECK: ret %swift.metadata_response [[RESULT_METADATA]]
// CHECK: [[EXIT_NORMAL]]:
// CHECK: {{%[0-9]+}} = call swiftcc %swift.metadata_response @__swift_instantiateGenericMetadata(
// CHECK: [[INT]] [[METADATA_REQUEST]],
// CHECK: i8* [[ERASED_ARGUMENT1]],
Expand Down
Loading