[cfe-commits] r111789 - in /cfe/trunk: include/clang/AST/Type.h lib/CodeGen/CGCXX.cpp lib/CodeGen/CGCXXABI.h lib/CodeGen/CGExpr.cpp lib/CodeGen/CGExprConstant.cpp lib/CodeGen/CGExprScalar.cpp lib/CodeGen/CodeGenModule.h lib/CodeGen/CodeGenTypes.cpp lib/CodeGen/ItaniumCXXABI.cpp test/CodeGenCXX/member-function-pointers.cpp test/CodeGenCXX/pointers-to-data-members.cpp
John McCall
rjmccall at apple.com
Sun Aug 22 18:21:21 PDT 2010
Author: rjmccall
Date: Sun Aug 22 20:21:21 2010
New Revision: 111789
URL: http://llvm.org/viewvc/llvm-project?rev=111789&view=rev
Log:
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.
Modified:
cfe/trunk/include/clang/AST/Type.h
cfe/trunk/lib/CodeGen/CGCXX.cpp
cfe/trunk/lib/CodeGen/CGCXXABI.h
cfe/trunk/lib/CodeGen/CGExpr.cpp
cfe/trunk/lib/CodeGen/CGExprConstant.cpp
cfe/trunk/lib/CodeGen/CGExprScalar.cpp
cfe/trunk/lib/CodeGen/CodeGenModule.h
cfe/trunk/lib/CodeGen/CodeGenTypes.cpp
cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
cfe/trunk/test/CodeGenCXX/member-function-pointers.cpp
cfe/trunk/test/CodeGenCXX/pointers-to-data-members.cpp
Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=111789&r1=111788&r2=111789&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Sun Aug 22 20:21:21 2010
@@ -1359,9 +1359,20 @@
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::isMemberFunctionPointerType() const {
if (const MemberPointerType* T = getAs<MemberPointerType>())
- return T->getPointeeType()->isFunctionType();
+ return T->isMemberFunctionPointer();
else
return false;
}
inline bool Type::isMemberDataPointerType() const {
if (const MemberPointerType* T = getAs<MemberPointerType>())
- return !T->getPointeeType()->isFunctionType();
+ return T->isMemberDataPointer();
else
return false;
}
Modified: cfe/trunk/lib/CodeGen/CGCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXX.cpp?rev=111789&r1=111788&r2=111789&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCXX.cpp Sun Aug 22 20:21:21 2010
@@ -318,6 +318,9 @@
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 @@
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 @@
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;
Modified: cfe/trunk/lib/CodeGen/CGCXXABI.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.h?rev=111789&r1=111788&r2=111789&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXXABI.h (original)
+++ cfe/trunk/lib/CodeGen/CGCXXABI.h Sun Aug 22 20:21:21 2010
@@ -17,6 +17,7 @@
namespace llvm {
class Constant;
+ class Type;
class Value;
}
@@ -24,6 +25,7 @@
class CastExpr;
class CXXMethodDecl;
class CXXRecordDecl;
+ class FieldDecl;
class MemberPointerType;
class QualType;
@@ -46,44 +48,57 @@
/// 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);
-
- // Manipulations on constant expressions.
-
- /// \brief Returns true if the given member pointer can be
- /// zero-initialized (in the C++ sense) with an LLVM
- /// zeroinitialized.
+ /// Perform a derived-to-base or base-to-derived member pointer
+ /// conversion.
+ virtual llvm::Value *EmitMemberPointerConversion(CodeGenFunction &CGF,
+ const CastExpr *E,
+ llvm::Value *Src);
+
+ /// 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);
+
+ /// 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.
Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=111789&r1=111788&r2=111789&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Sun Aug 22 20:21:21 2010
@@ -65,12 +65,12 @@
/// 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<MemberPointerType>()) {
llvm::Value *MemPtr = EmitScalarExpr(E);
- return CGM.getCXXABI().EmitMemberFunctionPointerIsNotNull(CGF, MemPtr,
- E->getType()->getAs<MemberPointerType>());
+ 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 @@
// we're actually emitting a member pointer.
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(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<FunctionDecl>(ND))
@@ -1185,7 +1185,7 @@
// If we're emitting a field as an independent lvalue, we're
// actually emitting a member pointer.
if (const FieldDecl *FD = dyn_cast<FieldDecl>(ND)) {
- llvm::Value *V = CGM.EmitPointerToDataMember(FD);
+ llvm::Value *V = CGM.getCXXABI().EmitMemberPointer(FD);
return MakeAddrLValue(V, FD->getType(), Alignment);
}
Modified: cfe/trunk/lib/CodeGen/CGExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprConstant.cpp?rev=111789&r1=111788&r2=111789&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprConstant.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprConstant.cpp Sun Aug 22 20:21:21 2010
@@ -454,22 +454,15 @@
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<MemberPointerType>()) {
- QualType T = MPT->getPointeeType();
DeclRefExpr *DRE = cast<DeclRefExpr>(E->getSubExpr());
-
NamedDecl *ND = DRE->getDecl();
- if (T->isFunctionProtoType())
- return EmitMemberFunctionPointer(cast<CXXMethodDecl>(ND));
-
- // We have a pointer to data member.
- return CGM.EmitPointerToDataMember(cast<FieldDecl>(ND));
+ if (MPT->isMemberFunctionPointer())
+ return CGM.getCXXABI().EmitMemberPointer(cast<CXXMethodDecl>(ND));
+ else
+ return CGM.getCXXABI().EmitMemberPointer(cast<FieldDecl>(ND));
}
return 0;
@@ -535,24 +528,16 @@
}
case CastExpr::CK_NullToMemberPointer: {
const MemberPointerType *MPT = E->getType()->getAs<MemberPointerType>();
- 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<MemberPointerType>();
-
- // 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 @@
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<CXXRecordDecl>(FD->getParent());
- QualType ClassType =
- getContext().getTypeDeclType(const_cast<CXXRecordDecl *>(ClassDecl));
-
- const llvm::StructType *ClassLTy =
- cast<llvm::StructType>(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);
-}
Modified: cfe/trunk/lib/CodeGen/CGExprScalar.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprScalar.cpp?rev=111789&r1=111788&r2=111789&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprScalar.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprScalar.cpp Sun Aug 22 20:21:21 2010
@@ -414,11 +414,8 @@
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<MemberPointerType>(SrcType))
+ return CGF.CGM.getCXXABI().EmitMemberPointerIsNotNull(CGF, Src, MPT);
assert((SrcType->isIntegerType() || isa<llvm::PointerType>(Src->getType())) &&
"Unknown scalar type to convert");
@@ -567,14 +564,10 @@
}
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<MemberPointerType>())
+ return CGF.CGM.getCXXABI().EmitNullMemberPointer(MPT);
+
+ return llvm::Constant::getNullValue(ConvertType(Ty));
}
//===----------------------------------------------------------------------===//
@@ -994,17 +987,15 @@
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<MemberPointerType>());
-
- return CGF.CGM.EmitNullConstant(DestTy);
+ const MemberPointerType *MPT = CE->getType()->getAs<MemberPointerType>();
+ return CGF.CGM.getCXXABI().EmitNullMemberPointer(MPT);
+ }
case CastExpr::CK_BaseToDerivedMemberPointer:
case CastExpr::CK_DerivedToBaseMemberPointer: {
@@ -1016,33 +1007,9 @@
// 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<CXXRecordDecl>(E->getType()->getAs<MemberPointerType>()->
- getClass()->getAs<RecordType>()->getDecl());
- const CXXRecordDecl *DerivedDecl =
- cast<CXXRecordDecl>(CE->getType()->getAs<MemberPointerType>()->
- getClass()->getAs<RecordType>()->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 @@
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<MemberPointerType>();
+ 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 @@
TestAndClearIgnoreResultAssign();
Value *Result;
QualType LHSTy = E->getLHS()->getType();
- if (LHSTy->isMemberFunctionPointerType()) {
+ if (const MemberPointerType *MPT = LHSTy->getAs<MemberPointerType>()) {
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<MemberPointerType>(),
- 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());
Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=111789&r1=111788&r2=111789&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.h Sun Aug 22 20:21:21 2010
@@ -434,8 +434,6 @@
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
Modified: cfe/trunk/lib/CodeGen/CodeGenTypes.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenTypes.cpp?rev=111789&r1=111788&r2=111789&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenTypes.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenTypes.cpp Sun Aug 22 20:21:21 2010
@@ -402,17 +402,7 @@
}
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<MemberPointerType>(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<MemberPointerType>(&Ty));
}
}
Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=111789&r1=111788&r2=111789&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Sun Aug 22 20:21:21 2010
@@ -19,10 +19,12 @@
//===----------------------------------------------------------------------===//
#include "CGCXXABI.h"
+#include "CGRecordLayout.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "Mangle.h"
#include <clang/AST/Type.h>
+#include <llvm/Target/TargetData.h>
#include <llvm/Value.h>
using namespace clang;
@@ -30,12 +32,26 @@
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<llvm::IntegerType>(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 @@
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::Constant *EmitMemberFunctionPointerConversion(llvm::Constant *C,
- const CastExpr *E);
-
- llvm::Constant *EmitNullMemberFunctionPointer(const MemberPointerType *MPT);
-
- llvm::Constant *EmitMemberFunctionPointer(const CXXMethodDecl *MD);
-
- llvm::Value *EmitMemberFunctionPointerComparison(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 *EmitMemberPointerConversion(CodeGenFunction &CGF,
+ const CastExpr *E,
+ llvm::Value *Src);
+
+ llvm::Constant *EmitMemberPointerConversion(llvm::Constant *C,
+ const CastExpr *E);
+
+ llvm::Constant *EmitNullMemberPointer(const MemberPointerType *MPT);
+
+ llvm::Constant *EmitMemberPointer(const CXXMethodDecl *MD);
+ llvm::Constant *EmitMemberPointer(const FieldDecl *FD);
+
+ llvm::Value *EmitMemberPointerComparison(CodeGenFunction &CGF,
+ llvm::Value *L,
+ llvm::Value *R,
+ const MemberPointerType *MPT,
+ bool Inequality);
+
+ llvm::Value *EmitMemberPointerIsNotNull(CodeGenFunction &CGF,
+ llvm::Value *Addr,
+ const MemberPointerType *MPT);
};
class ARMCXXABI : public ItaniumCXXABI {
@@ -88,11 +103,15 @@
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 @@
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 @@
}
/// 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<llvm::Constant>(Src))
- return EmitMemberFunctionPointerConversion(cast<llvm::Constant>(Src), E);
+ return EmitMemberPointerConversion(cast<llvm::Constant>(Src), E);
CGBuilderTy &Builder = CGF.Builder;
@@ -233,6 +271,21 @@
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<llvm::ConstantInt>(Adj)->getZExtValue();
@@ -243,16 +296,16 @@
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<MemberPointerType>();
const MemberPointerType *DestTy =
@@ -275,28 +328,68 @@
// 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<llvm::ConstantInt>(C)) {
+ int64_t Src = CI->getSExtValue();
+
+ // Null converts to null.
+ if (Src == -1) return CI;
+
+ // Otherwise, just add the offset.
+ int64_t OffsetV = cast<llvm::ConstantInt>(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<llvm::ConstantInt>(Offset)->getZExtValue();
+ int64_t OffsetV = cast<llvm::ConstantInt>(Offset)->getSExtValue();
OffsetV <<= 1;
Offset = llvm::ConstantInt::get(Offset->getType(), OffsetV);
}
llvm::ConstantStruct *CS = cast<llvm::ConstantStruct>(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 @@
/*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<llvm::StructType>(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 @@
///
/// 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 @@
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 @@
}
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");
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=111789&r1=111788&r2=111789&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/member-function-pointers.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/member-function-pointers.cpp Sun Aug 22 20:21:21 2010
@@ -38,14 +38,14 @@
// 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<void (A::*)()>(pc);
Modified: cfe/trunk/test/CodeGenCXX/pointers-to-data-members.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/pointers-to-data-members.cpp?rev=111789&r1=111788&r2=111789&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/pointers-to-data-members.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/pointers-to-data-members.cpp Sun Aug 22 20:21:21 2010
@@ -65,15 +65,21 @@
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<int A::*>(pc);
}
More information about the cfe-commits
mailing list