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
60 changes: 46 additions & 14 deletions lib/IRGen/GenFunc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,9 @@ namespace {
class FuncTypeInfo : public ScalarTypeInfo<FuncTypeInfo, ReferenceTypeInfo>,
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)
{
}
Expand All @@ -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.
Expand Down Expand Up @@ -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);
}

Expand All @@ -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,
Expand All @@ -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 {
Expand All @@ -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 {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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),
Expand All @@ -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");
Expand Down
4 changes: 4 additions & 0 deletions lib/IRGen/IRGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions lib/IRGen/IRGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -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*
Expand Down
4 changes: 2 additions & 2 deletions lib/IRGen/ReferenceTypeInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{}

Expand Down
4 changes: 1 addition & 3 deletions lib/SIL/SILVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2700,9 +2700,7 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
// 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<WitnessMethodInst>(branchArg) &&
!(isa<MethodInst>(branchArg) &&
require(!(isa<MethodInst>(branchArg) &&
cast<MethodInst>(branchArg)->getMember().isForeign),
"branch argument cannot be a witness_method or an objc method_inst");
return branchArg->getType() == bbArg->getType();
Expand Down
6 changes: 4 additions & 2 deletions test/IRGen/function_types.sil
Original file line number Diff line number Diff line change
Expand Up @@ -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) () -> ()):
Expand Down
16 changes: 16 additions & 0 deletions test/IRGen/witness_method_phi.sil
Original file line number Diff line number Diff line change
@@ -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) <T: P> () -> () {
entry:
%1 = witness_method $T, #P.foo!1 : $@convention(witness_method) <T: P> (@in P) -> ()
br bb1(%1 : $@convention(witness_method) <T: P> (@in P) -> ())

// CHECK: phi i8* [ %0, %entry ]
// CHECK-NEXT: phi i8** [ %T.P, %entry ]
bb1(%2 : $@convention(witness_method) <T: P> (@in P) -> ()):
unreachable
}