From: John McCall Date: Mon, 23 Aug 2010 01:21:21 +0000 (+0000) Subject: Abstract out everything having to do with member pointers into the ABI X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0bab0cdab751248ca389a5592bcb70eac5d39260;p=clang Abstract out everything having to do with member pointers into the ABI class; they should just be completely opaque throughout IR gen now, although I haven't really audited that. Fix a bug apparently inherited from gcc-4.2 where we failed to null-check member data pointers when performing derived-to-base or base-to-derived conversions on them. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@111789 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 754f1f74ff..5a69932051 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -1359,9 +1359,20 @@ protected: virtual Linkage getLinkageImpl() const; public: - QualType getPointeeType() const { return PointeeType; } + /// Returns true if the member type (i.e. the pointee type) is a + /// function type rather than a data-member type. + bool isMemberFunctionPointer() const { + return PointeeType->isFunctionProtoType(); + } + + /// Returns true if the member type (i.e. the pointee type) is a + /// data type rather than a function type. + bool isMemberDataPointer() const { + return !PointeeType->isFunctionProtoType(); + } + const Type *getClass() const { return Class; } bool isSugared() const { return false; } @@ -3483,13 +3494,13 @@ inline bool Type::isMemberPointerType() const { } inline bool Type::isMemberFunctionPointerType() const { if (const MemberPointerType* T = getAs()) - return T->getPointeeType()->isFunctionType(); + return T->isMemberFunctionPointer(); else return false; } inline bool Type::isMemberDataPointerType() const { if (const MemberPointerType* T = getAs()) - return !T->getPointeeType()->isFunctionType(); + return T->isMemberDataPointer(); else return false; } diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 8fb3fe3d4b..94378b79e6 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -318,6 +318,9 @@ CodeGenFunction::BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type, return ::BuildVirtualCall(*this, VTableIndex, This, Ty); } +/// Implementation for CGCXXABI. Possibly this should be moved into +/// the incomplete ABI implementations? + CGCXXABI::~CGCXXABI() {} static void ErrorUnsupportedABI(CodeGenFunction &CGF, @@ -335,6 +338,11 @@ static llvm::Constant *GetBogusMemberPointer(CodeGenModule &CGM, return llvm::Constant::getNullValue(CGM.getTypes().ConvertType(T)); } +const llvm::Type * +CGCXXABI::ConvertMemberPointerType(const MemberPointerType *MPT) { + return CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType()); +} + llvm::Value *CGCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, llvm::Value *&This, llvm::Value *MemPtr, @@ -351,48 +359,53 @@ llvm::Value *CGCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, return llvm::Constant::getNullValue(FTy->getPointerTo()); } -llvm::Value *CGCXXABI::EmitMemberFunctionPointerConversion(CodeGenFunction &CGF, - const CastExpr *E, - llvm::Value *Src) { +llvm::Value *CGCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF, + const CastExpr *E, + llvm::Value *Src) { ErrorUnsupportedABI(CGF, "member function pointer conversions"); return GetBogusMemberPointer(CGM, E->getType()); } llvm::Value * -CGCXXABI::EmitMemberFunctionPointerComparison(CodeGenFunction &CGF, - llvm::Value *L, - llvm::Value *R, - const MemberPointerType *MPT, - bool Inequality) { +CGCXXABI::EmitMemberPointerComparison(CodeGenFunction &CGF, + llvm::Value *L, + llvm::Value *R, + const MemberPointerType *MPT, + bool Inequality) { ErrorUnsupportedABI(CGF, "member function pointer comparison"); return CGF.Builder.getFalse(); } llvm::Value * -CGCXXABI::EmitMemberFunctionPointerIsNotNull(CodeGenFunction &CGF, - llvm::Value *MemPtr, - const MemberPointerType *MPT) { +CGCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF, + llvm::Value *MemPtr, + const MemberPointerType *MPT) { ErrorUnsupportedABI(CGF, "member function pointer null testing"); return CGF.Builder.getFalse(); } llvm::Constant * -CGCXXABI::EmitMemberFunctionPointerConversion(llvm::Constant *C, - const CastExpr *E) { +CGCXXABI::EmitMemberPointerConversion(llvm::Constant *C, const CastExpr *E) { return GetBogusMemberPointer(CGM, E->getType()); } llvm::Constant * -CGCXXABI::EmitNullMemberFunctionPointer(const MemberPointerType *MPT) { +CGCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) { return GetBogusMemberPointer(CGM, QualType(MPT, 0)); } -llvm::Constant *CGCXXABI::EmitMemberFunctionPointer(const CXXMethodDecl *MD) { +llvm::Constant *CGCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) { return GetBogusMemberPointer(CGM, CGM.getContext().getMemberPointerType(MD->getType(), MD->getParent()->getTypeForDecl())); } +llvm::Constant *CGCXXABI::EmitMemberPointer(const FieldDecl *FD) { + return GetBogusMemberPointer(CGM, + CGM.getContext().getMemberPointerType(FD->getType(), + FD->getParent()->getTypeForDecl())); +} + bool CGCXXABI::isZeroInitializable(const MemberPointerType *MPT) { // Fake answer. return true; diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h index c248f1d64d..25110eb3b8 100644 --- a/lib/CodeGen/CGCXXABI.h +++ b/lib/CodeGen/CGCXXABI.h @@ -17,6 +17,7 @@ namespace llvm { class Constant; + class Type; class Value; } @@ -24,6 +25,7 @@ namespace clang { class CastExpr; class CXXMethodDecl; class CXXRecordDecl; + class FieldDecl; class MemberPointerType; class QualType; @@ -46,44 +48,57 @@ public: /// Gets the mangle context. virtual MangleContext &getMangleContext() = 0; + /// Find the LLVM type used to represent the given member pointer + /// type. + virtual const llvm::Type * + ConvertMemberPointerType(const MemberPointerType *MPT); + + /// Load a member function from an object and a member function + /// pointer. Apply the this-adjustment and set 'This' to the + /// adjusted value. virtual llvm::Value * EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, llvm::Value *&This, llvm::Value *MemPtr, const MemberPointerType *MPT); - virtual llvm::Value * - EmitMemberFunctionPointerConversion(CodeGenFunction &CGF, - const CastExpr *E, - llvm::Value *Src); + /// Perform a derived-to-base or base-to-derived member pointer + /// conversion. + virtual llvm::Value *EmitMemberPointerConversion(CodeGenFunction &CGF, + const CastExpr *E, + llvm::Value *Src); - // Manipulations on constant expressions. + /// Perform a derived-to-base or base-to-derived member pointer + /// conversion on a constant member pointer. + virtual llvm::Constant *EmitMemberPointerConversion(llvm::Constant *C, + const CastExpr *E); - /// \brief Returns true if the given member pointer can be - /// zero-initialized (in the C++ sense) with an LLVM - /// zeroinitialized. + /// Return true if the given member pointer can be zero-initialized + /// (in the C++ sense) with an LLVM zeroinitializer. virtual bool isZeroInitializable(const MemberPointerType *MPT); - virtual llvm::Constant * - EmitMemberFunctionPointerConversion(llvm::Constant *C, - const CastExpr *E); + /// Create a null member pointer of the given type. + virtual llvm::Constant *EmitNullMemberPointer(const MemberPointerType *MPT); - virtual llvm::Constant * - EmitNullMemberFunctionPointer(const MemberPointerType *MPT); + /// Create a member pointer for the given method. + virtual llvm::Constant *EmitMemberPointer(const CXXMethodDecl *MD); - virtual llvm::Constant *EmitMemberFunctionPointer(const CXXMethodDecl *MD); + /// Create a member pointer for the given field. + virtual llvm::Constant *EmitMemberPointer(const FieldDecl *FD); + /// Emit a comparison between two member pointers. Returns an i1. virtual llvm::Value * - EmitMemberFunctionPointerComparison(CodeGenFunction &CGF, - llvm::Value *L, - llvm::Value *R, - const MemberPointerType *MPT, - bool Inequality); + EmitMemberPointerComparison(CodeGenFunction &CGF, + llvm::Value *L, + llvm::Value *R, + const MemberPointerType *MPT, + bool Inequality); + /// Determine if a member pointer is non-null. Returns an i1. virtual llvm::Value * - EmitMemberFunctionPointerIsNotNull(CodeGenFunction &CGF, - llvm::Value *MemPtr, - const MemberPointerType *MPT); + EmitMemberPointerIsNotNull(CodeGenFunction &CGF, + llvm::Value *MemPtr, + const MemberPointerType *MPT); }; /// Creates an instance of a C++ ABI class. diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 55abaa31cd..0cfd8b6ef9 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -65,12 +65,12 @@ llvm::AllocaInst *CodeGenFunction::CreateMemTemp(QualType Ty, /// EvaluateExprAsBool - Perform the usual unary conversions on the specified /// expression and compare the result against zero, returning an Int1Ty value. llvm::Value *CodeGenFunction::EvaluateExprAsBool(const Expr *E) { - QualType BoolTy = getContext().BoolTy; - if (E->getType()->isMemberFunctionPointerType()) { + if (const MemberPointerType *MPT = E->getType()->getAs()) { llvm::Value *MemPtr = EmitScalarExpr(E); - return CGM.getCXXABI().EmitMemberFunctionPointerIsNotNull(CGF, MemPtr, - E->getType()->getAs()); + return CGM.getCXXABI().EmitMemberPointerIsNotNull(CGF, MemPtr, MPT); } + + QualType BoolTy = getContext().BoolTy; if (!E->getType()->isAnyComplexType()) return EmitScalarConversion(EmitScalarExpr(E), E->getType(), BoolTy); @@ -1176,7 +1176,7 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { // we're actually emitting a member pointer. if (const CXXMethodDecl *MD = dyn_cast(ND)) if (MD->isInstance()) { - llvm::Value *V = CGM.getCXXABI().EmitMemberFunctionPointer(MD); + llvm::Value *V = CGM.getCXXABI().EmitMemberPointer(MD); return MakeAddrLValue(V, MD->getType(), Alignment); } if (const FunctionDecl *FD = dyn_cast(ND)) @@ -1185,7 +1185,7 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { // If we're emitting a field as an independent lvalue, we're // actually emitting a member pointer. if (const FieldDecl *FD = dyn_cast(ND)) { - llvm::Value *V = CGM.EmitPointerToDataMember(FD); + llvm::Value *V = CGM.getCXXABI().EmitMemberPointer(FD); return MakeAddrLValue(V, FD->getType(), Alignment); } diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 48826492df..0dcee6ef6a 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -454,22 +454,15 @@ public: return Visit(E->getInitializer()); } - llvm::Constant *EmitMemberFunctionPointer(CXXMethodDecl *MD) { - return CGM.getCXXABI().EmitMemberFunctionPointer(MD); - } - llvm::Constant *VisitUnaryAddrOf(UnaryOperator *E) { if (const MemberPointerType *MPT = E->getType()->getAs()) { - QualType T = MPT->getPointeeType(); DeclRefExpr *DRE = cast(E->getSubExpr()); - NamedDecl *ND = DRE->getDecl(); - if (T->isFunctionProtoType()) - return EmitMemberFunctionPointer(cast(ND)); - - // We have a pointer to data member. - return CGM.EmitPointerToDataMember(cast(ND)); + if (MPT->isMemberFunctionPointer()) + return CGM.getCXXABI().EmitMemberPointer(cast(ND)); + else + return CGM.getCXXABI().EmitMemberPointer(cast(ND)); } return 0; @@ -535,24 +528,16 @@ public: } case CastExpr::CK_NullToMemberPointer: { const MemberPointerType *MPT = E->getType()->getAs(); - if (MPT->getPointeeType()->isFunctionType()) - return CGM.getCXXABI().EmitNullMemberFunctionPointer(MPT); - return CGM.EmitNullConstant(E->getType()); + return CGM.getCXXABI().EmitNullMemberPointer(MPT); } case CastExpr::CK_BaseToDerivedMemberPointer: { - const MemberPointerType *MPT = E->getType()->getAs(); - - // TODO: support data-member conversions here! - if (!MPT->getPointeeType()->isFunctionType()) - return 0; - Expr *SubExpr = E->getSubExpr(); llvm::Constant *C = CGM.EmitConstantExpr(SubExpr, SubExpr->getType(), CGF); if (!C) return 0; - return CGM.getCXXABI().EmitMemberFunctionPointerConversion(C, E); + return CGM.getCXXABI().EmitMemberPointerConversion(C, E); } case CastExpr::CK_BitCast: @@ -1134,29 +1119,3 @@ llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) { return llvm::ConstantInt::get(getTypes().ConvertTypeForMem(T), -1ULL, /*isSigned=*/true); } - -llvm::Constant * -CodeGenModule::EmitPointerToDataMember(const FieldDecl *FD) { - - // Itanium C++ ABI 2.3: - // A pointer to data member is an offset from the base address of the class - // object containing it, represented as a ptrdiff_t - - const CXXRecordDecl *ClassDecl = cast(FD->getParent()); - QualType ClassType = - getContext().getTypeDeclType(const_cast(ClassDecl)); - - const llvm::StructType *ClassLTy = - cast(getTypes().ConvertType(ClassType)); - - const CGRecordLayout &RL = - getTypes().getCGRecordLayout(FD->getParent()); - unsigned FieldNo = RL.getLLVMFieldNo(FD); - uint64_t Offset = - getTargetData().getStructLayout(ClassLTy)->getElementOffset(FieldNo); - - const llvm::Type *PtrDiffTy = - getTypes().ConvertType(getContext().getPointerDiffType()); - - return llvm::ConstantInt::get(PtrDiffTy, Offset); -} diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 4d4ddd948c..4487f17f60 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -414,11 +414,8 @@ Value *ScalarExprEmitter::EmitConversionToBool(Value *Src, QualType SrcType) { return Builder.CreateFCmpUNE(Src, Zero, "tobool"); } - if (SrcType->isMemberPointerType()) { - // Compare against -1. - llvm::Value *NegativeOne = llvm::Constant::getAllOnesValue(Src->getType()); - return Builder.CreateICmpNE(Src, NegativeOne, "tobool"); - } + if (const MemberPointerType *MPT = dyn_cast(SrcType)) + return CGF.CGM.getCXXABI().EmitMemberPointerIsNotNull(CGF, Src, MPT); assert((SrcType->isIntegerType() || isa(Src->getType())) && "Unknown scalar type to convert"); @@ -567,14 +564,10 @@ EmitComplexToScalarConversion(CodeGenFunction::ComplexPairTy Src, } Value *ScalarExprEmitter::EmitNullValue(QualType Ty) { - const llvm::Type *LTy = ConvertType(Ty); - - if (!Ty->isMemberDataPointerType()) - return llvm::Constant::getNullValue(LTy); - - // Itanium C++ ABI 2.3: - // A NULL pointer is represented as -1. - return llvm::ConstantInt::get(LTy, -1ULL, /*isSigned=*/true); + if (const MemberPointerType *MPT = Ty->getAs()) + return CGF.CGM.getCXXABI().EmitNullMemberPointer(MPT); + + return llvm::Constant::getNullValue(ConvertType(Ty)); } //===----------------------------------------------------------------------===// @@ -994,17 +987,15 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { case CastExpr::CK_FunctionToPointerDecay: return EmitLValue(E).getAddress(); - case CastExpr::CK_NullToMemberPointer: + case CastExpr::CK_NullToMemberPointer: { // If the subexpression's type is the C++0x nullptr_t, emit the // subexpression, which may have side effects. if (E->getType()->isNullPtrType()) (void) Visit(E); - if (CE->getType()->isMemberFunctionPointerType()) - return CGF.CGM.getCXXABI().EmitNullMemberFunctionPointer( - CE->getType()->getAs()); - - return CGF.CGM.EmitNullConstant(DestTy); + const MemberPointerType *MPT = CE->getType()->getAs(); + return CGF.CGM.getCXXABI().EmitNullMemberPointer(MPT); + } case CastExpr::CK_BaseToDerivedMemberPointer: case CastExpr::CK_DerivedToBaseMemberPointer: { @@ -1016,33 +1007,9 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { // actual control flow may be required in order to perform the // check, which it is for data member pointers (but not member // function pointers on Itanium and ARM). - - if (CE->getType()->isMemberFunctionPointerType()) - return CGF.CGM.getCXXABI().EmitMemberFunctionPointerConversion(CGF, CE, - Src); - - // See if we need to adjust the pointer. - const CXXRecordDecl *BaseDecl = - cast(E->getType()->getAs()-> - getClass()->getAs()->getDecl()); - const CXXRecordDecl *DerivedDecl = - cast(CE->getType()->getAs()-> - getClass()->getAs()->getDecl()); - if (CE->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer) - std::swap(DerivedDecl, BaseDecl); - - if (llvm::Constant *Adj = - CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl, - CE->path_begin(), - CE->path_end())) { - if (CE->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer) - Src = Builder.CreateNSWSub(Src, Adj, "adj"); - else - Src = Builder.CreateNSWAdd(Src, Adj, "adj"); - } - - return Src; + return CGF.CGM.getCXXABI().EmitMemberPointerConversion(CGF, CE, Src); } + case CastExpr::CK_ConstructorConversion: assert(0 && "Should be unreachable!"); @@ -1096,10 +1063,13 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { case CastExpr::CK_FloatingCast: return EmitScalarConversion(Visit(E), E->getType(), DestTy); - case CastExpr::CK_MemberPointerToBoolean: - return CGF.EvaluateExprAsBool(E); + case CastExpr::CK_MemberPointerToBoolean: { + llvm::Value *MemPtr = Visit(E); + const MemberPointerType *MPT = E->getType()->getAs(); + return CGF.CGM.getCXXABI().EmitMemberPointerIsNotNull(CGF, MemPtr, MPT); } - + } + // Handle cases where the source is an non-complex type. if (!CGF.hasAggregateLLVMType(E->getType())) { @@ -1821,14 +1791,13 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc, TestAndClearIgnoreResultAssign(); Value *Result; QualType LHSTy = E->getLHS()->getType(); - if (LHSTy->isMemberFunctionPointerType()) { + if (const MemberPointerType *MPT = LHSTy->getAs()) { assert(E->getOpcode() == BinaryOperator::EQ || E->getOpcode() == BinaryOperator::NE); Value *LHS = CGF.EmitScalarExpr(E->getLHS()); Value *RHS = CGF.EmitScalarExpr(E->getRHS()); - Result = CGF.CGM.getCXXABI().EmitMemberFunctionPointerComparison( - CGF, LHS, RHS, LHSTy->getAs(), - E->getOpcode() == BinaryOperator::NE); + Result = CGF.CGM.getCXXABI().EmitMemberPointerComparison( + CGF, LHS, RHS, MPT, E->getOpcode() == BinaryOperator::NE); } else if (!LHSTy->isAnyComplexType()) { Value *LHS = Visit(E->getLHS()); Value *RHS = Visit(E->getRHS()); diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index f44c8236fe..cd00f438c8 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -434,8 +434,6 @@ public: llvm::Constant *EmitAnnotateAttr(llvm::GlobalValue *GV, const AnnotateAttr *AA, unsigned LineNo); - llvm::Constant *EmitPointerToDataMember(const FieldDecl *FD); - /// ErrorUnsupported - Print out an error that codegen doesn't support the /// specified stmt yet. /// \param OmitOnError - If true, then this error should only be emitted if no diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp index 1402af14a5..5ab65c5779 100644 --- a/lib/CodeGen/CodeGenTypes.cpp +++ b/lib/CodeGen/CodeGenTypes.cpp @@ -402,17 +402,7 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { } case Type::MemberPointer: { - // FIXME: This is ABI dependent. We use the Itanium C++ ABI. - // http://www.codesourcery.com/public/cxx-abi/abi.html#member-pointers - // If we ever want to support other ABIs this needs to be abstracted. - - QualType ETy = cast(Ty).getPointeeType(); - const llvm::Type *PtrDiffTy = - ConvertTypeRecursive(Context.getPointerDiffType()); - if (ETy->isFunctionType()) - return llvm::StructType::get(TheModule.getContext(), PtrDiffTy, PtrDiffTy, - NULL); - return PtrDiffTy; + return getCXXABI().ConvertMemberPointerType(cast(&Ty)); } } diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index 37244398f3..f6864059de 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -19,10 +19,12 @@ //===----------------------------------------------------------------------===// #include "CGCXXABI.h" +#include "CGRecordLayout.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "Mangle.h" #include +#include #include using namespace clang; @@ -30,12 +32,26 @@ using namespace CodeGen; namespace { class ItaniumCXXABI : public CodeGen::CGCXXABI { +private: + const llvm::IntegerType *PtrDiffTy; protected: CodeGen::MangleContext MangleCtx; bool IsARM; + + // It's a little silly for us to cache this. + const llvm::IntegerType *getPtrDiffTy() { + if (!PtrDiffTy) { + QualType T = CGM.getContext().getPointerDiffType(); + const llvm::Type *Ty = CGM.getTypes().ConvertTypeRecursive(T); + PtrDiffTy = cast(Ty); + } + return PtrDiffTy; + } + public: ItaniumCXXABI(CodeGen::CodeGenModule &CGM, bool IsARM = false) : - CGCXXABI(CGM), MangleCtx(CGM.getContext(), CGM.getDiags()), IsARM(IsARM) { } + CGCXXABI(CGM), PtrDiffTy(0), MangleCtx(CGM.getContext(), CGM.getDiags()), + IsARM(IsARM) { } CodeGen::MangleContext &getMangleContext() { return MangleCtx; @@ -43,35 +59,34 @@ public: bool isZeroInitializable(const MemberPointerType *MPT); + const llvm::Type *ConvertMemberPointerType(const MemberPointerType *MPT); + llvm::Value *EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, llvm::Value *&This, llvm::Value *MemFnPtr, const MemberPointerType *MPT); - llvm::Value *EmitMemberFunctionPointerConversion(CodeGenFunction &CGF, - const CastExpr *E, - llvm::Value *Src); + llvm::Value *EmitMemberPointerConversion(CodeGenFunction &CGF, + const CastExpr *E, + llvm::Value *Src); - llvm::Constant *EmitMemberFunctionPointerConversion(llvm::Constant *C, - const CastExpr *E); + llvm::Constant *EmitMemberPointerConversion(llvm::Constant *C, + const CastExpr *E); - llvm::Constant *EmitNullMemberFunctionPointer(const MemberPointerType *MPT); + llvm::Constant *EmitNullMemberPointer(const MemberPointerType *MPT); - llvm::Constant *EmitMemberFunctionPointer(const CXXMethodDecl *MD); + llvm::Constant *EmitMemberPointer(const CXXMethodDecl *MD); + llvm::Constant *EmitMemberPointer(const FieldDecl *FD); - llvm::Value *EmitMemberFunctionPointerComparison(CodeGenFunction &CGF, - llvm::Value *L, - llvm::Value *R, - const MemberPointerType *MPT, - bool Inequality); + llvm::Value *EmitMemberPointerComparison(CodeGenFunction &CGF, + llvm::Value *L, + llvm::Value *R, + const MemberPointerType *MPT, + bool Inequality); - llvm::Value *EmitMemberFunctionPointerIsNotNull(CodeGenFunction &CGF, - llvm::Value *Addr, - const MemberPointerType *MPT); - -private: - void GetMemberFunctionPointer(const CXXMethodDecl *MD, - llvm::Constant *(&Array)[2]); + llvm::Value *EmitMemberPointerIsNotNull(CodeGenFunction &CGF, + llvm::Value *Addr, + const MemberPointerType *MPT); }; class ARMCXXABI : public ItaniumCXXABI { @@ -88,11 +103,15 @@ CodeGen::CGCXXABI *CodeGen::CreateARMCXXABI(CodeGenModule &CGM) { return new ARMCXXABI(CGM); } -void ItaniumCXXABI::GetMemberFunctionPointer(const CXXMethodDecl *MD, - llvm::Constant *(&MemPtr)[2]) { +const llvm::Type * +ItaniumCXXABI::ConvertMemberPointerType(const MemberPointerType *MPT) { + if (MPT->isMemberDataPointer()) + return getPtrDiffTy(); + else + return llvm::StructType::get(CGM.getLLVMContext(), + getPtrDiffTy(), getPtrDiffTy(), NULL); } - /// In the Itanium and ARM ABIs, method pointers have the form: /// struct { ptrdiff_t ptr; ptrdiff_t adj; } memptr; /// @@ -129,7 +148,7 @@ ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(RD, FPT), FPT->isVariadic()); - const llvm::IntegerType *ptrdiff = CGF.IntPtrTy; + const llvm::IntegerType *ptrdiff = getPtrDiffTy(); llvm::Constant *ptrdiff_1 = llvm::ConstantInt::get(ptrdiff, 1); llvm::BasicBlock *FnVirtual = CGF.createBasicBlock("memptr.virtual"); @@ -199,15 +218,34 @@ ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, } /// Perform a derived-to-base or base-to-derived member pointer conversion. +/// +/// Obligatory offset/adjustment diagram: +/// <-- offset --> <-- adjustment --> +/// |--------------------------|----------------------|--------------------| +/// ^Derived address point ^Base address point ^Member address point +/// +/// So when converting a base member pointer to a derived member pointer, +/// we add the offset to the adjustment because the address point has +/// decreased; and conversely, when converting a derived MP to a base MP +/// we subtract the offset from the adjustment because the address point +/// has increased. +/// +/// The standard forbids (at compile time) conversion to and from +/// virtual bases, which is why we don't have to consider them here. +/// +/// The standard forbids (at run time) casting a derived MP to a base +/// MP when the derived MP does not point to a member of the base. +/// This is why -1 is a reasonable choice for null data member +/// pointers. llvm::Value * -ItaniumCXXABI::EmitMemberFunctionPointerConversion(CodeGenFunction &CGF, - const CastExpr *E, - llvm::Value *Src) { +ItaniumCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF, + const CastExpr *E, + llvm::Value *Src) { assert(E->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer || E->getCastKind() == CastExpr::CK_BaseToDerivedMemberPointer); if (isa(Src)) - return EmitMemberFunctionPointerConversion(cast(Src), E); + return EmitMemberPointerConversion(cast(Src), E); CGBuilderTy &Builder = CGF.Builder; @@ -233,6 +271,21 @@ ItaniumCXXABI::EmitMemberFunctionPointerConversion(CodeGenFunction &CGF, E->path_end()); if (!Adj) return Src; + // For member data pointers, this is just a matter of adding the + // offset if the source is non-null. + if (SrcTy->isMemberDataPointer()) { + llvm::Value *Dst; + if (DerivedToBase) + Dst = Builder.CreateNSWSub(Src, Adj, "adj"); + else + Dst = Builder.CreateNSWAdd(Src, Adj, "adj"); + + // Null check. + llvm::Value *Null = llvm::Constant::getAllOnesValue(Src->getType()); + llvm::Value *IsNull = Builder.CreateICmpEQ(Src, Null, "memptr.isnull"); + return Builder.CreateSelect(IsNull, Src, Dst); + } + // The this-adjustment is left-shifted by 1 on ARM. if (IsARM) { uint64_t Offset = cast(Adj)->getZExtValue(); @@ -243,16 +296,16 @@ ItaniumCXXABI::EmitMemberFunctionPointerConversion(CodeGenFunction &CGF, llvm::Value *SrcAdj = Builder.CreateExtractValue(Src, 1, "src.adj"); llvm::Value *DstAdj; if (DerivedToBase) - DstAdj = Builder.CreateSub(SrcAdj, Adj, "adj"); + DstAdj = Builder.CreateNSWSub(SrcAdj, Adj, "adj"); else - DstAdj = Builder.CreateAdd(SrcAdj, Adj, "adj"); + DstAdj = Builder.CreateNSWAdd(SrcAdj, Adj, "adj"); return Builder.CreateInsertValue(Src, DstAdj, 1); } llvm::Constant * -ItaniumCXXABI::EmitMemberFunctionPointerConversion(llvm::Constant *C, - const CastExpr *E) { +ItaniumCXXABI::EmitMemberPointerConversion(llvm::Constant *C, + const CastExpr *E) { const MemberPointerType *SrcTy = E->getSubExpr()->getType()->getAs(); const MemberPointerType *DestTy = @@ -275,28 +328,68 @@ ItaniumCXXABI::EmitMemberFunctionPointerConversion(llvm::Constant *C, // If there's no offset, we're done. if (!Offset) return C; + // If the source is a member data pointer, we have to do a null + // check and then add the offset. In the common case, we can fold + // away the offset. + if (SrcTy->isMemberDataPointer()) { + assert(C->getType() == getPtrDiffTy()); + + // If it's a constant int, just create a new constant int. + if (llvm::ConstantInt *CI = dyn_cast(C)) { + int64_t Src = CI->getSExtValue(); + + // Null converts to null. + if (Src == -1) return CI; + + // Otherwise, just add the offset. + int64_t OffsetV = cast(Offset)->getSExtValue(); + int64_t Dst = (DerivedToBase ? Src - OffsetV : Src + OffsetV); + return llvm::ConstantInt::get(CI->getType(), Dst, /*signed*/ true); + } + + // Otherwise, we have to form a constant select expression. + llvm::Constant *Null = llvm::Constant::getAllOnesValue(C->getType()); + + llvm::Constant *IsNull = + llvm::ConstantExpr::getICmp(llvm::ICmpInst::ICMP_EQ, C, Null); + + llvm::Constant *Dst; + if (DerivedToBase) + Dst = llvm::ConstantExpr::getNSWSub(C, Offset); + else + Dst = llvm::ConstantExpr::getNSWAdd(C, Offset); + + return llvm::ConstantExpr::getSelect(IsNull, Null, Dst); + } + // The this-adjustment is left-shifted by 1 on ARM. if (IsARM) { - uint64_t OffsetV = cast(Offset)->getZExtValue(); + int64_t OffsetV = cast(Offset)->getSExtValue(); OffsetV <<= 1; Offset = llvm::ConstantInt::get(Offset->getType(), OffsetV); } llvm::ConstantStruct *CS = cast(C); - llvm::Constant *Values[2] = { - CS->getOperand(0), - llvm::ConstantExpr::getAdd(CS->getOperand(1), Offset) - }; + llvm::Constant *Values[2] = { CS->getOperand(0), 0 }; + if (DerivedToBase) + Values[1] = llvm::ConstantExpr::getSub(CS->getOperand(1), Offset); + else + Values[1] = llvm::ConstantExpr::getAdd(CS->getOperand(1), Offset); + return llvm::ConstantStruct::get(CGM.getLLVMContext(), Values, 2, /*Packed=*/false); } llvm::Constant * -ItaniumCXXABI::EmitNullMemberFunctionPointer(const MemberPointerType *MPT) { - const llvm::Type *ptrdiff_t = - CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType()); +ItaniumCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) { + const llvm::Type *ptrdiff_t = getPtrDiffTy(); + + // Itanium C++ ABI 2.3: + // A NULL pointer is represented as -1. + if (MPT->isMemberDataPointer()) + return llvm::ConstantInt::get(ptrdiff_t, -1ULL, /*isSigned=*/true); llvm::Constant *Zero = llvm::ConstantInt::get(ptrdiff_t, 0); llvm::Constant *Values[2] = { Zero, Zero }; @@ -304,14 +397,29 @@ ItaniumCXXABI::EmitNullMemberFunctionPointer(const MemberPointerType *MPT) { /*Packed=*/false); } -llvm::Constant * -ItaniumCXXABI::EmitMemberFunctionPointer(const CXXMethodDecl *MD) { +llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const FieldDecl *FD) { + // Itanium C++ ABI 2.3: + // A pointer to data member is an offset from the base address of + // the class object containing it, represented as a ptrdiff_t + + QualType ClassType = CGM.getContext().getTypeDeclType(FD->getParent()); + const llvm::StructType *ClassLTy = + cast(CGM.getTypes().ConvertType(ClassType)); + + const CGRecordLayout &RL = CGM.getTypes().getCGRecordLayout(FD->getParent()); + unsigned FieldNo = RL.getLLVMFieldNo(FD); + uint64_t Offset = + CGM.getTargetData().getStructLayout(ClassLTy)->getElementOffset(FieldNo); + + return llvm::ConstantInt::get(getPtrDiffTy(), Offset); +} + +llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) { 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()); + const llvm::Type *ptrdiff_t = getPtrDiffTy(); // Get the function pointer (or index if this is a virtual function). llvm::Constant *MemPtr[2]; @@ -367,25 +475,13 @@ ItaniumCXXABI::EmitMemberFunctionPointer(const CXXMethodDecl *MD) { /// /// ARM is different here only because null-ness is more complicated. llvm::Value * -ItaniumCXXABI::EmitMemberFunctionPointerComparison(CodeGenFunction &CGF, - llvm::Value *L, - llvm::Value *R, - const MemberPointerType *MPT, - bool Inequality) { +ItaniumCXXABI::EmitMemberPointerComparison(CodeGenFunction &CGF, + llvm::Value *L, + llvm::Value *R, + const MemberPointerType *MPT, + bool Inequality) { CGBuilderTy &Builder = CGF.Builder; - llvm::Value *LPtr = Builder.CreateExtractValue(L, 0, "lhs.memptr.ptr"); - llvm::Value *RPtr = Builder.CreateExtractValue(R, 0, "rhs.memptr.ptr"); - - // The Itanium tautology is: - // (L == R) <==> (L.ptr == R.ptr /\ (L.ptr == 0 \/ L.adj == R.adj)) - // The ARM tautology is: - // (L == R) <==> (L.ptr == R.ptr /\ - // (L.adj == R.adj \/ - // (L.ptr == 0 /\ ((L.adj|R.adj) & 1) == 0))) - // The inequality tautologies have exactly the same structure, except - // applying De Morgan's laws. - llvm::ICmpInst::Predicate Eq; llvm::Instruction::BinaryOps And, Or; if (Inequality) { @@ -398,6 +494,24 @@ ItaniumCXXABI::EmitMemberFunctionPointerComparison(CodeGenFunction &CGF, Or = llvm::Instruction::Or; } + // Member data pointers are easy because there's a unique null + // value, so it just comes down to bitwise equality. + if (MPT->isMemberDataPointer()) + return Builder.CreateICmp(Eq, L, R); + + // For member function pointers, the tautologies are more complex. + // The Itanium tautology is: + // (L == R) <==> (L.ptr == R.ptr /\ (L.ptr == 0 \/ L.adj == R.adj)) + // The ARM tautology is: + // (L == R) <==> (L.ptr == R.ptr /\ + // (L.adj == R.adj \/ + // (L.ptr == 0 /\ ((L.adj|R.adj) & 1) == 0))) + // The inequality tautologies have exactly the same structure, except + // applying De Morgan's laws. + + llvm::Value *LPtr = Builder.CreateExtractValue(L, 0, "lhs.memptr.ptr"); + llvm::Value *RPtr = Builder.CreateExtractValue(R, 0, "rhs.memptr.ptr"); + // This condition tests whether L.ptr == R.ptr. This must always be // true for equality to hold. llvm::Value *PtrEq = Builder.CreateICmp(Eq, LPtr, RPtr, "cmp.ptr"); @@ -435,10 +549,18 @@ ItaniumCXXABI::EmitMemberFunctionPointerComparison(CodeGenFunction &CGF, } llvm::Value * -ItaniumCXXABI::EmitMemberFunctionPointerIsNotNull(CodeGenFunction &CGF, - llvm::Value *MemPtr, - const MemberPointerType *MPT) { +ItaniumCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF, + llvm::Value *MemPtr, + const MemberPointerType *MPT) { CGBuilderTy &Builder = CGF.Builder; + + /// For member data pointers, this is just a check against -1. + if (MPT->isMemberDataPointer()) { + assert(MemPtr->getType() == getPtrDiffTy()); + llvm::Value *NegativeOne = + llvm::Constant::getAllOnesValue(MemPtr->getType()); + return Builder.CreateICmpNE(MemPtr, NegativeOne, "memptr.tobool"); + } // In Itanium, a member function pointer is null if 'ptr' is null. llvm::Value *Ptr = Builder.CreateExtractValue(MemPtr, 0, "memptr.ptr"); diff --git a/test/CodeGenCXX/member-function-pointers.cpp b/test/CodeGenCXX/member-function-pointers.cpp index 3e95f39a42..78a571e196 100644 --- a/test/CodeGenCXX/member-function-pointers.cpp +++ b/test/CodeGenCXX/member-function-pointers.cpp @@ -38,14 +38,14 @@ void f() { // CHECK: [[TMP:%.*]] = load %0* @pa, align 8 // CHECK: [[TMPADJ:%.*]] = extractvalue %0 [[TMP]], 1 - // CHECK: [[ADJ:%.*]] = add i64 [[TMPADJ]], 16 + // CHECK: [[ADJ:%.*]] = add nsw i64 [[TMPADJ]], 16 // CHECK: [[RES:%.*]] = insertvalue %0 [[TMP]], i64 [[ADJ]], 1 // CHECK: store %0 [[RES]], %0* @pc, align 8 pc = pa; // CHECK: [[TMP:%.*]] = load %0* @pc, align 8 // CHECK: [[TMPADJ:%.*]] = extractvalue %0 [[TMP]], 1 - // CHECK: [[ADJ:%.*]] = sub i64 [[TMPADJ]], 16 + // CHECK: [[ADJ:%.*]] = sub nsw i64 [[TMPADJ]], 16 // CHECK: [[RES:%.*]] = insertvalue %0 [[TMP]], i64 [[ADJ]], 1 // CHECK: store %0 [[RES]], %0* @pa, align 8 pa = static_cast(pc); diff --git a/test/CodeGenCXX/pointers-to-data-members.cpp b/test/CodeGenCXX/pointers-to-data-members.cpp index 70308c6abc..60c1661e06 100644 --- a/test/CodeGenCXX/pointers-to-data-members.cpp +++ b/test/CodeGenCXX/pointers-to-data-members.cpp @@ -65,15 +65,21 @@ int A::*pa; int C::*pc; void f() { - // CHECK: store i64 -1, i64* @_ZN5Casts2paE + // CHECK: store i64 -1, i64* @_ZN5Casts2paE pa = 0; - // CHECK: [[ADJ:%[a-zA-Z0-9\.]+]] = add nsw i64 {{.*}}, 4 - // CHECK: store i64 [[ADJ]], i64* @_ZN5Casts2pcE + // CHECK-NEXT: [[TMP:%.*]] = load i64* @_ZN5Casts2paE, align 8 + // CHECK-NEXT: [[ADJ:%.*]] = add nsw i64 [[TMP]], 4 + // CHECK-NEXT: [[ISNULL:%.*]] = icmp eq i64 [[TMP]], -1 + // CHECK-NEXT: [[RES:%.*]] = select i1 [[ISNULL]], i64 [[TMP]], i64 [[ADJ]] + // CHECK-NEXT: store i64 [[RES]], i64* @_ZN5Casts2pcE pc = pa; - // CHECK: [[ADJ:%[a-zA-Z0-9\.]+]] = sub nsw i64 {{.*}}, 4 - // CHECK: store i64 [[ADJ]], i64* @_ZN5Casts2paE + // CHECK-NEXT: [[TMP:%.*]] = load i64* @_ZN5Casts2pcE, align 8 + // CHECK-NEXT: [[ADJ:%.*]] = sub nsw i64 [[TMP]], 4 + // CHECK-NEXT: [[ISNULL:%.*]] = icmp eq i64 [[TMP]], -1 + // CHECK-NEXT: [[RES:%.*]] = select i1 [[ISNULL]], i64 [[TMP]], i64 [[ADJ]] + // CHECK-NEXT: store i64 [[RES]], i64* @_ZN5Casts2paE pa = static_cast(pc); }