[cfe-commits] r83271 - in /cfe/trunk: lib/CodeGen/CGCXX.cpp lib/CodeGen/CGCall.cpp lib/CodeGen/CodeGenFunction.h lib/CodeGen/CodeGenTypes.h test/CodeGenCXX/member-function-pointers.cpp
Anders Carlsson
andersca at mac.com
Sat Oct 3 12:43:09 PDT 2009
Author: andersca
Date: Sat Oct 3 14:43:08 2009
New Revision: 83271
URL: http://llvm.org/viewvc/llvm-project?rev=83271&view=rev
Log:
Implement code generation of member function pointer calls. Fixes PR5121.
Modified:
cfe/trunk/lib/CodeGen/CGCXX.cpp
cfe/trunk/lib/CodeGen/CGCall.cpp
cfe/trunk/lib/CodeGen/CodeGenFunction.h
cfe/trunk/lib/CodeGen/CodeGenTypes.h
cfe/trunk/test/CodeGenCXX/member-function-pointers.cpp
Modified: cfe/trunk/lib/CodeGen/CGCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXX.cpp?rev=83271&r1=83270&r2=83271&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCXX.cpp Sat Oct 3 14:43:08 2009
@@ -199,6 +199,9 @@
}
RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE) {
+ if (isa<BinaryOperator>(CE->getCallee()))
+ return EmitCXXMemberPointerCallExpr(CE);
+
const MemberExpr *ME = cast<MemberExpr>(CE->getCallee());
const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl());
@@ -242,6 +245,112 @@
}
RValue
+CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E) {
+ const BinaryOperator *BO = cast<BinaryOperator>(E->getCallee());
+ const DeclRefExpr *BaseExpr = cast<DeclRefExpr>(BO->getLHS());
+ const DeclRefExpr *MemFn = cast<DeclRefExpr>(BO->getRHS());
+
+ const MemberPointerType *MPT = MemFn->getType()->getAs<MemberPointerType>();
+ const FunctionProtoType *FPT =
+ MPT->getPointeeType()->getAs<FunctionProtoType>();
+ const CXXRecordDecl *RD =
+ cast<CXXRecordDecl>(cast<RecordType>(MPT->getClass())->getDecl());
+
+ const llvm::FunctionType *FTy =
+ CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(RD, FPT),
+ FPT->isVariadic());
+
+ const llvm::Type *Int8PtrTy =
+ llvm::Type::getInt8Ty(VMContext)->getPointerTo();
+
+ // Get the member function pointer.
+ llvm::Value *MemFnPtr =
+ CreateTempAlloca(ConvertType(MemFn->getType()), "mem.fn");
+ EmitAggExpr(MemFn, MemFnPtr, /*VolatileDest=*/false);
+
+ // Emit the 'this' pointer.
+ llvm::Value *This;
+
+ if (BO->getOpcode() == BinaryOperator::PtrMemI)
+ 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));
+
+ 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()->getPointerTo();
+
+ llvm::Value *VTable = Builder.CreateBitCast(This, VTableTy);
+ VTable = Builder.CreateLoad(VTable);
+
+ VTable = Builder.CreateGEP(VTable, FnAsInt, "fn");
+
+ // Since the function pointer is 1 plus the virtual table offset, we
+ // subtract 1 by using a GEP.
+ VTable = Builder.CreateConstGEP1_64(VTable, -1);
+
+ 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 =
+ getContext().getPointerType(getContext().getTagDeclType(RD));
+
+ // Push the this ptr.
+ Args.push_back(std::make_pair(RValue::get(This), ThisType));
+
+ // And the rest of the call args
+ EmitCallArgs(Args, FPT, E->arg_begin(), E->arg_end());
+ QualType ResultType = BO->getType()->getAs<FunctionType>()->getResultType();
+ return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args),
+ Callee, Args, 0);
+}
+
+RValue
CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E,
const CXXMethodDecl *MD) {
assert(MD->isInstance() &&
Modified: cfe/trunk/lib/CodeGen/CGCall.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCall.cpp?rev=83271&r1=83270&r2=83271&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCall.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCall.cpp Sat Oct 3 14:43:08 2009
@@ -63,6 +63,21 @@
return llvm::CallingConv::C;
}
+const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXRecordDecl *RD,
+ const FunctionProtoType *FTP) {
+ llvm::SmallVector<QualType, 16> ArgTys;
+
+ // Add the 'this' pointer.
+ ArgTys.push_back(Context.getPointerType(Context.getTagDeclType(RD)));
+
+ for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i)
+ ArgTys.push_back(FTP->getArgType(i));
+
+ // FIXME: Set calling convention correctly, it needs to be associated with the
+ // type somehow.
+ return getFunctionInfo(FTP->getResultType(), ArgTys, 0);
+}
+
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXMethodDecl *MD) {
llvm::SmallVector<QualType, 16> ArgTys;
// Add the 'this' pointer unless this is a static method.
Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=83271&r1=83270&r2=83271&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Sat Oct 3 14:43:08 2009
@@ -864,10 +864,12 @@
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd);
RValue EmitCXXMemberCallExpr(const CXXMemberCallExpr *E);
+ RValue EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E);
RValue EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E,
const CXXMethodDecl *MD);
+
RValue EmitBuiltinExpr(const FunctionDecl *FD,
unsigned BuiltinID, const CallExpr *E);
Modified: cfe/trunk/lib/CodeGen/CodeGenTypes.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenTypes.h?rev=83271&r1=83270&r2=83271&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenTypes.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenTypes.h Sat Oct 3 14:43:08 2009
@@ -181,7 +181,11 @@
const CGFunctionInfo &getFunctionInfo(const FunctionDecl *FD);
const CGFunctionInfo &getFunctionInfo(const CXXMethodDecl *MD);
const CGFunctionInfo &getFunctionInfo(const ObjCMethodDecl *MD);
-
+
+ // getFunctionInfo - Get the function info for a member function.
+ const CGFunctionInfo &getFunctionInfo(const CXXRecordDecl *RD,
+ const FunctionProtoType *FTP);
+
/// getFunctionInfo - Get the function info for a function described by a
/// return type and argument types. If the calling convention is not
/// specified, the "C" calling convention will be used.
Modified: cfe/trunk/test/CodeGenCXX/member-function-pointers.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/member-function-pointers.cpp?rev=83271&r1=83270&r2=83271&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/member-function-pointers.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/member-function-pointers.cpp Sat Oct 3 14:43:08 2009
@@ -49,3 +49,8 @@
// CHECK: store i64 0, i64* [[pa2adj]]
void (A::*pa3)() = &A::vf;
}
+
+void f3(A *a, A &ar) {
+ (a->*pa)();
+ (ar.*pa)();
+}
More information about the cfe-commits
mailing list