From 22c4e08b9648734db3055220ee62e497aca0dfd8 Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Mon, 13 Jun 2016 20:42:27 -0700 Subject: [PATCH] IRGen: Fix TypeInfo for witness_method SIL values. @convention(witness_method) values were changed to carry a pointer to their source witness table, but the type info wasn't changed to match. Fixing this fixes rdar://problem/26268544. --- lib/IRGen/GenFunc.cpp | 60 +++++++++++++++++++++++-------- lib/IRGen/IRGenModule.cpp | 4 +++ lib/IRGen/IRGenModule.h | 1 + lib/IRGen/ReferenceTypeInfo.h | 4 +-- lib/SIL/SILVerifier.cpp | 4 +-- test/IRGen/function_types.sil | 6 ++-- test/IRGen/witness_method_phi.sil | 16 +++++++++ 7 files changed, 74 insertions(+), 21 deletions(-) create mode 100644 test/IRGen/witness_method_phi.sil diff --git a/lib/IRGen/GenFunc.cpp b/lib/IRGen/GenFunc.cpp index 85a57668ddd33..e8da2392cbe59 100644 --- a/lib/IRGen/GenFunc.cpp +++ b/lib/IRGen/GenFunc.cpp @@ -176,8 +176,9 @@ namespace { class FuncTypeInfo : public ScalarTypeInfo, public FuncSignatureInfo { FuncTypeInfo(CanSILFunctionType formalType, llvm::StructType *storageType, - Size size, Alignment align, SpareBitVector &&spareBits) - : ScalarTypeInfo(storageType, size, std::move(spareBits), align), + Size size, Alignment align, SpareBitVector &&spareBits, + IsPOD_t pod) + : ScalarTypeInfo(storageType, size, std::move(spareBits), align, pod), FuncSignatureInfo(formalType) { } @@ -186,9 +187,10 @@ namespace { static const FuncTypeInfo *create(CanSILFunctionType formalType, llvm::StructType *storageType, Size size, Alignment align, - SpareBitVector &&spareBits) { + SpareBitVector &&spareBits, + IsPOD_t pod) { return new FuncTypeInfo(formalType, storageType, size, align, - std::move(spareBits)); + std::move(spareBits), pod); } // Function types do not satisfy allowsOwnership. @@ -247,7 +249,8 @@ namespace { Address dataAddr = projectData(IGF, address); auto data = IGF.Builder.CreateLoad(dataAddr); - IGF.emitNativeStrongRetain(data); + if (!isPOD(ResilienceExpansion::Maximal)) + IGF.emitNativeStrongRetain(data); e.add(data); } @@ -268,7 +271,11 @@ namespace { IGF.Builder.CreateStore(e.claimNext(), fnAddr); Address dataAddr = projectData(IGF, address); - IGF.emitNativeStrongAssign(e.claimNext(), dataAddr); + auto context = e.claimNext(); + if (isPOD(ResilienceExpansion::Maximal)) + IGF.Builder.CreateStore(context, dataAddr); + else + IGF.emitNativeStrongAssign(context, dataAddr); } void initialize(IRGenFunction &IGF, Explosion &e, @@ -279,21 +286,28 @@ namespace { // Store the data pointer, if any, transferring the +1. Address dataAddr = projectData(IGF, address); - IGF.emitNativeStrongInit(e.claimNext(), dataAddr); + auto context = e.claimNext(); + if (isPOD(ResilienceExpansion::Maximal)) + IGF.Builder.CreateStore(context, dataAddr); + else + IGF.emitNativeStrongInit(context, dataAddr); } void copy(IRGenFunction &IGF, Explosion &src, Explosion &dest, Atomicity atomicity) const override { src.transferInto(dest, 1); auto data = src.claimNext(); - IGF.emitNativeStrongRetain(data, atomicity); + if (!isPOD(ResilienceExpansion::Maximal)) + IGF.emitNativeStrongRetain(data, atomicity); dest.add(data); } void consume(IRGenFunction &IGF, Explosion &src, Atomicity atomicity) const override { src.claimNext(); - IGF.emitNativeStrongRelease(src.claimNext(), atomicity); + auto context = src.claimNext(); + if (!isPOD(ResilienceExpansion::Maximal)) + IGF.emitNativeStrongRelease(context, atomicity); } void fixLifetime(IRGenFunction &IGF, Explosion &src) const override { @@ -304,13 +318,17 @@ namespace { void strongRetain(IRGenFunction &IGF, Explosion &e, Atomicity atomicity) const override { e.claimNext(); - IGF.emitNativeStrongRetain(e.claimNext(), atomicity); + auto context = e.claimNext(); + if (!isPOD(ResilienceExpansion::Maximal)) + IGF.emitNativeStrongRetain(context, atomicity); } void strongRelease(IRGenFunction &IGF, Explosion &e, Atomicity atomicity) const override { e.claimNext(); - IGF.emitNativeStrongRelease(e.claimNext(), atomicity); + auto context = e.claimNext(); + if (!isPOD(ResilienceExpansion::Maximal)) + IGF.emitNativeStrongRelease(context, atomicity); } void strongRetainUnowned(IRGenFunction &IGF, Explosion &e) const override { @@ -352,7 +370,8 @@ namespace { void destroy(IRGenFunction &IGF, Address addr, SILType T) const override { auto data = IGF.Builder.CreateLoad(projectData(IGF, addr)); - IGF.emitNativeStrongRelease(data); + if (!isPOD(ResilienceExpansion::Maximal)) + IGF.emitNativeStrongRelease(data); } void packIntoEnumPayload(IRGenFunction &IGF, @@ -534,7 +553,6 @@ const TypeInfo *TypeConverter::convertFunctionType(SILFunctionType *T) { case SILFunctionType::Representation::Thin: case SILFunctionType::Representation::Method: - case SILFunctionType::Representation::WitnessMethod: case SILFunctionType::Representation::ObjCMethod: case SILFunctionType::Representation::CFunctionPointer: return ThinFuncTypeInfo::create(CanSILFunctionType(T), @@ -552,7 +570,21 @@ const TypeInfo *TypeConverter::convertFunctionType(SILFunctionType *T) { IGM.FunctionPairTy, IGM.getPointerSize() * 2, IGM.getPointerAlignment(), - std::move(spareBits)); + std::move(spareBits), + IsNotPOD); + } + // Witness method values carry a reference to their originating witness table + // as context. + case SILFunctionType::Representation::WitnessMethod: { + SpareBitVector spareBits; + spareBits.append(IGM.getFunctionPointerSpareBits()); + spareBits.append(IGM.getWitnessTablePtrSpareBits()); + return FuncTypeInfo::create(CanSILFunctionType(T), + IGM.WitnessFunctionPairTy, + IGM.getPointerSize() * 2, + IGM.getPointerAlignment(), + std::move(spareBits), + IsPOD); } } llvm_unreachable("bad function type representation"); diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp index 918ee7283a2ac..a6c5f05c830a5 100644 --- a/lib/IRGen/IRGenModule.cpp +++ b/lib/IRGen/IRGenModule.cpp @@ -274,6 +274,10 @@ IRGenModule::IRGenModule(IRGenerator &irgen, FunctionPtrTy, RefCountedPtrTy, }); + WitnessFunctionPairTy = createStructType(*this, "swift.function", { + FunctionPtrTy, + WitnessTablePtrTy, + }); OpaquePtrTy = llvm::StructType::create(LLVMContext, "swift.opaque") ->getPointerTo(DefaultAS); diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h index 1ffdc264a1419..a99a289e6c3e3 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -405,6 +405,7 @@ class IRGenModule { llvm::PointerType *UnownedReferencePtrTy;/// %swift.unowned_reference* llvm::Constant *RefCountedNull; /// %swift.refcounted* null llvm::StructType *FunctionPairTy; /// { i8*, %swift.refcounted* } + llvm::StructType *WitnessFunctionPairTy; /// { i8*, %witness.table* } llvm::FunctionType *DeallocatingDtorTy; /// void (%swift.refcounted*) llvm::StructType *TypeMetadataStructTy; /// %swift.type = type { ... } llvm::PointerType *TypeMetadataPtrTy;/// %swift.type* diff --git a/lib/IRGen/ReferenceTypeInfo.h b/lib/IRGen/ReferenceTypeInfo.h index a6dcbd728e985..04d3749105edc 100644 --- a/lib/IRGen/ReferenceTypeInfo.h +++ b/lib/IRGen/ReferenceTypeInfo.h @@ -33,8 +33,8 @@ class ReferenceTypeInfo : public LoadableTypeInfo { protected: // FIXME: Get spare bits for pointers from a TargetInfo-like structure. ReferenceTypeInfo(llvm::Type *type, Size size, SpareBitVector spareBits, - Alignment align) - : LoadableTypeInfo(type, size, spareBits, align, IsNotPOD, + Alignment align, IsPOD_t pod = IsNotPOD) + : LoadableTypeInfo(type, size, spareBits, align, pod, IsFixedSize, STIK_Reference) {} diff --git a/lib/SIL/SILVerifier.cpp b/lib/SIL/SILVerifier.cpp index 07c192cb86a3f..5c73108d5e20e 100644 --- a/lib/SIL/SILVerifier.cpp +++ b/lib/SIL/SILVerifier.cpp @@ -2700,9 +2700,7 @@ class SILVerifier : public SILVerifierBase { // NOTE: IRGen currently does not support the following method_inst // variants as branch arguments. // Once this is supported, the check can be removed. - require( - !isa(branchArg) && - !(isa(branchArg) && + require(!(isa(branchArg) && cast(branchArg)->getMember().isForeign), "branch argument cannot be a witness_method or an objc method_inst"); return branchArg->getType() == bbArg->getType(); diff --git a/test/IRGen/function_types.sil b/test/IRGen/function_types.sil index dbe576500ad5e..309937a94f5b5 100644 --- a/test/IRGen/function_types.sil +++ b/test/IRGen/function_types.sil @@ -36,9 +36,11 @@ entry(%x : $() -> ()): return %x : $() -> () } -// CHECK-LABEL: define{{( protected)?}} i8* @thin_witness_value(i8*) {{.*}} { +// CHECK-LABEL: define{{( protected)?}} { i8*, i8** } @thin_witness_value(i8*, i8**) {{.*}} { // CHECK-NEXT: entry: -// CHECK-NEXT: ret i8* %0 +// CHECK-NEXT: [[T0:%.*]] = insertvalue { i8*, i8** } undef, i8* %0, 0 +// CHECK-NEXT: [[T1:%.*]] = insertvalue { i8*, i8** } [[T0]], i8** %1, 1 +// CHECK-NEXT: ret { i8*, i8** } [[T1]] // CHECK-NEXT: } sil @thin_witness_value : $@convention(thin) (@convention(witness_method) () -> ()) -> @convention(witness_method) () -> () { entry(%x : $@convention(witness_method) () -> ()): diff --git a/test/IRGen/witness_method_phi.sil b/test/IRGen/witness_method_phi.sil new file mode 100644 index 0000000000000..5d926e58fe6f4 --- /dev/null +++ b/test/IRGen/witness_method_phi.sil @@ -0,0 +1,16 @@ +// RUN: %target-swift-frontend -emit-ir %s | FileCheck %s + +sil_stage canonical + +protocol P { func foo() } +// CHECK-LABEL: define{{( protected)?}} void @phi_witness_method(%swift.type* %T, i8** %T.P) #0 { +sil @phi_witness_method : $@convention(thin) () -> () { +entry: + %1 = witness_method $T, #P.foo!1 : $@convention(witness_method) (@in P) -> () + br bb1(%1 : $@convention(witness_method) (@in P) -> ()) + +// CHECK: phi i8* [ %0, %entry ] +// CHECK-NEXT: phi i8** [ %T.P, %entry ] +bb1(%2 : $@convention(witness_method) (@in P) -> ()): + unreachable +}