1; RUN: llc -verify-machineinstrs < %s -mtriple=armv7-apple-ios | FileCheck --check-prefix=CHECK-APPLE --check-prefix=CHECK-ARMV7 %s
2; RUN: llc -verify-machineinstrs -O0 < %s -mtriple=armv7-apple-ios | FileCheck --check-prefix=CHECK-O0 %s
3; RUN: llc -verify-machineinstrs < %s -mtriple=armv7-linux-androideabi | FileCheck --check-prefix=CHECK-ANDROID %s
4
5declare i8* @malloc(i64)
6declare void @free(i8*)
7%swift_error = type { i64, i8 }
8%struct.S = type { i32, i32, i32, i32, i32, i32 }
9
10; This tests the basic usage of a swifterror parameter. "foo" is the function
11; that takes a swifterror parameter and "caller" is the caller of "foo".
12define float @foo(%swift_error** swifterror %error_ptr_ref) {
13; CHECK-APPLE-LABEL: foo:
14; CHECK-APPLE: mov r0, #16
15; CHECK-APPLE: malloc
16; CHECK-APPLE-DAG: mov [[ID:r[0-9]+]], #1
17; CHECK-APPLE-DAG: mov r8, r{{.*}}
18; CHECK-APPLE-DAG: strb [[ID]], [r{{.*}}, #8]
19
20; CHECK-O0-LABEL: foo:
21; CHECK-O0: mov r{{.*}}, #16
22; CHECK-O0: malloc
23; CHECK-O0: mov [[ID2:r[0-9]+]], r0
24; CHECK-O0: mov r8, [[ID2]]
25; CHECK-O0: mov [[ID:r[0-9]+]], #1
26; CHECK-O0: strb [[ID]], {{\[}}[[ID2]], #8]
27entry:
28  %call = call i8* @malloc(i64 16)
29  %call.0 = bitcast i8* %call to %swift_error*
30  store %swift_error* %call.0, %swift_error** %error_ptr_ref
31  %tmp = getelementptr inbounds i8, i8* %call, i64 8
32  store i8 1, i8* %tmp
33  ret float 1.0
34}
35
36; "caller" calls "foo" that takes a swifterror parameter.
37define float @caller(i8* %error_ref) {
38; CHECK-APPLE-LABEL: caller:
39; CHECK-APPLE-DAG: mov [[ID:r[0-9]+]], r0
40; CHECK-APPLE-DAG: mov r8, #0
41; CHECK-APPLE: bl {{.*}}foo
42; CHECK-APPLE: mov r0, r8
43; CHECK-APPLE: cmp r8, #0
44; Access part of the error object and save it to error_ref
45; CHECK-APPLE: ldrbeq [[CODE:r[0-9]+]], [r0, #8]
46; CHECK-APPLE: strbeq [[CODE]], [{{.*}}[[ID]]]
47; CHECK-APPLE: bl {{.*}}free
48
49; CHECK-O0-LABEL: caller:
50; spill r0
51; CHECK-O0-DAG: mov r8, #0
52; CHECK-O0-DAG: str r0, [sp[[SLOT:(, #[0-9]+)?]]]
53; CHECK-O0: bl {{.*}}foo
54; CHECK-O0: mov [[TMP:r[0-9]+]], r8
55; CHECK-O0: str [[TMP]], [sp[[SLOT2:(, #[0-9]+)?]]]
56; CHECK-O0: bne
57; CHECK-O0: ldr [[ID:r[0-9]+]], [sp[[SLOT]]]
58; CHECK-O0: ldrb [[CODE:r[0-9]+]], [r0, #8]
59; CHECK-O0: strb [[CODE]], [{{.*}}[[ID]]]
60; reload r0
61; CHECK-O0: ldr r0, [sp[[SLOT2]]]
62; CHECK-O0: free
63entry:
64  %error_ptr_ref = alloca swifterror %swift_error*
65  store %swift_error* null, %swift_error** %error_ptr_ref
66  %call = call float @foo(%swift_error** swifterror %error_ptr_ref)
67  %error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref
68  %had_error_from_foo = icmp ne %swift_error* %error_from_foo, null
69  %tmp = bitcast %swift_error* %error_from_foo to i8*
70  br i1 %had_error_from_foo, label %handler, label %cont
71cont:
72  %v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1
73  %t = load i8, i8* %v1
74  store i8 %t, i8* %error_ref
75  br label %handler
76handler:
77  call void @free(i8* %tmp)
78  ret float 1.0
79}
80
81; "caller2" is the caller of "foo", it calls "foo" inside a loop.
82define float @caller2(i8* %error_ref) {
83; CHECK-APPLE-LABEL: caller2:
84; CHECK-APPLE-DAG: mov [[ID:r[0-9]+]], r0
85; CHECK-APPLE-DAG: mov r8, #0
86; CHECK-APPLE: bl {{.*}}foo
87; CHECK-APPLE: cmp r8, #0
88; CHECK-APPLE: bne
89; Access part of the error object and save it to error_ref
90; CHECK-APPLE: ldrb [[CODE:r[0-9]+]], [r8, #8]
91; CHECK-APPLE: strb [[CODE]], [{{.*}}[[ID]]]
92; CHECK-APPLE: mov r0, r8
93; CHECK-APPLE: bl {{.*}}free
94
95; CHECK-O0-LABEL: caller2:
96; spill r0
97; CHECK-O0-DAG: str r0,
98; CHECK-O0-DAG: mov r8, #0
99; CHECK-O0: bl {{.*}}foo
100; CHECK-O0: mov r{{.*}}, r8
101; CHECK-O0: str r0, [sp{{(, #[0-9]+)?}}]
102; CHECK-O0: bne
103; CHECK-O0: ble
104; reload r0
105; CHECK-O0: ldr [[ID:r[0-9]+]],
106; CHECK-O0: ldrb [[CODE:r[0-9]+]], [r0, #8]
107; CHECK-O0: strb [[CODE]], [{{.*}}[[ID]]]
108; CHECK-O0: ldr r0, [sp{{(, #[0-9]+)?}}]
109; CHECK-O0: free
110entry:
111  %error_ptr_ref = alloca swifterror %swift_error*
112  br label %bb_loop
113bb_loop:
114  store %swift_error* null, %swift_error** %error_ptr_ref
115  %call = call float @foo(%swift_error** swifterror %error_ptr_ref)
116  %error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref
117  %had_error_from_foo = icmp ne %swift_error* %error_from_foo, null
118  %tmp = bitcast %swift_error* %error_from_foo to i8*
119  br i1 %had_error_from_foo, label %handler, label %cont
120cont:
121  %cmp = fcmp ogt float %call, 1.000000e+00
122  br i1 %cmp, label %bb_end, label %bb_loop
123bb_end:
124  %v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1
125  %t = load i8, i8* %v1
126  store i8 %t, i8* %error_ref
127  br label %handler
128handler:
129  call void @free(i8* %tmp)
130  ret float 1.0
131}
132
133; "foo_if" is a function that takes a swifterror parameter, it sets swifterror
134; under a certain condition.
135define float @foo_if(%swift_error** swifterror %error_ptr_ref, i32 %cc) {
136; CHECK-APPLE-LABEL: foo_if:
137; CHECK-APPLE: cmp r0, #0
138; CHECK-APPLE: eq
139; CHECK-APPLE: mov r0, #16
140; CHECK-APPLE: malloc
141; CHECK-APPLE-DAG: mov [[ID:r[0-9]+]], #1
142; CHECK-APPLE-DAG: mov r8, r{{.*}}
143; CHECK-APPLE-DAG: strb [[ID]], [r{{.*}}, #8]
144
145; CHECK-O0-LABEL: foo_if:
146; spill to stack
147; CHECK-O0: str r8
148; CHECK-O0: cmp r0, #0
149; CHECK-O0: beq
150; CHECK-O0: mov r0, #16
151; CHECK-O0: malloc
152; CHECK-O0: mov [[ID:r[0-9]+]], r0
153; CHECK-O0: mov [[ID2:[a-z0-9]+]], #1
154; CHECK-O0: strb [[ID2]], {{\[}}[[ID]], #8]
155; reload from stack
156; CHECK-O0: ldr r8
157entry:
158  %cond = icmp ne i32 %cc, 0
159  br i1 %cond, label %gen_error, label %normal
160
161gen_error:
162  %call = call i8* @malloc(i64 16)
163  %call.0 = bitcast i8* %call to %swift_error*
164  store %swift_error* %call.0, %swift_error** %error_ptr_ref
165  %tmp = getelementptr inbounds i8, i8* %call, i64 8
166  store i8 1, i8* %tmp
167  ret float 1.0
168
169normal:
170  ret float 0.0
171}
172
173; "foo_loop" is a function that takes a swifterror parameter, it sets swifterror
174; under a certain condition inside a loop.
175define float @foo_loop(%swift_error** swifterror %error_ptr_ref, i32 %cc, float %cc2) {
176; CHECK-APPLE-LABEL: foo_loop:
177; CHECK-APPLE: mov [[CODE:r[0-9]+]], r0
178; swifterror is kept in a register
179; CHECK-APPLE: cmp [[CODE]], #0
180; CHECK-APPLE: beq
181; CHECK-APPLE: mov r0, #16
182; CHECK-APPLE: malloc
183; CHECK-APPLE: strb r{{.*}}, [r0, #8]
184; CHECK-APPLE: b
185
186; CHECK-O0-LABEL: foo_loop:
187; CHECK-O0: cmp r{{.*}}, #0
188; CHECK-O0: beq
189; CHECK-O0: mov r0, #16
190; CHECK-O0: malloc
191; CHECK-O0-DAG: mov [[ID:r[0-9]+]], r0
192; CHECK-O0-DAG: movw [[ID2:.*]], #1
193; CHECK-O0: strb [[ID2]], [{{.*}}[[ID]], #8]
194; spill r0
195; CHECK-O0: str r0, [sp{{.*}}]
196; CHECK-O0: vcmp
197; CHECK-O0: ble
198; reload from stack
199; CHECK-O0: ldr r8
200entry:
201  br label %bb_loop
202
203bb_loop:
204  %cond = icmp ne i32 %cc, 0
205  br i1 %cond, label %gen_error, label %bb_cont
206
207gen_error:
208  %call = call i8* @malloc(i64 16)
209  %call.0 = bitcast i8* %call to %swift_error*
210  store %swift_error* %call.0, %swift_error** %error_ptr_ref
211  %tmp = getelementptr inbounds i8, i8* %call, i64 8
212  store i8 1, i8* %tmp
213  br label %bb_cont
214
215bb_cont:
216  %cmp = fcmp ogt float %cc2, 1.000000e+00
217  br i1 %cmp, label %bb_end, label %bb_loop
218bb_end:
219  ret float 0.0
220}
221
222; "foo_sret" is a function that takes a swifterror parameter, it also has a sret
223; parameter.
224define void @foo_sret(%struct.S* sret(%struct.S) %agg.result, i32 %val1, %swift_error** swifterror %error_ptr_ref) {
225; CHECK-APPLE-LABEL: foo_sret:
226; CHECK-APPLE: mov [[SRET:r[0-9]+]], r0
227; CHECK-APPLE: mov r0, #16
228; CHECK-APPLE: malloc
229; CHECK-APPLE: mov [[REG:r[0-9]+]], #1
230; CHECK-APPLE-DAG: mov r8, r0
231; CHECK-APPLE-DAG: strb [[REG]], [r0, #8]
232; CHECK-APPLE-DAG: str r{{.*}}, [{{.*}}[[SRET]], #4]
233
234; CHECK-O0-LABEL: foo_sret:
235; CHECK-O0-DAG: mov r{{.*}}, #16
236; spill to stack: sret and val1
237; CHECK-O0-DAG: str r0
238; CHECK-O0-DAG: str r1
239; CHECK-O0: malloc
240; reload from stack: sret and val1
241; CHECK-O0: ldr
242; CHECK-O0: ldr
243; CHECK-O0-DAG: mov r8
244; CHECK-O0-DAG: mov [[ID:r[0-9]+]], #1
245; CHECK-O0-DAG: strb [[ID]], [{{r[0-9]+}}, #8]
246; CHECK-O0-DAG: str r{{.*}}, [{{.*}}, #4]
247entry:
248  %call = call i8* @malloc(i64 16)
249  %call.0 = bitcast i8* %call to %swift_error*
250  store %swift_error* %call.0, %swift_error** %error_ptr_ref
251  %tmp = getelementptr inbounds i8, i8* %call, i64 8
252  store i8 1, i8* %tmp
253  %v2 = getelementptr inbounds %struct.S, %struct.S* %agg.result, i32 0, i32 1
254  store i32 %val1, i32* %v2
255  ret void
256}
257
258; "caller3" calls "foo_sret" that takes a swifterror parameter.
259define float @caller3(i8* %error_ref) {
260; CHECK-APPLE-LABEL: caller3:
261; CHECK-APPLE: mov [[ID:r[0-9]+]], r0
262; CHECK-APPLE: mov r8, #0
263; CHECK-APPLE: bl {{.*}}foo_sret
264; CHECK-APPLE: mov r0, r8
265; CHECK-APPLE: cmp r8, #0
266; Access part of the error object and save it to error_ref
267; CHECK-APPLE: ldrbeq [[CODE:r[0-9]+]], [r0, #8]
268; CHECK-APPLE: strbeq [[CODE]], [{{.*}}[[ID]]]
269; CHECK-APPLE: bl {{.*}}free
270
271; CHECK-O0-LABEL: caller3:
272; CHECK-O0-DAG: mov r8, #0
273; CHECK-O0-DAG: mov r1
274; CHECK-O0: bl {{.*}}foo_sret
275; CHECK-O0: mov [[ID2:r[0-9]+]], r8
276; CHECK-O0: str [[ID2]], [sp[[SLOT:.*]]]
277; CHECK-O0: cmp r8
278; CHECK-O0: bne
279; Access part of the error object and save it to error_ref
280; CHECK-O0: ldr [[ID:r[0-9]+]]
281; CHECK-O0: ldrb [[CODE:r[0-9]+]]
282; CHECK-O0: strb [[CODE]], [{{.*}}[[ID]]]
283; CHECK-O0: ldr r0, [sp[[SLOT]]
284; CHECK-O0: bl {{.*}}free
285entry:
286  %s = alloca %struct.S, align 8
287  %error_ptr_ref = alloca swifterror %swift_error*
288  store %swift_error* null, %swift_error** %error_ptr_ref
289  call void @foo_sret(%struct.S* sret(%struct.S) %s, i32 1, %swift_error** swifterror %error_ptr_ref)
290  %error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref
291  %had_error_from_foo = icmp ne %swift_error* %error_from_foo, null
292  %tmp = bitcast %swift_error* %error_from_foo to i8*
293  br i1 %had_error_from_foo, label %handler, label %cont
294cont:
295  %v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1
296  %t = load i8, i8* %v1
297  store i8 %t, i8* %error_ref
298  br label %handler
299handler:
300  call void @free(i8* %tmp)
301  ret float 1.0
302}
303
304; "foo_vararg" is a function that takes a swifterror parameter, it also has
305; variable number of arguments.
306declare void @llvm.va_start(i8*) nounwind
307define float @foo_vararg(%swift_error** swifterror %error_ptr_ref, ...) {
308; CHECK-APPLE-LABEL: foo_vararg:
309; CHECK-APPLE: mov r0, #16
310; CHECK-APPLE: malloc
311; CHECK-APPLE: mov r8, r0
312; CHECK-APPLE: mov [[ID:r[0-9]+]], #1
313; CHECK-APPLE-DAG: strb [[ID]], [r8, #8]
314
315entry:
316  %call = call i8* @malloc(i64 16)
317  %call.0 = bitcast i8* %call to %swift_error*
318  store %swift_error* %call.0, %swift_error** %error_ptr_ref
319  %tmp = getelementptr inbounds i8, i8* %call, i64 8
320  store i8 1, i8* %tmp
321
322  %args = alloca i8*, align 8
323  %a10 = alloca i32, align 4
324  %a11 = alloca i32, align 4
325  %a12 = alloca i32, align 4
326  %v10 = bitcast i8** %args to i8*
327  call void @llvm.va_start(i8* %v10)
328  %v11 = va_arg i8** %args, i32
329  store i32 %v11, i32* %a10, align 4
330  %v12 = va_arg i8** %args, i32
331  store i32 %v12, i32* %a11, align 4
332  %v13 = va_arg i8** %args, i32
333  store i32 %v13, i32* %a12, align 4
334
335  ret float 1.0
336}
337
338; "caller4" calls "foo_vararg" that takes a swifterror parameter.
339define float @caller4(i8* %error_ref) {
340; CHECK-APPLE-LABEL: caller4:
341; CHECK-APPLE: mov [[ID:r[0-9]+]], r0
342; CHECK-APPLE: mov r8, #0
343; CHECK-APPLE: bl {{.*}}foo_vararg
344; CHECK-APPLE: mov r0, r8
345; CHECK-APPLE: cmp r8, #0
346; Access part of the error object and save it to error_ref
347; CHECK-APPLE: ldrbeq [[CODE:r[0-9]+]], [r0, #8]
348; CHECK-APPLE: strbeq [[CODE]], [{{.*}}[[ID]]]
349; CHECK-APPLE: bl {{.*}}free
350entry:
351  %error_ptr_ref = alloca swifterror %swift_error*
352  store %swift_error* null, %swift_error** %error_ptr_ref
353
354  %a10 = alloca i32, align 4
355  %a11 = alloca i32, align 4
356  %a12 = alloca i32, align 4
357  store i32 10, i32* %a10, align 4
358  store i32 11, i32* %a11, align 4
359  store i32 12, i32* %a12, align 4
360  %v10 = load i32, i32* %a10, align 4
361  %v11 = load i32, i32* %a11, align 4
362  %v12 = load i32, i32* %a12, align 4
363
364  %call = call float (%swift_error**, ...) @foo_vararg(%swift_error** swifterror %error_ptr_ref, i32 %v10, i32 %v11, i32 %v12)
365  %error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref
366  %had_error_from_foo = icmp ne %swift_error* %error_from_foo, null
367  %tmp = bitcast %swift_error* %error_from_foo to i8*
368  br i1 %had_error_from_foo, label %handler, label %cont
369
370cont:
371  %v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1
372  %t = load i8, i8* %v1
373  store i8 %t, i8* %error_ref
374  br label %handler
375handler:
376  call void @free(i8* %tmp)
377  ret float 1.0
378}
379
380; Check that we don't blow up on tail calling swifterror argument functions.
381define float @tailcallswifterror(%swift_error** swifterror %error_ptr_ref) {
382entry:
383  %0 = tail call float @tailcallswifterror(%swift_error** swifterror %error_ptr_ref)
384  ret float %0
385}
386define swiftcc float @tailcallswifterror_swiftcc(%swift_error** swifterror %error_ptr_ref) {
387entry:
388  %0 = tail call swiftcc float @tailcallswifterror_swiftcc(%swift_error** swifterror %error_ptr_ref)
389  ret float %0
390}
391
392; CHECK-APPLE-LABEL: swifterror_clobber
393; CHECK-APPLE: mov [[REG:r[0-9]+]], r8
394; CHECK-APPLE: nop
395; CHECK-APPLE: mov r8, [[REG]]
396define swiftcc void @swifterror_clobber(%swift_error** nocapture swifterror %err) {
397  call void asm sideeffect "nop", "~{r8}"()
398  ret void
399}
400
401; CHECK-APPLE-LABEL: swifterror_reg_clobber
402; CHECK-APPLE: push {{.*}}r8
403; CHECK-APPLE: nop
404; CHECK-APPLE: pop  {{.*}}r8
405define swiftcc void @swifterror_reg_clobber(%swift_error** nocapture %err) {
406  call void asm sideeffect "nop", "~{r8}"()
407  ret void
408}
409
410; CHECK-ARMV7-LABEL: _params_in_reg
411; Store callee saved registers excluding swifterror.
412; CHECK-ARMV7:  push   {r4, r5, r6, r7, r10, r11, lr}
413; Store swiftself (r10) and swifterror (r8).
414; CHECK-ARMV7-DAG:  str     r8, [s[[STK1:.*]]]
415; CHECK-ARMV7-DAG:  str     r10, [s[[STK2:.*]]]
416; Store arguments.
417; CHECK-ARMV7-DAG:  mov     r6, r3
418; CHECK-ARMV7-DAG:  mov     r4, r2
419; CHECK-ARMV7-DAG:  mov     r11, r1
420; CHECK-ARMV7-DAG:  mov     r5, r0
421; Setup call.
422; CHECK-ARMV7:  mov     r0, #1
423; CHECK-ARMV7:  mov     r1, #2
424; CHECK-ARMV7:  mov     r2, #3
425; CHECK-ARMV7:  mov     r3, #4
426; CHECK-ARMV7:  mov     r10, #0
427; CHECK-ARMV7:  mov     r8, #0
428; CHECK-ARMV7:  bl      _params_in_reg2
429; Restore original arguments.
430; CHECK-ARMV7-DAG:  ldr     r10, [s[[STK2]]]
431; CHECK-ARMV7-DAG:  ldr     r8, [s[[STK1]]]
432; CHECK-ARMV7-DAG:  mov     r0, r5
433; CHECK-ARMV7-DAG:  mov     r1, r11
434; CHECK-ARMV7-DAG:  mov     r2, r4
435; CHECK-ARMV7-DAG:  mov     r3, r6
436; CHECK-ARMV7:  bl      _params_in_reg2
437; CHECK-ARMV7:  pop     {r4, r5, r6, r7, r10, r11, pc}
438define swiftcc void @params_in_reg(i32, i32, i32, i32, i8* swiftself, %swift_error** nocapture swifterror %err) {
439  %error_ptr_ref = alloca swifterror %swift_error*, align 8
440  store %swift_error* null, %swift_error** %error_ptr_ref
441  call swiftcc void @params_in_reg2(i32 1, i32 2, i32 3, i32 4, i8* swiftself null, %swift_error** nocapture swifterror %error_ptr_ref)
442  call swiftcc void @params_in_reg2(i32 %0, i32 %1, i32 %2, i32 %3, i8* swiftself %4, %swift_error** nocapture swifterror %err)
443  ret void
444}
445declare swiftcc void @params_in_reg2(i32, i32, i32, i32, i8* swiftself, %swift_error** nocapture swifterror %err)
446
447; CHECK-ARMV7-LABEL: params_and_return_in_reg
448; CHECK-ARMV7:  push    {r4, r5, r6, r7, r10, r11, lr}
449; Store swifterror and swiftself
450; CHECK-ARMV7:  mov     r6, r8
451; CHECK-ARMV7:  str     r10, [s[[STK1:.*]]]
452; Store arguments.
453; CHECK-ARMV7:  str     r3, [s[[STK2:.*]]]
454; CHECK-ARMV7:  mov     r4, r2
455; CHECK-ARMV7:  mov     r11, r1
456; CHECK-ARMV7:  mov     r5, r0
457; Setup call.
458; CHECK-ARMV7:  mov     r0, #1
459; CHECK-ARMV7:  mov     r1, #2
460; CHECK-ARMV7:  mov     r2, #3
461; CHECK-ARMV7:  mov     r3, #4
462; CHECK-ARMV7:  mov     r10, #0
463; CHECK-ARMV7:  mov     r8, #0
464; CHECK-ARMV7:  bl      _params_in_reg2
465; Restore original arguments.
466; CHECK-ARMV7-DAG:  ldr     r3, [s[[STK2]]]
467; CHECK-ARMV7-DAG:  ldr     r10, [s[[STK1]]]
468; Store %error_ptr_ref;
469; CHECK-ARMV7-DAG:  str     r8, [s[[STK3:.*]]]
470; Restore original arguments.
471; CHECK-ARMV7-DAG:  mov     r0, r5
472; CHECK-ARMV7-DAG:  mov     r1, r11
473; CHECK-ARMV7-DAG:  mov     r2, r4
474; CHECK-ARMV7-DAG:  mov     r8, r6
475; CHECK-ARMV7:  bl      _params_and_return_in_reg2
476; Store swifterror return %err;
477; CHECK-ARMV7-DAG:  str     r8, [s[[STK1]]]
478; Load swifterror value %error_ptr_ref.
479; CHECK-ARMV7-DAG:  ldr     r8, [s[[STK3]]]
480; Save return values.
481; CHECK-ARMV7-DAG:  mov     r4, r0
482; CHECK-ARMV7-DAG:  mov     r5, r1
483; CHECK-ARMV7-DAG:  mov     r6, r2
484; CHECK-ARMV7-DAG:  mov     r11, r3
485; Setup call.
486; CHECK-ARMV7:  mov     r0, #1
487; CHECK-ARMV7:  mov     r1, #2
488; CHECK-ARMV7:  mov     r2, #3
489; CHECK-ARMV7:  mov     r3, #4
490; CHECK-ARMV7:  mov     r10, #0
491; CHECK-ARMV7:  bl      _params_in_reg2
492; Load swifterror %err;
493; CHECK-ARMV7-DAG:  ldr     r8, [s[[STK1]]]
494; Restore return values for returning.
495; CHECK-ARMV7-DAG:  mov     r0, r4
496; CHECK-ARMV7-DAG:  mov     r1, r5
497; CHECK-ARMV7-DAG:  mov     r2, r6
498; CHECK-ARMV7-DAG:  mov     r3, r11
499; CHECK-ARMV7:  pop     {r4, r5, r6, r7, r10, r11, pc}
500
501; CHECK-ANDROID-LABEL: params_and_return_in_reg
502; CHECK-ANDROID:  push    {r4, r5, r6, r7, r9, r10, r11, lr}
503; CHECK-ANDROID:  sub     sp, sp, #16
504; CHECK-ANDROID:  str     r8, [sp, #4]            @ 4-byte Spill
505; CHECK-ANDROID:  mov     r11, r10
506; CHECK-ANDROID:  mov     r6, r3
507; CHECK-ANDROID:  mov     r7, r2
508; CHECK-ANDROID:  mov     r4, r1
509; CHECK-ANDROID:  mov     r5, r0
510; CHECK-ANDROID:  mov     r0, #1
511; CHECK-ANDROID:  mov     r1, #2
512; CHECK-ANDROID:  mov     r2, #3
513; CHECK-ANDROID:  mov     r3, #4
514; CHECK-ANDROID:  mov     r10, #0
515; CHECK-ANDROID:  mov     r8, #0
516; CHECK-ANDROID:  bl      params_in_reg2
517; CHECK-ANDROID:  mov     r9, r8
518; CHECK-ANDROID:  ldr     r8, [sp, #4]            @ 4-byte Reload
519; CHECK-ANDROID:  mov     r0, r5
520; CHECK-ANDROID:  mov     r1, r4
521; CHECK-ANDROID:  mov     r2, r7
522; CHECK-ANDROID:  mov     r3, r6
523; CHECK-ANDROID:  mov     r10, r11
524; CHECK-ANDROID:  bl      params_and_return_in_reg2
525; CHECK-ANDROID:  mov     r4, r0
526; CHECK-ANDROID:  mov     r5, r1
527; CHECK-ANDROID:  mov     r6, r2
528; CHECK-ANDROID:  mov     r7, r3
529; CHECK-ANDROID:  mov     r11, r8
530; CHECK-ANDROID:  mov     r0, #1
531; CHECK-ANDROID:  mov     r1, #2
532; CHECK-ANDROID:  mov     r2, #3
533; CHECK-ANDROID:  mov     r3, #4
534; CHECK-ANDROID:  mov     r10, #0
535; CHECK-ANDROID:  mov     r8, r9
536; CHECK-ANDROID:  bl      params_in_reg2
537; CHECK-ANDROID:  mov     r0, r4
538; CHECK-ANDROID:  mov     r1, r5
539; CHECK-ANDROID:  mov     r2, r6
540; CHECK-ANDROID:  mov     r3, r7
541; CHECK-ANDROID:  mov     r8, r11
542; CHECK-ANDROID:  add     sp, sp, #16
543; CHECK-ANDROID:  pop	{r4, r5, r6, r7, r9, r10, r11, pc}
544
545define swiftcc { i32, i32, i32, i32} @params_and_return_in_reg(i32, i32, i32, i32, i8* swiftself, %swift_error** nocapture swifterror %err) {
546  %error_ptr_ref = alloca swifterror %swift_error*, align 8
547  store %swift_error* null, %swift_error** %error_ptr_ref
548  call swiftcc void @params_in_reg2(i32 1, i32 2, i32 3, i32 4, i8* swiftself null, %swift_error** nocapture swifterror %error_ptr_ref)
549  %val = call swiftcc  { i32, i32, i32, i32 } @params_and_return_in_reg2(i32 %0, i32 %1, i32 %2, i32 %3, i8* swiftself %4, %swift_error** nocapture swifterror %err)
550  call swiftcc void @params_in_reg2(i32 1, i32 2, i32 3, i32 4, i8* swiftself null, %swift_error** nocapture swifterror %error_ptr_ref)
551  ret { i32, i32, i32, i32 }%val
552}
553
554declare swiftcc { i32, i32, i32, i32 } @params_and_return_in_reg2(i32, i32, i32, i32, i8* swiftself, %swift_error** nocapture swifterror %err)
555
556
557declare void @acallee(i8*)
558
559; Make sure we don't tail call if the caller returns a swifterror value. We
560; would have to move into the swifterror register before the tail call.
561; CHECK-APPLE: tailcall_from_swifterror:
562; CHECK-APPLE-NOT: b _acallee
563; CHECK-APPLE: bl _acallee
564; CHECK-ANDROID: tailcall_from_swifterror:
565; CHECK-ANDROID-NOT: b acallee
566; CHECK-ANDROID: bl acallee
567
568define swiftcc void @tailcall_from_swifterror(%swift_error** swifterror %error_ptr_ref) {
569entry:
570  tail call void @acallee(i8* null)
571  ret void
572}
573
574
575declare swiftcc void @foo2(%swift_error** swifterror)
576
577; Make sure we properly assign registers during fast-isel.
578; CHECK-O0-LABEL: testAssign
579; CHECK-O0: mov     r8, #0
580; CHECK-O0: bl      _foo2
581; CHECK-O0: str     r8, [s[[STK:p.*]]]
582; CHECK-O0: ldr     r0, [s[[STK]]]
583; CHECK-O0: pop
584
585; CHECK-APPLE-LABEL: testAssign
586; CHECK-APPLE:  mov     r8, #0
587; CHECK-APPLE:  bl      _foo2
588; CHECK-APPLE:  mov     r0, r8
589
590; CHECK-ANDROID-LABEL: testAssign
591; CHECK-ANDROID:  mov     r8, #0
592; CHECK-ANDROID:  bl      foo2
593; CHECK-ANDROID:  mov     r0, r8
594
595define swiftcc %swift_error* @testAssign(i8* %error_ref) {
596entry:
597  %error_ptr = alloca swifterror %swift_error*
598  store %swift_error* null, %swift_error** %error_ptr
599  call swiftcc void @foo2(%swift_error** swifterror %error_ptr)
600  br label %a
601
602a:
603  %error = load %swift_error*, %swift_error** %error_ptr
604  ret %swift_error* %error
605}
606