[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