Extract calls to method pointers out as an ABI routine.

No functionality change.

llvm-svn: 111752
This commit is contained in:
John McCall 2010-08-22 00:05:51 +00:00
parent 940e211c87
commit 475999dcf9
4 changed files with 126 additions and 66 deletions

View File

@ -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<FunctionProtoType>();
const CXXRecordDecl *RD =
cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl());
const llvm::FunctionType *FTy =
CGF.CGM.getTypes().GetFunctionType(
CGF.CGM.getTypes().getFunctionInfo(RD, FPT),
FPT->isVariadic());
return llvm::Constant::getNullValue(FTy->getPointerTo());
}

View File

@ -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);
}
}

View File

@ -153,17 +153,12 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
const MemberPointerType *MPT =
MemFnExpr->getType()->getAs<MemberPointerType>();
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());
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");
// Ask the ABI to load the callee. Note that This is modified.
llvm::Value *Callee =
CGM.getCXXABI().EmitLoadOfMemberFunctionPointer(CGF, This, MemFnPtr, MPT);
// 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));
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 =

View File

@ -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;
}