1 ; RUN: llc -verify-machineinstrs -frame-pointer=all -global-isel < %s -mtriple=aarch64-apple-ios | FileCheck %s
3 declare ptr @malloc(i64)
4 declare void @free(ptr)
5 %swift_error = type {i64, i8}
7 ; This tests the basic usage of a swifterror parameter. "foo" is the function
8 ; that takes a swifterror parameter and "caller" is the caller of "foo".
9 define float @foo(ptr swifterror %error_ptr_ref) {
13 ; CHECK: mov [[ID:w[0-9]+]], #1
15 ; CHECK: strb [[ID]], [x0, #8]
19 %call = call ptr @malloc(i64 16)
20 store ptr %call, ptr %error_ptr_ref
21 %tmp = getelementptr inbounds i8, ptr %call, i64 8
26 ; "caller" calls "foo" that takes a swifterror parameter.
27 define float @caller(ptr %error_ref) {
28 ; CHECK-LABEL: caller:
29 ; CHECK: mov [[ID:x[0-9]+]], x0
33 ; Access part of the error object and save it to error_ref
34 ; CHECK: ldrb [[CODE:w[0-9]+]], [x0, #8]
35 ; CHECK: strb [[CODE]], [{{.*}}[[ID]]]
36 ; CHECK: bl {{.*}}free
39 %error_ptr_ref = alloca swifterror ptr
40 store ptr null, ptr %error_ptr_ref
41 %call = call float @foo(ptr swifterror %error_ptr_ref)
42 %error_from_foo = load ptr, ptr %error_ptr_ref
43 %had_error_from_foo = icmp ne ptr %error_from_foo, null
44 br i1 %had_error_from_foo, label %handler, label %cont
46 %v1 = getelementptr inbounds %swift_error, ptr %error_from_foo, i64 0, i32 1
48 store i8 %t, ptr %error_ref
51 call void @free(ptr %error_from_foo)
55 ; "caller2" is the caller of "foo", it calls "foo" inside a loop.
56 define float @caller2(ptr %error_ref) {
57 ; CHECK-LABEL: caller2:
58 ; CHECK: fmov [[CMP:s[0-9]+]], #1.0
59 ; CHECK: mov [[ID:x[0-9]+]], x0
63 ; CHECK: fcmp s0, [[CMP]]
65 ; Access part of the error object and save it to error_ref
66 ; CHECK: ldrb [[CODE:w[0-9]+]], [x21, #8]
67 ; CHECK: strb [[CODE]], [{{.*}}[[ID]]]
69 ; CHECK: bl {{.*}}free
72 %error_ptr_ref = alloca swifterror ptr
75 store ptr null, ptr %error_ptr_ref
76 %call = call float @foo(ptr swifterror %error_ptr_ref)
77 %error_from_foo = load ptr, ptr %error_ptr_ref
78 %had_error_from_foo = icmp ne ptr %error_from_foo, null
79 br i1 %had_error_from_foo, label %handler, label %cont
81 %cmp = fcmp ogt float %call, 1.000000e+00
82 br i1 %cmp, label %bb_end, label %bb_loop
84 %v1 = getelementptr inbounds %swift_error, ptr %error_from_foo, i64 0, i32 1
86 store i8 %t, ptr %error_ref
89 call void @free(ptr %error_from_foo)
93 ; "foo_if" is a function that takes a swifterror parameter, it sets swifterror
94 ; under a certain condition.
95 define float @foo_if(ptr swifterror %error_ptr_ref, i32 %cc) {
96 ; CHECK-LABEL: foo_if:
100 ; CHECK-DAG: mov x21, x0
101 ; CHECK-DAG: mov [[ID:w[0-9]+]], #1
102 ; CHECK: strb [[ID]], [x0, #8]
107 %cond = icmp ne i32 %cc, 0
108 br i1 %cond, label %gen_error, label %normal
111 %call = call ptr @malloc(i64 16)
112 store ptr %call, ptr %error_ptr_ref
113 %tmp = getelementptr inbounds i8, ptr %call, i64 8
121 ; "foo_loop" is a function that takes a swifterror parameter, it sets swifterror
122 ; under a certain condition inside a loop.
123 define float @foo_loop(ptr swifterror %error_ptr_ref, i32 %cc, float %cc2) {
124 ; CHECK-LABEL: foo_loop:
129 ; CHECK: strb w{{.*}}, [x0, #8]
136 %cond = icmp ne i32 %cc, 0
137 br i1 %cond, label %gen_error, label %bb_cont
140 %call = call ptr @malloc(i64 16)
141 store ptr %call, ptr %error_ptr_ref
142 %tmp = getelementptr inbounds i8, ptr %call, i64 8
147 %cmp = fcmp ogt float %cc2, 1.000000e+00
148 br i1 %cmp, label %bb_end, label %bb_loop
153 %struct.S = type { i32, i32, i32, i32, i32, i32 }
155 ; "foo_sret" is a function that takes a swifterror parameter, it also has a sret
157 define void @foo_sret(ptr sret(%struct.S) %agg.result, i32 %val1, ptr swifterror %error_ptr_ref) {
158 ; CHECK-LABEL: foo_sret:
159 ; CHECK-DAG: mov [[SRET:x[0-9]+]], x8
160 ; CHECK-DAG: mov w0, #16
162 ; CHECK: mov [[ID:w[0-9]+]], #1
163 ; CHECK: strb [[ID]], [x0, #8]
165 ; CHECK: str w{{.*}}, [{{.*}}[[SRET]], #4]
169 %call = call ptr @malloc(i64 16)
170 store ptr %call, ptr %error_ptr_ref
171 %tmp = getelementptr inbounds i8, ptr %call, i64 8
173 %v2 = getelementptr inbounds %struct.S, ptr %agg.result, i32 0, i32 1
174 store i32 %val1, ptr %v2
178 ; "caller3" calls "foo_sret" that takes a swifterror parameter.
179 define float @caller3(ptr %error_ref) {
180 ; CHECK-LABEL: caller3:
181 ; CHECK: mov [[ID:x[0-9]+]], x0
182 ; CHECK: mov [[ZERO:x[0-9]+]], xzr
183 ; CHECK: bl {{.*}}foo_sret
186 ; Access part of the error object and save it to error_ref
187 ; CHECK: ldrb [[CODE:w[0-9]+]], [x0, #8]
188 ; CHECK: strb [[CODE]], [{{.*}}[[ID]]]
189 ; CHECK: bl {{.*}}free
192 %s = alloca %struct.S, align 8
193 %error_ptr_ref = alloca swifterror ptr
194 store ptr null, ptr %error_ptr_ref
195 call void @foo_sret(ptr sret(%struct.S) %s, i32 1, ptr swifterror %error_ptr_ref)
196 %error_from_foo = load ptr, ptr %error_ptr_ref
197 %had_error_from_foo = icmp ne ptr %error_from_foo, null
198 br i1 %had_error_from_foo, label %handler, label %cont
200 %v1 = getelementptr inbounds %swift_error, ptr %error_from_foo, i64 0, i32 1
201 %t = load i8, ptr %v1
202 store i8 %t, ptr %error_ref
205 call void @free(ptr %error_from_foo)
209 ; "foo_vararg" is a function that takes a swifterror parameter, it also has
210 ; variable number of arguments.
211 declare void @llvm.va_start(ptr) nounwind
212 define float @foo_vararg(ptr swifterror %error_ptr_ref, ...) {
213 ; CHECK-LABEL: foo_vararg:
216 ; CHECK: mov [[ID:w[0-9]+]], #1
217 ; CHECK: strb [[ID]], [x0, #8]
222 ; CHECK: ldr {{w[0-9]+}}, [x[[ARG1:[0-9]+]]]
225 ; CHECK: ldr {{w[0-9]+}}, [x[[ARG1]]]
228 ; CHECK: ldr {{w[0-9]+}}, [x[[ARG1]]]
231 %call = call ptr @malloc(i64 16)
232 store ptr %call, ptr %error_ptr_ref
233 %tmp = getelementptr inbounds i8, ptr %call, i64 8
236 %args = alloca ptr, align 8
237 %a10 = alloca i32, align 4
238 %a11 = alloca i32, align 4
239 %a12 = alloca i32, align 4
240 call void @llvm.va_start(ptr %args)
241 %v11 = va_arg ptr %args, i32
242 store i32 %v11, ptr %a10, align 4
243 %v12 = va_arg ptr %args, i32
244 store i32 %v12, ptr %a11, align 4
245 %v13 = va_arg ptr %args, i32
246 store i32 %v13, ptr %a12, align 4
251 ; "caller4" calls "foo_vararg" that takes a swifterror parameter.
252 define float @caller4(ptr %error_ref) {
253 ; CHECK-LABEL: caller4:
255 ; CHECK: mov x21, xzr
256 ; CHECK: mov [[ID:x[0-9]+]], x0
257 ; CHECK: stp {{x[0-9]+}}, {{x[0-9]+}}, [sp]
258 ; CHECK: str {{x[0-9]+}}, [sp, #16]
260 ; CHECK: bl {{.*}}foo_vararg
263 ; Access part of the error object and save it to error_ref
264 ; CHECK: ldrb [[CODE:w[0-9]+]], [x0, #8]
265 ; CHECK: strb [[CODE]], [{{.*}}[[ID]]]
266 ; CHECK: bl {{.*}}free
268 %error_ptr_ref = alloca swifterror ptr
269 store ptr null, ptr %error_ptr_ref
271 %a10 = alloca i32, align 4
272 %a11 = alloca i32, align 4
273 %a12 = alloca i32, align 4
274 store i32 10, ptr %a10, align 4
275 store i32 11, ptr %a11, align 4
276 store i32 12, ptr %a12, align 4
277 %v10 = load i32, ptr %a10, align 4
278 %v11 = load i32, ptr %a11, align 4
279 %v12 = load i32, ptr %a12, align 4
281 %call = call float (ptr, ...) @foo_vararg(ptr swifterror %error_ptr_ref, i32 %v10, i32 %v11, i32 %v12)
282 %error_from_foo = load ptr, ptr %error_ptr_ref
283 %had_error_from_foo = icmp ne ptr %error_from_foo, null
284 br i1 %had_error_from_foo, label %handler, label %cont
287 %v1 = getelementptr inbounds %swift_error, ptr %error_from_foo, i64 0, i32 1
288 %t = load i8, ptr %v1
289 store i8 %t, ptr %error_ref
292 call void @free(ptr %error_from_foo)
296 ; Check that we don't blow up on tail calling swifterror argument functions.
297 define float @tailcallswifterror(ptr swifterror %error_ptr_ref) {
299 %0 = tail call float @tailcallswifterror(ptr swifterror %error_ptr_ref)
302 define swiftcc float @tailcallswifterror_swiftcc(ptr swifterror %error_ptr_ref) {
304 %0 = tail call swiftcc float @tailcallswifterror_swiftcc(ptr swifterror %error_ptr_ref)
308 ; CHECK-LABEL: params_in_reg
309 ; Save callee saved registers and swifterror since it will be clobbered by the first call to params_in_reg2.
310 ; CHECK: str x28, [sp
311 ; CHECK: stp x27, x26, [sp
312 ; CHECK: stp x25, x24, [sp
313 ; CHECK: stp x23, x22, [sp
314 ; CHECK: stp x20, x19, [sp
315 ; CHECK: stp x29, x30, [sp
316 ; Store argument registers.
324 ; CHECK: mov x28, x21
334 ; CHECK: mov x21, xzr
335 ; CHECK: str xzr, [sp]
336 ; CHECK: bl _params_in_reg2
337 ; Restore original arguments for next call.
338 ; CHECK: ldr x8, [sp, #24]
346 ; Restore original swiftself argument and swifterror %err.
347 ; CHECK: mov x21, x28
348 ; CHECK: bl _params_in_reg2
349 ; Restore calle save registers but don't clober swifterror x21.
351 ; CHECK: ldp x29, x30, [sp
353 ; CHECK: ldr x28, [sp
355 ; CHECK: ldp x20, x19, [sp
357 ; CHECK: ldp x23, x22, [sp
359 ; CHECK: ldp x25, x24, [sp
361 ; CHECK: ldp x27, x26, [sp
364 define swiftcc void @params_in_reg(i64, i64, i64, i64, i64, i64, i64, i64, ptr, ptr nocapture swifterror %err) {
365 %error_ptr_ref = alloca swifterror ptr, align 8
366 store ptr null, ptr %error_ptr_ref
367 call swiftcc void @params_in_reg2(i64 1, i64 2, i64 3, i64 4, i64 5, i64 6, i64 7, i64 8, ptr null, ptr nocapture swifterror %error_ptr_ref)
368 call swiftcc void @params_in_reg2(i64 %0, i64 %1, i64 %2, i64 %3, i64 %4, i64 %5, i64 %6, i64 %7, ptr %8, ptr nocapture swifterror %err)
371 declare swiftcc void @params_in_reg2(i64, i64, i64, i64, i64, i64, i64, i64, ptr , ptr nocapture swifterror %err)
373 ; CHECK-LABEL: params_and_return_in_reg
374 ; Store callee saved registers.
375 ; CHECK: stp x28, x0, [sp, #16
376 ; CHECK: stp x27, x26, [sp
377 ; CHECK: stp x25, x24, [sp
378 ; CHECK: stp x23, x22, [sp
379 ; CHECK: stp x20, x19, [sp
380 ; CHECK: stp x29, x30, [sp
381 ; Save original arguments.
389 ; Setup call arguments.
398 ; CHECK: mov x21, xzr
399 ; CHECK: bl _params_in_reg2
400 ; Store swifterror %error_ptr_ref.
401 ; CHECK: ldr x0, [sp, #24]
402 ; CHECK: stp {{x[0-9]+}}, x21, [sp]
403 ; Setup call arguments from original arguments.
411 ; CHECK: mov x21, x28
412 ; CHECK: bl _params_and_return_in_reg2
413 ; CHECK: mov x19, x21
414 ; CHECK: ldr x21, [sp, #8
415 ; Store return values.
433 ; CHECK: str xzr, [sp]
434 ; CHECK: bl _params_in_reg2
435 ; Restore return values for return from this function.
443 ; CHECK: mov x21, x19
445 ; CHECK: ldp x29, x30, [sp, #96] ; 16-byte Folded Reload
446 ; CHECK: ldr x28, [sp, #16] ; 8-byte Folded Reload
447 ; CHECK: ldp x20, x19, [sp, #80] ; 16-byte Folded Reload
448 ; CHECK: ldp x23, x22, [sp, #64] ; 16-byte Folded Reload
449 ; CHECK: ldp x25, x24, [sp, #48] ; 16-byte Folded Reload
450 ; CHECK: ldp x27, x26, [sp, #32] ; 16-byte Folded Reload
451 ; CHECK: add sp, sp, #112
453 define swiftcc { i64, i64, i64, i64, i64, i64, i64, i64 } @params_and_return_in_reg(i64, i64, i64, i64, i64, i64, i64, i64, ptr , ptr nocapture swifterror %err) {
454 %error_ptr_ref = alloca swifterror ptr, align 8
455 store ptr null, ptr %error_ptr_ref
456 call swiftcc void @params_in_reg2(i64 1, i64 2, i64 3, i64 4, i64 5, i64 6, i64 7, i64 8, ptr null, ptr nocapture swifterror %error_ptr_ref)
457 %val = call swiftcc { i64, i64, i64, i64, i64, i64, i64, i64 } @params_and_return_in_reg2(i64 %0, i64 %1, i64 %2, i64 %3, i64 %4, i64 %5, i64 %6, i64 %7, ptr %8, ptr nocapture swifterror %err)
458 call swiftcc void @params_in_reg2(i64 1, i64 2, i64 3, i64 4, i64 5, i64 6, i64 7, i64 8, ptr null, ptr nocapture swifterror %error_ptr_ref)
459 ret { i64, i64, i64, i64, i64, i64, i64, i64 } %val
462 declare swiftcc { i64, i64, i64, i64, i64, i64, i64, i64 } @params_and_return_in_reg2(i64, i64, i64, i64, i64, i64, i64, i64, ptr , ptr nocapture swifterror %err)
464 declare void @acallee(ptr)
466 ; Make sure we don't tail call if the caller returns a swifterror value. We
467 ; would have to move into the swifterror register before the tail call.
468 ; CHECK-LABEL: tailcall_from_swifterror:
469 ; CHECK-NOT: b _acallee
472 define swiftcc void @tailcall_from_swifterror(ptr swifterror %error_ptr_ref) {
474 tail call void @acallee(ptr null)
478 ; CHECK: tailcall_from_swifterror2
479 ; CHECK-NOT: b _simple_fn
480 ; CHECK: bl _simple_fn
481 declare void @simple_fn()
482 define swiftcc void @tailcall_from_swifterror2(ptr swifterror %error_ptr_ref) {
483 tail call void @simple_fn()
487 declare swiftcc void @foo2(ptr swifterror)
488 ; CHECK-LABEL: testAssign
489 ; CHECK: mov x21, xzr
493 define swiftcc ptr @testAssign(ptr %error_ref) {
495 %error_ptr = alloca swifterror ptr
496 store ptr null, ptr %error_ptr
497 call swiftcc void @foo2(ptr swifterror %error_ptr)
501 %error = load ptr, ptr %error_ptr
505 ; foo takes a swifterror parameter. We should be able to see that even when
506 ; it isn't explicitly on the call.
507 define float @swifterror_param_not_on_call(ptr %error_ref) {
508 ; CHECK-LABEL: swifterror_param_not_on_call:
509 ; CHECK: mov [[ID:x[0-9]+]], x0
510 ; CHECK: bl {{.*}}foo
513 ; Access part of the error object and save it to error_ref
514 ; CHECK: ldrb [[CODE:w[0-9]+]], [x0, #8]
515 ; CHECK: strb [[CODE]], [{{.*}}[[ID]]]
516 ; CHECK: bl {{.*}}free
519 %error_ptr_ref = alloca swifterror ptr
520 store ptr null, ptr %error_ptr_ref
521 %call = call float @foo(ptr %error_ptr_ref)
522 %error_from_foo = load ptr, ptr %error_ptr_ref
523 %had_error_from_foo = icmp ne ptr %error_from_foo, null
524 br i1 %had_error_from_foo, label %handler, label %cont
526 %v1 = getelementptr inbounds %swift_error, ptr %error_from_foo, i64 0, i32 1
527 %t = load i8, ptr %v1
528 store i8 %t, ptr %error_ref
531 call void @free(ptr %error_from_foo)
535 ; foo_sret takes an sret parameter and a swifterror parameter. We should be
536 ; able to see that, even if it's not explicitly on the call.
537 define float @swifterror_param_not_on_call2(ptr %error_ref) {
538 ; CHECK-LABEL: swifterror_param_not_on_call2:
539 ; CHECK: mov [[ID:x[0-9]+]], x0
540 ; CHECK: mov [[ZERO:x[0-9]+]], xzr
541 ; CHECK: bl {{.*}}foo_sret
544 ; Access part of the error object and save it to error_ref
545 ; CHECK: ldrb [[CODE:w[0-9]+]], [x0, #8]
546 ; CHECK: strb [[CODE]], [{{.*}}[[ID]]]
547 ; CHECK: bl {{.*}}free
550 %s = alloca %struct.S, align 8
551 %error_ptr_ref = alloca swifterror ptr
552 store ptr null, ptr %error_ptr_ref
553 call void @foo_sret(ptr %s, i32 1, ptr %error_ptr_ref)
554 %error_from_foo = load ptr, ptr %error_ptr_ref
555 %had_error_from_foo = icmp ne ptr %error_from_foo, null
556 br i1 %had_error_from_foo, label %handler, label %cont
558 %v1 = getelementptr inbounds %swift_error, ptr %error_from_foo, i64 0, i32 1
559 %t = load i8, ptr %v1
560 store i8 %t, ptr %error_ref
563 call void @free(ptr %error_from_foo)