From a5f0069b8dfef390b93c6e373133d9e422bf124f Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Fri, 19 Jun 2020 17:25:43 -0700 Subject: [PATCH] [metadata prespecialization] Check conformances. Previously, the metadata accessor for a generic type for which some metadata prespecialization was done only tested that the type metadata arguments were equal to those of the prespecialization. If the generic type had an argument which was constrained to conform to a protocol, the particular conformance to that protocol was determined at compile time, but the conformance was ignored in the metadata accessor. As a result it was possible--in certain multi-module cases--for the metadata accessor to incorrectly return a prespecialized metadata record whose type arguments matched the type arguments passed to the accessor but whose conformance arguments did not. For example, given the following, Base: struct K {} protocol P {} Conformance1: import Base struct G {} extension K : P {} // first conformance prespecialize( G.self ) Conformance2: import Base extension K : P {} // second conformance the metadata accessor for G defined in Conformance1 would behave like MetadataResponse `metadata accessor for G`( MetadataRequest request, const Metadata *M, const WitnessTable *WT) { if (M == `type metadata for K`) { return `canonical prespecialized type metadata for G` } return swift_getGenericMetadata(request, {M, WT}); } Here, the WitnessTable argument is the witness table describing a conformance of the type whose metadata is provided to the protocol P. The incorrect behavior occurs when calling the metadata accessor with these arguments: `some request` `type metadata for K` `protocol witness table for Base.K : Base.P in Conformance2` The accessor would return the `canonical prespecialized type metadata for G`. The problem is that the prespecialized metadata contains the following generic arguments: `type metadata for K` `protocol witness table for Base.K : Base.P in Conformance1` Specificallly, the witness table is for the conformance from Conformance1, not the conformance from Conformance2. Here, the problem is addressed by testing that the witness tables passed into the accessor are for the same conformance as the witness table referred to by the prespecialized record. Now, the metadata accessor for G will behave like MetadataResponse `metadata accessor for G`( MetadataRequest request, const Metadata *M, const WitnessTable *WT) { if (M == `type metadata for K` swift_compareProtocolConformanceDescriptors( WT->getDescription(), `protocol conformance descriptor for Base.K : Base.P in Conformance1`) ) { return `canonical prespecialized type metadata for G` } return swift_getGenericMetadata(request, {M, WT}); } Consequently, when the accessor is called with the same arguments as before, the call to swift_compareProtocolConformanceDescriptors will return false and the non-matching prespecialized metadata will not be returned. --- lib/IRGen/MetadataRequest.cpp | 52 +++++- ...1argument-1conformance-1distinct_use.swift | 7 +- ...nt-1conformance-public-1distinct_use.swift | 7 +- ...1argument-1conformance-1distinct_use.swift | 7 +- ...1argument-2conformance-1distinct_use.swift | 12 +- ...1argument-3conformance-1distinct_use.swift | 23 ++- ...1argument-4conformance-1distinct_use.swift | 30 +++- ...1argument-5conformance-1distinct_use.swift | 37 ++++- .../struct-multi-conformance.swift | 157 ++++++++++++++++++ 9 files changed, 316 insertions(+), 16 deletions(-) create mode 100644 test/IRGen/prespecialized-metadata/struct-multi-conformance.swift diff --git a/lib/IRGen/MetadataRequest.cpp b/lib/IRGen/MetadataRequest.cpp index cea729733462a..e69c72d0914ac 100644 --- a/lib/IRGen/MetadataRequest.cpp +++ b/lib/IRGen/MetadataRequest.cpp @@ -1953,16 +1953,51 @@ static void emitCanonicalSpecializationsForGenericTypeMetadataAccessFunction( auto requirements = GenericTypeRequirements(IGF.IGM, nominal); int requirementIndex = 0; for (auto requirement : requirements.getRequirements()) { - if (requirement.Protocol) { - continue; - } auto parameter = requirement.TypeParameter; auto argument = parameter.subst(substitutions); - 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))); + 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(); + auto *expectedDescriptor = + IGF.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); + + auto *call = IGF.Builder.CreateCall( + IGF.IGM.getCompareProtocolConformanceDescriptorsFn(), + {providedDescriptor, expectedDescriptor}); + call->setDoesNotThrow(); + call->setCallingConv(IGF.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); @@ -2053,7 +2088,6 @@ MetadataResponse irgen::emitGenericTypeMetadataAccessFunction( emitCanonicalSpecializationsForGenericTypeMetadataAccessFunction( IGF, request, nominal, genericArgs, [&](int index) { llvm::Value *indexValue = llvm::ConstantInt::get(IGM.Int64Ty, index); - llvm::SmallVector indices{indexValue}; llvm::Value *elementPointer = IGF.Builder.CreateGEP(argumentsBuffer, indexValue); llvm::LoadInst *retval = IGF.Builder.CreateLoad( diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-1distinct_use.swift index 129e4e580ea9b..09bf049302cc2 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-1distinct_use.swift @@ -72,7 +72,12 @@ doit() // CHECK: [[TYPE_COMPARISON_LABEL]]: // CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE]] // CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] +// CHECK: [[ARGUMENT_BUFFER:%[0-9]+]] = bitcast i8* [[ERASED_TABLE]] to i8** +// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR:%[0-9]+]] = load i8*, i8** [[ARGUMENT_BUFFER]], align 1 +// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR]] to %swift.protocol_conformance_descriptor* +// CHECK: [[EQUAL_DESCRIPTORS:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors(%swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR]], %swift.protocol_conformance_descriptor* @"$sSi4main1PAAMc") +// CHECK: [[EQUAL_ARGUMENTS:%[0-9]+]] = and i1 [[EQUAL_TYPES]], [[EQUAL_DESCRIPTORS]] +// CHECK: br i1 [[EQUAL_ARGUMENTS]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] // CHECK: [[EXIT_PRESPECIALIZED]]: // CHECK: ret %swift.metadata_response { // CHECK-SAME: %swift.type* getelementptr inbounds ( diff --git a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-public-1distinct_use.swift b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-public-1distinct_use.swift index de96de5c8537c..3413489175ede 100644 --- a/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-public-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/enum-inmodule-1argument-1conformance-public-1distinct_use.swift @@ -72,7 +72,12 @@ doit() // CHECK: [[TYPE_COMPARISON_LABEL]]: // CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE]] // CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] +// CHECK: [[ARGUMENT_BUFFER:%[0-9]+]] = bitcast i8* [[ERASED_TABLE]] to i8** +// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR:%[0-9]+]] = load i8*, i8** [[ARGUMENT_BUFFER]], align 1 +// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR]] to %swift.protocol_conformance_descriptor* +// CHECK: [[EQUAL_DESCRIPTORS:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors(%swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR]], %swift.protocol_conformance_descriptor* @"$sSi4main1PAAMc") +// CHECK: [[EQUAL_ARGUMENTS:%[0-9]+]] = and i1 [[EQUAL_TYPES]], [[EQUAL_DESCRIPTORS]] +// CHECK: br i1 [[EQUAL_ARGUMENTS]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] // CHECK: [[EXIT_PRESPECIALIZED]]: // CHECK: ret %swift.metadata_response { // CHECK-SAME: %swift.type* getelementptr inbounds ( diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1conformance-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1conformance-1distinct_use.swift index 4b904ed09cc01..80024353f89dc 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1conformance-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-1conformance-1distinct_use.swift @@ -55,7 +55,12 @@ doit() // CHECK: [[TYPE_COMPARISON_LABEL]]: // CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE]] // CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] +// CHECK: [[ARGUMENT_BUFFER:%[0-9]+]] = bitcast i8* [[ERASED_TABLE]] to i8** +// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR:%[0-9]+]] = load i8*, i8** [[ARGUMENT_BUFFER]], align 1 +// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR]] to %swift.protocol_conformance_descriptor* +// CHECK: [[EQUAL_DESCRIPTORS:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors(%swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR]], %swift.protocol_conformance_descriptor* @"$sSi4main1PAAMc") +// CHECK: [[EQUAL_ARGUMENTS:%[0-9]+]] = and i1 [[EQUAL_TYPES]], [[EQUAL_DESCRIPTORS]] +// CHECK: br i1 [[EQUAL_ARGUMENTS]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] // CHECK: [[EXIT_PRESPECIALIZED]]: // CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i8**, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } // CHECK: [[EXIT_NORMAL]]: diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-2conformance-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-2conformance-1distinct_use.swift index 15874f76018ff..6a3d0ffa4696c 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-2conformance-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-2conformance-1distinct_use.swift @@ -60,7 +60,17 @@ doit() // CHECK: [[TYPE_COMPARISON_LABEL]]: // CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), [[ERASED_TYPE]] // CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] +// CHECK: [[UNERASED_TABLE_1:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_1]] to i8** +// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_1:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_1]], align 1 +// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_1:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_1]] to %swift.protocol_conformance_descriptor* +// CHECK: [[EQUAL_DESCRIPTORS_1:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors(%swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_1]], %swift.protocol_conformance_descriptor* @"$sSi4main1PAAMc") +// CHECK: [[EQUAL_ARGUMENTS_1:%[0-9]+]] = and i1 [[EQUAL_TYPES]], [[EQUAL_DESCRIPTORS_1]] +// CHECK: [[UNERASED_TABLE_2:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_2]] to i8** +// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_2:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_2]], align 1 +// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_2:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_2]] to %swift.protocol_conformance_descriptor* +// CHECK: [[EQUAL_DESCRIPTORS_2:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors(%swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_2]], %swift.protocol_conformance_descriptor* @"$sSi4main1QAAMc") +// CHECK: [[EQUAL_ARGUMENTS_2:%[0-9]+]] = and i1 [[EQUAL_ARGUMENTS_1]], [[EQUAL_DESCRIPTORS_2]] +// CHECK: br i1 [[EQUAL_ARGUMENTS_2]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] // CHECK: [[EXIT_PRESPECIALIZED]]: // CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i8**, i8**, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } // CHECK: [[EXIT_NORMAL]]: diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-3conformance-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-3conformance-1distinct_use.swift index 9b0790f395684..16c4fa9e4b909 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-3conformance-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-3conformance-1distinct_use.swift @@ -64,7 +64,28 @@ doit() // CHECK: %"load argument at index 0 from buffer" = load i8*, i8** [[ERASED_TYPE_ADDRESS]] // CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), %"load argument at index 0 from buffer" // CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] +// CHECK: [[POINTER_TO_ERASED_TABLE_1:%[0-9]+]] = getelementptr i8*, i8** %1, i64 1 +// CHECK: [[ERASED_TABLE_1:%"load argument at index 1 from buffer"]] = load i8*, i8** [[POINTER_TO_ERASED_TABLE_1]], align 1 +// CHECK: [[UNERASED_TABLE_1:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_1]] to i8** +// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_1:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_1]], align 1 +// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_1:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_1]] to %swift.protocol_conformance_descriptor* +// CHECK: [[EQUAL_DESCRIPTORS_1:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors(%swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_1]], %swift.protocol_conformance_descriptor* @"$sSi4main1PAAMc") +// CHECK: [[EQUAL_ARGUMENTS_1:%[0-9]+]] = and i1 [[EQUAL_TYPES]], [[EQUAL_DESCRIPTORS_1]] +// CHECK: [[POINTER_TO_ERASED_TABLE_2:%[0-9]+]] = getelementptr i8*, i8** %1, i64 2 +// CHECK: [[ERASED_TABLE_2:%"load argument at index 2 from buffer"]] = load i8*, i8** [[POINTER_TO_ERASED_TABLE_2]], align 1 +// CHECK: [[UNERASED_TABLE_2:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_2]] to i8** +// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_2:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_2]], align 1 +// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_2:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_2]] to %swift.protocol_conformance_descriptor* +// CHECK: [[EQUAL_DESCRIPTORS_2:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors(%swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_2]], %swift.protocol_conformance_descriptor* @"$sSi4main1QAAMc") +// CHECK: [[EQUAL_ARGUMENTS_2:%[0-9]+]] = and i1 [[EQUAL_ARGUMENTS_1]], [[EQUAL_DESCRIPTORS_2]] +// CHECK: [[POINTER_TO_ERASED_TABLE_3:%[0-9]+]] = getelementptr i8*, i8** %1, i64 3 +// CHECK: [[ERASED_TABLE_3:%"load argument at index 3 from buffer"]] = load i8*, i8** [[POINTER_TO_ERASED_TABLE_3]], align 1 +// CHECK: [[UNERASED_TABLE_3:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_3]] to i8** +// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_3:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_3]], align 1 +// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_3:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_3]] to %swift.protocol_conformance_descriptor* +// CHECK: [[EQUAL_DESCRIPTORS_3:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors(%swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_3]], %swift.protocol_conformance_descriptor* @"$sSi4main1RAAMc") +// CHECK: [[EQUAL_ARGUMENTS_3:%[0-9]+]] = and i1 [[EQUAL_ARGUMENTS_2]], [[EQUAL_DESCRIPTORS_3]] +// CHECK: br i1 [[EQUAL_ARGUMENTS_3]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] // CHECK: [[EXIT_PRESPECIALIZED]]: // CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i8**, i8**, i8**, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } // CHECK: [[EXIT_NORMAL]]: diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-4conformance-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-4conformance-1distinct_use.swift index 64632a842a242..5c53fd4853d9a 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-4conformance-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-4conformance-1distinct_use.swift @@ -68,7 +68,35 @@ doit() // CHECK: %"load argument at index 0 from buffer" = load i8*, i8** [[ERASED_TYPE_ADDRESS]] // CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), %"load argument at index 0 from buffer" // CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] +// CHECK: [[POINTER_TO_ERASED_TABLE_1:%[0-9]+]] = getelementptr i8*, i8** %1, i64 1 +// CHECK: [[ERASED_TABLE_1:%"load argument at index 1 from buffer"]] = load i8*, i8** [[POINTER_TO_ERASED_TABLE_1]], align 1 +// CHECK: [[UNERASED_TABLE_1:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_1]] to i8** +// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_1:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_1]], align 1 +// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_1:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_1]] to %swift.protocol_conformance_descriptor* +// CHECK: [[EQUAL_DESCRIPTORS_1:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors(%swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_1]], %swift.protocol_conformance_descriptor* @"$sSi4main1PAAMc") +// CHECK: [[EQUAL_ARGUMENTS_1:%[0-9]+]] = and i1 [[EQUAL_TYPES]], [[EQUAL_DESCRIPTORS_1]] +// CHECK: [[POINTER_TO_ERASED_TABLE_2:%[0-9]+]] = getelementptr i8*, i8** %1, i64 2 +// CHECK: [[ERASED_TABLE_2:%"load argument at index 2 from buffer"]] = load i8*, i8** [[POINTER_TO_ERASED_TABLE_2]], align 1 +// CHECK: [[UNERASED_TABLE_2:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_2]] to i8** +// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_2:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_2]], align 1 +// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_2:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_2]] to %swift.protocol_conformance_descriptor* +// CHECK: [[EQUAL_DESCRIPTORS_2:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors(%swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_2]], %swift.protocol_conformance_descriptor* @"$sSi4main1QAAMc") +// CHECK: [[EQUAL_ARGUMENTS_2:%[0-9]+]] = and i1 [[EQUAL_ARGUMENTS_1]], [[EQUAL_DESCRIPTORS_2]] +// CHECK: [[POINTER_TO_ERASED_TABLE_3:%[0-9]+]] = getelementptr i8*, i8** %1, i64 3 +// CHECK: [[ERASED_TABLE_3:%"load argument at index 3 from buffer"]] = load i8*, i8** [[POINTER_TO_ERASED_TABLE_3]], align 1 +// CHECK: [[UNERASED_TABLE_3:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_3]] to i8** +// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_3:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_3]], align 1 +// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_3:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_3]] to %swift.protocol_conformance_descriptor* +// CHECK: [[EQUAL_DESCRIPTORS_3:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors(%swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_3]], %swift.protocol_conformance_descriptor* @"$sSi4main1RAAMc") +// CHECK: [[EQUAL_ARGUMENTS_3:%[0-9]+]] = and i1 [[EQUAL_ARGUMENTS_2]], [[EQUAL_DESCRIPTORS_3]] +// CHECK: [[POINTER_TO_ERASED_TABLE_4:%[0-9]+]] = getelementptr i8*, i8** %1, i64 4 +// CHECK: [[ERASED_TABLE_4:%"load argument at index 4 from buffer"]] = load i8*, i8** [[POINTER_TO_ERASED_TABLE_4]], align 1 +// CHECK: [[UNERASED_TABLE_4:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_4]] to i8** +// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_4:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_4]], align 1 +// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_4:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_4]] to %swift.protocol_conformance_descriptor* +// CHECK: [[EQUAL_DESCRIPTORS_4:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors(%swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_4]], %swift.protocol_conformance_descriptor* @"$sSi4main1SAAMc") +// CHECK: [[EQUAL_ARGUMENTS_4:%[0-9]+]] = and i1 [[EQUAL_ARGUMENTS_3]], [[EQUAL_DESCRIPTORS_4]] +// CHECK: br i1 [[EQUAL_ARGUMENTS_4]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] // CHECK: [[EXIT_PRESPECIALIZED]]: // CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i8**, i8**, i8**, i8**, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } // CHECK: [[EXIT_NORMAL]]: diff --git a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-5conformance-1distinct_use.swift b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-5conformance-1distinct_use.swift index ff974470aa1a3..d5de2eea02c44 100644 --- a/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-5conformance-1distinct_use.swift +++ b/test/IRGen/prespecialized-metadata/struct-inmodule-1argument-5conformance-1distinct_use.swift @@ -72,7 +72,42 @@ doit() // CHECK: %"load argument at index 0 from buffer" = load i8*, i8** [[ERASED_TYPE_ADDRESS]] // CHECK: [[EQUAL_TYPE:%[0-9]+]] = icmp eq i8* bitcast (%swift.type* @"$sSiN" to i8*), %"load argument at index 0 from buffer" // CHECK: [[EQUAL_TYPES:%[0-9]+]] = and i1 true, [[EQUAL_TYPE]] -// CHECK: br i1 [[EQUAL_TYPES]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] +// CHECK: [[POINTER_TO_ERASED_TABLE_1:%[0-9]+]] = getelementptr i8*, i8** %1, i64 1 +// CHECK: [[ERASED_TABLE_1:%"load argument at index 1 from buffer"]] = load i8*, i8** [[POINTER_TO_ERASED_TABLE_1]], align 1 +// CHECK: [[UNERASED_TABLE_1:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_1]] to i8** +// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_1:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_1]], align 1 +// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_1:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_1]] to %swift.protocol_conformance_descriptor* +// CHECK: [[EQUAL_DESCRIPTORS_1:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors(%swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_1]], %swift.protocol_conformance_descriptor* @"$sSi4main1PAAMc") +// CHECK: [[EQUAL_ARGUMENTS_1:%[0-9]+]] = and i1 [[EQUAL_TYPES]], [[EQUAL_DESCRIPTORS_1]] +// CHECK: [[POINTER_TO_ERASED_TABLE_2:%[0-9]+]] = getelementptr i8*, i8** %1, i64 2 +// CHECK: [[ERASED_TABLE_2:%"load argument at index 2 from buffer"]] = load i8*, i8** [[POINTER_TO_ERASED_TABLE_2]], align 1 +// CHECK: [[UNERASED_TABLE_2:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_2]] to i8** +// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_2:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_2]], align 1 +// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_2:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_2]] to %swift.protocol_conformance_descriptor* +// CHECK: [[EQUAL_DESCRIPTORS_2:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors(%swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_2]], %swift.protocol_conformance_descriptor* @"$sSi4main1QAAMc") +// CHECK: [[EQUAL_ARGUMENTS_2:%[0-9]+]] = and i1 [[EQUAL_ARGUMENTS_1]], [[EQUAL_DESCRIPTORS_2]] +// CHECK: [[POINTER_TO_ERASED_TABLE_3:%[0-9]+]] = getelementptr i8*, i8** %1, i64 3 +// CHECK: [[ERASED_TABLE_3:%"load argument at index 3 from buffer"]] = load i8*, i8** [[POINTER_TO_ERASED_TABLE_3]], align 1 +// CHECK: [[UNERASED_TABLE_3:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_3]] to i8** +// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_3:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_3]], align 1 +// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_3:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_3]] to %swift.protocol_conformance_descriptor* +// CHECK: [[EQUAL_DESCRIPTORS_3:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors(%swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_3]], %swift.protocol_conformance_descriptor* @"$sSi4main1RAAMc") +// CHECK: [[EQUAL_ARGUMENTS_3:%[0-9]+]] = and i1 [[EQUAL_ARGUMENTS_2]], [[EQUAL_DESCRIPTORS_3]] +// CHECK: [[POINTER_TO_ERASED_TABLE_4:%[0-9]+]] = getelementptr i8*, i8** %1, i64 4 +// CHECK: [[ERASED_TABLE_4:%"load argument at index 4 from buffer"]] = load i8*, i8** [[POINTER_TO_ERASED_TABLE_4]], align 1 +// CHECK: [[UNERASED_TABLE_4:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_4]] to i8** +// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_4:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_4]], align 1 +// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_4:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_4]] to %swift.protocol_conformance_descriptor* +// CHECK: [[EQUAL_DESCRIPTORS_4:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors(%swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_4]], %swift.protocol_conformance_descriptor* @"$sSi4main1SAAMc") +// CHECK: [[EQUAL_ARGUMENTS_4:%[0-9]+]] = and i1 [[EQUAL_ARGUMENTS_3]], [[EQUAL_DESCRIPTORS_4]] +// CHECK: [[POINTER_TO_ERASED_TABLE_5:%[0-9]+]] = getelementptr i8*, i8** %1, i64 5 +// CHECK: [[ERASED_TABLE_5:%"load argument at index 5 from buffer"]] = load i8*, i8** [[POINTER_TO_ERASED_TABLE_5]], align 1 +// CHECK: [[UNERASED_TABLE_5:%[0-9]+]] = bitcast i8* [[ERASED_TABLE_5]] to i8** +// CHECK: [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_5:%[0-9]+]] = load i8*, i8** [[UNERASED_TABLE_5]], align 1 +// CHECK: [[PROVIDED_PROTOCOL_DESCRIPTOR_5:%[0-9]+]] = bitcast i8* [[UNCAST_PROVIDED_PROTOCOL_DESCRIPTOR_5]] to %swift.protocol_conformance_descriptor* +// CHECK: [[EQUAL_DESCRIPTORS_5:%[0-9]+]] = call swiftcc i1 @swift_compareProtocolConformanceDescriptors(%swift.protocol_conformance_descriptor* [[PROVIDED_PROTOCOL_DESCRIPTOR_5]], %swift.protocol_conformance_descriptor* @"$sSi4main1TAAMc") +// CHECK: [[EQUAL_ARGUMENTS_5:%[0-9]+]] = and i1 [[EQUAL_ARGUMENTS_4]], [[EQUAL_DESCRIPTORS_5]] +// CHECK: br i1 [[EQUAL_ARGUMENTS_5]], label %[[EXIT_PRESPECIALIZED:[0-9]+]], label %[[EXIT_NORMAL:[0-9]+]] // CHECK: [[EXIT_PRESPECIALIZED]]: // CHECK: ret %swift.metadata_response { %swift.type* getelementptr inbounds (%swift.full_type, %swift.full_type* bitcast (<{ i8**, [[INT]], %swift.type_descriptor*, %swift.type*, i8**, i8**, i8**, i8**, i8**, i32{{(, \[4 x i8\])?}}, i64 }>* @"$s4main5ValueVySiGMf" to %swift.full_type*), i32 0, i32 1), [[INT]] 0 } // CHECK: [[EXIT_NORMAL]]: diff --git a/test/IRGen/prespecialized-metadata/struct-multi-conformance.swift b/test/IRGen/prespecialized-metadata/struct-multi-conformance.swift new file mode 100644 index 0000000000000..f9af774a8b102 --- /dev/null +++ b/test/IRGen/prespecialized-metadata/struct-multi-conformance.swift @@ -0,0 +1,157 @@ +// RUN: %empty-directory(%t) + +// RUN: %target-build-swift -c %s -DBASE -emit-library -emit-module -module-name Base -target %module-target-future -Xfrontend -prespecialize-generic-metadata -emit-module-path %t/Base.swiftmodule -o %t/%target-library-name(Base) +// RUN: %target-build-swift -c %s -DCONFORMANCE_1 -emit-library -emit-module -module-name Conformance1 -target %module-target-future -Xfrontend -prespecialize-generic-metadata -emit-module-path %t/Conformance1.swiftmodule -o %t/%target-library-name(Conformance1) -lBase -I %t -L %t +// RUN: %target-build-swift -c %s -DCONFORMANCE_2 -emit-library -emit-module -module-name Conformance2 -target %module-target-future -Xfrontend -prespecialize-generic-metadata -emit-module-path %t/Conformance2.swiftmodule -o %t/%target-library-name(Conformance2) -lBase -I %t -L %t +// RUN: %target-build-swift -c %s -DGENERIC -emit-library -emit-module -module-name Generic -target %module-target-future -Xfrontend -prespecialize-generic-metadata -emit-module-path %t/Generic.swiftmodule -o %t/%target-library-name(Generic) -lBase -lConformance1 -I %t -L %t +// RUN: %target-build-swift -c %s -DERASE -emit-library -emit-module -module-name Erase -target %module-target-future -Xfrontend -prespecialize-generic-metadata -emit-module-path %t/Erase.swiftmodule -o %t/%target-library-name(Erase) -lBase -lConformance2 -I %t -L %t +// RUN: %clang -c -v %target-cc-options -g -O0 -isysroot %sdk %S/Inputs/isPrespecialized.cpp -o %t/isPrespecialized.o -I %clang-include-dir -I %swift_src_root/include/ -I %swift_src_root/../llvm-project/llvm/include -I %clang-include-dir/../../llvm-macosx-x86_64/include -L %clang-include-dir/../lib/swift/macosx +// RUN: %target-build-swift %s %S/Inputs/main.swift %S/Inputs/consume-logging-metadata-value.swift %t/isPrespecialized.o -import-objc-header %S/Inputs/isPrespecialized.h -DMAIN -target %module-target-future -Xfrontend -prespecialize-generic-metadata -lBase -lConformance1 -lConformance2 -lGeneric -lErase -lc++ -I %t -L %t -L %clang-include-dir/../lib/swift/macosx -o %t/main + +// RUN: %target-codesign %t/main +// RUN: %target-run %t/main | %FileCheck %s + +// REQUIRES: OS=macosx +// REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib +// UNSUPPORTED: swift_test_mode_optimize +// UNSUPPORTED: swift_test_mode_optimize_size + +#if BASE +public struct K { + public init() {} +} + +public protocol P { + var name: String { get } +} +#endif + +#if CONFORMANCE_1 +import Base + +extension K : P { + + public var name: String { "Conformance1" } + +} +#endif + +#if CONFORMANCE_2 +import Base + +extension K : P { + + public var name: String { "Conformance2" } + +} +#endif + +#if GENERIC +import Base +import Conformance1 + +public struct G { + public let t: T + + public init(_ t: T) { + self.t = t + } + + public var name: String { + t.name + } +} + +@inline(never) +func consume(_ t: T) { + withExtendedLifetime(t) {} +} + + +public func prespecialize() { + consume(G.self) +} +#endif + +#if ERASE +import Base +import Conformance2 + +public struct AnyP : P { + + private class _BoxBase { + public var name: String { + fatalError() + } + public func visit(_ v: Visitor) { + fatalError() + } + } + + private final class _Box : _BoxBase { + private let t: T + + init(_ t: T) { + self.t = t + } + + override var name: String { + t.name + } + override func visit(_ v: Visitor) { + v.visit(t) + } + } + + private let _box: _BoxBase + + init(_ t: T) { + self._box = _Box(t) + } + + public var name: String { + _box.name + } + + public func visit(_ v: Visitor) { + _box.visit(v) + } + +} + +public protocol PVisitor { + func visit(_ t: T) +} + +public func getKAsAnyP() -> AnyP { + AnyP(K()) +} +#endif + +#if MAIN +import Base +import Generic +import Conformance2 +import Erase + +func ptr(to ty: T.Type) -> UnsafeMutableRawPointer { + UnsafeMutableRawPointer(mutating: unsafePointerToMetadata(of: ty))! +} + +func printTheName(_ t: T, prespecialized: Bool) { + print(G(t).name) + assert(isCanonicalStaticallySpecializedGenericMetadata(ptr(to: G.self)) == prespecialized) +} +struct Visitor : PVisitor { + func visit(_ t: T) { + printTheName(t, prespecialized: false) + } +} +func doit() { + // CHECK: Conformance1 + printTheName(K(), prespecialized: true) + // CHECK: Conformance2 + getKAsAnyP().visit(Visitor()) +} +#endif