1*0a6a1f1dSLionel Sambuc // RUN: %clang_cc1 %s -fno-rtti -triple=i686-pc-win32 -emit-llvm -o - | FileCheck --check-prefix=CHECK32 %s
2*0a6a1f1dSLionel Sambuc // RUN: %clang_cc1 %s -fno-rtti -triple=x86_64-pc-win32 -emit-llvm -o - | FileCheck --check-prefix=CHECK64 %s
3*0a6a1f1dSLionel Sambuc
4*0a6a1f1dSLionel Sambuc namespace byval_thunk {
5*0a6a1f1dSLionel Sambuc struct Agg {
6*0a6a1f1dSLionel Sambuc Agg();
7*0a6a1f1dSLionel Sambuc Agg(const Agg &);
8*0a6a1f1dSLionel Sambuc ~Agg();
9*0a6a1f1dSLionel Sambuc int x;
10*0a6a1f1dSLionel Sambuc };
11*0a6a1f1dSLionel Sambuc
12*0a6a1f1dSLionel Sambuc struct A { virtual void foo(Agg x); };
13*0a6a1f1dSLionel Sambuc struct B { virtual void foo(Agg x); };
14*0a6a1f1dSLionel Sambuc struct C : A, B { C(); virtual void foo(Agg x); };
C()15*0a6a1f1dSLionel Sambuc C::C() {} // force emission
16*0a6a1f1dSLionel Sambuc
17*0a6a1f1dSLionel Sambuc // CHECK32-LABEL: define linkonce_odr x86_thiscallcc void @"\01?foo@C@byval_thunk@@W3AEXUAgg@2@@Z"
18*0a6a1f1dSLionel Sambuc // CHECK32: (%"struct.byval_thunk::C"* %this, <{ %"struct.byval_thunk::Agg" }>* inalloca)
19*0a6a1f1dSLionel Sambuc // CHECK32: getelementptr i8* %{{.*}}, i32 -4
20*0a6a1f1dSLionel Sambuc // CHECK32: musttail call x86_thiscallcc void @"\01?foo@C@byval_thunk@@UAEXUAgg@2@@Z"
21*0a6a1f1dSLionel Sambuc // CHECK32: (%"struct.byval_thunk::C"* %{{.*}}, <{ %"struct.byval_thunk::Agg" }>* inalloca %0)
22*0a6a1f1dSLionel Sambuc // CHECK32-NEXT: ret void
23*0a6a1f1dSLionel Sambuc
24*0a6a1f1dSLionel Sambuc // CHECK64-LABEL: define linkonce_odr void @"\01?foo@C@byval_thunk@@W7EAAXUAgg@2@@Z"
25*0a6a1f1dSLionel Sambuc // CHECK64: (%"struct.byval_thunk::C"* %this, %"struct.byval_thunk::Agg"* %x)
26*0a6a1f1dSLionel Sambuc // CHECK64: getelementptr i8* %{{.*}}, i32 -8
27*0a6a1f1dSLionel Sambuc // CHECK64: call void @"\01?foo@C@byval_thunk@@UEAAXUAgg@2@@Z"
28*0a6a1f1dSLionel Sambuc // CHECK64: (%"struct.byval_thunk::C"* %{{.*}}, %"struct.byval_thunk::Agg"* %x)
29*0a6a1f1dSLionel Sambuc // CHECK64-NOT: call
30*0a6a1f1dSLionel Sambuc // CHECK64: ret void
31*0a6a1f1dSLionel Sambuc }
32*0a6a1f1dSLionel Sambuc
33*0a6a1f1dSLionel Sambuc namespace stdcall_thunk {
34*0a6a1f1dSLionel Sambuc struct Agg {
35*0a6a1f1dSLionel Sambuc Agg();
36*0a6a1f1dSLionel Sambuc Agg(const Agg &);
37*0a6a1f1dSLionel Sambuc ~Agg();
38*0a6a1f1dSLionel Sambuc int x;
39*0a6a1f1dSLionel Sambuc };
40*0a6a1f1dSLionel Sambuc
41*0a6a1f1dSLionel Sambuc struct A { virtual void __stdcall foo(Agg x); };
42*0a6a1f1dSLionel Sambuc struct B { virtual void __stdcall foo(Agg x); };
43*0a6a1f1dSLionel Sambuc struct C : A, B { C(); virtual void __stdcall foo(Agg x); };
C()44*0a6a1f1dSLionel Sambuc C::C() {} // force emission
45*0a6a1f1dSLionel Sambuc
46*0a6a1f1dSLionel Sambuc // CHECK32-LABEL: define linkonce_odr x86_stdcallcc void @"\01?foo@C@stdcall_thunk@@W3AGXUAgg@2@@Z"
47*0a6a1f1dSLionel Sambuc // CHECK32: (<{ %"struct.stdcall_thunk::C"*, %"struct.stdcall_thunk::Agg" }>* inalloca)
48*0a6a1f1dSLionel Sambuc // CHECK32: %[[this_slot:[^ ]*]] = getelementptr inbounds <{ %"struct.stdcall_thunk::C"*, %"struct.stdcall_thunk::Agg" }>* %0, i32 0, i32 0
49*0a6a1f1dSLionel Sambuc // CHECK32: load %"struct.stdcall_thunk::C"** %[[this_slot]]
50*0a6a1f1dSLionel Sambuc // CHECK32: getelementptr i8* %{{.*}}, i32 -4
51*0a6a1f1dSLionel Sambuc // CHECK32: store %"struct.stdcall_thunk::C"* %{{.*}}, %"struct.stdcall_thunk::C"** %[[this_slot]]
52*0a6a1f1dSLionel Sambuc // CHECK32: musttail call x86_stdcallcc void @"\01?foo@C@stdcall_thunk@@UAGXUAgg@2@@Z"
53*0a6a1f1dSLionel Sambuc // CHECK32: (<{ %"struct.stdcall_thunk::C"*, %"struct.stdcall_thunk::Agg" }>* inalloca %0)
54*0a6a1f1dSLionel Sambuc // CHECK32-NEXT: ret void
55*0a6a1f1dSLionel Sambuc
56*0a6a1f1dSLionel Sambuc // CHECK64-LABEL: define linkonce_odr void @"\01?foo@C@stdcall_thunk@@W7EAAXUAgg@2@@Z"
57*0a6a1f1dSLionel Sambuc // CHECK64: (%"struct.stdcall_thunk::C"* %this, %"struct.stdcall_thunk::Agg"* %x)
58*0a6a1f1dSLionel Sambuc // CHECK64: getelementptr i8* %{{.*}}, i32 -8
59*0a6a1f1dSLionel Sambuc // CHECK64: call void @"\01?foo@C@stdcall_thunk@@UEAAXUAgg@2@@Z"
60*0a6a1f1dSLionel Sambuc // CHECK64: (%"struct.stdcall_thunk::C"* %{{.*}}, %"struct.stdcall_thunk::Agg"* %x)
61*0a6a1f1dSLionel Sambuc // CHECK64-NOT: call
62*0a6a1f1dSLionel Sambuc // CHECK64: ret void
63*0a6a1f1dSLionel Sambuc }
64*0a6a1f1dSLionel Sambuc
65*0a6a1f1dSLionel Sambuc namespace sret_thunk {
66*0a6a1f1dSLionel Sambuc struct Agg {
67*0a6a1f1dSLionel Sambuc Agg();
68*0a6a1f1dSLionel Sambuc Agg(const Agg &);
69*0a6a1f1dSLionel Sambuc ~Agg();
70*0a6a1f1dSLionel Sambuc int x;
71*0a6a1f1dSLionel Sambuc };
72*0a6a1f1dSLionel Sambuc
73*0a6a1f1dSLionel Sambuc struct A { virtual Agg __cdecl foo(Agg x); };
74*0a6a1f1dSLionel Sambuc struct B { virtual Agg __cdecl foo(Agg x); };
75*0a6a1f1dSLionel Sambuc struct C : A, B { C(); virtual Agg __cdecl foo(Agg x); };
C()76*0a6a1f1dSLionel Sambuc C::C() {} // force emission
77*0a6a1f1dSLionel Sambuc
78*0a6a1f1dSLionel Sambuc // CHECK32-LABEL: define linkonce_odr %"struct.sret_thunk::Agg"* @"\01?foo@C@sret_thunk@@W3AA?AUAgg@2@U32@@Z"
79*0a6a1f1dSLionel Sambuc // CHECK32: (<{ %"struct.sret_thunk::C"*, %"struct.sret_thunk::Agg"*, %"struct.sret_thunk::Agg" }>* inalloca)
80*0a6a1f1dSLionel Sambuc // CHECK32: %[[this_slot:[^ ]*]] = getelementptr inbounds <{ %"struct.sret_thunk::C"*, %"struct.sret_thunk::Agg"*, %"struct.sret_thunk::Agg" }>* %0, i32 0, i32 0
81*0a6a1f1dSLionel Sambuc // CHECK32: load %"struct.sret_thunk::C"** %[[this_slot]]
82*0a6a1f1dSLionel Sambuc // CHECK32: getelementptr i8* %{{.*}}, i32 -4
83*0a6a1f1dSLionel Sambuc // CHECK32: store %"struct.sret_thunk::C"* %{{.*}}, %"struct.sret_thunk::C"** %[[this_slot]]
84*0a6a1f1dSLionel Sambuc // CHECK32: %[[rv:[^ ]*]] = musttail call %"struct.sret_thunk::Agg"* @"\01?foo@C@sret_thunk@@UAA?AUAgg@2@U32@@Z"
85*0a6a1f1dSLionel Sambuc // CHECK32: (<{ %"struct.sret_thunk::C"*, %"struct.sret_thunk::Agg"*, %"struct.sret_thunk::Agg" }>* inalloca %0)
86*0a6a1f1dSLionel Sambuc // CHECK32-NEXT: ret %"struct.sret_thunk::Agg"* %[[rv]]
87*0a6a1f1dSLionel Sambuc
88*0a6a1f1dSLionel Sambuc // CHECK64-LABEL: define linkonce_odr void @"\01?foo@C@sret_thunk@@W7EAA?AUAgg@2@U32@@Z"
89*0a6a1f1dSLionel Sambuc // CHECK64: (%"struct.sret_thunk::C"* %this, %"struct.sret_thunk::Agg"* noalias sret %agg.result, %"struct.sret_thunk::Agg"* %x)
90*0a6a1f1dSLionel Sambuc // CHECK64: getelementptr i8* %{{.*}}, i32 -8
91*0a6a1f1dSLionel Sambuc // CHECK64: call void @"\01?foo@C@sret_thunk@@UEAA?AUAgg@2@U32@@Z"
92*0a6a1f1dSLionel Sambuc // CHECK64: (%"struct.sret_thunk::C"* %{{.*}}, %"struct.sret_thunk::Agg"* sret %agg.result, %"struct.sret_thunk::Agg"* %x)
93*0a6a1f1dSLionel Sambuc // CHECK64-NOT: call
94*0a6a1f1dSLionel Sambuc // CHECK64: ret void
95*0a6a1f1dSLionel Sambuc }
96*0a6a1f1dSLionel Sambuc
97*0a6a1f1dSLionel Sambuc #if 0
98*0a6a1f1dSLionel Sambuc // FIXME: When we extend LLVM IR to allow forwarding of varargs through musttail
99*0a6a1f1dSLionel Sambuc // calls, use this test.
100*0a6a1f1dSLionel Sambuc namespace variadic_thunk {
101*0a6a1f1dSLionel Sambuc struct Agg {
102*0a6a1f1dSLionel Sambuc Agg();
103*0a6a1f1dSLionel Sambuc Agg(const Agg &);
104*0a6a1f1dSLionel Sambuc ~Agg();
105*0a6a1f1dSLionel Sambuc int x;
106*0a6a1f1dSLionel Sambuc };
107*0a6a1f1dSLionel Sambuc
108*0a6a1f1dSLionel Sambuc struct A { virtual void foo(Agg x, ...); };
109*0a6a1f1dSLionel Sambuc struct B { virtual void foo(Agg x, ...); };
110*0a6a1f1dSLionel Sambuc struct C : A, B { C(); virtual void foo(Agg x, ...); };
111*0a6a1f1dSLionel Sambuc C::C() {} // force emission
112*0a6a1f1dSLionel Sambuc }
113*0a6a1f1dSLionel Sambuc #endif
114