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