1; RUN: llc < %s -mtriple=i686-pc-linux | FileCheck %s -check-prefix=LINUX -check-prefix=CHECK
2; RUN: llc < %s -mtriple=i686-apple-darwin | FileCheck %s -check-prefix=DARWIN -check-prefix=CHECK
3
4declare i32 @__gxx_personality_v0(...)
5declare void @good(i32 %a, i32 %b, i32 %c, i32 %d)
6declare void @large(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f)
7declare void @empty()
8
9; When we use an invoke, we expect a .cfi_escape GNU_ARGS_SIZE
10; with size 16 before the invocation. Without FP, we also expect
11; .cfi_adjust_cfa_offset after each push.
12; Darwin should not generate pushes in either circumstance.
13; CHECK-LABEL: test1_nofp:
14; LINUX: .cfi_escape 0x2e, 0x10
15; LINUX-NEXT: pushl   $4
16; LINUX-NEXT: Ltmp{{[0-9]+}}:
17; LINUX-NEXT: .cfi_adjust_cfa_offset 4
18; LINUX-NEXT: pushl   $3
19; LINUX-NEXT: Ltmp{{[0-9]+}}:
20; LINUX-NEXT: .cfi_adjust_cfa_offset 4
21; LINUX-NEXT: pushl   $2
22; LINUX-NEXT: Ltmp{{[0-9]+}}:
23; LINUX-NEXT: .cfi_adjust_cfa_offset 4
24; LINUX-NEXT: pushl   $1
25; LINUX-NEXT: Ltmp{{[0-9]+}}:
26; LINUX-NEXT: .cfi_adjust_cfa_offset 4
27; LINUX-NEXT: call
28; LINUX-NEXT: addl $16, %esp
29; LINUX: .cfi_adjust_cfa_offset -16
30; DARWIN-NOT: .cfi_escape
31; DARWIN-NOT: pushl
32define void @test1_nofp() #0 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
33entry:
34  invoke void @good(i32 1, i32 2, i32 3, i32 4)
35          to label %continue unwind label %cleanup
36continue:
37  ret void
38cleanup:
39  landingpad { i8*, i32 }
40     cleanup
41  ret void
42}
43
44; CHECK-LABEL: test1_fp:
45; LINUX: .cfi_escape 0x2e, 0x10
46; LINUX-NEXT: pushl   $4
47; LINUX-NEXT: pushl   $3
48; LINUX-NEXT: pushl   $2
49; LINUX-NEXT: pushl   $1
50; LINUX-NEXT: call
51; LINUX-NEXT: addl $16, %esp
52; DARWIN: pushl %ebp
53; DARWIN-NOT: .cfi_escape
54; DARWIN-NOT: pushl
55define void @test1_fp() #1 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
56entry:
57  invoke void @good(i32 1, i32 2, i32 3, i32 4)
58          to label %continue unwind label %cleanup
59continue:
60  ret void
61cleanup:
62  landingpad { i8*, i32 }
63     cleanup
64  ret void
65}
66
67; If the function has no handlers, we don't need to generate GNU_ARGS_SIZE,
68; even if it has an unwind table. Without FP, we still need cfi_adjust_cfa_offset,
69; so darwin should not generate pushes.
70; CHECK-LABEL: test2_nofp:
71; LINUX-NOT: .cfi_escape
72; LINUX: pushl   $4
73; LINUX-NEXT: Ltmp{{[0-9]+}}:
74; LINUX-NEXT: .cfi_adjust_cfa_offset 4
75; LINUX-NEXT: pushl   $3
76; LINUX-NEXT: Ltmp{{[0-9]+}}:
77; LINUX-NEXT: .cfi_adjust_cfa_offset 4
78; LINUX-NEXT: pushl   $2
79; LINUX-NEXT: Ltmp{{[0-9]+}}:
80; LINUX-NEXT: .cfi_adjust_cfa_offset 4
81; LINUX-NEXT: pushl   $1
82; LINUX-NEXT: Ltmp{{[0-9]+}}:
83; LINUX-NEXT: .cfi_adjust_cfa_offset 4
84; LINUX-NEXT: call
85; LINUX-NEXT: addl $16, %esp
86; LINUX: .cfi_adjust_cfa_offset -16
87; DARWIN-NOT: .cfi_escape
88; DARWIN-NOT: pushl
89define void @test2_nofp() #0 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
90entry:
91  call void @good(i32 1, i32 2, i32 3, i32 4)
92  ret void
93}
94
95; CHECK-LABEL: test2_fp:
96; CHECK-NOT: .cfi_escape
97; CHECK-NOT: .cfi_adjust_cfa_offset
98; CHECK: pushl   $4
99; CHECK-NEXT: pushl   $3
100; CHECK-NEXT: pushl   $2
101; CHECK-NEXT: pushl   $1
102; CHECK-NEXT: call
103; CHECK-NEXT: addl $24, %esp
104define void @test2_fp() #1 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
105entry:
106  call void @good(i32 1, i32 2, i32 3, i32 4)
107  ret void
108}
109
110; If we did not end up using any pushes, no need for GNU_ARGS_SIZE or
111; cfi_adjust_cfa_offset.
112; CHECK-LABEL: test3_nofp:
113; LINUX-NOT: .cfi_escape
114; LINUX-NOT: .cfi_adjust_cfa_offset
115; LINUX-NOT: pushl
116; LINUX: retl
117define void @test3_nofp() #0 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
118entry:
119  invoke void @empty()
120          to label %continue unwind label %cleanup
121continue:
122  ret void
123cleanup:
124  landingpad { i8*, i32 }
125     cleanup
126  ret void
127}
128
129; If we did not end up using any pushes, no need for GNU_ARGS_SIZE or
130; cfi_adjust_cfa_offset.
131; CHECK-LABEL: test3_fp:
132; LINUX: pushl %ebp
133; LINUX-NOT: .cfi_escape
134; LINUX-NOT: .cfi_adjust_cfa_offset
135; LINUX-NOT: pushl
136; LINUX: retl
137define void @test3_fp() #1 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
138entry:
139  invoke void @empty()
140          to label %continue unwind label %cleanup
141continue:
142  ret void
143cleanup:
144  landingpad { i8*, i32 }
145     cleanup
146  ret void
147}
148
149; Different sized stacks need different GNU_ARGS_SIZEs
150; CHECK-LABEL: test4:
151; LINUX: .cfi_escape 0x2e, 0x10
152; LINUX-NEXT: pushl   $4
153; LINUX-NEXT: pushl   $3
154; LINUX-NEXT: pushl   $2
155; LINUX-NEXT: pushl   $1
156; LINUX-NEXT: call
157; LINUX-NEXT: addl $16, %esp
158; LINUX: .cfi_escape 0x2e, 0x20
159; LINUX: subl    $8, %esp
160; LINUX-NEXT: pushl   $11
161; LINUX-NEXT: pushl   $10
162; LINUX-NEXT: pushl   $9
163; LINUX-NEXT: pushl   $8
164; LINUX-NEXT: pushl   $7
165; LINUX-NEXT: pushl   $6
166; LINUX-NEXT: calll   large
167; LINUX-NEXT: addl $32, %esp
168define void @test4() #1 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
169entry:
170  invoke void @good(i32 1, i32 2, i32 3, i32 4)
171          to label %continue1 unwind label %cleanup
172continue1:
173  invoke void @large(i32 6, i32 7, i32 8, i32 9, i32 10, i32 11)
174          to label %continue2 unwind label %cleanup
175continue2:
176  ret void
177cleanup:
178  landingpad { i8*, i32 }
179     cleanup
180  ret void
181}
182
183; If we did use pushes, we need to reset GNU_ARGS_SIZE before a call
184; without parameters, but don't need to adjust the cfa offset
185; CHECK-LABEL: test5_nofp:
186; LINUX: .cfi_escape 0x2e, 0x10
187; LINUX-NEXT: pushl   $4
188; LINUX-NEXT: Ltmp{{[0-9]+}}:
189; LINUX-NEXT: .cfi_adjust_cfa_offset 4
190; LINUX-NEXT: pushl   $3
191; LINUX-NEXT: Ltmp{{[0-9]+}}:
192; LINUX-NEXT: .cfi_adjust_cfa_offset 4
193; LINUX-NEXT: pushl   $2
194; LINUX-NEXT: Ltmp{{[0-9]+}}:
195; LINUX-NEXT: .cfi_adjust_cfa_offset 4
196; LINUX-NEXT: pushl   $1
197; LINUX-NEXT: Ltmp{{[0-9]+}}:
198; LINUX-NEXT: .cfi_adjust_cfa_offset 4
199; LINUX-NEXT: call
200; LINUX-NEXT: addl $16, %esp
201; LINUX: .cfi_adjust_cfa_offset -16
202; LINUX-NOT: .cfi_adjust_cfa_offset
203; LINUX: .cfi_escape 0x2e, 0x00
204; LINUX-NOT: .cfi_adjust_cfa_offset
205; LINUX: call
206define void @test5_nofp() #0 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
207entry:
208  invoke void @good(i32 1, i32 2, i32 3, i32 4)
209          to label %continue1 unwind label %cleanup
210continue1:
211  invoke void @empty()
212          to label %continue2 unwind label %cleanup
213continue2:
214  ret void
215cleanup:
216  landingpad { i8*, i32 }
217     cleanup
218  ret void
219}
220
221; CHECK-LABEL: test5_fp:
222; LINUX: .cfi_escape 0x2e, 0x10
223; LINUX-NEXT: pushl   $4
224; LINUX-NEXT: pushl   $3
225; LINUX-NEXT: pushl   $2
226; LINUX-NEXT: pushl   $1
227; LINUX-NEXT: call
228; LINUX-NEXT: addl $16, %esp
229; LINUX: .cfi_escape 0x2e, 0x00
230; LINUX-NOT: .cfi_adjust_cfa_offset
231; LINUX: call
232define void @test5_fp() #1 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
233entry:
234  invoke void @good(i32 1, i32 2, i32 3, i32 4)
235          to label %continue1 unwind label %cleanup
236continue1:
237  invoke void @empty()
238          to label %continue2 unwind label %cleanup
239continue2:
240  ret void
241cleanup:
242  landingpad { i8*, i32 }
243     cleanup
244  ret void
245}
246
247; FIXME: This is actually inefficient - we don't need to repeat the .cfi_escape twice.
248; CHECK-LABEL: test6:
249; LINUX: .cfi_escape 0x2e, 0x10
250; LINUX: call
251; LINUX: .cfi_escape 0x2e, 0x10
252; LINUX: call
253define void @test6() #1 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
254entry:
255  invoke void @good(i32 1, i32 2, i32 3, i32 4)
256          to label %continue1 unwind label %cleanup
257continue1:
258  invoke void @good(i32 5, i32 6, i32 7, i32 8)
259          to label %continue2 unwind label %cleanup
260continue2:
261  ret void
262cleanup:
263  landingpad { i8*, i32 }
264     cleanup
265  ret void
266}
267
268; Darwin should generate pushes in the presense of FP and an unwind table,
269; but not FP and invoke.
270; CHECK-LABEL: test7:
271; DARWIN: pushl %ebp
272; DARWIN: movl %esp, %ebp
273; DARWIN: .cfi_def_cfa_register %ebp
274; DARWIN-NOT: .cfi_adjust_cfa_offset
275; DARWIN: pushl   $4
276; DARWIN-NEXT: pushl   $3
277; DARWIN-NEXT: pushl   $2
278; DARWIN-NEXT: pushl   $1
279; DARWIN-NEXT: call
280define void @test7() #1 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
281entry:
282  call void @good(i32 1, i32 2, i32 3, i32 4)
283  ret void
284}
285
286; CHECK-LABEL: test8:
287; DARWIN: pushl %ebp
288; DARWIN: movl %esp, %ebp
289; DARWIN-NOT: .cfi_adjust_cfa_offset
290; DARWIN-NOT: pushl
291define void @test8() #1 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
292entry:
293  invoke void @good(i32 1, i32 2, i32 3, i32 4)
294          to label %continue unwind label %cleanup
295continue:
296  ret void
297cleanup:
298  landingpad { i8*, i32 }
299     cleanup
300  ret void
301}
302
303attributes #0 = { optsize }
304attributes #1 = { optsize "no-frame-pointer-elim"="true" }
305