1; RUN: llc -verify-machineinstrs < %s -mtriple=armv7-apple-ios | FileCheck --check-prefix=CHECK-APPLE %s
2; RUN: llc -verify-machineinstrs -O0 < %s -mtriple=armv7-apple-ios | FileCheck --check-prefix=CHECK-O0 %s
3
4declare i8* @malloc(i64)
5declare void @free(i8*)
6%swift_error = type { i64, i8 }
7%struct.S = type { i32, i32, i32, i32, i32, i32 }
8
9; This tests the basic usage of a swifterror parameter. "foo" is the function
10; that takes a swifterror parameter and "caller" is the caller of "foo".
11define float @foo(%swift_error** swifterror %error_ptr_ref) {
12; CHECK-APPLE-LABEL: foo:
13; CHECK-APPLE: mov r0, #16
14; CHECK-APPLE: malloc
15; CHECK-APPLE-DAG: mov [[ID:r[0-9]+]], #1
16; CHECK-APPLE-DAG: mov r6, r{{.*}}
17; CHECK-APPLE-DAG: strb [[ID]], [r{{.*}}, #8]
18
19; CHECK-O0-LABEL: foo:
20; CHECK-O0: mov r{{.*}}, #16
21; CHECK-O0: malloc
22; CHECK-O0: mov [[ID2:r[0-9]+]], r0
23; CHECK-O0: mov [[ID:r[0-9]+]], #1
24; CHECK-O0: strb [[ID]], [r0, #8]
25; CHECK-O0: mov r6, [[ID2]]
26entry:
27  %call = call i8* @malloc(i64 16)
28  %call.0 = bitcast i8* %call to %swift_error*
29  store %swift_error* %call.0, %swift_error** %error_ptr_ref
30  %tmp = getelementptr inbounds i8, i8* %call, i64 8
31  store i8 1, i8* %tmp
32  ret float 1.0
33}
34
35; "caller" calls "foo" that takes a swifterror parameter.
36define float @caller(i8* %error_ref) {
37; CHECK-APPLE-LABEL: caller:
38; CHECK-APPLE-DAG: mov [[ID:r[0-9]+]], r0
39; CHECK-APPLE-DAG: mov r6, #0
40; CHECK-APPLE: bl {{.*}}foo
41; CHECK-APPLE: cmp r6, #0
42; Access part of the error object and save it to error_ref
43; CHECK-APPLE: ldrbeq [[CODE:r[0-9]+]], [r6, #8]
44; CHECK-APPLE: strbeq [[CODE]], [{{.*}}[[ID]]]
45; CHECK-APPLE: mov r0, r6
46; CHECK_APPLE: bl {{.*}}free
47
48; CHECK-O0-LABEL: caller:
49; spill r0
50; CHECK-O0-DAG: str r0,
51; CHECK-O0-DAG: mov r6, #0
52; CHECK-O0: bl {{.*}}foo
53; CHECK-O0: mov r{{.*}}, r6
54; CHECK-O0: bne
55; CHECK-O0: ldrb [[CODE:r[0-9]+]], [r0, #8]
56; reload r0
57; CHECK-O0: ldr [[ID:r[0-9]+]],
58; CHECK-O0: strb [[CODE]], [{{.*}}[[ID]]]
59; CHECK-O0: mov r0,
60; CHECK-O0: free
61entry:
62  %error_ptr_ref = alloca swifterror %swift_error*
63  store %swift_error* null, %swift_error** %error_ptr_ref
64  %call = call float @foo(%swift_error** swifterror %error_ptr_ref)
65  %error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref
66  %had_error_from_foo = icmp ne %swift_error* %error_from_foo, null
67  %tmp = bitcast %swift_error* %error_from_foo to i8*
68  br i1 %had_error_from_foo, label %handler, label %cont
69cont:
70  %v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1
71  %t = load i8, i8* %v1
72  store i8 %t, i8* %error_ref
73  br label %handler
74handler:
75  call void @free(i8* %tmp)
76  ret float 1.0
77}
78
79; "caller2" is the caller of "foo", it calls "foo" inside a loop.
80define float @caller2(i8* %error_ref) {
81; CHECK-APPLE-LABEL: caller2:
82; CHECK-APPLE-DAG: mov [[ID:r[0-9]+]], r0
83; CHECK-APPLE-DAG: mov r6, #0
84; CHECK-APPLE: bl {{.*}}foo
85; CHECK-APPLE: cmp r6, #0
86; CHECK-APPLE: bne
87; Access part of the error object and save it to error_ref
88; CHECK-APPLE: ldrb [[CODE:r[0-9]+]], [r6, #8]
89; CHECK-APPLE: strb [[CODE]], [{{.*}}[[ID]]]
90; CHECK-APPLE: mov r0, r6
91; CHECK_APPLE: bl {{.*}}free
92
93; CHECK-O0-LABEL: caller2:
94; spill r0
95; CHECK-O0-DAG: str r0,
96; CHECK-O0-DAG: mov r6, #0
97; CHECK-O0: bl {{.*}}foo
98; CHECK-O0: mov r{{.*}}, r6
99; CHECK-O0: bne
100; CHECK-O0: ble
101; CHECK-O0: ldrb [[CODE:r[0-9]+]], [r0, #8]
102; reload r0
103; CHECK-O0: ldr [[ID:r[0-9]+]],
104; CHECK-O0: strb [[CODE]], [{{.*}}[[ID]]]
105; CHECK-O0: mov r0,
106; CHECK-O0: free
107entry:
108  %error_ptr_ref = alloca swifterror %swift_error*
109  br label %bb_loop
110bb_loop:
111  store %swift_error* null, %swift_error** %error_ptr_ref
112  %call = call float @foo(%swift_error** swifterror %error_ptr_ref)
113  %error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref
114  %had_error_from_foo = icmp ne %swift_error* %error_from_foo, null
115  %tmp = bitcast %swift_error* %error_from_foo to i8*
116  br i1 %had_error_from_foo, label %handler, label %cont
117cont:
118  %cmp = fcmp ogt float %call, 1.000000e+00
119  br i1 %cmp, label %bb_end, label %bb_loop
120bb_end:
121  %v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1
122  %t = load i8, i8* %v1
123  store i8 %t, i8* %error_ref
124  br label %handler
125handler:
126  call void @free(i8* %tmp)
127  ret float 1.0
128}
129
130; "foo_if" is a function that takes a swifterror parameter, it sets swifterror
131; under a certain condition.
132define float @foo_if(%swift_error** swifterror %error_ptr_ref, i32 %cc) {
133; CHECK-APPLE-LABEL: foo_if:
134; CHECK-APPLE: cmp r0, #0
135; CHECK-APPLE: eq
136; CHECK-APPLE: mov r0, #16
137; CHECK-APPLE: malloc
138; CHECK-APPLE: mov [[ID:r[0-9]+]], #1
139; CHECK-APPLE-DAG: mov r6, r{{.*}}
140; CHECK-APPLE-DAG: strb [[ID]], [r{{.*}}, #8]
141
142; CHECK-O0-LABEL: foo_if:
143; CHECK-O0: cmp r0, #0
144; spill to stack
145; CHECK-O0: str r6
146; CHECK-O0: beq
147; CHECK-O0: mov r0, #16
148; CHECK-O0: malloc
149; CHECK-O0: mov [[ID:r[0-9]+]], r0
150; CHECK-O0: mov [[ID2:[a-z0-9]+]], #1
151; CHECK-O0: strb [[ID2]], [r0, #8]
152; CHECK-O0: mov r6, [[ID]]
153; reload from stack
154; CHECK-O0: ldr r6
155entry:
156  %cond = icmp ne i32 %cc, 0
157  br i1 %cond, label %gen_error, label %normal
158
159gen_error:
160  %call = call i8* @malloc(i64 16)
161  %call.0 = bitcast i8* %call to %swift_error*
162  store %swift_error* %call.0, %swift_error** %error_ptr_ref
163  %tmp = getelementptr inbounds i8, i8* %call, i64 8
164  store i8 1, i8* %tmp
165  ret float 1.0
166
167normal:
168  ret float 0.0
169}
170
171; "foo_loop" is a function that takes a swifterror parameter, it sets swifterror
172; under a certain condition inside a loop.
173define float @foo_loop(%swift_error** swifterror %error_ptr_ref, i32 %cc, float %cc2) {
174; CHECK-APPLE-LABEL: foo_loop:
175; CHECK-APPLE: mov [[CODE:r[0-9]+]], r0
176; swifterror is kept in a register
177; CHECK-APPLE: mov [[ID:r[0-9]+]], r6
178; CHECK-APPLE: cmp [[CODE]], #0
179; CHECK-APPLE: beq
180; CHECK-APPLE: mov r0, #16
181; CHECK-APPLE: malloc
182; CHECK-APPLE: strb r{{.*}}, [{{.*}}[[ID]], #8]
183; CHECK-APPLE: ble
184; CHECK-APPLE: mov r6, [[ID]]
185
186; CHECK-O0-LABEL: foo_loop:
187; CHECK-O0: mov r{{.*}}, r6
188; CHECK-O0: cmp r{{.*}}, #0
189; CHECK-O0: beq
190; CHECK-O0-DAG: movw r{{.*}}, #1
191; CHECK-O0-DAG: mov r{{.*}}, #16
192; CHECK-O0: malloc
193; CHECK-O0-DAG: mov [[ID:r[0-9]+]], r0
194; CHECK-O0-DAG: ldr [[ID2:r[0-9]+]], [sp{{.*}}]
195; CHECK-O0: strb [[ID2]], [{{.*}}[[ID]], #8]
196; spill r0
197; CHECK-O0: str r0, [sp{{.*}}]
198; CHECK-O0: vcmpe
199; CHECK-O0: ble
200; reload from stack
201; CHECK-O0: ldr r6
202entry:
203  br label %bb_loop
204
205bb_loop:
206  %cond = icmp ne i32 %cc, 0
207  br i1 %cond, label %gen_error, label %bb_cont
208
209gen_error:
210  %call = call i8* @malloc(i64 16)
211  %call.0 = bitcast i8* %call to %swift_error*
212  store %swift_error* %call.0, %swift_error** %error_ptr_ref
213  %tmp = getelementptr inbounds i8, i8* %call, i64 8
214  store i8 1, i8* %tmp
215  br label %bb_cont
216
217bb_cont:
218  %cmp = fcmp ogt float %cc2, 1.000000e+00
219  br i1 %cmp, label %bb_end, label %bb_loop
220bb_end:
221  ret float 0.0
222}
223
224; "foo_sret" is a function that takes a swifterror parameter, it also has a sret
225; parameter.
226define void @foo_sret(%struct.S* sret %agg.result, i32 %val1, %swift_error** swifterror %error_ptr_ref) {
227; CHECK-APPLE-LABEL: foo_sret:
228; CHECK-APPLE: mov [[SRET:r[0-9]+]], r0
229; CHECK-APPLE: mov r0, #16
230; CHECK-APPLE: malloc
231; CHECK-APPLE: mov [[REG:r[0-9]+]], #1
232; CHECK-APPLE-DAG: mov r6, r0
233; CHECK-APPLE-DAG: strb [[REG]], [r0, #8]
234; CHECK-APPLE-DAG: str r{{.*}}, [{{.*}}[[SRET]], #4]
235
236; CHECK-O0-LABEL: foo_sret:
237; CHECK-O0: mov r{{.*}}, #16
238; spill to stack: sret and val1
239; CHECK-O0-DAG: str r0
240; CHECK-O0-DAG: str r1
241; CHECK-O0: malloc
242; CHECK-O0: mov [[ID:r[0-9]+]], #1
243; CHECK-O0: strb [[ID]], [r0, #8]
244; reload from stack: sret and val1
245; CHECK-O0: ldr
246; CHECK-O0: ldr
247; CHECK-O0: str r{{.*}}, [{{.*}}, #4]
248; CHECK-O0: mov r6
249entry:
250  %call = call i8* @malloc(i64 16)
251  %call.0 = bitcast i8* %call to %swift_error*
252  store %swift_error* %call.0, %swift_error** %error_ptr_ref
253  %tmp = getelementptr inbounds i8, i8* %call, i64 8
254  store i8 1, i8* %tmp
255  %v2 = getelementptr inbounds %struct.S, %struct.S* %agg.result, i32 0, i32 1
256  store i32 %val1, i32* %v2
257  ret void
258}
259
260; "caller3" calls "foo_sret" that takes a swifterror parameter.
261define float @caller3(i8* %error_ref) {
262; CHECK-APPLE-LABEL: caller3:
263; CHECK-APPLE: mov [[ID:r[0-9]+]], r0
264; CHECK-APPLE: mov r6, #0
265; CHECK-APPLE: bl {{.*}}foo_sret
266; CHECK-APPLE: cmp r6, #0
267; Access part of the error object and save it to error_ref
268; CHECK-APPLE: ldrbeq [[CODE:r[0-9]+]], [r6, #8]
269; CHECK-APPLE: strbeq [[CODE]], [{{.*}}[[ID]]]
270; CHECK-APPLE: mov r0, r6
271; CHECK_APPLE: bl {{.*}}free
272
273; CHECK-O0-LABEL: caller3:
274; CHECK-O0-DAG: mov r6, #0
275; CHECK-O0-DAG: mov r0
276; CHECK-O0-DAG: mov r1
277; CHECK-O0: bl {{.*}}foo_sret
278; CHECK-O0: mov [[ID2:r[0-9]+]], r6
279; CHECK-O0: cmp [[ID2]]
280; CHECK-O0: bne
281; Access part of the error object and save it to error_ref
282; CHECK-O0: ldrb [[CODE:r[0-9]+]]
283; CHECK-O0: ldr [[ID:r[0-9]+]]
284; CHECK-O0: strb [[CODE]], [{{.*}}[[ID]]]
285; CHECK-O0: mov r0,
286; CHECK_O0: bl {{.*}}free
287entry:
288  %s = alloca %struct.S, align 8
289  %error_ptr_ref = alloca swifterror %swift_error*
290  store %swift_error* null, %swift_error** %error_ptr_ref
291  call void @foo_sret(%struct.S* sret %s, i32 1, %swift_error** swifterror %error_ptr_ref)
292  %error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref
293  %had_error_from_foo = icmp ne %swift_error* %error_from_foo, null
294  %tmp = bitcast %swift_error* %error_from_foo to i8*
295  br i1 %had_error_from_foo, label %handler, label %cont
296cont:
297  %v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1
298  %t = load i8, i8* %v1
299  store i8 %t, i8* %error_ref
300  br label %handler
301handler:
302  call void @free(i8* %tmp)
303  ret float 1.0
304}
305
306; "foo_vararg" is a function that takes a swifterror parameter, it also has
307; variable number of arguments.
308declare void @llvm.va_start(i8*) nounwind
309define float @foo_vararg(%swift_error** swifterror %error_ptr_ref, ...) {
310; CHECK-APPLE-LABEL: foo_vararg:
311; CHECK-APPLE: mov r0, #16
312; CHECK-APPLE: malloc
313; CHECK-APPLE: mov [[REG:r[0-9]+]], r0
314; CHECK-APPLE: mov [[ID:r[0-9]+]], #1
315; CHECK-APPLE-DAG: strb [[ID]], [{{.*}}[[REG]], #8]
316; CHECK-APPLE-DAG: mov r6, [[REG]]
317
318entry:
319  %call = call i8* @malloc(i64 16)
320  %call.0 = bitcast i8* %call to %swift_error*
321  store %swift_error* %call.0, %swift_error** %error_ptr_ref
322  %tmp = getelementptr inbounds i8, i8* %call, i64 8
323  store i8 1, i8* %tmp
324
325  %args = alloca i8*, align 8
326  %a10 = alloca i32, align 4
327  %a11 = alloca i32, align 4
328  %a12 = alloca i32, align 4
329  %v10 = bitcast i8** %args to i8*
330  call void @llvm.va_start(i8* %v10)
331  %v11 = va_arg i8** %args, i32
332  store i32 %v11, i32* %a10, align 4
333  %v12 = va_arg i8** %args, i32
334  store i32 %v12, i32* %a11, align 4
335  %v13 = va_arg i8** %args, i32
336  store i32 %v13, i32* %a12, align 4
337
338  ret float 1.0
339}
340
341; "caller4" calls "foo_vararg" that takes a swifterror parameter.
342define float @caller4(i8* %error_ref) {
343; CHECK-APPLE-LABEL: caller4:
344; CHECK-APPLE: mov [[ID:r[0-9]+]], r0
345; CHECK-APPLE: mov r6, #0
346; CHECK-APPLE: bl {{.*}}foo_vararg
347; CHECK-APPLE: cmp r6, #0
348; Access part of the error object and save it to error_ref
349; CHECK-APPLE: ldrbeq [[CODE:r[0-9]+]], [r6, #8]
350; CHECK-APPLE: strbeq [[CODE]], [{{.*}}[[ID]]]
351; CHECK-APPLE: mov r0, r6
352; CHECK_APPLE: bl {{.*}}free
353entry:
354  %error_ptr_ref = alloca swifterror %swift_error*
355  store %swift_error* null, %swift_error** %error_ptr_ref
356
357  %a10 = alloca i32, align 4
358  %a11 = alloca i32, align 4
359  %a12 = alloca i32, align 4
360  store i32 10, i32* %a10, align 4
361  store i32 11, i32* %a11, align 4
362  store i32 12, i32* %a12, align 4
363  %v10 = load i32, i32* %a10, align 4
364  %v11 = load i32, i32* %a11, align 4
365  %v12 = load i32, i32* %a12, align 4
366
367  %call = call float (%swift_error**, ...) @foo_vararg(%swift_error** swifterror %error_ptr_ref, i32 %v10, i32 %v11, i32 %v12)
368  %error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref
369  %had_error_from_foo = icmp ne %swift_error* %error_from_foo, null
370  %tmp = bitcast %swift_error* %error_from_foo to i8*
371  br i1 %had_error_from_foo, label %handler, label %cont
372
373cont:
374  %v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1
375  %t = load i8, i8* %v1
376  store i8 %t, i8* %error_ref
377  br label %handler
378handler:
379  call void @free(i8* %tmp)
380  ret float 1.0
381}
382