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 | |
4 | namespace byval_thunk { |
5 | struct Agg { |
6 | Agg(); |
7 | Agg(const Agg &); |
8 | ~Agg(); |
9 | int x; |
10 | }; |
11 | |
12 | struct A { virtual void foo(Agg x); }; |
13 | struct B { virtual void foo(Agg x); }; |
14 | struct C : A, B { C(); virtual void foo(Agg x); }; |
15 | C::C() {} // force emission |
16 | |
17 | // CHECK32-LABEL: define linkonce_odr dso_local x86_thiscallcc void @"?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 @"?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 dso_local void @"?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 @"?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 | |
33 | namespace stdcall_thunk { |
34 | struct Agg { |
35 | Agg(); |
36 | Agg(const Agg &); |
37 | ~Agg(); |
38 | int x; |
39 | }; |
40 | |
41 | struct A { virtual void __stdcall foo(Agg x); }; |
42 | struct B { virtual void __stdcall foo(Agg x); }; |
43 | struct C : A, B { C(); virtual void __stdcall foo(Agg x); }; |
44 | C::C() {} // force emission |
45 | |
46 | // CHECK32-LABEL: define linkonce_odr dso_local x86_stdcallcc void @"?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 @"?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 dso_local void @"?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 @"?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 | |
65 | namespace sret_thunk { |
66 | struct Agg { |
67 | Agg(); |
68 | Agg(const Agg &); |
69 | ~Agg(); |
70 | int x; |
71 | }; |
72 | |
73 | struct A { virtual Agg __cdecl foo(Agg x); }; |
74 | struct B { virtual Agg __cdecl foo(Agg x); }; |
75 | struct C : A, B { C(); virtual Agg __cdecl foo(Agg x); }; |
76 | C::C() {} // force emission |
77 | |
78 | // CHECK32-LABEL: define linkonce_odr dso_local %"struct.sret_thunk::Agg"* @"?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"* @"?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 dso_local void @"?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 @"?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. |
100 | namespace variadic_thunk { |
101 | struct Agg { |
102 | Agg(); |
103 | Agg(const Agg &); |
104 | ~Agg(); |
105 | int x; |
106 | }; |
107 | |
108 | struct A { virtual void foo(Agg x, ...); }; |
109 | struct B { virtual void foo(Agg x, ...); }; |
110 | struct C : A, B { C(); virtual void foo(Agg x, ...); }; |
111 | C::C() {} // force emission |
112 | } |
113 | #endif |
114 | |