xref: /llvm-project/llvm/test/CodeGen/X86/musttail-indirect.ll (revision 2f448bf509432c1a19ec46ab8cbc7353c03c6280)
1; RUN: llc -verify-machineinstrs < %s -mtriple=i686-win32 | FileCheck %s
2; RUN: llc -verify-machineinstrs < %s -mtriple=i686-win32 -O0 | FileCheck %s
3
4; IR simplified from the following C++ snippet compiled for i686-windows-msvc:
5
6; struct A { A(); ~A(); int a; };
7;
8; struct B {
9;   virtual int  f(int);
10;   virtual int  g(A, int, A);
11;   virtual void h(A, int, A);
12;   virtual A    i(A, int, A);
13;   virtual A    j(int);
14; };
15;
16; int  (B::*mp_f)(int)       = &B::f;
17; int  (B::*mp_g)(A, int, A) = &B::g;
18; void (B::*mp_h)(A, int, A) = &B::h;
19; A    (B::*mp_i)(A, int, A) = &B::i;
20; A    (B::*mp_j)(int)       = &B::j;
21
22; Each member pointer creates a thunk.  The ones with inalloca are required to
23; tail calls by the ABI, even at O0.
24
25%struct.B = type { ptr }
26%struct.A = type { i32 }
27
28; CHECK-LABEL: f_thunk:
29; CHECK: jmpl
30; CHECK-NOT: ret
31define x86_thiscallcc i32 @f_thunk(ptr %this, i32) {
32entry:
33  %vtable = load ptr, ptr %this
34  %1 = load ptr, ptr %vtable
35  %2 = musttail call x86_thiscallcc i32 %1(ptr %this, i32 %0)
36  ret i32 %2
37}
38
39; Inalloca thunks shouldn't require any stores to the stack.
40; CHECK-LABEL: g_thunk:
41; CHECK-NOT: mov %{{.*}}, {{.*(.*esp.*)}}
42; CHECK: jmpl
43; CHECK-NOT: ret
44define x86_thiscallcc i32 @g_thunk(ptr %this, ptr inalloca(<{ %struct.A, i32, %struct.A }>)) {
45entry:
46  %vtable = load ptr, ptr %this
47  %vfn = getelementptr inbounds ptr, ptr %vtable, i32 1
48  %1 = load ptr, ptr %vfn
49  %2 = musttail call x86_thiscallcc i32 %1(ptr %this, ptr inalloca(<{ %struct.A, i32, %struct.A }>) %0)
50  ret i32 %2
51}
52
53; Preallocated thunks shouldn't require any stores to the stack.
54; CHECK-LABEL: g_thunk_preallocated:
55; CHECK-NOT: mov %{{.*}}, {{.*(.*esp.*)}}
56; CHECK: jmpl
57; CHECK-NOT: ret
58define x86_thiscallcc i32 @g_thunk_preallocated(ptr %this, ptr preallocated(<{ %struct.A, i32, %struct.A }>)) {
59entry:
60  %vtable = load ptr, ptr %this
61  %vfn = getelementptr inbounds ptr, ptr %vtable, i32 1
62  %1 = load ptr, ptr %vfn
63  %2 = musttail call x86_thiscallcc i32 %1(ptr %this, ptr preallocated(<{ %struct.A, i32, %struct.A }>) %0)
64  ret i32 %2
65}
66
67; CHECK-LABEL: h_thunk:
68; CHECK: jmpl
69; CHECK-NOT: mov %{{.*}}, {{.*(.*esp.*)}}
70; CHECK-NOT: ret
71define x86_thiscallcc void @h_thunk(ptr %this, ptr inalloca(<{ %struct.A, i32, %struct.A }>)) {
72entry:
73  %vtable = load ptr, ptr %this
74  %vfn = getelementptr inbounds ptr, ptr %vtable, i32 2
75  %1 = load ptr, ptr %vfn
76  musttail call x86_thiscallcc void %1(ptr %this, ptr inalloca(<{ %struct.A, i32, %struct.A }>) %0)
77  ret void
78}
79
80; CHECK-LABEL: h_thunk_preallocated:
81; CHECK: jmpl
82; CHECK-NOT: mov %{{.*}}, {{.*(.*esp.*)}}
83; CHECK-NOT: ret
84define x86_thiscallcc void @h_thunk_preallocated(ptr %this, ptr preallocated(<{ %struct.A, i32, %struct.A }>)) {
85entry:
86  %vtable = load ptr, ptr %this
87  %vfn = getelementptr inbounds ptr, ptr %vtable, i32 2
88  %1 = load ptr, ptr %vfn
89  musttail call x86_thiscallcc void %1(ptr %this, ptr preallocated(<{ %struct.A, i32, %struct.A }>) %0)
90  ret void
91}
92
93; CHECK-LABEL: i_thunk:
94; CHECK-NOT: mov %{{.*}}, {{.*(.*esp.*)}}
95; CHECK: jmpl
96; CHECK-NOT: ret
97define x86_thiscallcc ptr @i_thunk(ptr %this, ptr inalloca(<{ ptr, %struct.A, i32, %struct.A }>)) {
98entry:
99  %vtable = load ptr, ptr %this
100  %vfn = getelementptr inbounds ptr, ptr %vtable, i32 3
101  %1 = load ptr, ptr %vfn
102  %2 = musttail call x86_thiscallcc ptr %1(ptr %this, ptr inalloca(<{ ptr, %struct.A, i32, %struct.A }>) %0)
103  ret ptr %2
104}
105
106; CHECK-LABEL: i_thunk_preallocated:
107; CHECK-NOT: mov %{{.*}}, {{.*(.*esp.*)}}
108; CHECK: jmpl
109; CHECK-NOT: ret
110define x86_thiscallcc ptr @i_thunk_preallocated(ptr %this, ptr preallocated(<{ ptr, %struct.A, i32, %struct.A }>)) {
111entry:
112  %vtable = load ptr, ptr %this
113  %vfn = getelementptr inbounds ptr, ptr %vtable, i32 3
114  %1 = load ptr, ptr %vfn
115  %2 = musttail call x86_thiscallcc ptr %1(ptr %this, ptr preallocated(<{ ptr, %struct.A, i32, %struct.A }>) %0)
116  ret ptr %2
117}
118
119; CHECK-LABEL: j_thunk:
120; CHECK: jmpl
121; CHECK-NOT: ret
122define x86_thiscallcc void @j_thunk(ptr noalias sret(%struct.A) %agg.result, ptr %this, i32) {
123entry:
124  %vtable = load ptr, ptr %this
125  %vfn = getelementptr inbounds ptr, ptr %vtable, i32 4
126  %1 = load ptr, ptr %vfn
127  musttail call x86_thiscallcc void %1(ptr sret(%struct.A) %agg.result, ptr %this, i32 %0)
128  ret void
129}
130
131; CHECK-LABEL: _stdcall_thunk@8:
132; CHECK-NOT: mov %{{.*}}, {{.*(.*esp.*)}}
133; CHECK: jmpl
134; CHECK-NOT: ret
135define x86_stdcallcc i32 @stdcall_thunk(ptr inalloca(<{ ptr, %struct.A }>)) {
136entry:
137  %this_ptr = getelementptr inbounds <{ ptr, %struct.A }>, ptr %0, i32 0, i32 0
138  %this = load ptr, ptr %this_ptr
139  %vtable = load ptr, ptr %this
140  %vfn = getelementptr inbounds ptr, ptr %vtable, i32 1
141  %1 = load ptr, ptr %vfn
142  %2 = musttail call x86_stdcallcc i32 %1(ptr inalloca(<{ ptr, %struct.A }>) %0)
143  ret i32 %2
144}
145
146; CHECK-LABEL: _stdcall_thunk_preallocated@8:
147; CHECK-NOT: mov %{{.*}}, {{.*(.*esp.*)}}
148; CHECK: jmpl
149; CHECK-NOT: ret
150define x86_stdcallcc i32 @stdcall_thunk_preallocated(ptr preallocated(<{ ptr, %struct.A }>)) {
151entry:
152  %this_ptr = getelementptr inbounds <{ ptr, %struct.A }>, ptr %0, i32 0, i32 0
153  %this = load ptr, ptr %this_ptr
154  %vtable = load ptr, ptr %this
155  %vfn = getelementptr inbounds ptr, ptr %vtable, i32 1
156  %1 = load ptr, ptr %vfn
157  %2 = musttail call x86_stdcallcc i32 %1(ptr preallocated(<{ ptr, %struct.A }>) %0)
158  ret i32 %2
159}
160
161; CHECK-LABEL: @fastcall_thunk@8:
162; CHECK-NOT: mov %{{.*}}, {{.*(.*esp.*)}}
163; CHECK: jmpl
164; CHECK-NOT: ret
165define x86_fastcallcc i32 @fastcall_thunk(ptr inreg %this, ptr inalloca(<{ %struct.A }>)) {
166entry:
167  %vtable = load ptr, ptr %this
168  %vfn = getelementptr inbounds ptr, ptr %vtable, i32 1
169  %1 = load ptr, ptr %vfn
170  %2 = musttail call x86_fastcallcc i32 %1(ptr inreg %this, ptr inalloca(<{ %struct.A }>) %0)
171  ret i32 %2
172}
173
174; CHECK-LABEL: @fastcall_thunk_preallocated@8:
175; CHECK-NOT: mov %{{.*}}, {{.*(.*esp.*)}}
176; CHECK: jmpl
177; CHECK-NOT: ret
178define x86_fastcallcc i32 @fastcall_thunk_preallocated(ptr inreg %this, ptr preallocated(<{ %struct.A }>)) {
179entry:
180  %vtable = load ptr, ptr %this
181  %vfn = getelementptr inbounds ptr, ptr %vtable, i32 1
182  %1 = load ptr, ptr %vfn
183  %2 = musttail call x86_fastcallcc i32 %1(ptr inreg %this, ptr preallocated(<{ %struct.A }>) %0)
184  ret i32 %2
185}
186