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