forked from OSchip/llvm-project
Extract calls to method pointers out as an ABI routine.
No functionality change. llvm-svn: 111752
This commit is contained in:
parent
940e211c87
commit
475999dcf9
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue