- Fix null handling for reinterpret casts.

Hi rjmccall,

http://llvm-reviews.chandlerc.com/D741

CHANGE SINCE LAST DIFF
  http://llvm-reviews.chandlerc.com/D741?vs=1827&id=1828#toc

Files:
  lib/CodeGen/MicrosoftCXXABI.cpp
  test/CodeGenCXX/microsoft-abi-member-pointers.cpp
Index: lib/CodeGen/MicrosoftCXXABI.cpp
===================================================================
--- lib/CodeGen/MicrosoftCXXABI.cpp
+++ lib/CodeGen/MicrosoftCXXABI.cpp
@@ -130,6 +130,10 @@
     return  llvm::Constant::getAllOnesValue(CGM.IntTy);
   }
 
+  llvm::Constant *getConstantOrZeroInt(llvm::Constant *C) {
+    return C ? C : getZeroInt();
+  }
+
   void
   GetNullMemberPointerFields(const MemberPointerType *MPT,
                              llvm::SmallVectorImpl<llvm::Constant *> &fields);
@@ -143,7 +147,15 @@
   /// function member pointers.
   llvm::Constant *EmitFullMemberPointer(llvm::Constant *FirstField,
                                         bool IsMemberFunction,
-                                        const CXXRecordDecl *RD);
+                                        const CXXRecordDecl *RD,
+                                        CharUnits NonVirtualBaseAdjustment);
+
+  llvm::Constant *BuildMemberPointer(const CXXRecordDecl *RD,
+                                     const CXXMethodDecl *MD,
+                                     CharUnits NonVirtualBaseAdjustment);
+
+  bool MemberPointerConstantIsNull(const MemberPointerType *MPT,
+                                   llvm::Constant *MP);
 
 public:
   virtual llvm::Type *ConvertMemberPointerType(const MemberPointerType *MPT);
@@ -172,6 +184,13 @@
                                                     llvm::Value *MemPtr,
                                                   const MemberPointerType *MPT);
 
+  virtual llvm::Value *EmitMemberPointerConversion(CodeGenFunction &CGF,
+                                                   const CastExpr *E,
+                                                   llvm::Value *Src);
+
+  virtual llvm::Constant *EmitMemberPointerConversion(const CastExpr *E,
+                                                      llvm::Constant *Src);
+
   virtual llvm::Value *
   EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
                                   llvm::Value *&This,
@@ -429,8 +448,10 @@
   return Inheritance == MSIM_Unspecified;
 }
 
-static bool hasOnlyOneField(MSInheritanceModel Inheritance) {
-  return Inheritance <= MSIM_SinglePolymorphic;
+static bool hasOnlyOneField(bool IsMemberFunction,
+                            MSInheritanceModel Inheritance) {
+  return Inheritance <= MSIM_SinglePolymorphic ||
+      (!IsMemberFunction && Inheritance <= MSIM_MultiplePolymorphic);
 }
 
 // Only member pointers to functions need a this adjustment, since it can be
@@ -531,22 +552,25 @@
 llvm::Constant *
 MicrosoftCXXABI::EmitFullMemberPointer(llvm::Constant *FirstField,
                                        bool IsMemberFunction,
-                                       const CXXRecordDecl *RD)
+                                       const CXXRecordDecl *RD,
+                                       CharUnits NonVirtualBaseAdjustment)
 {
   MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
 
   // Single inheritance class member pointer are represented as scalars instead
   // of aggregates.
-  if (hasOnlyOneField(Inheritance))
+  if (hasOnlyOneField(IsMemberFunction, Inheritance))
     return FirstField;
 
   llvm::SmallVector<llvm::Constant *, 4> fields;
   fields.push_back(FirstField);
 
   if (hasNonVirtualBaseAdjustmentField(IsMemberFunction, Inheritance))
-    fields.push_back(getZeroInt());
+    fields.push_back(llvm::ConstantInt::get(
+      CGM.IntTy, NonVirtualBaseAdjustment.getQuantity()));
 
   if (hasVBPtrOffsetField(Inheritance)) {
+    // FIXME: We actually need to search non-virtual bases for vbptrs.
     int64_t VBPtrOffset =
       getContext().getASTRecordLayout(RD).getVBPtrOffset().getQuantity();
     if (VBPtrOffset == -1)
@@ -567,14 +591,54 @@
   const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
   llvm::Constant *FirstField =
     llvm::ConstantInt::get(CGM.IntTy, offset.getQuantity());
-  return EmitFullMemberPointer(FirstField, /*IsMemberFunction=*/false, RD);
+  return EmitFullMemberPointer(FirstField, /*IsMemberFunction=*/false, RD,
+                               CharUnits::Zero());
+}
+
+llvm::Constant *MicrosoftCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) {
+  return BuildMemberPointer(MD->getParent(), MD, CharUnits::Zero());
+}
+
+llvm::Constant *MicrosoftCXXABI::EmitMemberPointer(const APValue &MP,
+                                                   QualType MPType) {
+  const MemberPointerType *MPT = MPType->castAs<MemberPointerType>();
+  const ValueDecl *MPD = MP.getMemberPointerDecl();
+  if (!MPD)
+    return EmitNullMemberPointer(MPT);
+
+  // Compute the non-virtual this adjustment.
+  // FIXME PR15713: Support virtual inheritance paths.
+  CharUnits ThisAdjustment = CharUnits::Zero();
+  ArrayRef<const CXXRecordDecl*> Path = MP.getMemberPointerPath();
+  bool DerivedMember = MP.isMemberPointerToDerivedMember();
+  const CXXRecordDecl *RD = cast<CXXRecordDecl>(MPD->getDeclContext());
+  for (unsigned I = 0, N = Path.size(); I != N; ++I) {
+    const CXXRecordDecl *Base = RD;
+    const CXXRecordDecl *Derived = Path[I];
+    if (DerivedMember)
+      std::swap(Base, Derived);
+    ThisAdjustment +=
+      getContext().getASTRecordLayout(Derived).getBaseClassOffset(Base);
+    RD = Path[I];
+  }
+  if (DerivedMember)
+    ThisAdjustment = -ThisAdjustment;
+
+  if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MPD))
+    return BuildMemberPointer(MPT->getClass()->getAsCXXRecordDecl(),
+                              MD, ThisAdjustment);
+
+  CharUnits FieldOffset =
+    getContext().toCharUnitsFromBits(getContext().getFieldOffset(MPD));
+  return EmitMemberDataPointer(MPT, ThisAdjustment + FieldOffset);
 }
 
 llvm::Constant *
-MicrosoftCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) {
+MicrosoftCXXABI::BuildMemberPointer(const CXXRecordDecl *RD,
+                                    const CXXMethodDecl *MD,
+                                    CharUnits NonVirtualBaseAdjustment) {
   assert(MD->isInstance() && "Member function must not be static!");
   MD = MD->getCanonicalDecl();
-  const CXXRecordDecl *RD = MD->getParent();
   CodeGenTypes &Types = CGM.getTypes();
 
   llvm::Constant *FirstField;
@@ -599,15 +663,8 @@
   }
 
   // The rest of the fields are common with data member pointers.
-  return EmitFullMemberPointer(FirstField, /*IsMemberFunction=*/true, RD);
-}
-
-llvm::Constant *
-MicrosoftCXXABI::EmitMemberPointer(const APValue &MP, QualType MPT) {
-  // FIXME PR15875: Implement member pointer conversions for Constants.
-  const CXXRecordDecl *RD = MPT->castAs<MemberPointerType>()->getClass()->getAsCXXRecordDecl();
-  return EmitFullMemberPointer(llvm::Constant::getNullValue(CGM.VoidPtrTy),
-                               /*IsMemberFunction=*/true, RD);
+  return EmitFullMemberPointer(FirstField, /*IsMemberFunction=*/true, RD,
+                               NonVirtualBaseAdjustment);
 }
 
 /// Member pointers are the same if they're either bitwise identical *or* both
@@ -638,7 +695,7 @@
   // single icmp.
   const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
   MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
-  if (hasOnlyOneField(Inheritance))
+  if (hasOnlyOneField(MPT->isMemberFunctionPointer(), Inheritance))
     return Builder.CreateICmp(Eq, L, R);
 
   // Compare the first field.
@@ -703,6 +760,37 @@
   return Res;
 }
 
