[ms-cxxabi] Implement member pointer emission and dereferencing

Summary:
Handles all inheritance models for both data and function member
pointers.

Also implements isZeroInitializable() and refactors some of the null
member pointer code.

MSVC supports converting member pointers through virtual bases, which
clang does not (yet?) support.  Implementing that extension is covered
by http://llvm.org/15713

Reviewers: rjmccall

CC: cfe-commits

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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@179305 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/CodeGenCXX/microsoft-abi-member-pointers.cpp b/test/CodeGenCXX/microsoft-abi-member-pointers.cpp
index 997e007..1206463 100755
--- a/test/CodeGenCXX/microsoft-abi-member-pointers.cpp
+++ b/test/CodeGenCXX/microsoft-abi-member-pointers.cpp
@@ -1,10 +1,59 @@
-// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s
+// RUN: %clang_cc1 -fno-rtti -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s
+
+struct B1 {
+  int b;
+};
+struct B2 { };
+struct Single : B1 { };
+struct Multiple : B1, B2 { };
+struct Virtual : virtual B1 {
+  int v;
+};
 
 struct POD {
   int a;
   int b;
 };
 
+struct Polymorphic {
+  virtual void myVirtual();
+  int a;
+  int b;
+};
+
+// This class uses the virtual inheritance model, yet its vbptr offset is not 0.
+// We still use zero for the null field offset, despite it being a valid field
+// offset.
+struct NonZeroVBPtr : POD, Virtual {
+  int n;
+};
+
+struct Unspecified;
+
+// Check that we can lower the LLVM types and get the initializers right.
+int Single     ::*s_d_memptr;
+int Polymorphic::*p_d_memptr;
+int Multiple   ::*m_d_memptr;
+int Virtual    ::*v_d_memptr;
+int NonZeroVBPtr::*n_d_memptr;
+int Unspecified::*u_d_memptr;
+// CHECK: @"\01?s_d_memptr@@3PQSingle@@HA" = global i32 -1, align 4
+// CHECK: @"\01?p_d_memptr@@3PQPolymorphic@@HA" = global i32 0, align 4
+// CHECK: @"\01?m_d_memptr@@3PQMultiple@@HA" = global i32 -1, align 4
+// CHECK: @"\01?v_d_memptr@@3PQVirtual@@HA" = global { i32, i32 }
+// CHECK:   { i32 0, i32 -1 }, align 4
+// CHECK: @"\01?n_d_memptr@@3PQNonZeroVBPtr@@HA" = global { i32, i32 }
+// CHECK:   { i32 0, i32 -1 }, align 4
+// CHECK: @"\01?u_d_memptr@@3PQUnspecified@@HA" = global { i32, i32, i32 }
+// CHECK:   { i32 0, i32 0, i32 -1 }, align 4
+
+void (Single  ::*s_f_memptr)();
+void (Multiple::*m_f_memptr)();
+void (Virtual ::*v_f_memptr)();
+// CHECK: @"\01?s_f_memptr@@3P8Single@@AEXXZA" = global i8* null, align 4
+// CHECK: @"\01?m_f_memptr@@3P8Multiple@@AEXXZA" = global { i8*, i32 } zeroinitializer, align 4
+// CHECK: @"\01?v_f_memptr@@3P8Virtual@@AEXXZA" = global { i8*, i32, i32 } zeroinitializer, align 4
+
 void podMemPtrs() {
   int POD::*memptr;
   memptr = &POD::a;
@@ -24,12 +73,6 @@
 // CHECK:      }
 }
 
-struct Polymorphic {
-  virtual void myVirtual();
-  int a;
-  int b;
-};
-
 void polymorphicMemPtrs() {
   int Polymorphic::*memptr;
   memptr = &Polymorphic::a;
@@ -49,3 +92,133 @@
 // CHECK:        ret void
 // CHECK:      }
 }
