From: John McCall Date: Sun, 22 Aug 2010 00:05:51 +0000 (+0000) Subject: Extract calls to method pointers out as an ABI routine. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=93d557bc1867b7d7b102f87290194b4be7932c92;p=clang Extract calls to method pointers out as an ABI routine. No functionality change. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@111752 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index edfbe0e72e..7ae83f44b4 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -357,3 +357,25 @@ CodeGenFunction::BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type, } CGCXXABI::~CGCXXABI() {} + +llvm::Value *CGCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, + llvm::Value *&This, + llvm::Value *MemPtr, + const MemberPointerType *MPT) { + Diagnostic &Diags = CGF.CGM.getDiags(); + unsigned DiagID = + Diags.getCustomDiagID(Diagnostic::Error, + "cannot yet compile member pointer calls in this ABI"); + Diags.Report(CGF.getContext().getFullLoc(CGF.CurCodeDecl->getLocation()), + DiagID); + + const FunctionProtoType *FPT = + MPT->getPointeeType()->getAs(); + const CXXRecordDecl *RD = + cast(MPT->getClass()->getAs()->getDecl()); + const llvm::FunctionType *FTy = + CGF.CGM.getTypes().GetFunctionType( + CGF.CGM.getTypes().getFunctionInfo(RD, FPT), + FPT->isVariadic()); + return llvm::Constant::getNullValue(FTy->getPointerTo()); +} diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h index 7df63d38be..7a89a3deac 100644 --- a/lib/CodeGen/CGCXXABI.h +++ b/lib/CodeGen/CGCXXABI.h @@ -15,8 +15,15 @@ #ifndef CLANG_CODEGEN_CXXABI_H #define CLANG_CODEGEN_CXXABI_H +namespace llvm { + class Value; +} + namespace clang { + class MemberPointerType; + namespace CodeGen { + class CodeGenFunction; class CodeGenModule; class MangleContext; @@ -27,12 +34,19 @@ public: /// Gets the mangle context. virtual MangleContext &getMangleContext() = 0; + + virtual llvm::Value * + EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, + llvm::Value *&This, + llvm::Value *MemPtr, + const MemberPointerType *MPT); }; /// Creates an instance of a C++ ABI class. CGCXXABI *CreateARMCXXABI(CodeGenModule &CGM); CGCXXABI *CreateItaniumCXXABI(CodeGenModule &CGM); CGCXXABI *CreateMicrosoftCXXABI(CodeGenModule &CGM); + } } diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index 0faba72a8a..11b6f053b2 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -153,17 +153,12 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E, const MemberPointerType *MPT = MemFnExpr->getType()->getAs(); + const FunctionProtoType *FPT = MPT->getPointeeType()->getAs(); const CXXRecordDecl *RD = cast(MPT->getClass()->getAs()->getDecl()); - const llvm::FunctionType *FTy = - CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(RD, FPT), - FPT->isVariadic()); - - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); - // Get the member function pointer. llvm::Value *MemFnPtr = CreateMemTemp(MemFnExpr->getType(), "mem.fn"); EmitAggExpr(MemFnExpr, MemFnPtr, /*VolatileDest=*/false); @@ -175,67 +170,11 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E, This = EmitScalarExpr(BaseExpr); else This = EmitLValue(BaseExpr).getAddress(); - - // Adjust it. - llvm::Value *Adj = Builder.CreateStructGEP(MemFnPtr, 1); - Adj = Builder.CreateLoad(Adj, "mem.fn.adj"); - - llvm::Value *Ptr = Builder.CreateBitCast(This, Int8PtrTy, "ptr"); - Ptr = Builder.CreateGEP(Ptr, Adj, "adj"); - - This = Builder.CreateBitCast(Ptr, This->getType(), "this"); - - llvm::Value *FnPtr = Builder.CreateStructGEP(MemFnPtr, 0, "mem.fn.ptr"); - - const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType()); - llvm::Value *FnAsInt = Builder.CreateLoad(FnPtr, "fn"); - - // If the LSB in the function pointer is 1, the function pointer points to - // a virtual function. - llvm::Value *IsVirtual - = Builder.CreateAnd(FnAsInt, llvm::ConstantInt::get(PtrDiffTy, 1), - "and"); - - IsVirtual = Builder.CreateTrunc(IsVirtual, - llvm::Type::getInt1Ty(VMContext)); + // Ask the ABI to load the callee. Note that This is modified. + llvm::Value *Callee = + CGM.getCXXABI().EmitLoadOfMemberFunctionPointer(CGF, This, MemFnPtr, MPT); - llvm::BasicBlock *FnVirtual = createBasicBlock("fn.virtual"); - llvm::BasicBlock *FnNonVirtual = createBasicBlock("fn.nonvirtual"); - llvm::BasicBlock *FnEnd = createBasicBlock("fn.end"); - - Builder.CreateCondBr(IsVirtual, FnVirtual, FnNonVirtual); - EmitBlock(FnVirtual); - - const llvm::Type *VTableTy = - FTy->getPointerTo()->getPointerTo(); - - llvm::Value *VTable = Builder.CreateBitCast(This, VTableTy->getPointerTo()); - VTable = Builder.CreateLoad(VTable); - - VTable = Builder.CreateBitCast(VTable, Int8PtrTy); - llvm::Value *VTableOffset = - Builder.CreateSub(FnAsInt, llvm::ConstantInt::get(PtrDiffTy, 1)); - - VTable = Builder.CreateGEP(VTable, VTableOffset, "fn"); - VTable = Builder.CreateBitCast(VTable, VTableTy); - - llvm::Value *VirtualFn = Builder.CreateLoad(VTable, "virtualfn"); - - EmitBranch(FnEnd); - EmitBlock(FnNonVirtual); - - // If the function is not virtual, just load the pointer. - llvm::Value *NonVirtualFn = Builder.CreateLoad(FnPtr, "fn"); - NonVirtualFn = Builder.CreateIntToPtr(NonVirtualFn, FTy->getPointerTo()); - - EmitBlock(FnEnd); - - llvm::PHINode *Callee = Builder.CreatePHI(FTy->getPointerTo()); - Callee->reserveOperandSpace(2); - Callee->addIncoming(VirtualFn, FnVirtual); - Callee->addIncoming(NonVirtualFn, FnNonVirtual); - CallArgList Args; QualType ThisType = diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index bd396d29d7..f9152db424 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -19,21 +19,32 @@ //===----------------------------------------------------------------------===// #include "CGCXXABI.h" +#include "CodeGenFunction.h" #include "CodeGenModule.h" #include "Mangle.h" +#include +#include using namespace clang; +using namespace CodeGen; namespace { class ItaniumCXXABI : public CodeGen::CGCXXABI { +protected: + CodeGenModule &CGM; CodeGen::MangleContext MangleCtx; public: ItaniumCXXABI(CodeGen::CodeGenModule &CGM) : - MangleCtx(CGM.getContext(), CGM.getDiags()) { } + CGM(CGM), MangleCtx(CGM.getContext(), CGM.getDiags()) { } CodeGen::MangleContext &getMangleContext() { return MangleCtx; } + + llvm::Value *EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, + llvm::Value *&This, + llvm::Value *MemFnPtr, + const MemberPointerType *MPT); }; class ARMCXXABI : public ItaniumCXXABI { @@ -50,3 +61,77 @@ CodeGen::CGCXXABI *CodeGen::CreateARMCXXABI(CodeGenModule &CGM) { return new ARMCXXABI(CGM); } +llvm::Value * +ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, + llvm::Value *&This, + llvm::Value *MemFnPtr, + const MemberPointerType *MPT) { + CGBuilderTy &Builder = CGF.Builder; + + const FunctionProtoType *FPT = + MPT->getPointeeType()->getAs(); + const CXXRecordDecl *RD = + cast(MPT->getClass()->getAs()->getDecl()); + + const llvm::FunctionType *FTy = + CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(RD, FPT), + FPT->isVariadic()); + + llvm::BasicBlock *FnVirtual = CGF.createBasicBlock("fn.virtual"); + llvm::BasicBlock *FnNonVirtual = CGF.createBasicBlock("fn.nonvirtual"); + llvm::BasicBlock *FnEnd = CGF.createBasicBlock("fn.end"); + + // Load the adjustment, which is in the second field. + llvm::Value *Adj = Builder.CreateStructGEP(MemFnPtr, 1); + Adj = Builder.CreateLoad(Adj, "mem.fn.adj"); + + // Apply the adjustment and cast back to the original struct type + // for consistency. + llvm::Value *Ptr = Builder.CreateBitCast(This, Builder.getInt8PtrTy(), "ptr"); + Ptr = Builder.CreateInBoundsGEP(Ptr, Adj, "adj"); + This = Builder.CreateBitCast(Ptr, This->getType(), "this"); + + // Load the function pointer. + llvm::Value *FnPtr = Builder.CreateStructGEP(MemFnPtr, 0, "mem.fn.ptr"); + llvm::Value *FnAsInt = Builder.CreateLoad(FnPtr, "fn"); + + // If the LSB in the function pointer is 1, the function pointer points to + // a virtual function. + llvm::Constant *iptr_1 = llvm::ConstantInt::get(FnAsInt->getType(), 1); + llvm::Value *IsVirtual = Builder.CreateAnd(FnAsInt, iptr_1); + IsVirtual = Builder.CreateIsNotNull(IsVirtual); + Builder.CreateCondBr(IsVirtual, FnVirtual, FnNonVirtual); + + // In the virtual path, the adjustment left 'This' pointing to the + // vtable of the correct base subobject. The "function pointer" is an + // offset within the vtable (+1 for the virtual flag). + CGF.EmitBlock(FnVirtual); + + // Cast the adjusted this to a pointer to vtable pointer and load. + const llvm::Type *VTableTy = Builder.getInt8PtrTy(); + llvm::Value *VTable = Builder.CreateBitCast(This, VTableTy->getPointerTo()); + VTable = Builder.CreateLoad(VTable); + + // Apply the offset. + llvm::Value *VTableOffset = Builder.CreateSub(FnAsInt, iptr_1); + VTable = Builder.CreateGEP(VTable, VTableOffset, "fn"); + + // Load the virtual function to call. + VTable = Builder.CreateBitCast(VTable, FTy->getPointerTo()->getPointerTo()); + llvm::Value *VirtualFn = Builder.CreateLoad(VTable, "virtualfn"); + CGF.EmitBranch(FnEnd); + + // In the non-virtual path, the function pointer is actually a + // function pointer. + CGF.EmitBlock(FnNonVirtual); + llvm::Value *NonVirtualFn = + Builder.CreateIntToPtr(FnAsInt, FTy->getPointerTo()); + + // We're done. + CGF.EmitBlock(FnEnd); + llvm::PHINode *Callee = Builder.CreatePHI(FTy->getPointerTo()); + Callee->reserveOperandSpace(2); + Callee->addIncoming(VirtualFn, FnVirtual); + Callee->addIncoming(NonVirtualFn, FnNonVirtual); + return Callee; +}