+bool MicrosoftCXXABI::MemberPointerConstantIsNull(const MemberPointerType *MPT,
+                                                  llvm::Constant *Val) {
+  // Function pointers are null if the pointer in the first field is null.
+  if (MPT->isMemberFunctionPointer()) {
+    llvm::Constant *FirstField = Val->getType()->isStructTy() ?
+      Val->getAggregateElement(0U) : Val;
+    return FirstField->isNullValue();
+  }
+
+  // If it's not a function pointer and it's zero initializable, we can easily
+  // check zero.
+  if (isZeroInitializable(MPT) && Val->isNullValue())
+    return true;
+
+  // Otherwise, break down all the fields for comparison.  Hopefully these
+  // little Constants are reused, while a big null struct might not be.
+  llvm::SmallVector<llvm::Constant *, 4> Fields;
+  GetNullMemberPointerFields(MPT, Fields);
+  if (Fields.size() == 1) {
+    assert(Val->getType()->isIntegerTy());
+    return Val == Fields[0];
+  }
+
+  unsigned I, E;
+  for (I = 0, E = Fields.size(); I != E; ++I) {
+    if (Val->getAggregateElement(I) != Fields[I])
+      break;
+  }
+  return I == E;
+}
+
 // Returns an adjusted base cast to i8*, since we do more address arithmetic on
 // it.
 llvm::Value *
@@ -803,6 +891,183 @@
   return Builder.CreateBitCast(Addr, PType);
 }
 
