aboutsummaryrefslogtreecommitdiff
path: root/test/CodeGenCXX
diff options
context:
space:
mode:
authorReid Kleckner <reid@kleckner.net>2013-04-11 18:13:19 +0000
committerReid Kleckner <reid@kleckner.net>2013-04-11 18:13:19 +0000
commita3609b0c7685346308ed2c8022f94949bbfe7cdf (patch)
tree6eed7cf92072db17d06badd27a0ff359f4b613bc /test/CodeGenCXX
parent413549fbd85f507855f1adb355cb855faf4d8b55 (diff)
[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
Diffstat (limited to 'test/CodeGenCXX')
-rwxr-xr-xtest/CodeGenCXX/microsoft-abi-member-pointers.cpp187
1 files changed, 180 insertions, 7 deletions
diff --git a/test/CodeGenCXX/microsoft-abi-member-pointers.cpp b/test/CodeGenCXX/microsoft-abi-member-pointers.cpp
index 997e007086..1206463587 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 @@ void podMemPtrs() {
// CHECK: }
}
-struct Polymorphic {
- virtual void myVirtual();
- int a;
- int b;
-};
-
void polymorphicMemPtrs() {
int Polymorphic::*memptr;
memptr = &Polymorphic::a;
@@ -49,3 +92,133 @@ void polymorphicMemPtrs() {
// 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: }
+}