From 1c456c89dc9792e5dc50ccdfc0b738c888de8ca4 Mon Sep 17 00:00:00 2001 From: John McCall Date: Sun, 22 Aug 2010 06:43:33 +0000 Subject: [PATCH] Abstract out member-pointer creation. I'm really unhappy about the current duplication between the constant and non-constant paths in all of this. Implement ARM ABI semantics for member pointer constants and conversion. llvm-svn: 111772 --- clang/lib/CodeGen/CGCXX.cpp | 49 ++------ clang/lib/CodeGen/CGCXXABI.h | 7 ++ clang/lib/CodeGen/CGExprAgg.cpp | 20 +--- clang/lib/CodeGen/CGExprConstant.cpp | 17 +-- clang/lib/CodeGen/CodeGenModule.h | 4 - clang/lib/CodeGen/ItaniumCXXABI.cpp | 106 ++++++++++++++++++ clang/lib/Frontend/ASTUnit.cpp | 2 +- clang/lib/Frontend/CompilerInvocation.cpp | 10 +- .../CodeGenCXX/member-function-pointers.cpp | 20 ++++ 9 files changed, 154 insertions(+), 81 deletions(-) diff --git a/clang/lib/CodeGen/CGCXX.cpp b/clang/lib/CodeGen/CGCXX.cpp index f56ea42427ab..293465753198 100644 --- a/clang/lib/CodeGen/CGCXX.cpp +++ b/clang/lib/CodeGen/CGCXX.cpp @@ -287,44 +287,6 @@ CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *D, return cast(GetOrCreateLLVMFunction(Name, FTy, GD)); } -llvm::Constant * -CodeGenModule::GetCXXMemberFunctionPointerValue(const CXXMethodDecl *MD) { - assert(MD->isInstance() && "Member function must not be static!"); - - MD = MD->getCanonicalDecl(); - - const llvm::Type *PtrDiffTy = Types.ConvertType(Context.getPointerDiffType()); - - // Get the function pointer (or index if this is a virtual function). - if (MD->isVirtual()) { - uint64_t Index = VTables.getMethodVTableIndex(MD); - - // FIXME: We shouldn't use / 8 here. - uint64_t PointerWidthInBytes = Context.Target.getPointerWidth(0) / 8; - - // Itanium C++ ABI 2.3: - // For a non-virtual function, this field is a simple function pointer. - // For a virtual function, it is 1 plus the virtual table offset - // (in bytes) of the function, represented as a ptrdiff_t. - return llvm::ConstantInt::get(PtrDiffTy, (Index * PointerWidthInBytes) + 1); - } - - const FunctionProtoType *FPT = MD->getType()->getAs(); - const llvm::Type *Ty; - // Check whether the function has a computable LLVM signature. - if (!CodeGenTypes::VerifyFuncTypeComplete(FPT)) { - // The function has a computable LLVM signature; use the correct type. - Ty = Types.GetFunctionType(Types.getFunctionInfo(MD), FPT->isVariadic()); - } else { - // Use an arbitrary non-function type to tell GetAddrOfFunction that the - // function type is incomplete. - Ty = PtrDiffTy; - } - - llvm::Constant *FuncPtr = GetAddrOfFunction(MD, Ty); - return llvm::ConstantExpr::getPtrToInt(FuncPtr, PtrDiffTy); -} - static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, uint64_t VTableIndex, llvm::Value *This, const llvm::Type *Ty) { Ty = Ty->getPointerTo()->getPointerTo()->getPointerTo(); @@ -400,6 +362,13 @@ void CGCXXABI::EmitNullMemberFunctionPointer(CodeGenFunction &CGF, ErrorUnsupportedABI(CGF, "null member function pointers"); } +void CGCXXABI::EmitMemberFunctionPointer(CodeGenFunction &CGF, + const CXXMethodDecl *MD, + llvm::Value *DestPtr, + bool VolatileDest) { + ErrorUnsupportedABI(CGF, "member function pointers"); +} + llvm::Constant * CGCXXABI::EmitMemberFunctionPointerConversion(llvm::Constant *C, const CastExpr *E) { @@ -411,6 +380,10 @@ CGCXXABI::EmitNullMemberFunctionPointer(const MemberPointerType *MPT) { return 0; } +llvm::Constant *CGCXXABI::EmitMemberFunctionPointer(const CXXMethodDecl *MD) { + return 0; +} + bool CGCXXABI::RequiresNonZeroInitializer(QualType T) { return false; } diff --git a/clang/lib/CodeGen/CGCXXABI.h b/clang/lib/CodeGen/CGCXXABI.h index 36f8230b0c1e..a07b98c1eaeb 100644 --- a/clang/lib/CodeGen/CGCXXABI.h +++ b/clang/lib/CodeGen/CGCXXABI.h @@ -22,6 +22,7 @@ namespace llvm { namespace clang { class CastExpr; + class CXXMethodDecl; class CXXRecordDecl; class MemberPointerType; class QualType; @@ -70,6 +71,12 @@ public: virtual llvm::Constant * EmitNullMemberFunctionPointer(const MemberPointerType *MPT); + + virtual llvm::Constant *EmitMemberFunctionPointer(const CXXMethodDecl *MD); + virtual void EmitMemberFunctionPointer(CodeGenFunction &CGF, + const CXXMethodDecl *MD, + llvm::Value *DestPtr, + bool VolatileDest); }; /// Creates an instance of a C++ ABI class. diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index 1f8964d0b625..b75aeb13b898 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -364,9 +364,8 @@ void AggExprEmitter::VisitBinComma(const BinaryOperator *E) { void AggExprEmitter::VisitUnaryAddrOf(const UnaryOperator *E) { // We have a member function pointer. - const MemberPointerType *MPT = E->getType()->getAs(); - (void) MPT; - assert(MPT->getPointeeType()->isFunctionProtoType() && + assert(E->getType()->getAs() + ->getPointeeType()->isFunctionProtoType() && "Unexpected member pointer type!"); // The creation of member function pointers has no side effects; if @@ -375,20 +374,9 @@ void AggExprEmitter::VisitUnaryAddrOf(const UnaryOperator *E) { return; const DeclRefExpr *DRE = cast(E->getSubExpr()); - const CXXMethodDecl *MD = - cast(DRE->getDecl())->getCanonicalDecl(); + const CXXMethodDecl *MD = cast(DRE->getDecl()); - const llvm::Type *PtrDiffTy = - CGF.ConvertType(CGF.getContext().getPointerDiffType()); - - llvm::Value *DstPtr = Builder.CreateStructGEP(DestPtr, 0, "dst.ptr"); - llvm::Value *FuncPtr = CGF.CGM.GetCXXMemberFunctionPointerValue(MD); - Builder.CreateStore(FuncPtr, DstPtr, VolatileDest); - - llvm::Value *AdjPtr = Builder.CreateStructGEP(DestPtr, 1, "dst.adj"); - // The adjustment will always be 0. - Builder.CreateStore(llvm::ConstantInt::get(PtrDiffTy, 0), AdjPtr, - VolatileDest); + CGF.CGM.getCXXABI().EmitMemberFunctionPointer(CGF, MD, DestPtr, VolatileDest); } void AggExprEmitter::VisitStmtExpr(const StmtExpr *E) { diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index e72e7fd1d1cd..e0335b6559b4 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -455,22 +455,7 @@ public: } llvm::Constant *EmitMemberFunctionPointer(CXXMethodDecl *MD) { - assert(MD->isInstance() && "Member function must not be static!"); - - MD = MD->getCanonicalDecl(); - - const llvm::Type *PtrDiffTy = - CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType()); - - llvm::Constant *Values[2]; - - Values[0] = CGM.GetCXXMemberFunctionPointerValue(MD); - - // The adjustment will always be 0. - Values[1] = llvm::ConstantInt::get(PtrDiffTy, 0); - - return llvm::ConstantStruct::get(CGM.getLLVMContext(), - Values, 2, /*Packed=*/false); + return CGM.getCXXABI().EmitMemberFunctionPointer(MD); } llvm::Constant *VisitUnaryAddrOf(UnaryOperator *E) { diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index eca449c702e0..426499d6eb7a 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -371,10 +371,6 @@ public: llvm::GlobalValue *GetAddrOfCXXDestructor(const CXXDestructorDecl *D, CXXDtorType Type); - // GetCXXMemberFunctionPointerValue - Given a method declaration, return the - // integer used in a member function pointer to refer to that value. - llvm::Constant *GetCXXMemberFunctionPointerValue(const CXXMethodDecl *MD); - /// getBuiltinLibFunction - Given a builtin id for a function like /// "__builtin_fabsf", return a Function* for "fabsf". llvm::Value *getBuiltinLibFunction(const FunctionDecl *FD, diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index b7211058c960..ac394956c8d3 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -66,6 +66,16 @@ public: llvm::Constant *EmitNullMemberFunctionPointer(const MemberPointerType *MPT); + void EmitMemberFunctionPointer(CodeGenFunction &CGF, + const CXXMethodDecl *MD, + llvm::Value *Dest, + bool VolatileDest); + + llvm::Constant *EmitMemberFunctionPointer(const CXXMethodDecl *MD); + +private: + void GetMemberFunctionPointer(const CXXMethodDecl *MD, + llvm::Constant *(&Array)[2]); }; class ARMCXXABI : public ItaniumCXXABI { @@ -82,6 +92,62 @@ CodeGen::CGCXXABI *CodeGen::CreateARMCXXABI(CodeGenModule &CGM) { return new ARMCXXABI(CGM); } +void ItaniumCXXABI::GetMemberFunctionPointer(const CXXMethodDecl *MD, + llvm::Constant *(&MemPtr)[2]) { + assert(MD->isInstance() && "Member function must not be static!"); + + MD = MD->getCanonicalDecl(); + + CodeGenTypes &Types = CGM.getTypes(); + const llvm::Type *ptrdiff_t = + Types.ConvertType(CGM.getContext().getPointerDiffType()); + + // Get the function pointer (or index if this is a virtual function). + if (MD->isVirtual()) { + uint64_t Index = CGM.getVTables().getMethodVTableIndex(MD); + + // FIXME: We shouldn't use / 8 here. + uint64_t PointerWidthInBytes = + CGM.getContext().Target.getPointerWidth(0) / 8; + uint64_t VTableOffset = (Index * PointerWidthInBytes); + + if (IsARM) { + // ARM C++ ABI 3.2.1: + // This ABI specifies that adj contains twice the this + // adjustment, plus 1 if the member function is virtual. The + // least significant bit of adj then makes exactly the same + // discrimination as the least significant bit of ptr does for + // Itanium. + MemPtr[0] = llvm::ConstantInt::get(ptrdiff_t, VTableOffset); + MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 1); + } else { + // Itanium C++ ABI 2.3: + // For a virtual function, [the pointer field] is 1 plus the + // virtual table offset (in bytes) of the function, + // represented as a ptrdiff_t. + MemPtr[0] = llvm::ConstantInt::get(ptrdiff_t, VTableOffset + 1); + MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 0); + } + } else { + const FunctionProtoType *FPT = MD->getType()->getAs(); + const llvm::Type *Ty; + // Check whether the function has a computable LLVM signature. + if (!CodeGenTypes::VerifyFuncTypeComplete(FPT)) { + // The function has a computable LLVM signature; use the correct type. + Ty = Types.GetFunctionType(Types.getFunctionInfo(MD), FPT->isVariadic()); + } else { + // Use an arbitrary non-function type to tell GetAddrOfFunction that the + // function type is incomplete. + Ty = ptrdiff_t; + } + + llvm::Constant *Addr = CGM.GetAddrOfFunction(MD, Ty); + MemPtr[0] = llvm::ConstantExpr::getPtrToInt(Addr, ptrdiff_t); + MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 0); + } +} + + /// In the Itanium and ARM ABIs, method pointers have the form: /// struct { ptrdiff_t ptr; ptrdiff_t adj; } memptr; /// @@ -231,6 +297,13 @@ void ItaniumCXXABI::EmitMemberFunctionPointerConversion(CodeGenFunction &CGF, CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl, E->path_begin(), E->path_end())) { + // The this-adjustment is left-shifted by 1 on ARM. + if (IsARM) { + uint64_t Offset = cast(Adj)->getZExtValue(); + Offset <<= 1; + Adj = llvm::ConstantInt::get(Adj->getType(), Offset); + } + if (DerivedToBase) SrcAdj = Builder.CreateSub(SrcAdj, Adj, "adj"); else @@ -265,6 +338,13 @@ ItaniumCXXABI::EmitMemberFunctionPointerConversion(llvm::Constant *C, // If there's no offset, we're done. if (!Offset) return C; + // The this-adjustment is left-shifted by 1 on ARM. + if (IsARM) { + uint64_t OffsetV = cast(Offset)->getZExtValue(); + OffsetV <<= 1; + Offset = llvm::ConstantInt::get(Offset->getType(), OffsetV); + } + llvm::ConstantStruct *CS = cast(C); llvm::Constant *Values[2] = { @@ -300,6 +380,32 @@ ItaniumCXXABI::EmitNullMemberFunctionPointer(const MemberPointerType *MPT) { return CGM.EmitNullConstant(QualType(MPT, 0)); } +llvm::Constant * +ItaniumCXXABI::EmitMemberFunctionPointer(const CXXMethodDecl *MD) { + llvm::Constant *Values[2]; + GetMemberFunctionPointer(MD, Values); + + return llvm::ConstantStruct::get(CGM.getLLVMContext(), + Values, 2, /*Packed=*/false); +} + +void ItaniumCXXABI::EmitMemberFunctionPointer(CodeGenFunction &CGF, + const CXXMethodDecl *MD, + llvm::Value *DestPtr, + bool VolatileDest) { + llvm::Constant *Values[2]; + GetMemberFunctionPointer(MD, Values); + + CGBuilderTy &Builder = CGF.Builder; + + llvm::Value *DstPtr = Builder.CreateStructGEP(DestPtr, 0, "memptr.ptr"); + Builder.CreateStore(Values[0], DstPtr, VolatileDest); + + llvm::Value *AdjPtr = Builder.CreateStructGEP(DestPtr, 1, "memptr.adj"); + Builder.CreateStore(Values[1], AdjPtr, VolatileDest); +} + + bool ItaniumCXXABI::RequiresNonZeroInitializer(QualType T) { return CGM.getTypes().ContainsPointerToDataMember(T); } diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp index 1377e739ed62..9aa9f5b6ccab 100644 --- a/clang/lib/Frontend/ASTUnit.cpp +++ b/clang/lib/Frontend/ASTUnit.cpp @@ -484,7 +484,7 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename, // FIXME: This is broken, we should store the TargetOptions in the AST file. TargetOptions TargetOpts; TargetOpts.ABI = ""; - TargetOpts.CXXABI = "itanium"; + TargetOpts.CXXABI = ""; TargetOpts.CPU = ""; TargetOpts.Features.clear(); TargetOpts.Triple = TargetTriple; diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index f8a56a0badc0..7622eb79064c 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -713,8 +713,10 @@ static void TargetOptsToArgs(const TargetOptions &Opts, Res.push_back("-target-linker-version"); Res.push_back(Opts.LinkerVersion); } - Res.push_back("-cxx-abi"); - Res.push_back(Opts.CXXABI); + if (!Opts.CXXABI.empty()) { + Res.push_back("-cxx-abi"); + Res.push_back(Opts.CXXABI); + } for (unsigned i = 0, e = Opts.Features.size(); i != e; ++i) { Res.push_back("-target-feature"); Res.push_back(Opts.Features[i]); @@ -1471,10 +1473,6 @@ static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) { // Use the host triple if unspecified. if (Opts.Triple.empty()) Opts.Triple = llvm::sys::getHostTriple(); - - // Use the Itanium C++ ABI if unspecified. - if (Opts.CXXABI.empty()) - Opts.CXXABI = "itanium"; } // diff --git a/clang/test/CodeGenCXX/member-function-pointers.cpp b/clang/test/CodeGenCXX/member-function-pointers.cpp index e4beee15bb17..c0756fa14431 100644 --- a/clang/test/CodeGenCXX/member-function-pointers.cpp +++ b/clang/test/CodeGenCXX/member-function-pointers.cpp @@ -1,5 +1,6 @@ // RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-apple-darwin9 | FileCheck %s // RUN: %clang_cc1 %s -emit-llvm -o - -triple=i386-apple-darwin9 | FileCheck -check-prefix LP32 %s +// RUN: %clang_cc1 %s -emit-llvm -o - -triple=armv7-unknown-unknown | FileCheck -check-prefix ARM %s struct A { int a; void f(); virtual void vf1(); virtual void vf2(); }; struct B { int b; virtual void g(); }; @@ -190,3 +191,22 @@ namespace PR7027 { struct X { void test( ); }; void testX() { &X::test; } } + +namespace test7 { + struct A { void foo(); virtual void vfoo(); }; + struct B { void foo(); virtual void vfoo(); }; + struct C : A, B { void foo(); virtual void vfoo(); }; + + // CHECK-ARM: @_ZN5test74ptr0E = global {{.*}} { i32 ptrtoint ({{.*}}* @_ZN5test71A3fooEv to i32), i32 0 } + // CHECK-ARM: @_ZN5test74ptr1E = global {{.*}} { i32 ptrtoint ({{.*}}* @_ZN5test71B3fooEv to i32), i32 8 } + // CHECK-ARM: @_ZN5test74ptr2E = global {{.*}} { i32 ptrtoint ({{.*}}* @_ZN5test71C3fooEv to i32), i32 0 } + // CHECK-ARM: @_ZN5test74ptr3E = global {{.*}} { i32 0, i32 1 } + // CHECK-ARM: @_ZN5test74ptr4E = global {{.*}} { i32 0, i32 9 } + // CHECK-ARM: @_ZN5test74ptr5E = global {{.*}} { i32 0, i32 1 } + void (C::*ptr0)() = &A::foo; + void (C::*ptr1)() = &B::foo; + void (C::*ptr2)() = &C::foo; + void (C::*ptr3)() = &A::vfoo; + void (C::*ptr4)() = &B::vfoo; + void (C::*ptr5)() = &C::vfoo; +}