From 0e20f76d4500b95b90f6652d3c7781303a2a340c Mon Sep 17 00:00:00 2001 From: Parker Schuh Date: Wed, 14 Aug 2019 14:51:22 -0700 Subject: [PATCH] Add cxx_virtual_method instruction. --- include/swift/SIL/SILBuilder.h | 8 +++ include/swift/SIL/SILCloner.h | 11 ++++ include/swift/SIL/SILInstruction.h | 60 ++++++++++++++++++ include/swift/SIL/SILNodes.def | 11 ++-- lib/IRGen/GenCall.cpp | 20 ++++-- lib/IRGen/IRGenSIL.cpp | 63 +++++++++++++------ lib/IRGen/Signature.h | 6 ++ lib/ParseSIL/ParseSIL.cpp | 4 ++ lib/SIL/OperandOwnership.cpp | 1 + lib/SIL/SILDeclRef.cpp | 16 +++-- lib/SIL/SILInstructions.cpp | 22 +++++++ lib/SIL/SILPrinter.cpp | 6 ++ lib/SIL/ValueOwnership.cpp | 46 ++++---------- lib/SILGen/SILGenApply.cpp | 49 ++++++++------- lib/SILOptimizer/Utils/SILInliner.cpp | 1 + lib/Serialization/DeserializeSIL.cpp | 6 ++ lib/Serialization/SerializeSIL.cpp | 19 ++++++ .../Inputs/custom-modules/cxx_interop.h | 5 ++ test/ClangImporter/cxx_interop.sil | 42 +++++++++++++ test/ClangImporter/cxx_interop_ir.swift | 13 ++++ test/ClangImporter/cxx_interop_sil.swift | 15 +++++ test/IRGen/Inputs/abi/cxx_module.h | 6 ++ test/IRGen/Inputs/abi/module.map | 1 + test/IRGen/cxx_virtual_method.sil | 24 +++++++ 24 files changed, 369 insertions(+), 86 deletions(-) create mode 100644 test/ClangImporter/cxx_interop.sil create mode 100644 test/ClangImporter/cxx_interop_sil.swift create mode 100644 test/IRGen/Inputs/abi/cxx_module.h create mode 100644 test/IRGen/cxx_virtual_method.sil diff --git a/include/swift/SIL/SILBuilder.h b/include/swift/SIL/SILBuilder.h index 6ff0db2be36de..da32fb33ed2af 100644 --- a/include/swift/SIL/SILBuilder.h +++ b/include/swift/SIL/SILBuilder.h @@ -1472,6 +1472,14 @@ class SILBuilder { getSILDebugLocation(Loc), Operand, Member, MethodTy)); } + CXXVirtualMethodInst *createCXXVirtualMethod(SILLocation Loc, + SILValue Operand, + SILDeclRef Member, + SILType MethodTy) { + return insert(CXXVirtualMethodInst::create(getSILDebugLocation(Loc), + Operand, Member, MethodTy)); + } + WitnessMethodInst *createWitnessMethod(SILLocation Loc, CanType LookupTy, ProtocolConformanceRef Conformance, SILDeclRef Member, SILType MethodTy) { diff --git a/include/swift/SIL/SILCloner.h b/include/swift/SIL/SILCloner.h index f6b357ea30dda..817c9cb7a54be 100644 --- a/include/swift/SIL/SILCloner.h +++ b/include/swift/SIL/SILCloner.h @@ -2023,6 +2023,17 @@ SILCloner::visitObjCSuperMethodInst(ObjCSuperMethodInst *Inst) { Inst->getMember(), Inst->getType())); } +template +void SILCloner::visitCXXVirtualMethodInst( + CXXVirtualMethodInst *Inst) { + getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope())); + recordClonedInstruction( + Inst, + getBuilder().createCXXVirtualMethod( + getOpLocation(Inst->getLoc()), getOpValue(Inst->getOperand()), + Inst->getMember(), getOpType(Inst->getExtractedMethod()->getType()))); +} + template void SILCloner::visitWitnessMethodInst(WitnessMethodInst *Inst) { diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h index 15f7552c1dc1d..e442716cf3715 100644 --- a/include/swift/SIL/SILInstruction.h +++ b/include/swift/SIL/SILInstruction.h @@ -5881,6 +5881,66 @@ class ObjCSuperMethodInst : UnaryInstructionBase(DebugLoc, Operand, Ty, Member) {} }; +/// This is either the extracted method or the adjusted this ptr that +/// is the result of a CXXVirtualMethodInst. +class CXXVirtualMethodInst; +class CXXVirtualMethodResult final : public MultipleValueInstructionResult { +public: + CXXVirtualMethodResult(unsigned index, SILType type, + ValueOwnershipKind ownershipKind) + : MultipleValueInstructionResult(ValueKind::CXXVirtualMethodResult, index, + type, ownershipKind) {} + + CXXVirtualMethodInst *getParent(); // inline below + const CXXVirtualMethodInst *getParent() const { + return const_cast(this)->getParent(); + } + + bool isExtractedMethod() const { return getIndex() == 0; } + bool isAdjustedThisPtr() const { return getIndex() == 1; } + + static bool classof(const SILNode *N) { + return N->getKind() == SILNodeKind::CXXVirtualMethodResult; + } +}; + +/// Represents looking up a virtual method from a c++ virtual method table and +/// adjusting the this pointer. +class CXXVirtualMethodInst final + : public UnaryInstructionBase, + public MultipleValueInstructionTrailingObjects { + SILDeclRef Member; + friend SILBuilder; + + template friend class llvm::TrailingObjects; + using MultipleValueInstructionTrailingObjects::numTrailingObjects; + + using MultipleValueInstructionTrailingObjects::getTrailingObjects; + + CXXVirtualMethodInst(SILDebugLocation debugLoc, SILValue ThisPtr, + SILDeclRef Member, SILType Ty); + + static CXXVirtualMethodInst *create(SILDebugLocation debugLoc, + SILValue ThisPtr, SILDeclRef Member, + SILType Ty); + +public: + using MultipleValueInstructionTrailingObjects::totalSizeToAlloc; + + SILDeclRef getMember() const { return Member; } + + SILValue getExtractedMethod() const { return &getAllResultsBuffer().front(); } + + SILValue getAdjustedThisPtr() const { return &getAllResultsBuffer().back(); } +}; + +inline CXXVirtualMethodInst *CXXVirtualMethodResult::getParent() { + auto *Parent = MultipleValueInstructionResult::getParent(); + return cast(Parent); +} + /// WitnessMethodInst - Given a type, a protocol conformance, /// and a protocol method constant, extracts the implementation of that method /// for the type. diff --git a/include/swift/SIL/SILNodes.def b/include/swift/SIL/SILNodes.def index e347415a21719..6890271d28b37 100644 --- a/include/swift/SIL/SILNodes.def +++ b/include/swift/SIL/SILNodes.def @@ -415,7 +415,8 @@ ABSTRACT_VALUE(MultipleValueInstructionResult, ValueBase) MULTIPLE_VALUE_INST_RESULT(BeginApplyResult, MultipleValueInstructionResult) MULTIPLE_VALUE_INST_RESULT(DestructureStructResult, MultipleValueInstructionResult) MULTIPLE_VALUE_INST_RESULT(DestructureTupleResult, MultipleValueInstructionResult) - VALUE_RANGE(MultipleValueInstructionResult, BeginApplyResult, DestructureTupleResult) + MULTIPLE_VALUE_INST_RESULT(CXXVirtualMethodResult, MultipleValueInstructionResult) + VALUE_RANGE(MultipleValueInstructionResult, BeginApplyResult, CXXVirtualMethodResult) VALUE(SILUndef, ValueBase) @@ -855,10 +856,12 @@ MULTIPLE_VALUE_INST(DestructureStructInst, destructure_struct, MultipleValueInstruction, None, DoesNotRelease) MULTIPLE_VALUE_INST(DestructureTupleInst, destructure_tuple, MultipleValueInstruction, None, DoesNotRelease) -INST_RANGE(MultipleValueInstruction, BeginApplyInst, DestructureTupleInst) +MULTIPLE_VALUE_INST(CXXVirtualMethodInst, cxx_virtual_method, + MultipleValueInstruction, None, DoesNotRelease) +INST_RANGE(MultipleValueInstruction, BeginApplyInst, CXXVirtualMethodInst) -NODE_RANGE(SILInstruction, AllocStackInst, DestructureTupleInst) -NODE_RANGE(SILNode, SILPhiArgument, DestructureTupleInst) +NODE_RANGE(SILInstruction, AllocStackInst, CXXVirtualMethodInst) +NODE_RANGE(SILNode, SILPhiArgument, CXXVirtualMethodInst) #undef SINGLE_VALUE_INST_RANGE #undef INST_RANGE diff --git a/lib/IRGen/GenCall.cpp b/lib/IRGen/GenCall.cpp index c996d87679e4f..dd18b3c6a9d8f 100644 --- a/lib/IRGen/GenCall.cpp +++ b/lib/IRGen/GenCall.cpp @@ -247,7 +247,7 @@ namespace { /// function type. void expandCoroutineContinuationType(); - Signature getSignature(); + Signature getSignature(llvm::FunctionType *llvmType = nullptr); private: void expand(SILParameterInfo param); @@ -1424,10 +1424,11 @@ void SignatureExpansion::expandCoroutineContinuationType() { expandCoroutineContinuationParameters(); } -Signature SignatureExpansion::getSignature() { +Signature SignatureExpansion::getSignature(llvm::FunctionType *llvmType) { // Create the appropriate LLVM type. - llvm::FunctionType *llvmType = - llvm::FunctionType::get(ResultIRType, ParamIRTypes, /*variadic*/ false); + if (!llvmType) + llvmType = + llvm::FunctionType::get(ResultIRType, ParamIRTypes, /*variadic*/ false); assert((ForeignInfo.ClangInfo != nullptr) == (FnType->getLanguage() == SILFunctionLanguage::C) && @@ -1470,6 +1471,17 @@ Signature Signature::forCoroutineContinuation(IRGenModule &IGM, return expansion.getSignature(); } +Signature Signature::forCXXMethod(IRGenModule &IGM, + const clang::CXXMethodDecl *decl, + CanSILFunctionType fnType) { + SignatureExpansion expansion(IGM, fnType); + expansion.ForeignInfo.ClangInfo = + &clang::CodeGen::arrangeCXXMethodDeclaration(IGM.getClangCGM(), decl); + llvm::FunctionType *Ty = clang::CodeGen::getFunctionType( + IGM.getClangCGM(), *expansion.ForeignInfo.ClangInfo); + return expansion.getSignature(Ty); +} + void irgen::extractScalarResults(IRGenFunction &IGF, llvm::Type *bodyType, llvm::Value *call, Explosion &out) { assert(!bodyType->isVoidTy() && "Unexpected void result type!"); diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp index ca8bb648bb413..2b0c78b7fd920 100644 --- a/lib/IRGen/IRGenSIL.cpp +++ b/lib/IRGen/IRGenSIL.cpp @@ -16,32 +16,18 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "irgensil" -#include "llvm/IR/DIBuilder.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/IntrinsicInst.h" -#include "llvm/IR/InlineAsm.h" -#include "llvm/IR/Intrinsics.h" -#include "llvm/ADT/MapVector.h" -#include "llvm/ADT/SmallBitVector.h" -#include "llvm/ADT/TinyPtrVector.h" -#include "llvm/Support/SaveAndRestore.h" -#include "llvm/Support/Debug.h" -#include "llvm/Transforms/Utils/Local.h" -#include "clang/AST/ASTContext.h" -#include "clang/Basic/TargetInfo.h" -#include "swift/Basic/ExternalUnion.h" -#include "swift/Basic/Range.h" -#include "swift/Basic/STLExtras.h" #include "swift/AST/ASTContext.h" #include "swift/AST/IRGenOptions.h" -#include "swift/AST/Pattern.h" #include "swift/AST/ParameterList.h" +#include "swift/AST/Pattern.h" #include "swift/AST/SubstitutionMap.h" #include "swift/AST/Types.h" +#include "swift/Basic/ExternalUnion.h" +#include "swift/Basic/Range.h" +#include "swift/Basic/STLExtras.h" #include "swift/SIL/ApplySite.h" #include "swift/SIL/Dominance.h" +#include "swift/SIL/InstructionUtils.h" #include "swift/SIL/PrettyStackTrace.h" #include "swift/SIL/SILDebugScope.h" #include "swift/SIL/SILDeclRef.h" @@ -49,8 +35,24 @@ #include "swift/SIL/SILModule.h" #include "swift/SIL/SILType.h" #include "swift/SIL/SILVisitor.h" -#include "swift/SIL/InstructionUtils.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclCXX.h" +#include "clang/Basic/TargetInfo.h" #include "clang/CodeGen/CodeGenABITypes.h" +#include "clang/CodeGen/SwiftCallingConv.h" +#include "llvm/ADT/MapVector.h" +#include "llvm/ADT/SmallBitVector.h" +#include "llvm/ADT/TinyPtrVector.h" +#include "llvm/IR/DIBuilder.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/InlineAsm.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/SaveAndRestore.h" +#include "llvm/Transforms/Utils/Local.h" #include "CallEmission.h" #include "Explosion.h" @@ -990,6 +992,7 @@ class IRGenSILFunction : void visitSuperMethodInst(SuperMethodInst *i); void visitObjCMethodInst(ObjCMethodInst *i); void visitObjCSuperMethodInst(ObjCSuperMethodInst *i); + void visitCXXVirtualMethodInst(CXXVirtualMethodInst *i); void visitWitnessMethodInst(WitnessMethodInst *i); void visitAllocValueBufferInst(AllocValueBufferInst *i); @@ -5589,6 +5592,26 @@ void IRGenSILFunction::visitObjCMethodInst(swift::ObjCMethodInst *i) { setLoweredObjCMethod(i, i->getMember()); } +void IRGenSILFunction::visitCXXVirtualMethodInst(CXXVirtualMethodInst *i) { + auto *cxxMethod = cast( + i->getMember().getAbstractFunctionDecl()->getClangDecl()); + + auto signature = Signature::forCXXMethod( + IGM, cxxMethod, + i->getExtractedMethod()->getType().castTo()); + + auto selfAddress = getLoweredAddress(i->getOperand()); + llvm::Value *self = selfAddress.getAddress(); + + auto *result = clang::CodeGen::swiftcall::lowerCXXVirtualMethodDeclReference( + IGM.getClangCGM(), cxxMethod, self, + selfAddress.getAlignment().asCharUnits(), signature.getType(), &Builder); + + setLoweredValue(i->getExtractedMethod(), FunctionPointer(result, signature)); + selfAddress = Address(self, selfAddress.getAlignment()); + setLoweredAddress(i->getAdjustedThisPtr(), selfAddress); +} + void IRGenModule::emitSILStaticInitializers() { SmallVector StaticInitializers; for (SILGlobalVariable &Global : getSILModule().getSILGlobals()) { diff --git a/lib/IRGen/Signature.h b/lib/IRGen/Signature.h index 82971980440af..ceb72af88fca5 100644 --- a/lib/IRGen/Signature.h +++ b/lib/IRGen/Signature.h @@ -31,6 +31,7 @@ namespace clang { namespace CodeGen { class CGFunctionInfo; } + class CXXMethodDecl; } namespace swift { @@ -126,6 +127,11 @@ class Signature { static Signature forCoroutineContinuation(IRGenModule &IGM, CanSILFunctionType coroType); + /// Compute the singature of a C++ method. + static Signature forCXXMethod(IRGenModule &IGM, + const clang::CXXMethodDecl *decl, + CanSILFunctionType fnType); + llvm::FunctionType *getType() const { assert(isValid()); return Type; diff --git a/lib/ParseSIL/ParseSIL.cpp b/lib/ParseSIL/ParseSIL.cpp index 5ac4f6608dbd1..5225d6373b0f6 100644 --- a/lib/ParseSIL/ParseSIL.cpp +++ b/lib/ParseSIL/ParseSIL.cpp @@ -4243,6 +4243,7 @@ bool SILParser::parseSILInstruction(SILBuilder &B) { case SILInstructionKind::ClassMethodInst: case SILInstructionKind::SuperMethodInst: case SILInstructionKind::ObjCMethodInst: + case SILInstructionKind::CXXVirtualMethodInst: case SILInstructionKind::ObjCSuperMethodInst: { SILDeclRef Member; SILType MethodTy; @@ -4274,6 +4275,9 @@ bool SILParser::parseSILInstruction(SILBuilder &B) { case SILInstructionKind::ObjCSuperMethodInst: ResultVal = B.createObjCSuperMethod(InstLoc, Val, Member, MethodTy); break; + case SILInstructionKind::CXXVirtualMethodInst: + ResultVal = B.createCXXVirtualMethod(InstLoc, Val, Member, MethodTy); + break; } break; } diff --git a/lib/SIL/OperandOwnership.cpp b/lib/SIL/OperandOwnership.cpp index f046c1dbbb808..0b8d970798d80 100644 --- a/lib/SIL/OperandOwnership.cpp +++ b/lib/SIL/OperandOwnership.cpp @@ -280,6 +280,7 @@ ACCEPTS_ANY_NONTRIVIAL_OWNERSHIP_OR_METATYPE(MustBeLive, ClassMethod) ACCEPTS_ANY_NONTRIVIAL_OWNERSHIP_OR_METATYPE(MustBeLive, ObjCMethod) ACCEPTS_ANY_NONTRIVIAL_OWNERSHIP_OR_METATYPE(MustBeLive, ObjCSuperMethod) ACCEPTS_ANY_NONTRIVIAL_OWNERSHIP_OR_METATYPE(MustBeLive, SuperMethod) +ACCEPTS_ANY_NONTRIVIAL_OWNERSHIP_OR_METATYPE(MustBeLive, CXXVirtualMethod) #undef ACCEPTS_ANY_NONTRIVIAL_OWNERSHIP_OR_METATYPE // Trivial if trivial typed, otherwise must accept owned? diff --git a/lib/SIL/SILDeclRef.cpp b/lib/SIL/SILDeclRef.cpp index 3c088226ca21f..87f575b99502e 100644 --- a/lib/SIL/SILDeclRef.cpp +++ b/lib/SIL/SILDeclRef.cpp @@ -11,20 +11,21 @@ //===----------------------------------------------------------------------===// #include "swift/SIL/SILDeclRef.h" -#include "swift/SIL/SILLocation.h" -#include "swift/AST/AnyFunctionRef.h" #include "swift/AST/ASTContext.h" #include "swift/AST/ASTMangler.h" +#include "swift/AST/AnyFunctionRef.h" #include "swift/AST/Initializer.h" #include "swift/AST/ParameterList.h" #include "swift/ClangImporter/ClangImporter.h" #include "swift/ClangImporter/ClangModule.h" #include "swift/SIL/SILLinkage.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/raw_ostream.h" +#include "swift/SIL/SILLocation.h" #include "clang/AST/Attr.h" #include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/raw_ostream.h" using namespace swift; /// Get the method dispatch mechanism for a method. @@ -34,6 +35,13 @@ swift::getMethodDispatch(AbstractFunctionDecl *method) { if (method->hasForcedStaticDispatch()) return MethodDispatch::Static; + if (auto *mdecl = + dyn_cast_or_null(method->getClangDecl())) { + if (mdecl->isVirtual()) { + return MethodDispatch::Class; + } + } + // Import-as-member declarations are always statically referenced. if (method->isImportAsMember()) return MethodDispatch::Static; diff --git a/lib/SIL/SILInstructions.cpp b/lib/SIL/SILInstructions.cpp index 3abde025ccdce..b65a410eb41a2 100644 --- a/lib/SIL/SILInstructions.cpp +++ b/lib/SIL/SILInstructions.cpp @@ -1715,6 +1715,28 @@ ObjCMethodInst::create(SILDebugLocation DebugLoc, SILValue Operand, Member, Ty); } +CXXVirtualMethodInst::CXXVirtualMethodInst(SILDebugLocation DebugLoc, + SILValue Operand, SILDeclRef Member, + SILType Ty) + : UnaryInstructionBase(DebugLoc, Operand), + MultipleValueInstructionTrailingObjects( + this, {Ty, Operand->getType()}, + { /* extracted method */ ValueOwnershipKind::Any, + /* adjusted this */ ValueOwnershipKind::Any}), + Member(Member) {} + +CXXVirtualMethodInst *CXXVirtualMethodInst::create(SILDebugLocation DebugLoc, + SILValue Operand, + SILDeclRef Member, + SILType Ty) { + SILModule *Mod = Operand->getModule(); + unsigned size = + totalSizeToAlloc(1, + 2); + void *Buffer = Mod->allocateInst(size, alignof(CXXVirtualMethodInst)); + return ::new (Buffer) CXXVirtualMethodInst(DebugLoc, Operand, Member, Ty); +} + InitExistentialAddrInst *InitExistentialAddrInst::create( SILDebugLocation Loc, SILValue Existential, CanType ConcreteType, SILType ConcreteLoweredType, ArrayRef Conformances, diff --git a/lib/SIL/SILPrinter.cpp b/lib/SIL/SILPrinter.cpp index 233b01ca85813..f8136bd1e4fba 100644 --- a/lib/SIL/SILPrinter.cpp +++ b/lib/SIL/SILPrinter.cpp @@ -1693,6 +1693,12 @@ class SILPrinter : public SILInstructionVisitor { *this << ", "; *this << AMI->getType(); } + void visitCXXVirtualMethodInst(CXXVirtualMethodInst *CXXVMI) { + *this << getIDAndType(CXXVMI->getOperand()) << ", " << CXXVMI->getMember(); + *this << " : " << CXXVMI->getMember().getDecl()->getInterfaceType(); + *this << ", "; + *this << CXXVMI->getExtractedMethod()->getType(); + } void visitWitnessMethodInst(WitnessMethodInst *WMI) { PrintOptions QualifiedSILTypeOptions = PrintOptions::printQualifiedSILType(); diff --git a/lib/SIL/ValueOwnership.cpp b/lib/SIL/ValueOwnership.cpp index 165195a3da557..73fd41547851c 100644 --- a/lib/SIL/ValueOwnership.cpp +++ b/lib/SIL/ValueOwnership.cpp @@ -232,11 +232,12 @@ ValueOwnershipKindClassifier::visitForwardingInst(SILInstruction *i, return mergedValue.getValue(); } -#define FORWARDING_OWNERSHIP_INST(INST) \ - ValueOwnershipKind ValueOwnershipKindClassifier::visit##INST##Inst( \ - INST##Inst *I) { \ - return I->getOwnershipKind(); \ +#define FORWARDING_OWNERSHIP(VALUE) \ + ValueOwnershipKind ValueOwnershipKindClassifier::visit##VALUE( \ + VALUE *v) { \ + return v->getOwnershipKind(); \ } +#define FORWARDING_OWNERSHIP_INST(INST) FORWARDING_OWNERSHIP(INST##Inst) FORWARDING_OWNERSHIP_INST(BridgeObjectToRef) FORWARDING_OWNERSHIP_INST(ConvertFunction) FORWARDING_OWNERSHIP_INST(OpenExistentialRef) @@ -252,7 +253,15 @@ FORWARDING_OWNERSHIP_INST(MarkUninitialized) FORWARDING_OWNERSHIP_INST(UncheckedEnumData) FORWARDING_OWNERSHIP_INST(SelectEnum) FORWARDING_OWNERSHIP_INST(Enum) +FORWARDING_OWNERSHIP(SILUndef) +FORWARDING_OWNERSHIP(SILPhiArgument) +FORWARDING_OWNERSHIP(DestructureStructResult) +FORWARDING_OWNERSHIP(DestructureTupleResult) +FORWARDING_OWNERSHIP(BeginApplyResult) +FORWARDING_OWNERSHIP(CXXVirtualMethodResult) +FORWARDING_OWNERSHIP(SILFunctionArgument) #undef FORWARDING_OWNERSHIP_INST +#undef FORWARDING_OWNERSHIP ValueOwnershipKind ValueOwnershipKindClassifier::visitUncheckedOwnershipConversionInst( @@ -260,35 +269,6 @@ ValueOwnershipKindClassifier::visitUncheckedOwnershipConversionInst( return I->getConversionOwnershipKind(); } -ValueOwnershipKind ValueOwnershipKindClassifier::visitSILUndef(SILUndef *arg) { - return arg->getOwnershipKind(); -} - -ValueOwnershipKind -ValueOwnershipKindClassifier::visitSILPhiArgument(SILPhiArgument *Arg) { - return Arg->getOwnershipKind(); -} - -ValueOwnershipKind ValueOwnershipKindClassifier::visitDestructureStructResult( - DestructureStructResult *Result) { - return Result->getOwnershipKind(); -} - -ValueOwnershipKind ValueOwnershipKindClassifier::visitDestructureTupleResult( - DestructureTupleResult *Result) { - return Result->getOwnershipKind(); -} - -ValueOwnershipKind ValueOwnershipKindClassifier::visitBeginApplyResult( - BeginApplyResult *Result) { - return Result->getOwnershipKind(); -} - -ValueOwnershipKind ValueOwnershipKindClassifier::visitSILFunctionArgument( - SILFunctionArgument *Arg) { - return Arg->getOwnershipKind(); -} - // This is a forwarding instruction through only one of its arguments. ValueOwnershipKind ValueOwnershipKindClassifier::visitMarkDependenceInst(MarkDependenceInst *MDI) { diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp index 9adf84323a721..52352894b11cf 100644 --- a/lib/SILGen/SILGenApply.cpp +++ b/lib/SILGen/SILGenApply.cpp @@ -569,7 +569,16 @@ class Callee { } ManagedValue getFnValue(SILGenFunction &SGF, bool isCurried, - Optional borrowedSelf) const & { + ArrayRef args, + ImportAsMemberStatus foreignSelf) const & { + Optional borrowedSelf; + if (requiresSelfValueForDispatch()) { + if (foreignSelf.isInstance()) { + borrowedSelf = args[foreignSelf.getSelfIndex()]; + } else { + borrowedSelf = args.back(); + } + } Optional constant = None; if (!Constant) { @@ -612,9 +621,18 @@ class Callee { methodVal = SGF.emitClassMethodRef( Loc, borrowedSelf->getValue(), *constant, methodTy); } else { - methodVal = SGF.B.createObjCMethod( - Loc, borrowedSelf->getValue(), *constant, - SILType::getPrimitiveObjectType(methodTy)); + if (constant->getAbstractFunctionDecl()->isObjC()) { + methodVal = + SGF.B.createObjCMethod(Loc, borrowedSelf->getValue(), *constant, + SILType::getPrimitiveObjectType(methodTy)); + } else { + // TODO: Update borrowedSelf with the updated self-pointer... + methodVal = SGF.B + .createCXXVirtualMethod( + Loc, borrowedSelf->getValue(), *constant, + SILType::getPrimitiveObjectType(methodTy)) + ->getExtractedMethod(); + } } S.pop(); return ManagedValue::forUnmanaged(methodVal); @@ -3721,12 +3739,8 @@ CallEmission::applyCoroutine(SmallVectorImpl &yields) { uncurriedLoc, formalApplyType); // Now evaluate the callee. - Optional borrowedSelf; - if (callee.requiresSelfValueForDispatch()) { - borrowedSelf = uncurriedArgs.back(); - } - - auto fnValue = callee.getFnValue(SGF, isCurried, borrowedSelf); + auto fnValue = callee.getFnValue(SGF, isCurried, uncurriedArgs, + calleeTypeInfo.foreignSelf); return SGF.emitBeginApply(uncurriedLoc.getValue(), fnValue, callee.getSubstitutions(), uncurriedArgs, @@ -3844,12 +3858,8 @@ CallEmission::applyNormalCall(SGFContext C) { uncurriedLoc, formalApplyType); // Now evaluate the callee. - Optional borrowedSelf; - if (callee.requiresSelfValueForDispatch()) { - borrowedSelf = uncurriedArgs.back(); - } - - auto mv = callee.getFnValue(SGF, isCurried, borrowedSelf); + auto mv = callee.getFnValue(SGF, isCurried, uncurriedArgs, + calleeTypeInfo.foreignSelf); // Emit the uncurried call. firstLevelResult.value = SGF.emitApply( @@ -4758,11 +4768,8 @@ SILGenFunction::emitApplyOfLibraryIntrinsic(SILLocation loc, auto calleeTypeInfo = callee.getTypeInfo(*this, /*isCurried=*/false); - Optional borrowedSelf; - if (callee.requiresSelfValueForDispatch()) - borrowedSelf = args.back(); - auto mv = callee.getFnValue(*this, /*isCurried=*/false, - borrowedSelf); + auto mv = callee.getFnValue(*this, /*isCurried=*/false, args, + calleeTypeInfo.foreignSelf); assert(!calleeTypeInfo.foreignError); assert(!calleeTypeInfo.foreignSelf.isImportAsMember()); diff --git a/lib/SILOptimizer/Utils/SILInliner.cpp b/lib/SILOptimizer/Utils/SILInliner.cpp index 3642f013c7a90..00776b471e4f6 100644 --- a/lib/SILOptimizer/Utils/SILInliner.cpp +++ b/lib/SILOptimizer/Utils/SILInliner.cpp @@ -771,6 +771,7 @@ InlineCost swift::instructionInlineCost(SILInstruction &I) { case SILInstructionKind::CheckedCastAddrBranchInst: case SILInstructionKind::ClassMethodInst: case SILInstructionKind::ObjCMethodInst: + case SILInstructionKind::CXXVirtualMethodInst: case SILInstructionKind::CondBranchInst: case SILInstructionKind::CondFailInst: case SILInstructionKind::CopyBlockInst: diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp index c24bbf76a7277..dc4e8e02d18b6 100644 --- a/lib/Serialization/DeserializeSIL.cpp +++ b/lib/Serialization/DeserializeSIL.cpp @@ -2197,6 +2197,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, case SILInstructionKind::ClassMethodInst: case SILInstructionKind::SuperMethodInst: case SILInstructionKind::ObjCMethodInst: + case SILInstructionKind::CXXVirtualMethodInst: case SILInstructionKind::ObjCSuperMethodInst: { // Format: a type, an operand and a SILDeclRef. Use SILOneTypeValuesLayout: // type, Attr, SILDeclRef (DeclID, Kind, uncurryLevel), and an operand. @@ -2231,6 +2232,11 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, getLocalValue(ListOfValues[NextValueIndex], operandTy), DRef, Ty); break; + case SILInstructionKind::CXXVirtualMethodInst: + ResultVal = Builder.createCXXVirtualMethod( + Loc, getLocalValue(ListOfValues[NextValueIndex], operandTy), DRef, + Ty); + break; } break; } diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp index 3aa867647c9db..dff5a9240f11f 100644 --- a/lib/Serialization/SerializeSIL.cpp +++ b/lib/Serialization/SerializeSIL.cpp @@ -1888,6 +1888,25 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { UI->hasOperand() ? addValueRef(UI->getOperand()) : ValueID()); break; } + case SILInstructionKind::CXXVirtualMethodInst: { + // Format: a type, an operand and a SILDeclRef. Use SILOneTypeValuesLayout: + // type, Attr, SILDeclRef (DeclID, Kind, uncurryLevel), + // and an operand. + const auto *VMI = cast(&SI); + SILType Ty = VMI->getExtractedMethod()->getType(); + SmallVector ListOfValues; + auto operand = VMI->getOperand(); + handleSILDeclRef(S, VMI->getMember(), ListOfValues); + ListOfValues.push_back(S.addTypeRef(operand->getType().getASTType())); + ListOfValues.push_back((unsigned)operand->getType().getCategory()); + ListOfValues.push_back(addValueRef(operand)); + + SILOneTypeValuesLayout::emitRecord( + Out, ScratchRecord, SILAbbrCodes[SILOneTypeValuesLayout::Code], + (unsigned)SI.getKind(), S.addTypeRef(Ty.getASTType()), + (unsigned)Ty.getCategory(), ListOfValues); + break; + } case SILInstructionKind::WitnessMethodInst: { // Format: a type, an operand and a SILDeclRef. Use SILOneTypeValuesLayout: // type, Attr, SILDeclRef (DeclID, Kind, uncurryLevel, IsObjC), and a type. diff --git a/test/ClangImporter/Inputs/custom-modules/cxx_interop.h b/test/ClangImporter/Inputs/custom-modules/cxx_interop.h index 3b8364c4ae616..9fd24d7c87e6a 100644 --- a/test/ClangImporter/Inputs/custom-modules/cxx_interop.h +++ b/test/ClangImporter/Inputs/custom-modules/cxx_interop.h @@ -38,4 +38,9 @@ class Methods2 { int SimpleMethod(int); }; +class MethodsVirtual { +public: + virtual int SimpleVirtualMethod(int) = 0; +}; + enum __attribute__((enum_extensibility(open))) OpenEmptyEnum : char {}; diff --git a/test/ClangImporter/cxx_interop.sil b/test/ClangImporter/cxx_interop.sil new file mode 100644 index 0000000000000..154fb884a37d8 --- /dev/null +++ b/test/ClangImporter/cxx_interop.sil @@ -0,0 +1,42 @@ +// RUN: %target-swift-frontend -module-name cxx_ir -I %S/Inputs/custom-modules -module-cache-path %t -enable-cxx-interop -emit-ir -o - -primary-file %s | %FileCheck %s + +import Builtin +import Swift +import SwiftShims + +import CXXInterop + +// CHECK-LABEL: define hidden swiftcc i32 @"$call_cxx_virtual_method"(i8*) #0 { +// CHECK: [[THIS_PTR1:%.*]] = bitcast i8* %0 to %TSo14MethodsVirtualV* +// CHECK: [[THIS_PTR2:%.*]] = bitcast %TSo14MethodsVirtualV* [[THIS_PTR1]] to i32 (%class.MethodsVirtual*, i32)*** +// CHECK: [[VTABLE:%.*]] = load i32 (%class.MethodsVirtual*, i32)**, i32 (%class.MethodsVirtual*, i32)*** [[THIS_PTR2]], align 8 +// CHECK: [[VFN_PTR:%.*]] = getelementptr inbounds i32 (%class.MethodsVirtual*, i32)*, i32 (%class.MethodsVirtual*, i32)** [[VTABLE]], i64 0 +// CHECK: [[VFN:%.*]] = load i32 (%class.MethodsVirtual*, i32)*, i32 (%class.MethodsVirtual*, i32)** [[VFN_PTR]], align 8 +// CHECK: [[THIS_PTR3:%.*]] = bitcast %TSo14MethodsVirtualV* [[THIS_PTR1]] to %class.MethodsVirtual* +// CHECK: [[RESULT:%.*]] = call i32{{( signext)?}} [[VFN]](%class.MethodsVirtual* [[THIS_PTR3]], i32{{( signext)?}} 7) +// CHECK: ret i32 [[RESULT]] +sil hidden [ossa] @$call_cxx_virtual_method : $@convention(thin) (UnsafeMutablePointer) -> Int32 { +bb0(%0 : $UnsafeMutablePointer): + debug_value %0 : $UnsafeMutablePointer, let, name "a", argno 1 // id: %1 + %2 = integer_literal $Builtin.IntLiteral, 7 // user: %5 + %3 = metatype $@thin Int32.Type // user: %5 + // function_ref Int32.init(_builtinIntegerLiteral:) + %4 = function_ref @$ss5Int32V22_builtinIntegerLiteralABBI_tcfC : $@convention(method) (Builtin.IntLiteral, @thin Int32.Type) -> Int32 // user: %5 + %5 = apply %4(%2, %3) : $@convention(method) (Builtin.IntLiteral, @thin Int32.Type) -> Int32 // user: %13 + // function_ref UnsafeMutablePointer.pointee.unsafeMutableAddressor + %6 = function_ref @$sSp7pointeexvau : $@convention(method) <τ_0_0> (UnsafeMutablePointer<τ_0_0>) -> UnsafeMutablePointer<τ_0_0> // user: %7 + %7 = apply %6(%0) : $@convention(method) <τ_0_0> (UnsafeMutablePointer<τ_0_0>) -> UnsafeMutablePointer<τ_0_0> // user: %8 + %8 = struct_extract %7 : $UnsafeMutablePointer, #UnsafeMutablePointer._rawValue // user: %9 + %9 = pointer_to_address %8 : $Builtin.RawPointer to [strict] $*MethodsVirtual // user: %10 + %10 = begin_access [modify] [unsafe] %9 : $*MethodsVirtual // users: %14, %13, %11 + (%11, %12) = cxx_virtual_method %10 : $*MethodsVirtual, #MethodsVirtual.SimpleVirtualMethod!1.foreign : (inout MethodsVirtual) -> (Int32) -> Int32, $@convention(c) (@inout MethodsVirtual, Int32) -> Int32 // user: %13 + %13 = apply %11(%12, %5) : $@convention(c) (@inout MethodsVirtual, Int32) -> Int32 // user: %15 + end_access %10 : $*MethodsVirtual // id: %14 + return %13 : $Int32 // id: %15 +} + +// Int32.init(_builtinIntegerLiteral:) +sil [transparent] [serialized] @$ss5Int32V22_builtinIntegerLiteralABBI_tcfC : $@convention(method) (Builtin.IntLiteral, @thin Int32.Type) -> Int32 + +// UnsafeMutablePointer.pointee.unsafeMutableAddressor +sil [transparent] [serialized] @$sSp7pointeexvau : $@convention(method) <τ_0_0> (UnsafeMutablePointer<τ_0_0>) -> UnsafeMutablePointer<τ_0_0> diff --git a/test/ClangImporter/cxx_interop_ir.swift b/test/ClangImporter/cxx_interop_ir.swift index 59d7a075d6799..eb74e77ed64d7 100644 --- a/test/ClangImporter/cxx_interop_ir.swift +++ b/test/ClangImporter/cxx_interop_ir.swift @@ -63,3 +63,16 @@ func basicMethodsStatic() -> Int32 { func basicMethods(a: UnsafeMutablePointer) -> Int32 { return a.pointee.SimpleMethod(4) } + +// CHECK-LABEL: define hidden swiftcc i32 @"$s6cxx_ir13virtualMethod1as5Int32VSpySo14MethodsVirtualVG_tF"(i8*) #0 { +// CHECK: [[THIS_PTR1:%.*]] = bitcast i8* %0 to %TSo14MethodsVirtualV* +// CHECK: [[THIS_PTR2:%.*]] = bitcast %TSo14MethodsVirtualV* [[THIS_PTR1]] to i32 (%class.MethodsVirtual*, i32)*** +// CHECK: [[VTABLE:%.*]] = load i32 (%class.MethodsVirtual*, i32)**, i32 (%class.MethodsVirtual*, i32)*** [[THIS_PTR2]], align 8 +// CHECK: [[VFN_PTR:%.*]] = getelementptr inbounds i32 (%class.MethodsVirtual*, i32)*, i32 (%class.MethodsVirtual*, i32)** [[VTABLE]], i64 0 +// CHECK: [[VFN:%.*]] = load i32 (%class.MethodsVirtual*, i32)*, i32 (%class.MethodsVirtual*, i32)** [[VFN_PTR]], align 8 +// CHECK: [[THIS_PTR3:%.*]] = bitcast %TSo14MethodsVirtualV* [[THIS_PTR1]] to %class.MethodsVirtual* +// CHECK: [[RESULT:%.*]] = call i32{{( signext)?}} [[VFN]](%class.MethodsVirtual* [[THIS_PTR3]], i32{{( signext)?}} 7) +// CHECK: ret i32 [[RESULT]] +func virtualMethod(a: UnsafeMutablePointer) -> Int32 { + return a.pointee.SimpleVirtualMethod(7); +} diff --git a/test/ClangImporter/cxx_interop_sil.swift b/test/ClangImporter/cxx_interop_sil.swift new file mode 100644 index 0000000000000..42b8392fdfaaa --- /dev/null +++ b/test/ClangImporter/cxx_interop_sil.swift @@ -0,0 +1,15 @@ +// RUN: %target-swift-frontend -module-name cxx_sil -I %S/Inputs/custom-modules -module-cache-path %t -enable-cxx-interop -emit-sil -o - -primary-file %s | %FileCheck %s + +import CXXInterop + +// CHECK-LABEL: sil hidden @$s7cxx_sil13virtualMethod1as5Int32VSpySo14MethodsVirtualVG_tF +// CHECK: [[INT_LIT:%.*]] = integer_literal $Builtin.Int32, 7 +// CHECK: [[INT:%.*]] = struct $Int32 ([[INT_LIT]] : $Builtin.Int32) +// CHECK: [[THIS_PTR:%.*]] = begin_access [modify] [unsafe] {{%.*}} : $*MethodsVirtual +// CHECK: ([[VIRTUAL_METHOD:%.*]], [[THIS_PTR_ADJUST:%.*]]) = cxx_virtual_method [[THIS_PTR]] : $*MethodsVirtual, #MethodsVirtual.SimpleVirtualMethod!1.foreign : (inout MethodsVirtual) -> (Int32) -> Int32, $@convention(c) (@inout MethodsVirtual, Int32) -> Int32 +// TODO: Use adjusted this ptr here... +// CHECK: [[RESULT:%.*]] = apply [[VIRTUAL_METHOD]]([[THIS_PTR]], [[INT]]) : $@convention(c) (@inout MethodsVirtual, Int32) -> Int32 +// CHECK: return [[RESULT]] : $Int32 +func virtualMethod(a: UnsafeMutablePointer) -> Int32 { + return a.pointee.SimpleVirtualMethod(7); +} diff --git a/test/IRGen/Inputs/abi/cxx_module.h b/test/IRGen/Inputs/abi/cxx_module.h new file mode 100644 index 0000000000000..8656d0fcb8fb9 --- /dev/null +++ b/test/IRGen/Inputs/abi/cxx_module.h @@ -0,0 +1,6 @@ +#pragma once + +class MethodsVirtual { + public: + virtual int SimpleVirtualMethod(int) = 0; +}; diff --git a/test/IRGen/Inputs/abi/module.map b/test/IRGen/Inputs/abi/module.map index dd33aa515922b..c3563691d71a6 100644 --- a/test/IRGen/Inputs/abi/module.map +++ b/test/IRGen/Inputs/abi/module.map @@ -1,2 +1,3 @@ module gadget { header "Gadget.h" } module c_layout { header "c_layout.h" } +module cxx_module { header "cxx_module.h" } diff --git a/test/IRGen/cxx_virtual_method.sil b/test/IRGen/cxx_virtual_method.sil new file mode 100644 index 0000000000000..1b9af62a66cf1 --- /dev/null +++ b/test/IRGen/cxx_virtual_method.sil @@ -0,0 +1,24 @@ +// RUN: %target-swift-frontend -module-name cxx_ir -I %S/Inputs/abi -module-cache-path %t -enable-cxx-interop -emit-ir -o - -primary-file %s | %FileCheck %s +sil_stage canonical + +import Builtin +import Swift +import SwiftShims +import cxx_module + +// CHECK-LABEL: define hidden swiftcc i32 @virtual_method(%TSo14MethodsVirtualV* nocapture dereferenceable(8), i32) #0 { +// CHECK: [[THIS_PTR1:%.*]] = bitcast %TSo14MethodsVirtualV* %0 to i32 (%class.MethodsVirtual*, i32)*** +// CHECK: [[VTABLE:%.*]] = load i32 (%class.MethodsVirtual*, i32)**, i32 (%class.MethodsVirtual*, i32)*** %2, align 8 +// CHECK: [[VFN_PTR:%.*]] = getelementptr inbounds i32 (%class.MethodsVirtual*, i32)*, i32 (%class.MethodsVirtual*, i32)** %vtable, i64 0 +// CHECK: [[VFN:%.*]] = load i32 (%class.MethodsVirtual*, i32)*, i32 (%class.MethodsVirtual*, i32)** [[VFN_PTR]], align 8 +// CHECK: [[THIS_PTR2:%.*]] = bitcast %TSo14MethodsVirtualV* %0 to %class.MethodsVirtual* +// CHECK: [[RESULT:%.*]] = call i32 %3(%class.MethodsVirtual* [[THIS_PTR2]], i32 %1) +// CHECK: ret i32 [[RESULT]] +sil hidden @virtual_method : $@convention(thin) (@inout MethodsVirtual, Int32) -> Int32 { +bb0(%0 : $*MethodsVirtual, %1 : $Int32): + %2 = begin_access [modify] [static] %0 : $*MethodsVirtual + (%3, %4) = cxx_virtual_method %2 : $*MethodsVirtual, #MethodsVirtual.SimpleVirtualMethod!1.foreign : (inout MethodsVirtual) -> (Int32) -> Int32, $@convention(c) (@inout MethodsVirtual, Int32) -> Int32 + %5 = apply %3(%4, %1) : $@convention(c) (@inout MethodsVirtual, Int32) -> Int32 + end_access %2 : $*MethodsVirtual + return %5 : $Int32 +}