diff options
author | John McCall <rjmccall@apple.com> | 2010-08-22 00:05:51 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2010-08-22 00:05:51 +0000 |
commit | 93d557bc1867b7d7b102f87290194b4be7932c92 (patch) | |
tree | 4963b0e57fabfe78fa13c8b230b510bd28d65fa4 /lib/CodeGen/ItaniumCXXABI.cpp | |
parent | ee79a4c30e5d1c5285551c9a25b8ec6d45d46aa7 (diff) |
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
Diffstat (limited to 'lib/CodeGen/ItaniumCXXABI.cpp')
-rw-r--r-- | lib/CodeGen/ItaniumCXXABI.cpp | 87 |
1 files changed, 86 insertions, 1 deletions
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 <clang/AST/Type.h> +#include <llvm/Value.h> 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<FunctionProtoType>(); + const CXXRecordDecl *RD = + cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->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; +} |