diff options
author | Reid Kleckner <reid@kleckner.net> | 2013-04-11 18:13:19 +0000 |
---|---|---|
committer | Reid Kleckner <reid@kleckner.net> | 2013-04-11 18:13:19 +0000 |
commit | a3609b0c7685346308ed2c8022f94949bbfe7cdf (patch) | |
tree | 6eed7cf92072db17d06badd27a0ff359f4b613bc /test/CodeGenCXX | |
parent | 413549fbd85f507855f1adb355cb855faf4d8b55 (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-x | test/CodeGenCXX/microsoft-abi-member-pointers.cpp | 187 |
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: } +} |