[ms-cxxabi] Implement member pointer conversions

Summary:
This only supports converting along non-virtual inheritance paths by
changing the field offset or the non-virtual base adjustment.

This implements three kinds of conversions:
- codegen for Value conversions
- Constant emission for APValue
- Constant folding for CastExprs

In almost all constant initialization settings
EmitMemberPointer(APValue) is called, except when the expression
contains a reinterpret cast.

reinterpret casts end up being a big corner case because the null value
changes between different kinds of member pointers.

Reviewers: rsmith

CC: cfe-commits

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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181543 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/CodeGenCXX/microsoft-abi-member-pointers.cpp b/test/CodeGenCXX/microsoft-abi-member-pointers.cpp
index 3fffc9d..c4eba82 100644
--- a/test/CodeGenCXX/microsoft-abi-member-pointers.cpp
+++ b/test/CodeGenCXX/microsoft-abi-member-pointers.cpp
@@ -1,16 +1,20 @@
 // RUN: %clang_cc1 -fno-rtti -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s
+// FIXME: Test x86_64 member pointers when codegen no longer asserts on records
+// with virtual bases.
 
 struct B1 {
   void foo();
   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 +38,7 @@
 // offset.
 struct NonZeroVBPtr : POD, Virtual {
   int n;
+  void foo();
 };
 
 struct Unspecified;
@@ -68,6 +73,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 +143,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 +173,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 +193,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,7 +294,7 @@
 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: }
@@ -241,7 +302,7 @@
 
 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 +316,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 +422,107 @@
 // 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 } undef, 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 } undef, 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; };
+struct C : A {
+  int c;
+  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-NOT: select
+// CHECK:   ret i32
+// CHECK: }
+}
+
+int A::*reinterpret(int C::*mp) {
+  return reinterpret_cast<int A::*>(mp);
+// CHECK: define i32 @"\01?reinterpret@Test2@@YAPQA@1@HPQC@1@H@Z"{{.*}}  {
+// CHECK:   %[[mp:.*]] = load i32*
+// CHECK:   %[[cmp:.*]] = icmp ne i32 %[[mp]], 0
+// CHECK:   select i1 %[[cmp]], i32 %[[mp]], i32 -1
+// CHECK: }
+}
+
+}