+static MSInheritanceModel
+getInheritanceFromMemptr(const MemberPointerType *MPT) {
+  return MPT->getClass()->getAsCXXRecordDecl()->getMSInheritanceModel();
+}
+
+llvm::Value *
+MicrosoftCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF,
+                                             const CastExpr *E,
+                                             llvm::Value *Src) {
+  assert(E->getCastKind() == CK_DerivedToBaseMemberPointer ||
+         E->getCastKind() == CK_BaseToDerivedMemberPointer ||
+         E->getCastKind() == CK_ReinterpretMemberPointer);
+
+  // Use constant emission if we can.
+  if (isa<llvm::Constant>(Src))
+    return EmitMemberPointerConversion(E, cast<llvm::Constant>(Src));
+
+  // We may be adding or dropping fields from the member pointer, so we need
+  // both types and the inheritance models of both records.
+  const MemberPointerType *SrcTy =
+    E->getSubExpr()->getType()->castAs<MemberPointerType>();
+  const MemberPointerType *DstTy = E->getType()->castAs<MemberPointerType>();
+  MSInheritanceModel SrcInheritance = getInheritanceFromMemptr(SrcTy);
+  MSInheritanceModel DstInheritance = getInheritanceFromMemptr(DstTy);
+
+  CGBuilderTy &Builder = CGF.Builder;
+
+  // Branch past the conversion if Src is null.
+  llvm::Value *IsNotNull = EmitMemberPointerIsNotNull(CGF, Src, SrcTy);
+  llvm::Constant *DstNull = EmitNullMemberPointer(DstTy);
+
+  // Reinterpret casts are a select between null and src, since the null
+  // representation can change.
+  if (E->getCastKind() == CK_ReinterpretMemberPointer)
+    return Builder.CreateSelect(IsNotNull, Src, DstNull);
+
+  llvm::BasicBlock *OriginalBB = Builder.GetInsertBlock();
+  llvm::BasicBlock *ConvertBB = CGF.createBasicBlock("memptr.convert");
+  llvm::BasicBlock *ContinueBB = CGF.createBasicBlock("memptr.converted");
+  Builder.CreateCondBr(IsNotNull, ConvertBB, ContinueBB);
+  CGF.EmitBlock(ConvertBB);
+
+  // Decompose src.
+  llvm::Value *FirstField = Src;
+  llvm::Value *NonVirtualBaseAdjustment = 0;
+  llvm::Value *VirtualBaseAdjustmentOffset = 0;
+  llvm::Value *VBPtrOffset = 0;
+  bool IsFunc = SrcTy->isMemberFunctionPointer();
+  if (!hasOnlyOneField(IsFunc, SrcInheritance)) {
+    // We need to extract values.
+    unsigned I = 0;
+    FirstField = Builder.CreateExtractValue(Src, I++);
+    if (hasNonVirtualBaseAdjustmentField(IsFunc, SrcInheritance))
+      NonVirtualBaseAdjustment = Builder.CreateExtractValue(Src, I++);
+    if (hasVBPtrOffsetField(SrcInheritance))
+      VBPtrOffset = Builder.CreateExtractValue(Src, I++);
+    if (hasVirtualBaseAdjustmentField(SrcInheritance))
+      VirtualBaseAdjustmentOffset = Builder.CreateExtractValue(Src, I++);
+  }
+
+  // For data pointers, we adjust the field offset directly.  For functions, we
+  // have a separate field.
+  llvm::Constant *Adj = getMemberPointerAdjustment(E);
+  if (Adj) {
+    llvm::Value *&NVAdjustField = IsFunc ? NonVirtualBaseAdjustment : FirstField;
+    bool isDerivedToBase = (E->getCastKind() == CK_DerivedToBaseMemberPointer);
+    if (!NVAdjustField)  // If this field didn't exist in src, it's zero.
+      NVAdjustField = getZeroInt();
+    if (isDerivedToBase)
+      NVAdjustField = Builder.CreateNSWSub(NVAdjustField, Adj, "adj");
+    else
+      NVAdjustField = Builder.CreateNSWAdd(NVAdjustField, Adj, "adj");
+  }
+
+  // FIXME PR15713: Support conversions through virtually derived classes.
+
+  // Recompose dst from the null struct and the adjusted fields from src.
+  llvm::Value *Dst;
+  if (hasOnlyOneField(IsFunc, DstInheritance)) {
+    Dst = FirstField;
+  } else {
+    // Any fields not in src should be zero.
+    Dst = llvm::ConstantAggregateZero::get(ConvertMemberPointerType(DstTy));
+    unsigned Idx = 0;
+    Dst = Builder.CreateInsertValue(Dst, FirstField, Idx++);
+    if (NonVirtualBaseAdjustment &&
+        hasNonVirtualBaseAdjustmentField(IsFunc, DstInheritance))
+      Dst = Builder.CreateInsertValue(Dst, NonVirtualBaseAdjustment, Idx++);
+    // FIXME: Bug here if src had no VBPtrOffset but dst does, Idx isn't
+    // updated.
+    if (VBPtrOffset && hasVBPtrOffsetField(DstInheritance))
+      Dst = Builder.CreateInsertValue(Dst, VBPtrOffset, Idx++);
+    if (VirtualBaseAdjustmentOffset &&
+        hasVirtualBaseAdjustmentField(DstInheritance))
+      Dst = Builder.CreateInsertValue(Dst, VirtualBaseAdjustmentOffset, Idx++);
+  }
+  Builder.CreateBr(ContinueBB);
+
+  // In the continuation, choose between DstNull and Dst.
+  CGF.EmitBlock(ContinueBB);
+  llvm::PHINode *Phi = Builder.CreatePHI(DstNull->getType(), 2, "memptr.converted");
+  Phi->addIncoming(DstNull, OriginalBB);
+  Phi->addIncoming(Dst, ConvertBB);
+  return Phi;
+}
+
+llvm::Constant *
+MicrosoftCXXABI::EmitMemberPointerConversion(const CastExpr *E,
+                                             llvm::Constant *Src) {
+  const MemberPointerType *SrcTy =
+    E->getSubExpr()->getType()->castAs<MemberPointerType>();
+  const MemberPointerType *DstTy = E->getType()->castAs<MemberPointerType>();
+
+  // If src is null, emit a new null for dst.  We can't return src because dst
+  // might have a new representation.
+  if (MemberPointerConstantIsNull(SrcTy, Src))
+    return EmitNullMemberPointer(DstTy);
+
+  // We don't need to do anything for reinterpret_casts of non-null member
+  // pointers.  We should only get here when the two type representations have
+  // the same size.
+  if (E->getCastKind() == CK_ReinterpretMemberPointer)
+    return Src;
+
+  MSInheritanceModel SrcInheritance = getInheritanceFromMemptr(SrcTy);
+  MSInheritanceModel DstInheritance = getInheritanceFromMemptr(DstTy);
+
+  // Decompose src.
+  llvm::Constant *FirstField = Src;
+  llvm::Constant *NonVirtualBaseAdjustment = 0;
+  llvm::Constant *VirtualBaseAdjustmentOffset = 0;
+  llvm::Constant *VBPtrOffset = 0;
+  bool IsFunc = SrcTy->isMemberFunctionPointer();
+  if (!hasOnlyOneField(IsFunc, SrcInheritance)) {
+    // We need to extract values.
+    unsigned I = 0;
+    FirstField = Src->getAggregateElement(I++);
+    if (hasNonVirtualBaseAdjustmentField(IsFunc, SrcInheritance))
+      NonVirtualBaseAdjustment = Src->getAggregateElement(I++);
+    if (hasVBPtrOffsetField(SrcInheritance))
+      VBPtrOffset = Src->getAggregateElement(I++);
+    if (hasVirtualBaseAdjustmentField(SrcInheritance))
+      VirtualBaseAdjustmentOffset = Src->getAggregateElement(I++);
+  }
+
+  // For data pointers, we adjust the field offset directly.  For functions, we
+  // have a separate field.
+  llvm::Constant *Adj = getMemberPointerAdjustment(E);
+  if (Adj) {
+    llvm::Constant *&NVAdjustField =
+      IsFunc ? NonVirtualBaseAdjustment : FirstField;
+    bool isDerivedToBase = (E->getCastKind() == CK_DerivedToBaseMemberPointer);
+    if (!NVAdjustField)  // If this field didn't exist in src, it's zero.
+      NVAdjustField = getZeroInt();
+    if (isDerivedToBase)
+      NVAdjustField = llvm::ConstantExpr::getNSWSub(NVAdjustField, Adj);
+    else
+      NVAdjustField = llvm::ConstantExpr::getNSWAdd(NVAdjustField, Adj);
+  }
+
+  // FIXME PR15713: Support conversions through virtually derived classes.
+
+  // Recompose dst from the null struct and the adjusted fields from src.
+  if (hasOnlyOneField(IsFunc, DstInheritance))
+    return FirstField;
+
+  llvm::SmallVector<llvm::Constant *, 4> Fields;
+  Fields.push_back(FirstField);
+  if (hasNonVirtualBaseAdjustmentField(IsFunc, DstInheritance))
+    Fields.push_back(getConstantOrZeroInt(NonVirtualBaseAdjustment));
+  if (hasVBPtrOffsetField(DstInheritance))
+    Fields.push_back(getConstantOrZeroInt(VBPtrOffset));
+  if (hasVirtualBaseAdjustmentField(DstInheritance))
+    Fields.push_back(getConstantOrZeroInt(VirtualBaseAdjustmentOffset));
+  return llvm::ConstantStruct::getAnon(Fields);
+}
+
 llvm::Value *
 MicrosoftCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
                                                  llvm::Value *&This,
