xref: /llvm-project/llvm/test/CodeGen/AArch64/GlobalISel/swifterror.ll (revision 7b3bbd83c0c24087072ec5b22a76799ab31f87d5)
1; RUN: llc -verify-machineinstrs -frame-pointer=all -global-isel < %s -mtriple=aarch64-apple-ios | FileCheck %s
2
3declare ptr @malloc(i64)
4declare void @free(ptr)
5%swift_error = type {i64, i8}
6
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".
9define float @foo(ptr swifterror %error_ptr_ref) {
10; CHECK-LABEL: foo:
11; CHECK: mov w0, #16
12; CHECK: malloc
13; CHECK: mov [[ID:w[0-9]+]], #1
14; CHECK: mov x21, x0
15; CHECK: strb [[ID]], [x0, #8]
16; CHECK-NOT: x21
17
18entry:
19  %call = call ptr @malloc(i64 16)
20  store ptr %call, ptr %error_ptr_ref
21  %tmp = getelementptr inbounds i8, ptr %call, i64 8
22  store i8 1, ptr %tmp
23  ret float 1.0
24}
25
26; "caller" calls "foo" that takes a swifterror parameter.
27define float @caller(ptr %error_ref) {
28; CHECK-LABEL: caller:
29; CHECK: mov [[ID:x[0-9]+]], x0
30; CHECK: bl {{.*}}foo
31; CHECK: mov x0, x21
32; CHECK: cbnz x21
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
37
38entry:
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
45cont:
46  %v1 = getelementptr inbounds %swift_error, ptr %error_from_foo, i64 0, i32 1
47  %t = load i8, ptr %v1
48  store i8 %t, ptr %error_ref
49  br label %handler
50handler:
51  call void @free(ptr %error_from_foo)
52  ret float 1.0
53}
54
55; "caller2" is the caller of "foo", it calls "foo" inside a loop.
56define 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
60; CHECK: mov x21, xzr
61; CHECK: bl {{.*}}foo
62; CHECK: cbnz x21
63; CHECK: fcmp s0, [[CMP]]
64; CHECK: b.le
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]]]
68; CHECK: mov x0, x21
69; CHECK: bl {{.*}}free
70
71entry:
72  %error_ptr_ref = alloca swifterror ptr
73  br label %bb_loop
74bb_loop:
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
80cont:
81  %cmp = fcmp ogt float %call, 1.000000e+00
82  br i1 %cmp, label %bb_end, label %bb_loop
83bb_end:
84  %v1 = getelementptr inbounds %swift_error, ptr %error_from_foo, i64 0, i32 1
85  %t = load i8, ptr %v1
86  store i8 %t, ptr %error_ref
87  br label %handler
88handler:
89  call void @free(ptr %error_from_foo)
90  ret float 1.0
91}
92
93; "foo_if" is a function that takes a swifterror parameter, it sets swifterror
94; under a certain condition.
95define float @foo_if(ptr swifterror %error_ptr_ref, i32 %cc) {
96; CHECK-LABEL: foo_if:
97; CHECK: cbz w0
98; CHECK: mov w0, #16
99; CHECK: malloc
100; CHECK-DAG: mov x21, x0
101; CHECK-DAG: mov [[ID:w[0-9]+]], #1
102; CHECK: strb [[ID]], [x0, #8]
103; CHECK-NOT: x21
104; CHECK: ret
105
106entry:
107  %cond = icmp ne i32 %cc, 0
108  br i1 %cond, label %gen_error, label %normal
109
110gen_error:
111  %call = call ptr @malloc(i64 16)
112  store ptr %call, ptr %error_ptr_ref
113  %tmp = getelementptr inbounds i8, ptr %call, i64 8
114  store i8 1, ptr %tmp
115  ret float 1.0
116
117normal:
118  ret float 0.0
119}
120
121; "foo_loop" is a function that takes a swifterror parameter, it sets swifterror
122; under a certain condition inside a loop.
123define float @foo_loop(ptr swifterror %error_ptr_ref, i32 %cc, float %cc2) {
124; CHECK-LABEL: foo_loop:
125; CHECK: cbz
126; CHECK: mov w0, #16
127; CHECK: malloc
128; CHECK: mov x21, x0
129; CHECK: strb w{{.*}}, [x0, #8]
130; CHECK: ret
131
132entry:
133  br label %bb_loop
134
135bb_loop:
136  %cond = icmp ne i32 %cc, 0
137  br i1 %cond, label %gen_error, label %bb_cont
138
139gen_error:
140  %call = call ptr @malloc(i64 16)
141  store ptr %call, ptr %error_ptr_ref
142  %tmp = getelementptr inbounds i8, ptr %call, i64 8
143  store i8 1, ptr %tmp
144  br label %bb_cont
145
146bb_cont:
147  %cmp = fcmp ogt float %cc2, 1.000000e+00
148  br i1 %cmp, label %bb_end, label %bb_loop
149bb_end:
150  ret float 0.0
151}
152
153%struct.S = type { i32, i32, i32, i32, i32, i32 }
154
155; "foo_sret" is a function that takes a swifterror parameter, it also has a sret
156; parameter.
157define 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
161; CHECK: malloc
162; CHECK: mov [[ID:w[0-9]+]], #1
163; CHECK: strb [[ID]], [x0, #8]
164; CHECK: mov x21, x0
165; CHECK: str w{{.*}}, [{{.*}}[[SRET]], #4]
166; CHECK-NOT: x21
167
168entry:
169  %call = call ptr @malloc(i64 16)
170  store ptr %call, ptr %error_ptr_ref
171  %tmp = getelementptr inbounds i8, ptr %call, i64 8
172  store i8 1, ptr %tmp
173  %v2 = getelementptr inbounds %struct.S, ptr %agg.result, i32 0, i32 1
174  store i32 %val1, ptr %v2
175  ret void
176}
177
178; "caller3" calls "foo_sret" that takes a swifterror parameter.
179define 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
184; CHECK: mov x0, x21
185; CHECK: cbnz x21
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
190
191entry:
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
199cont:
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
203  br label %handler
204handler:
205  call void @free(ptr %error_from_foo)
206  ret float 1.0
207}
208
209; "foo_vararg" is a function that takes a swifterror parameter, it also has
210; variable number of arguments.
211declare void @llvm.va_start(ptr) nounwind
212define float @foo_vararg(ptr swifterror %error_ptr_ref, ...) {
213; CHECK-LABEL: foo_vararg:
214; CHECK: mov w0, #16
215; CHECK: malloc
216; CHECK: mov [[ID:w[0-9]+]], #1
217; CHECK: strb [[ID]], [x0, #8]
218; CHECK: mov x21, x0
219; CHECK-NOT: x21
220
221; First vararg
222; CHECK: ldr {{w[0-9]+}}, [x[[ARG1:[0-9]+]]]
223; CHECK-NOT: x21
224; Second vararg
225; CHECK: ldr {{w[0-9]+}}, [x[[ARG1]]]
226; CHECK-NOT: x21
227; Third vararg
228; CHECK: ldr {{w[0-9]+}}, [x[[ARG1]]]
229; CHECK-NOT: x21
230entry:
231  %call = call ptr @malloc(i64 16)
232  store ptr %call, ptr %error_ptr_ref
233  %tmp = getelementptr inbounds i8, ptr %call, i64 8
234  store i8 1, ptr %tmp
235
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
247
248  ret float 1.0
249}
250
251; "caller4" calls "foo_vararg" that takes a swifterror parameter.
252define float @caller4(ptr %error_ref) {
253; CHECK-LABEL: caller4:
254
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]
259
260; CHECK: bl {{.*}}foo_vararg
261; CHECK: mov x0, x21
262; CHECK: cbnz x21
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
267entry:
268  %error_ptr_ref = alloca swifterror ptr
269  store ptr null, ptr %error_ptr_ref
270
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
280
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
285
286cont:
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
290  br label %handler
291handler:
292  call void @free(ptr %error_from_foo)
293  ret float 1.0
294}
295
296; Check that we don't blow up on tail calling swifterror argument functions.
297define float @tailcallswifterror(ptr swifterror %error_ptr_ref) {
298entry:
299  %0 = tail call float @tailcallswifterror(ptr swifterror %error_ptr_ref)
300  ret float %0
301}
302define swiftcc float @tailcallswifterror_swiftcc(ptr swifterror %error_ptr_ref) {
303entry:
304  %0 = tail call swiftcc float @tailcallswifterror_swiftcc(ptr swifterror %error_ptr_ref)
305  ret float %0
306}
307
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.
317; CHECK:  mov      x20, x1
318; CHECK:  mov      x22, x2
319; CHECK:  mov      x23, x3
320; CHECK:  mov      x24, x4
321; CHECK:  mov      x25, x5
322; CHECK:  mov      x26, x6
323; CHECK:  mov      x27, x7
324; CHECK:  mov      x28, x21
325; Setup call.
326; CHECK:  mov     w0, #1
327; CHECK:  mov     w1, #2
328; CHECK:  mov     w2, #3
329; CHECK:  mov     w3, #4
330; CHECK:  mov     w4, #5
331; CHECK:  mov     w5, #6
332; CHECK:  mov     w6, #7
333; CHECK:  mov     w7, #8
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]
339; CHECK:  mov      x1, x20
340; CHECK:  mov      x2, x22
341; CHECK:  mov      x3, x23
342; CHECK:  mov      x4, x24
343; CHECK:  mov      x5, x25
344; CHECK:  mov      x6, x26
345; CHECK:  mov      x7, x27
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.
350; CHECK-NOT: x21
351; CHECK:  ldp     x29, x30, [sp
352; CHECK-NOT: x21
353; CHECK:  ldr     x28, [sp
354; CHECK-NOT: x21
355; CHECK:  ldp     x20, x19, [sp
356; CHECK-NOT: x21
357; CHECK:  ldp     x23, x22, [sp
358; CHECK-NOT: x21
359; CHECK:  ldp     x25, x24, [sp
360; CHECK-NOT: x21
361; CHECK:  ldp     x27, x26, [sp
362; CHECK-NOT: x21
363; CHECK:  ret
364define 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)
369  ret void
370}
371declare swiftcc void @params_in_reg2(i64, i64, i64, i64, i64, i64, i64, i64, ptr , ptr nocapture swifterror %err)
372
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.
382; CHECK:  mov      x20, x1
383; CHECK:  mov      x22, x2
384; CHECK:  mov      x23, x3
385; CHECK:  mov      x24, x4
386; CHECK:  mov      x25, x5
387; CHECK:  mov      x26, x6
388; CHECK:  mov      x27, x7
389; Setup call arguments.
390; CHECK:  mov     w0, #1
391; CHECK:  mov     w1, #2
392; CHECK:  mov     w2, #3
393; CHECK:  mov     w3, #4
394; CHECK:  mov     w4, #5
395; CHECK:  mov     w5, #6
396; CHECK:  mov     w6, #7
397; CHECK:  mov     w7, #8
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.
404; CHECK:  mov      x1, x20
405; CHECK:  mov      x2, x22
406; CHECK:  mov      x3, x23
407; CHECK:  mov      x4, x24
408; CHECK:  mov      x5, x25
409; CHECK:  mov      x6, x26
410; CHECK:  mov      x7, x27
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.
416; CHECK:  mov     x20, x0
417; CHECK:  mov     x22, x1
418; CHECK:  mov     x23, x2
419; CHECK:  mov     x24, x3
420; CHECK:  mov     x25, x4
421; CHECK:  mov     x26, x5
422; CHECK:  mov     x27, x6
423; CHECK:  mov     x28, x7
424; Setup call.
425; CHECK:  mov     w0, #1
426; CHECK:  mov     w1, #2
427; CHECK:  mov     w2, #3
428; CHECK:  mov     w3, #4
429; CHECK:  mov     w4, #5
430; CHECK:  mov     w5, #6
431; CHECK:  mov     w6, #7
432; CHECK:  mov     w7, #8
433; CHECK:  str     xzr, [sp]
434; CHECK:  bl      _params_in_reg2
435; Restore return values for return from this function.
436; CHECK:  mov     x0, x20
437; CHECK:  mov     x1, x22
438; CHECK:  mov     x2, x23
439; CHECK:  mov     x3, x24
440; CHECK:  mov     x4, x25
441; CHECK:  mov     x5, x26
442; CHECK:  mov     x6, x27
443; CHECK:  mov     x21, x19
444; CHECK:  mov     x7, x28
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
452; CHECK:  ret
453define 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
460}
461
462declare 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)
463
464declare void @acallee(ptr)
465
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
470; CHECK: bl _acallee
471
472define swiftcc void @tailcall_from_swifterror(ptr swifterror %error_ptr_ref) {
473entry:
474  tail call void @acallee(ptr null)
475  ret void
476}
477
478; CHECK: tailcall_from_swifterror2
479; CHECK-NOT: b _simple_fn
480; CHECK: bl _simple_fn
481declare void @simple_fn()
482define swiftcc void @tailcall_from_swifterror2(ptr swifterror %error_ptr_ref) {
483  tail call void @simple_fn()
484  ret void
485}
486
487declare swiftcc void @foo2(ptr swifterror)
488; CHECK-LABEL: testAssign
489; CHECK: mov      x21, xzr
490; CHECK: bl      _foo2
491; CHECK: mov      x0, x21
492
493define swiftcc ptr @testAssign(ptr %error_ref) {
494entry:
495  %error_ptr = alloca swifterror ptr
496  store ptr null, ptr %error_ptr
497  call swiftcc void @foo2(ptr swifterror %error_ptr)
498  br label %a
499
500a:
501  %error = load ptr, ptr %error_ptr
502  ret ptr %error
503}
504
505; foo takes a swifterror parameter. We should be able to see that even when
506; it isn't explicitly on the call.
507define 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
511; CHECK: mov x0, x21
512; CHECK: cbnz x21
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
517
518entry:
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
525cont:
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
529  br label %handler
530handler:
531  call void @free(ptr %error_from_foo)
532  ret float 1.0
533}
534
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.
537define 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
542; CHECK: mov x0, x21
543; CHECK: cbnz x21
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
548
549entry:
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
557cont:
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
561  br label %handler
562handler:
563  call void @free(ptr %error_from_foo)
564  ret float 1.0
565}
566