+
+bool nullTestDataUnspecified(int Unspecified::*mp) {
+  return mp;
+// CHECK: define zeroext i1 @"\01?nullTestDataUnspecified@@YA_NPQUnspecified@@H@Z"{{.*}} {
+// CHECK:   %{{.*}} = load { i32, i32, i32 }* %{{.*}}, align 4
+// CHECK:   store { i32, i32, i32 } {{.*}} align 4
+// CHECK:   %[[mp:.*]] = load { i32, i32, i32 }* %{{.*}}, align 4
+// CHECK:   %[[mp0:.*]] = extractvalue { i32, i32, i32 } %[[mp]], 0
+// CHECK:   %[[cmp0:.*]] = icmp ne i32 %[[mp0]], 0
+// CHECK:   %[[mp1:.*]] = extractvalue { i32, i32, i32 } %[[mp]], 1
+// CHECK:   %[[cmp1:.*]] = icmp ne i32 %[[mp1]], 0
+// CHECK:   %[[and0:.*]] = and i1 %[[cmp0]], %[[cmp1]]
+// CHECK:   %[[mp2:.*]] = extractvalue { i32, i32, i32 } %[[mp]], 2
+// CHECK:   %[[cmp2:.*]] = icmp ne i32 %[[mp2]], -1
+// CHECK:   %[[and1:.*]] = and i1 %[[and0]], %[[cmp2]]
+// CHECK:   ret i1 %[[and1]]
+// CHECK: }
+}
+
+bool nullTestFunctionUnspecified(void (Unspecified::*mp)()) {
+  return mp;
+// CHECK: define zeroext i1 @"\01?nullTestFunctionUnspecified@@YA_NP8Unspecified@@AEXXZ@Z"{{.*}} {
+// CHECK:   %{{.*}} = load { i8*, i32, i32, i32 }* %{{.*}}, align 4
+// CHECK:   store { i8*, i32, i32, i32 } {{.*}} align 4
+// CHECK:   %[[mp:.*]] = load { i8*, i32, i32, i32 }* %{{.*}}, align 4
+// CHECK:   %[[mp0:.*]] = extractvalue { i8*, i32, i32, i32 } %[[mp]], 0
+// CHECK:   %[[cmp0:.*]] = icmp ne i8* %[[mp0]], null
+// CHECK:   ret i1 %[[cmp0]]
+// CHECK: }
+}
+
+int loadDataMemberPointerVirtual(Virtual *o, int Virtual::*memptr) {
+  return o->*memptr;
+// Test that we can unpack this aggregate member pointer and load the member
+// data pointer.
+// CHECK: define i32 @"\01?loadDataMemberPointerVirtual@@YAHPAUVirtual@@PQ1@H@Z"{{.*}} {
+// CHECK:   %[[o:.*]] = load %{{.*}}** %{{.*}}, align 4
+// CHECK:   %[[memptr:.*]] = load { i32, i32 }* %memptr.addr, align 4
+// CHECK:   %[[memptr0:.*]] = extractvalue { i32, i32 } %[[memptr:.*]], 0
+// CHECK:   %[[memptr1:.*]] = extractvalue { i32, i32 } %[[memptr:.*]], 1
+// CHECK:   %[[v6:.*]] = bitcast %{{.*}}* %[[o]] to i8*
+// CHECK:   %[[vbptr:.*]] = getelementptr inbounds i8* %[[v6]], i32 0
+// CHECK:   %[[vbptr_a:.*]] = bitcast i8* %[[vbptr]] to i8**
+// CHECK:   %[[vbtable:.*]] = load i8** %[[vbptr_a:.*]]
+// CHECK:   %[[v7:.*]] = getelementptr inbounds i8* %[[vbtable]], i32 %[[memptr1]]
+// CHECK:   %[[v8:.*]] = bitcast i8* %[[v7]] to i32*
+// CHECK:   %[[vbase_offs:.*]] = load i32* %[[v8]]
+// CHECK:   %[[v10:.*]] = getelementptr inbounds i8* %[[vbptr]], i32 %[[vbase_offs]]
+// CHECK:   %[[offset:.*]] = getelementptr inbounds i8* %[[v10]], i32 %[[memptr0]]
+// CHECK:   %[[v11:.*]] = bitcast i8* %[[offset]] to i32*
+// CHECK:   %[[v12:.*]] = load i32* %[[v11]]
+// CHECK:   ret i32 %[[v12]]
+// CHECK: }
+}
+
+int loadDataMemberPointerUnspecified(Unspecified *o, int Unspecified::*memptr) {
+  return o->*memptr;
+// Test that we can unpack this aggregate member pointer and load the member
+// data pointer.
+// CHECK: define i32 @"\01?loadDataMemberPointerUnspecified@@YAHPAUUnspecified@@PQ1@H@Z"{{.*}} {
+// CHECK:   %[[o:.*]] = load %{{.*}}** %{{.*}}, align 4
+// CHECK:   %[[memptr:.*]] = load { i32, i32, i32 }* %memptr.addr, align 4
+// CHECK:   %[[memptr0:.*]] = extractvalue { i32, i32, i32 } %[[memptr:.*]], 0
+// CHECK:   %[[memptr1:.*]] = extractvalue { i32, i32, i32 } %[[memptr:.*]], 1
+// CHECK:   %[[memptr2:.*]] = extractvalue { i32, i32, i32 } %[[memptr:.*]], 2
+// CHECK:   %[[base:.*]] = bitcast %{{.*}}* %[[o]] to i8*
+// CHECK:   %[[is_vbase:.*]] = icmp ne i32 %[[memptr2]], 0
+// CHECK:   br i1 %[[is_vbase]], label %[[vadjust:.*]], label %[[skip:.*]]
+//
+// CHECK: [[vadjust]]:
+// CHECK:   %[[vbptr:.*]] = getelementptr inbounds i8* %[[base]], i32 %[[memptr1]]
+// CHECK:   %[[vbptr_a:.*]] = bitcast i8* %[[vbptr]] to i8**
+// CHECK:   %[[vbtable:.*]] = load i8** %[[vbptr_a:.*]]
+// CHECK:   %[[v7:.*]] = getelementptr inbounds i8* %[[vbtable]], i32 %[[memptr2]]
+// CHECK:   %[[v8:.*]] = bitcast i8* %[[v7]] to i32*
+// CHECK:   %[[vbase_offs:.*]] = load i32* %[[v8]]
+// CHECK:   %[[base_adj:.*]] = getelementptr inbounds i8* %[[vbptr]], i32 %[[vbase_offs]]
+//
+// CHECK: [[skip]]:
+// CHECK:   %[[new_base:.*]] = phi i8* [ %[[base]], %entry ], [ %[[base_adj]], %[[vadjust]] ]
+// CHECK:   %[[offset:.*]] = getelementptr inbounds i8* %[[new_base]], i32 %[[memptr0]]
+// CHECK:   %[[v11:.*]] = bitcast i8* %[[offset]] to i32*
+// CHECK:   %[[v12:.*]] = load i32* %[[v11]]
+// CHECK:   ret i32 %[[v12]]
+// CHECK: }
+}
+
+void callMemberPointerSingle(Single *o, void (Single::*memptr)()) {
+  (o->*memptr)();
+// Just look for an indirect thiscall.
+// CHECK: define void @"\01?callMemberPointerSingle@@{{.*}} #0 {
+// 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:   %[[memptr0:.*]] = extractvalue { i8*, i32 } %{{.*}}, 0
+// CHECK:   %[[memptr1:.*]] = extractvalue { i8*, i32 } %{{.*}}, 1
+// CHECK:   %[[this_adjusted:.*]] = getelementptr inbounds i8* %{{.*}}, i32 %[[memptr1]]
+// CHECK:   %[[this:.*]] = bitcast i8* %[[this_adjusted]] to {{.*}}
+// CHECK:   %[[fptr:.*]] = bitcast i8* %[[memptr0]] to {{.*}}
+// CHECK:   call x86_thiscallcc void %[[fptr]](%{{.*}} %[[this]])
+// CHECK:   ret void
+// CHECK: }
+}
+
+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:   %[[memptr0:.*]] = extractvalue { i8*, i32, i32 } %{{.*}}, 0
+// CHECK:   %[[memptr1:.*]] = extractvalue { i8*, i32, i32 } %{{.*}}, 1
+// CHECK:   %[[memptr2:.*]] = extractvalue { i8*, i32, i32 } %{{.*}}, 2
+// CHECK:   %[[vbptr:.*]] = getelementptr inbounds i8* %{{.*}}, i32 0
+// CHECK:   %[[vbptr_a:.*]] = bitcast i8* %[[vbptr]] to i8**
+// CHECK:   %[[vbtable:.*]] = load i8** %[[vbptr_a:.*]]
+// CHECK:   %[[v7:.*]] = getelementptr inbounds i8* %[[vbtable]], i32 %[[memptr2]]
+// CHECK:   %[[v8:.*]] = bitcast i8* %[[v7]] to i32*
+// CHECK:   %[[vbase_offs:.*]] = load i32* %[[v8]]
+// CHECK:   %[[v10:.*]] = getelementptr inbounds i8* %[[vbptr]], i32 %[[vbase_offs]]
+// CHECK:   %[[this_adjusted:.*]] = getelementptr inbounds i8* %[[v10]], i32 %[[memptr1]]
+// CHECK:   %[[fptr:.*]] = bitcast i8* %[[memptr0]] to void ({{.*}})
+// CHECK:   %[[this:.*]] = bitcast i8* %[[this_adjusted]] to {{.*}}
+// CHECK:   call x86_thiscallcc void %[[fptr]](%{{.*}} %[[this]])
+// CHECK:   ret void
+// CHECK: }
+}