Index: test/CodeGenCXX/microsoft-abi-member-pointers.cpp
===================================================================
--- test/CodeGenCXX/microsoft-abi-member-pointers.cpp
+++ test/CodeGenCXX/microsoft-abi-member-pointers.cpp
@@ -5,12 +5,14 @@
   int b;
 };
 struct B2 {
+  int b2;
   void foo();
 };
 struct Single : B1 {
   void foo();
 };
 struct Multiple : B1, B2 {
+  int m;
   void foo();
 };
 struct Virtual : virtual B1 {
@@ -34,6 +36,7 @@
 // offset.
 struct NonZeroVBPtr : POD, Virtual {
   int n;
+  void foo();
 };
 
 struct Unspecified;
@@ -68,6 +71,62 @@
   int u;
 };
 
+// Test memptr emission in a constant expression.
+namespace Const {
+void (Single     ::*s_f_mp)() = &Single::foo;
+void (Multiple   ::*m_f_mp)() = &B2::foo;
+void (Virtual    ::*v_f_mp)() = &Virtual::foo;
+void (Unspecified::*u_f_mp)() = &Unspecified::foo;
+// CHECK: @"\01?s_f_mp@Const@@3P8Single@@AEXXZA" =
+// CHECK:   global i8* bitcast ({{.*}} @"\01?foo@Single@@QAEXXZ" to i8*), align 4
+// CHECK: @"\01?m_f_mp@Const@@3P8Multiple@@AEXXZA" =
+// CHECK:   global { i8*, i32 } { i8* bitcast ({{.*}} @"\01?foo@B2@@QAEXXZ" to i8*), i32 4 }, align 4
+// CHECK: @"\01?v_f_mp@Const@@3P8Virtual@@AEXXZA" =
+// CHECK:   global { i8*, i32, i32 } { i8* bitcast ({{.*}} @"\01?foo@Virtual@@QAEXXZ" to i8*), i32 0, i32 0 }, align 4
+// CHECK: @"\01?u_f_mp@Const@@3P8Unspecified@@AEXXZA" =
+// CHECK:   global { i8*, i32, i32, i32 } { i8* bitcast ({{.*}} @"\01?foo@Unspecified@@QAEXXZ" to i8*), i32 0, i32 0, i32 0 }, align 4
+}
+
+namespace CastParam {
+// This exercises ConstExprEmitter instead of ValueDecl::evaluateValue.  The
+// extra reinterpret_cast for the parameter type requires more careful folding.
+// FIXME: Or does it?  If reinterpret_casts are no-ops, we should be able to
+// strip them in evaluateValue() and just proceed as normal with an APValue.
+struct A {
+  int a;
+  void foo(A *p);
+};
+struct B { int b; };
+struct C : B, A { int c; };
+
+void (A::*ptr1)(void *) = (void (A::*)(void *)) &A::foo;
+// CHECK: @"\01?ptr1@CastParam@@3P8A@1@AEXPAX@ZA" =
+// CHECK:   global i8* bitcast (void ({{.*}})* @"\01?foo@A@CastParam@@QAEXPAU12@@Z" to i8*), align 4
+
+// Try a reinterpret_cast followed by a memptr conversion.
+void (C::*ptr2)(void *) = (void (C::*)(void *)) (void (A::*)(void *)) &A::foo;
+// CHECK: @"\01?ptr2@CastParam@@3P8C@1@AEXPAX@ZA" =
+// CHECK:   global { i8*, i32 } { i8* bitcast (void ({{.*}})* @"\01?foo@A@CastParam@@QAEXPAU12@@Z" to i8*), i32 4 }, align 4
+
+void (C::*ptr3)(void *) = (void (C::*)(void *)) (void (A::*)(void *)) (void (A::*)(A *)) 0;
+// CHECK: @"\01?ptr3@CastParam@@3P8C@1@AEXPAX@ZA" =
+// CHECK:   global { i8*, i32 } zeroinitializer, align 4
+
+struct D : C {
+  virtual void isPolymorphic();
+  int d;
+};
+
+// Try a cast that changes the inheritance model.  Null for D is 0, but null for
+// C is -1.  We need the cast to long in order to hit the non-APValue path.
+int C::*ptr4 = (int C::*) (int D::*) (long D::*) 0;
+// CHECK: @"\01?ptr4@CastParam@@3PQC@1@HA" = global i32 -1, align 4
+
+// MSVC rejects this but we accept it.
+int C::*ptr5 = (int C::*) (long D::*) 0;
+// CHECK: @"\01?ptr5@CastParam@@3PQC@1@HA" = global i32 -1, align 4
+}
+
 struct UnspecWithVBPtr;
 int UnspecWithVBPtr::*forceUnspecWithVBPtr;
 struct UnspecWithVBPtr : B1, virtual B2 {
@@ -82,7 +141,7 @@
   void (Virtual    ::*v_f_memptr)() = &Virtual::foo;
   void (Unspecified::*u_f_memptr)() = &Unspecified::foo;
   void (UnspecWithVBPtr::*u2_f_memptr)() = &UnspecWithVBPtr::foo;
-// CHECK: define void @"\01?EmitNonVirtualMemberPointers@@YAXXZ"() #0 {
+// CHECK: define void @"\01?EmitNonVirtualMemberPointers@@YAXXZ"() {{.*}} {
 // CHECK:   alloca i8*, align 4
 // CHECK:   alloca { i8*, i32 }, align 4
 // CHECK:   alloca { i8*, i32, i32 }, align 4
@@ -112,7 +171,7 @@
   if (memptr)
     memptr = 0;
 // Check that member pointers use the right offsets and that null is -1.
-// CHECK:      define void @"\01?podMemPtrs@@YAXXZ"() #0 {
+// CHECK:      define void @"\01?podMemPtrs@@YAXXZ"() {{.*}} {
 // CHECK:        %[[memptr:.*]] = alloca i32, align 4
 // CHECK-NEXT:   store i32 0, i32* %[[memptr]], align 4
 // CHECK-NEXT:   store i32 4, i32* %[[memptr]], align 4
@@ -132,7 +191,7 @@
     memptr = 0;
 // Member pointers for polymorphic classes include the vtable slot in their
 // offset and use 0 to represent null.
-// CHECK:      define void @"\01?polymorphicMemPtrs@@YAXXZ"() #0 {
+// CHECK:      define void @"\01?polymorphicMemPtrs@@YAXXZ"() {{.*}} {
 // CHECK:        %[[memptr:.*]] = alloca i32, align 4
 // CHECK-NEXT:   store i32 4, i32* %[[memptr]], align 4
 // CHECK-NEXT:   store i32 8, i32* %[[memptr]], align 4
@@ -233,15 +292,15 @@
 void callMemberPointerSingle(Single *o, void (Single::*memptr)()) {
   (o->*memptr)();
 // Just look for an indirect thiscall.
-// CHECK: define void @"\01?callMemberPointerSingle@@{{.*}} #0 {
+// CHECK: define void @"\01?callMemberPointerSingle@@{{.*}} {{.*}} {
 // CHECK:   call x86_thiscallcc void %{{.*}}(%{{.*}} %{{.*}})
 // CHECK:   ret void
 // CHECK: }
 }
 
 void callMemberPointerMultiple(Multiple *o, void (Multiple::*memptr)()) {
   (o->*memptr)();
-// CHECK: define void @"\01?callMemberPointerMultiple@@{{.*}} #0 {
+// CHECK: define void @"\01?callMemberPointerMultiple@@{{.*}} {
 // CHECK:   %[[memptr0:.*]] = extractvalue { i8*, i32 } %{{.*}}, 0
 // CHECK:   %[[memptr1:.*]] = extractvalue { i8*, i32 } %{{.*}}, 1
 // CHECK:   %[[this_adjusted:.*]] = getelementptr inbounds i8* %{{.*}}, i32 %[[memptr1]]
@@ -255,7 +314,7 @@
 void callMemberPointerVirtualBase(Virtual *o, void (Virtual::*memptr)()) {
   (o->*memptr)();
 // This shares a lot with virtual data member pointers.
-// CHECK: define void @"\01?callMemberPointerVirtualBase@@{{.*}} #0 {
+// CHECK: define void @"\01?callMemberPointerVirtualBase@@{{.*}} {
 // CHECK:   %[[memptr0:.*]] = extractvalue { i8*, i32, i32 } %{{.*}}, 0
 // CHECK:   %[[memptr1:.*]] = extractvalue { i8*, i32, i32 } %{{.*}}, 1
 // CHECK:   %[[memptr2:.*]] = extractvalue { i8*, i32, i32 } %{{.*}}, 2
@@ -361,3 +420,98 @@
 // CHECK:   ret i1
 // CHECK: }
 }
+
+void (Multiple::*convertB2FuncToMultiple(void (B2::*mp)()))() {
+  return mp;
+// CHECK: define i64 @"\01?convertB2FuncToMultiple@@YAP8Multiple@@AEXXZP8B2@@AEXXZ@Z"{{.*}} {
+// CHECK:   store
+// CHECK:   %[[mp:.*]] = load i8** %{{.*}}, align 4
+// CHECK:   icmp ne i8* %[[mp]], null
+// CHECK:   br i1 %{{.*}} label %{{.*}}, label %{{.*}}
+//
+//        memptr.convert:                                   ; preds = %entry
+// CHECK:   insertvalue { i8*, i32 } zeroinitializer, i8* %[[mp]], 0
+// CHECK:   insertvalue { i8*, i32 } %{{.*}}, i32 4, 1
+// CHECK:   br label
+//
+//        memptr.converted:                                 ; preds = %memptr.convert, %entry
+// CHECK:   phi { i8*, i32 } [ zeroinitializer, %{{.*}} ], [ {{.*}} ]
+// CHECK: }
+}
+
+void (B2::*convertMultipleFuncToB2(void (Multiple::*mp)()))() {
+// FIXME: cl emits warning C4407 on this code because of the representation
+// change.  We might want to do the same.
+  return static_cast<void (B2::*)()>(mp);
+// FIXME: We should return i8* instead of i32 here.  The ptrtoint cast prevents
+// LLVM from optimizing away the branch.  This is likely a bug in
+// lib/CodeGen/TargetInfo.cpp with how we classify memptr types for returns.
+//
+// CHECK: define i32 @"\01?convertMultipleFuncToB2@@YAP8B2@@AEXXZP8Multiple@@AEXXZ@Z"{{.*}} {
+// CHECK:   store
+// CHECK:   %[[src:.*]] = load { i8*, i32 }* %{{.*}}, align 4
+// CHECK:   extractvalue { i8*, i32 } %[[src]], 0
+// CHECK:   icmp ne i8* %{{.*}}, null
+// CHECK:   br i1 %{{.*}}, label %{{.*}}, label %{{.*}}
+//
+//        memptr.convert:                                   ; preds = %entry
+// CHECK:   %[[fp:.*]] = extractvalue { i8*, i32 } %[[src]], 0
+// CHECK:   br label
+//
+//        memptr.converted:                                 ; preds = %memptr.convert, %entry
+// CHECK:   phi i8* [ null, %{{.*}} ], [ %[[fp]], %{{.*}} ]
+// CHECK: }
+}
+
+namespace Test1 {
+
+struct A { int a; };
+struct B { int b; };
+struct C : virtual A { int c; };
+struct D : B, C { int d; };
+
+void (D::*convertCToD(void (C::*mp)()))() {
+  return mp;
+// CHECK: define void @"\01?convertCToD@Test1@@YAP8D@1@AEXXZP8C@1@AEXXZ@Z"{{.*}} {
+// CHECK:   store
+// CHECK:   load { i8*, i32, i32 }* %{{.*}}, align 4
+// CHECK:   extractvalue { i8*, i32, i32 } %{{.*}}, 0
+// CHECK:   icmp ne i8* %{{.*}}, null
+// CHECK:   br i1 %{{.*}}, label %{{.*}}, label %{{.*}}
+//
+//        memptr.convert:                                   ; preds = %entry
+// CHECK:   extractvalue { i8*, i32, i32 } %{{.*}}, 0
+// CHECK:   extractvalue { i8*, i32, i32 } %{{.*}}, 1
+// CHECK:   extractvalue { i8*, i32, i32 } %{{.*}}, 2
+// CHECK:   %[[adj:.*]] = add nsw i32 %{{.*}}, 4
+// CHECK:   insertvalue { i8*, i32, i32 } zeroinitializer, i8* {{.*}}, 0
+// CHECK:   insertvalue { i8*, i32, i32 } {{.*}}, i32 %[[adj]], 1
+// CHECK:   insertvalue { i8*, i32, i32 } {{.*}}, i32 {{.*}}, 2
+// CHECK:   br label
+//
+//        memptr.converted:                                 ; preds = %memptr.convert, %entry
+// CHECK:   phi { i8*, i32, i32 } [ { i8* null, i32 0, i32 -1 }, {{.*}} ], [ {{.*}} ]
+// CHECK: }
+}
+
+}
+
+namespace Test2 {
+// Test that we dynamically convert between different null reps.
+
+struct A { int a; };
+struct B : A {
+  int b;
+  virtual void hasVfPtr();
+};
+
+int A::*reinterpret(int B::*mp) {
+  return reinterpret_cast<int A::*>(mp);
+// CHECK: define i32 @"\01?reinterpret@Test2@@YAPQA@1@HPQB@1@H@Z"{{.*}}  {
+// CHECK:   %[[mp:.*]] = load i32*
+// CHECK:   %[[cmp:.*]] = icmp ne i32 %[[mp]], 0
+// CHECK:   select i1 %[[cmp]], i32 %[[mp]], i32 -1
+// CHECK: }
+}
+
+}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to