From 2726267f094a0c1f5ac5b501ec5a9898c58876bf Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Thu, 20 Jan 2011 17:19:02 +0000 Subject: [PATCH] apple kext abi requires all vf calls, including qualified vf calls, be made indirect. This patch is towards that goal. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@123922 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGCXX.cpp | 29 ++++++++++++++++++++++ lib/CodeGen/CGExprCXX.cpp | 17 ++++++++++--- lib/CodeGen/CodeGenFunction.h | 4 +++ test/CodeGenCXX/apple-kext-indirect-call.C | 15 +++++++++++ 4 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 test/CodeGenCXX/apple-kext-indirect-call.C diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index bb217fbcc9..b6381de027 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -306,6 +306,35 @@ CodeGenFunction::BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *This, return ::BuildVirtualCall(*this, VTableIndex, This, Ty); } +/// BuildVirtualCall - This routine is to support gcc's kext ABI making +/// indirect call to virtual functions. It makes the call through indexing +/// into the vtable. +llvm::Value * +CodeGenFunction::BuildAppleKextVirtualCall(const CXXMethodDecl *MD, + NestedNameSpecifier *Qual, + llvm::Value *This, + const llvm::Type *Ty) { + llvm::Value *VTable = 0; + assert((Qual->getKind() == NestedNameSpecifier::TypeSpec) && + "BuildAppleKextVirtualCall - bad Qual kind"); + + const Type *QTy = Qual->getAsType(); + QualType T = QualType(QTy, 0); + const RecordType *RT = T->getAs(); + assert(RT && "BuildAppleKextVirtualCall - Qual type must be record"); + const CXXRecordDecl *RD = cast(RT->getDecl()); + VTable = CGM.getVTables().GetAddrOfVTable(RD); + Ty = Ty->getPointerTo()->getPointerTo(); + VTable = Builder.CreateBitCast(VTable, Ty); + assert(VTable && "BuildVirtualCall = kext vtbl pointer is null"); + MD = MD->getCanonicalDecl(); + uint64_t VTableIndex = CGM.getVTables().getMethodVTableIndex(MD); + VTableIndex += 2; + llvm::Value *VFuncPtr = + CGF.Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfnkxt"); + return CGF.Builder.CreateLoad(VFuncPtr); +} + llvm::Value * CodeGenFunction::BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type, llvm::Value *This, const llvm::Type *Ty) { diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index 01d671a2d9..08ff17e1fd 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -172,8 +172,12 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, // // We also don't emit a virtual call if the base expression has a record type // because then we know what the type is. - bool UseVirtualCall = MD->isVirtual() && !ME->hasQualifier() + bool UseVirtualCall; + if (!getContext().getLangOptions().AppleKext) + UseVirtualCall = MD->isVirtual() && !ME->hasQualifier() && !canDevirtualizeMemberFunctionCalls(ME->getBase(), MD); + else + UseVirtualCall = MD->isVirtual(); llvm::Value *Callee; if (const CXXDestructorDecl *Dtor = dyn_cast(MD)) { @@ -186,7 +190,12 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, dyn_cast(MD)) { Callee = CGM.GetAddrOfFunction(GlobalDecl(Ctor, Ctor_Complete), Ty); } else if (UseVirtualCall) { - Callee = BuildVirtualCall(MD, This, Ty); + if (getContext().getLangOptions().AppleKext && + ME->hasQualifier()) { + Callee = BuildAppleKextVirtualCall(MD, ME->getQualifier(), This, Ty); + } + else + Callee = BuildVirtualCall(MD, This, Ty); } else { Callee = CGM.GetAddrOfFunction(MD, Ty); } @@ -267,7 +276,9 @@ CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E, CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), FPT->isVariadic()); llvm::Value *Callee; - if (MD->isVirtual() && !canDevirtualizeMemberFunctionCalls(E->getArg(0), MD)) + if (MD->isVirtual() && + (getContext().getLangOptions().AppleKext || + !canDevirtualizeMemberFunctionCalls(E->getArg(0), MD))) Callee = BuildVirtualCall(MD, This, Ty); else Callee = CGM.GetAddrOfFunction(MD, Ty); diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 5f21d9fa43..7686b33365 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -1500,6 +1500,10 @@ public: const llvm::Type *Ty); llvm::Value *BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type, llvm::Value *This, const llvm::Type *Ty); + llvm::Value *BuildAppleKextVirtualCall(const CXXMethodDecl *MD, + NestedNameSpecifier *Qual, + llvm::Value *This, + const llvm::Type *Ty); RValue EmitCXXMemberCall(const CXXMethodDecl *MD, llvm::Value *Callee, diff --git a/test/CodeGenCXX/apple-kext-indirect-call.C b/test/CodeGenCXX/apple-kext-indirect-call.C new file mode 100644 index 0000000000..401e743305 --- /dev/null +++ b/test/CodeGenCXX/apple-kext-indirect-call.C @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fapple-kext -emit-llvm -o - %s | FileCheck %s + +struct Base { + virtual void abc1(void) const; + virtual void abc2(void) const; + virtual void abc(void) const; +}; + +void Base::abc(void) const {} + +void FUNC(Base* p) { + p->Base::abc(); +} + +// CHECK-NOT: call void @_ZNK4Base3abcEv