1 ;; Check that this produces the expected assembly output
2 ; RUN: llc -mtriple=thumbv7-windows -o - %s -verify-machineinstrs | FileCheck %s
3 ;; Also try to write an object file, which verifies that the SEH opcodes
4 ;; match the actual prologue/epilogue length.
5 ; RUN: llc -mtriple=thumbv7-windows -filetype=obj -o %t.obj %s -verify-machineinstrs
7 ; CHECK-LABEL: clobberR4Frame:
8 ; CHECK-NEXT: .seh_proc clobberR4Frame
9 ; CHECK-NEXT: @ %bb.0: @ %entry
10 ; CHECK-NEXT: push.w {r4, r7, r11, lr}
11 ; CHECK-NEXT: .seh_save_regs_w {r4, r7, r11, lr}
12 ; CHECK-NEXT: add.w r11, sp, #8
13 ; CHECK-NEXT: .seh_nop_w
14 ; CHECK-NEXT: .seh_endprologue
15 ; CHECK-NEXT: bl other
17 ; CHECK: .seh_startepilogue
18 ; CHECK-NEXT: pop.w {r4, r7, r11, pc}
19 ; CHECK-NEXT: .seh_save_regs_w {r4, r7, r11, lr}
20 ; CHECK-NEXT: .seh_endepilogue
21 ; CHECK-NEXT: .seh_endproc
23 define arm_aapcs_vfpcc void @clobberR4Frame() uwtable "frame-pointer"="all" {
25 call arm_aapcs_vfpcc void @other()
26 call void asm sideeffect "", "~{r4}"()
30 ; CHECK-LABEL: clobberR4NoFrame:
31 ; CHECK-NEXT: .seh_proc clobberR4NoFrame
32 ; CHECK-NEXT: @ %bb.0: @ %entry
33 ; CHECK-NEXT: push {r4, lr}
34 ; CHECK-NEXT: .seh_save_regs {r4, lr}
35 ; CHECK-NEXT: .seh_endprologue
36 ; CHECK-NEXT: bl other
38 ; CHECK: .seh_startepilogue
39 ; CHECK-NEXT: pop {r4, pc}
40 ; CHECK-NEXT: .seh_save_regs {r4, lr}
41 ; CHECK-NEXT: .seh_endepilogue
42 ; CHECK-NEXT: .seh_endproc
44 define arm_aapcs_vfpcc void @clobberR4NoFrame() uwtable "frame-pointer"="none" {
46 call arm_aapcs_vfpcc void @other()
47 call void asm sideeffect "", "~{r4}"()
51 ; CHECK-LABEL: clobberR4Tail:
52 ; CHECK-NEXT: .seh_proc clobberR4Tail
53 ; CHECK-NEXT: @ %bb.0: @ %entry
54 ; CHECK-NEXT: push {r4, lr}
55 ; CHECK-NEXT: .seh_save_regs {r4, lr}
56 ; CHECK-NEXT: .seh_endprologue
58 ; CHECK: .seh_startepilogue
59 ; CHECK-NEXT: pop.w {r4, lr}
60 ; CHECK-NEXT: .seh_save_regs_w {r4, lr}
61 ; CHECK-NEXT: b.w other
62 ; CHECK-NEXT: .seh_nop_w
63 ; CHECK-NEXT: .seh_endepilogue
64 ; CHECK-NEXT: .seh_endproc
66 define arm_aapcs_vfpcc void @clobberR4Tail() uwtable "frame-pointer"="none" {
68 call void asm sideeffect "", "~{r4}"()
69 tail call arm_aapcs_vfpcc void @other()
73 ; CHECK-LABEL: clobberD8D10:
74 ; CHECK-NEXT: .seh_proc clobberD8D10
75 ; CHECK-NEXT: @ %bb.0: @ %entry
76 ; CHECK-NEXT: vpush {d8, d9, d10}
77 ; CHECK-NEXT: .seh_save_fregs {d8-d10}
78 ; CHECK-NEXT: .seh_endprologue
80 ; CHECK: .seh_startepilogue
81 ; CHECK-NEXT: vpop {d8, d9, d10}
82 ; CHECK-NEXT: .seh_save_fregs {d8-d10}
83 ; CHECK-NEXT: b.w other
84 ; CHECK-NEXT: .seh_nop_w
85 ; CHECK-NEXT: .seh_endepilogue
86 ; CHECK-NEXT: .seh_endproc
88 define arm_aapcs_vfpcc void @clobberD8D10() uwtable "frame-pointer"="none" {
90 call void asm sideeffect "", "~{d8},~{d9},~{d10}"()
91 tail call arm_aapcs_vfpcc void @other()
95 declare arm_aapcs_vfpcc void @other()
97 ; CHECK-LABEL: vararg:
98 ; CHECK-NEXT: .seh_proc vararg
99 ; CHECK-NEXT: @ %bb.0: @ %entry
100 ; CHECK-NEXT: sub sp, #12
101 ; CHECK-NEXT: .seh_stackalloc 12
102 ; CHECK-NEXT: push.w {r11, lr}
103 ; CHECK-NEXT: .seh_save_regs_w {r11, lr}
104 ; CHECK-NEXT: sub sp, #4
105 ; CHECK-NEXT: .seh_stackalloc 4
106 ; CHECK-NEXT: .seh_endprologue
108 ; CHECK: .seh_startepilogue
109 ; CHECK-NEXT: add sp, #4
110 ; CHECK-NEXT: .seh_stackalloc 4
111 ; CHECK-NEXT: pop.w {r11, lr}
112 ; CHECK-NEXT: .seh_save_regs_w {r11, lr}
113 ; CHECK-NEXT: add sp, #12
114 ; CHECK-NEXT: .seh_stackalloc 12
116 ; CHECK-NEXT: .seh_nop
117 ; CHECK-NEXT: .seh_endepilogue
118 ; CHECK-NEXT: .seh_endproc
120 define arm_aapcs_vfpcc void @vararg(i32 noundef %a, ...) uwtable "frame-pointer"="none" {
122 %ap = alloca ptr, align 4
123 call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %ap)
124 call void @llvm.va_start(ptr nonnull %ap)
125 %0 = load ptr, ptr %ap
126 call arm_aapcs_vfpcc void @useva(ptr noundef %0)
127 call void @llvm.va_end(ptr nonnull %ap)
128 call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %ap)
132 declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture)
133 declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture)
134 declare void @llvm.va_start(ptr)
135 declare void @llvm.va_end(ptr)
137 declare arm_aapcs_vfpcc void @useva(ptr noundef)
139 ; CHECK-LABEL: onlystack:
140 ; CHECK-NEXT: .seh_proc onlystack
141 ; CHECK-NEXT: @ %bb.0: @ %entry
142 ; CHECK-NEXT: sub sp, #4
143 ; CHECK-NEXT: .seh_stackalloc 4
144 ; CHECK-NEXT: .seh_endprologue
146 ; CHECK: .seh_startepilogue
147 ; CHECK-NEXT: add sp, #4
148 ; CHECK-NEXT: .seh_stackalloc 4
150 ; CHECK-NEXT: .seh_nop
151 ; CHECK-NEXT: .seh_endepilogue
152 ; CHECK-NEXT: .seh_endproc
154 define dso_local arm_aapcs_vfpcc void @onlystack() uwtable "frame-pointer"="none" {
156 %buf = alloca [4 x i8], align 1
157 call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %buf)
158 call void asm sideeffect "", "r"(ptr nonnull %buf)
159 call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %buf)
163 ; CHECK-LABEL: func50:
164 ; CHECK-NEXT: .seh_proc func50
165 ; CHECK-NEXT: @ %bb.0: @ %entry
166 ; CHECK-NEXT: push.w {r11, lr}
167 ; CHECK-NEXT: .seh_save_regs_w {r11, lr}
168 ; CHECK-NEXT: sub sp, #56
169 ; CHECK-NEXT: .seh_stackalloc 56
170 ; CHECK-NEXT: .seh_endprologue
172 ; CHECK: .seh_startepilogue
173 ; CHECK-NEXT: add sp, #56
174 ; CHECK-NEXT: .seh_stackalloc 56
175 ; CHECK-NEXT: pop.w {r11, pc}
176 ; CHECK-NEXT: .seh_save_regs_w {r11, lr}
177 ; CHECK-NEXT: .seh_endepilogue
178 ; CHECK-NEXT: .seh_endproc
180 define arm_aapcs_vfpcc void @func50() {
182 %buf = alloca [50 x i8], align 1
183 call void @llvm.lifetime.start.p0(i64 50, ptr nonnull %buf)
184 call arm_aapcs_vfpcc void @useptr(ptr noundef nonnull %buf)
185 call void @llvm.lifetime.end.p0(i64 50, ptr nonnull %buf)
189 ; CHECK-LABEL: func4000:
190 ; CHECK-NEXT: .seh_proc func4000
191 ; CHECK-NEXT: @ %bb.0: @ %entry
192 ; CHECK-NEXT: push.w {r11, lr}
193 ; CHECK-NEXT: .seh_save_regs_w {r11, lr}
194 ; CHECK-NEXT: sub.w sp, sp, #4000
195 ; CHECK-NEXT: .seh_stackalloc_w 4000
196 ; CHECK-NEXT: .seh_endprologue
198 ; CHECK: .seh_startepilogue
199 ; CHECK-NEXT: add.w sp, sp, #4000
200 ; CHECK-NEXT: .seh_stackalloc_w 4000
201 ; CHECK-NEXT: pop.w {r11, pc}
202 ; CHECK-NEXT: .seh_save_regs_w {r11, lr}
203 ; CHECK-NEXT: .seh_endepilogue
204 ; CHECK-NEXT: .seh_endproc
206 define arm_aapcs_vfpcc void @func4000() {
208 %buf = alloca [4000 x i8], align 1
209 call void @llvm.lifetime.start.p0(i64 4000, ptr nonnull %buf)
210 call arm_aapcs_vfpcc void @useptr(ptr noundef nonnull %buf)
211 call void @llvm.lifetime.end.p0(i64 4000, ptr nonnull %buf)
215 ; CHECK-LABEL: func5000:
216 ; CHECK-NEXT: .seh_proc func5000
217 ; CHECK-NEXT: @ %bb.0: @ %entry
218 ; CHECK-NEXT: push {r4, r5, r6, lr}
219 ; CHECK-NEXT: .seh_save_regs {r4-r6, lr}
220 ; CHECK-NEXT: movw r4, #1250
221 ; CHECK-NEXT: .seh_nop_w
222 ; CHECK-NEXT: bl __chkstk
223 ; CHECK-NEXT: .seh_nop_w
224 ; CHECK-NEXT: sub.w sp, sp, r4
225 ; CHECK-NEXT: .seh_stackalloc_w 5000
226 ; CHECK-NEXT: .seh_endprologue
228 ; CHECK: .seh_startepilogue
229 ; CHECK-NEXT: add.w sp, sp, #4992
230 ; CHECK-NEXT: .seh_stackalloc_w 4992
231 ; CHECK-NEXT: add sp, #8
232 ; CHECK-NEXT: .seh_stackalloc 8
233 ; CHECK-NEXT: pop {r4, r5, r6, pc}
234 ; CHECK-NEXT: .seh_save_regs {r4-r6, lr}
235 ; CHECK-NEXT: .seh_endepilogue
236 ; CHECK-NEXT: .seh_endproc
238 define arm_aapcs_vfpcc void @func5000() {
240 %buf = alloca [5000 x i8], align 1
241 call void @llvm.lifetime.start.p0(i64 5000, ptr nonnull %buf)
242 call arm_aapcs_vfpcc void @useptr(ptr noundef nonnull %buf)
243 call void @llvm.lifetime.end.p0(i64 5000, ptr nonnull %buf)
247 ; CHECK-LABEL: func262144:
248 ; CHECK-NEXT: .seh_proc func262144
249 ; CHECK-NEXT: @ %bb.0: @ %entry
250 ; CHECK-NEXT: push {r4, r5, r6, lr}
251 ; CHECK-NEXT: .seh_save_regs {r4-r6, lr}
252 ; CHECK-NEXT: movs r4, #0
253 ; CHECK-NEXT: .seh_nop
254 ; CHECK-NEXT: movt r4, #1
255 ; CHECK-NEXT: .seh_nop_w
256 ; CHECK-NEXT: bl __chkstk
257 ; CHECK-NEXT: .seh_nop_w
258 ; CHECK-NEXT: sub.w sp, sp, r4
259 ; CHECK-NEXT: .seh_stackalloc_w 262144
260 ; CHECK-NEXT: .seh_endprologue
262 ; CHECK: .seh_startepilogue
263 ; CHECK-NEXT: add.w sp, sp, #262144
264 ; CHECK-NEXT: .seh_stackalloc_w 262144
265 ; CHECK-NEXT: pop {r4, r5, r6, pc}
266 ; CHECK-NEXT: .seh_save_regs {r4-r6, lr}
267 ; CHECK-NEXT: .seh_endepilogue
268 ; CHECK-NEXT: .seh_endproc
270 define arm_aapcs_vfpcc void @func262144() {
272 %buf = alloca [262144 x i8], align 1
273 call void @llvm.lifetime.start.p0(i64 262144, ptr nonnull %buf)
274 call arm_aapcs_vfpcc void @useptr(ptr noundef nonnull %buf)
275 call void @llvm.lifetime.end.p0(i64 262144, ptr nonnull %buf)
279 ; CHECK-LABEL: func270000:
280 ; CHECK-NEXT: .seh_proc func270000
281 ; CHECK-NEXT: @ %bb.0: @ %entry
282 ; CHECK-NEXT: push {r4, r5, r6, lr}
283 ; CHECK-NEXT: .seh_save_regs {r4-r6, lr}
284 ; CHECK-NEXT: movw r4, #1964
285 ; CHECK-NEXT: .seh_nop_w
286 ; CHECK-NEXT: movt r4, #1
287 ; CHECK-NEXT: .seh_nop_w
288 ; CHECK-NEXT: bl __chkstk
289 ; CHECK-NEXT: .seh_nop_w
290 ; CHECK-NEXT: sub.w sp, sp, r4
291 ; CHECK-NEXT: .seh_stackalloc_w 270000
292 ; CHECK-NEXT: .seh_endprologue
294 ; CHECK: .seh_startepilogue
295 ; CHECK-NEXT: add.w sp, sp, #268288
296 ; CHECK-NEXT: .seh_stackalloc_w 268288
297 ; CHECK-NEXT: add.w sp, sp, #1712
298 ; CHECK-NEXT: .seh_stackalloc_w 1712
299 ; CHECK-NEXT: pop {r4, r5, r6, pc}
300 ; CHECK-NEXT: .seh_save_regs {r4-r6, lr}
301 ; CHECK-NEXT: .seh_endepilogue
302 ; CHECK-NEXT: .seh_endproc
304 define arm_aapcs_vfpcc void @func270000() {
306 %buf = alloca [270000 x i8], align 1
307 call void @llvm.lifetime.start.p0(i64 270000, ptr nonnull %buf)
308 call arm_aapcs_vfpcc void @useptr(ptr noundef nonnull %buf)
309 call void @llvm.lifetime.end.p0(i64 270000, ptr nonnull %buf)
313 declare arm_aapcs_vfpcc void @useptr(ptr noundef)
315 ; CHECK-LABEL: func_fp:
316 ; CHECK-NEXT: .seh_proc func_fp
317 ; CHECK-NEXT: @ %bb.0: @ %entry
318 ; CHECK-NEXT: str r11, [sp, #-4]!
319 ; CHECK-NEXT: .seh_save_regs_w {r11}
320 ; CHECK-NEXT: mov r11, sp
321 ; CHECK-NEXT: .seh_save_sp r11
322 ; CHECK-NEXT: .seh_endprologue
324 ; CHECK-NEXT: mov r0, r11
326 ; CHECK-NEXT: .seh_startepilogue
327 ; CHECK-NEXT: ldr r11, [sp], #4
328 ; CHECK-NEXT: .seh_save_regs_w {r11}
330 ; CHECK-NEXT: .seh_nop
331 ; CHECK-NEXT: .seh_endepilogue
332 ; CHECK-NEXT: .seh_endproc
334 define arm_aapcs_vfpcc i32 @func_fp() {
336 %0 = tail call ptr @llvm.frameaddress.p0(i32 0)
337 %1 = ptrtoint ptr %0 to i32
341 declare ptr @llvm.frameaddress.p0(i32 immarg)