1; RUN: llc < %s -mtriple=s390x-linux-gnu -disable-block-placement | FileCheck %s
2; RUN: llc < %s -O0 -mtriple=s390x-linux-gnu -disable-block-placement | FileCheck --check-prefix=CHECK-O0 %s
3
4declare i8* @malloc(i64)
5declare void @free(i8*)
6%swift_error = type {i64, i8}
7
8; This tests the basic usage of a swifterror parameter. "foo" is the function
9; that takes a swifterror parameter and "caller" is the caller of "foo".
10define float @foo(%swift_error** swifterror %error_ptr_ref) {
11; CHECK-LABEL: foo:
12; CHECK: lghi %r2, 16
13; CHECK: brasl %r14, malloc
14; CHECK: mvi 8(%r2), 1
15; CHECK: lgr %r9, %r2
16; CHECK-O0-LABEL: foo:
17; CHECK-O0: lghi %r2, 16
18; CHECK-O0: brasl %r14, malloc
19; CHECK-O0: lgr [[T0:%r[0-9]+]], %r2
20; CHECK-O0: mvi 8(%r2), 1
21entry:
22  %call = call i8* @malloc(i64 16)
23  %call.0 = bitcast i8* %call to %swift_error*
24  store %swift_error* %call.0, %swift_error** %error_ptr_ref
25  %tmp = getelementptr inbounds i8, i8* %call, i64 8
26  store i8 1, i8* %tmp
27  ret float 1.0
28}
29
30; "caller" calls "foo" that takes a swifterror parameter.
31define float @caller(i8* %error_ref) {
32; CHECK-LABEL: caller:
33; Make a copy of error_ref because r2 is getting clobbered
34; CHECK: lgr %r[[REG1:[0-9]+]], %r2
35; CHECK: lghi %r9, 0
36; CHECK: brasl %r14, foo
37; CHECK: %r2, %r9
38; CHECK: jlh
39; Access part of the error object and save it to error_ref
40; CHECK: lb %r[[REG2:[0-9]+]], 8(%r2)
41; CHECK: stc %r[[REG2]], 0(%r[[REG1]])
42; CHECK: brasl %r14, free
43; CHECK-O0-LABEL: caller:
44; CHECK-O0: lghi %r9, 0
45; CHECK-O0: brasl %r14, foo
46; CHECK-O0: cghi %r9, 0
47; CHECK-O0: jlh
48entry:
49  %error_ptr_ref = alloca swifterror %swift_error*
50  store %swift_error* null, %swift_error** %error_ptr_ref
51  %call = call float @foo(%swift_error** swifterror %error_ptr_ref)
52  %error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref
53  %had_error_from_foo = icmp ne %swift_error* %error_from_foo, null
54  %tmp = bitcast %swift_error* %error_from_foo to i8*
55  br i1 %had_error_from_foo, label %handler, label %cont
56cont:
57  %v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1
58  %t = load i8, i8* %v1
59  store i8 %t, i8* %error_ref
60  br label %handler
61handler:
62  call void @free(i8* %tmp)
63  ret float 1.0
64}
65
66; "caller2" is the caller of "foo", it calls "foo" inside a loop.
67define float @caller2(i8* %error_ref) {
68; CHECK-LABEL: caller2:
69; Make a copy of error_ref because r2 is getting clobbered
70; CHECK: lgr %r[[REG1:[0-9]+]], %r2
71; CHECK: lghi %r9, 0
72; CHECK: brasl %r14, foo
73; CHECK: cgijlh %r9, 0,
74; CHECK: ceb %f0,
75; CHECK: jnh
76; Access part of the error object and save it to error_ref
77; CHECK: lb %r[[REG2:[0-9]+]], 8(%r9)
78; CHECK: stc %r[[REG2]], 0(%r[[REG1]])
79; CHECK: lgr %r2, %r9
80; CHECK: brasl %r14, free
81; CHECK-O0-LABEL: caller2:
82; CHECK-O0: lghi %r9, 0
83; CHECK-O0: brasl %r14, foo
84; CHECK-O0: cghi %r9, 0
85; CHECK-O0: jlh
86entry:
87  %error_ptr_ref = alloca swifterror %swift_error*
88  br label %bb_loop
89bb_loop:
90  store %swift_error* null, %swift_error** %error_ptr_ref
91  %call = call float @foo(%swift_error** swifterror %error_ptr_ref)
92  %error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref
93  %had_error_from_foo = icmp ne %swift_error* %error_from_foo, null
94  %tmp = bitcast %swift_error* %error_from_foo to i8*
95  br i1 %had_error_from_foo, label %handler, label %cont
96cont:
97  %cmp = fcmp ogt float %call, 1.000000e+00
98  br i1 %cmp, label %bb_end, label %bb_loop
99bb_end:
100  %v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1
101  %t = load i8, i8* %v1
102  store i8 %t, i8* %error_ref
103  br label %handler
104handler:
105  call void @free(i8* %tmp)
106  ret float 1.0
107}
108
109; "foo_if" is a function that takes a swifterror parameter, it sets swifterror
110; under a certain condition.
111define float @foo_if(%swift_error** swifterror %error_ptr_ref, i32 %cc) {
112; CHECK-LABEL: foo_if:
113; CHECK: cije %r2, 0
114; CHECK: lghi %r2, 16
115; CHECK: brasl %r14, malloc
116; CHECK: mvi 8(%r2), 1
117; CHECK: lgr %r9, %r2
118; CHECK-NOT: %r9
119; CHECK: br %r14
120; CHECK-O0-LABEL: foo_if:
121; spill to stack
122; CHECK-O0: stg %r9, [[OFFS:[0-9]+]](%r15)
123; CHECK-O0: chi %r2, 0
124; CHECK-O0: je
125; CHECK-O0: lghi %r2, 16
126; CHECK-O0: brasl %r14, malloc
127; CHECK-O0: lgr %r9, %r2
128; CHECK-O0: mvi 8(%r2), 1
129; CHECK-O0: br %r14
130; reload from stack
131; CHECK-O0: lg %r9, [[OFFS]](%r15)
132; CHECK-O0: br %r14
133entry:
134  %cond = icmp ne i32 %cc, 0
135  br i1 %cond, label %gen_error, label %normal
136
137gen_error:
138  %call = call i8* @malloc(i64 16)
139  %call.0 = bitcast i8* %call to %swift_error*
140  store %swift_error* %call.0, %swift_error** %error_ptr_ref
141  %tmp = getelementptr inbounds i8, i8* %call, i64 8
142  store i8 1, i8* %tmp
143  ret float 1.0
144
145normal:
146  ret float 0.0
147}
148
149; "foo_loop" is a function that takes a swifterror parameter, it sets swifterror
150; under a certain condition inside a loop.
151define float @foo_loop(%swift_error** swifterror %error_ptr_ref, i32 %cc, float %cc2) {
152; CHECK-LABEL: foo_loop:
153; CHECK: lr %r[[REG1:[0-9]+]], %r2
154; CHECK: cije %r[[REG1]], 0
155; CHECK: lghi %r2, 16
156; CHECK: brasl %r14, malloc
157; CHECK: mvi 8(%r2), 1
158; CHECK: ceb %f8,
159; CHECK: jnh
160; CHECK: lgr %r9, %r2
161; CHECK: br %r14
162; CHECK-O0-LABEL: foo_loop:
163; spill to stack
164; CHECK-O0: stg %r9, [[OFFS:[0-9]+]](%r15)
165; CHECK-O0: chi %r{{.*}}, 0
166; CHECK-O0: je
167; CHECK-O0: lghi %r2, 16
168; CHECK-O0: brasl %r14, malloc
169; CHECK-O0: lgr %r[[REG1:[0-9]+]], %r2
170; CHECK-O0: mvi 8(%r[[REG1]]), 1
171; CHECK-O0: jnh
172; reload from stack
173; CHECK-O0: lg %r9, [[OFFS:[0-9]+]](%r15)
174; CHECK-O0: br %r14
175entry:
176  br label %bb_loop
177
178bb_loop:
179  %cond = icmp ne i32 %cc, 0
180  br i1 %cond, label %gen_error, label %bb_cont
181
182gen_error:
183  %call = call i8* @malloc(i64 16)
184  %call.0 = bitcast i8* %call to %swift_error*
185  store %swift_error* %call.0, %swift_error** %error_ptr_ref
186  %tmp = getelementptr inbounds i8, i8* %call, i64 8
187  store i8 1, i8* %tmp
188  br label %bb_cont
189
190bb_cont:
191  %cmp = fcmp ogt float %cc2, 1.000000e+00
192  br i1 %cmp, label %bb_end, label %bb_loop
193bb_end:
194  ret float 0.0
195}
196
197%struct.S = type { i32, i32, i32, i32, i32, i32 }
198
199; "foo_sret" is a function that takes a swifterror parameter, it also has a sret
200; parameter.
201define void @foo_sret(%struct.S* sret(%struct.S) %agg.result, i32 %val1, %swift_error** swifterror %error_ptr_ref) {
202; CHECK-LABEL: foo_sret:
203; CHECK-DAG: lgr %r[[REG1:[0-9]+]], %r2
204; CHECK-DAG: lr %r[[REG2:[0-9]+]], %r3
205; CHECK: lghi %r2, 16
206; CHECK: brasl %r14, malloc
207; CHECK: mvi 8(%r2), 1
208; CHECK: st %r[[REG2]], 4(%r[[REG1]])
209; CHECK: lgr %r9, %r2
210; CHECK-NOT: %r9
211; CHECK: br %r14
212
213; CHECK-O0-LABEL: foo_sret:
214; spill sret to stack
215; CHECK-O0-DAG: stg %r2, [[OFFS1:[0-9]+]](%r15)
216; CHECK-O0-DAG: st %r3, [[OFFS2:[0-9]+]](%r15)
217; CHECK-O0: lghi %r2, 16
218; CHECK-O0: brasl %r14, malloc
219; CHECK-O0-DAG: lgr %r[[REG3:[0-9]+]], %r2
220; CHECK-O0-DAG: mvi 8(%r[[REG3]]), 1
221; CHECK-O0-DAG: lg %r[[REG1:[0-9]+]], [[OFFS1]](%r15)
222; CHECK-O0-DAG: lgr %r9, %r[[REG3]]
223; CHECK-O0-DAG: l %r[[REG2:[0-9]+]], [[OFFS2]](%r15)
224; CHECK-O0: st %r[[REG2]], 4(%r[[REG1]])
225; CHECK-O0: br %r14
226entry:
227  %call = call i8* @malloc(i64 16)
228  %call.0 = bitcast i8* %call to %swift_error*
229  store %swift_error* %call.0, %swift_error** %error_ptr_ref
230  %tmp = getelementptr inbounds i8, i8* %call, i64 8
231  store i8 1, i8* %tmp
232  %v2 = getelementptr inbounds %struct.S, %struct.S* %agg.result, i32 0, i32 1
233  store i32 %val1, i32* %v2
234  ret void
235}
236
237; "caller3" calls "foo_sret" that takes a swifterror parameter.
238define float @caller3(i8* %error_ref) {
239; CHECK-LABEL: caller3:
240; Make a copy of error_ref because r2 is getting clobbered
241; CHECK: lgr %r[[REG1:[0-9]+]], %r2
242; CHECK: lhi %r3, 1
243; CHECK: lghi %r9, 0
244; CHECK: brasl %r14, foo_sret
245; CHECK: jlh
246; Access part of the error object and save it to error_ref
247; CHECK: lb %r0, 8(%r2)
248; CHECK: stc %r0, 0(%r[[REG1]])
249; CHECK: brasl %r14, free
250
251; CHECK-O0-LABEL: caller3:
252; CHECK-O0: lghi %r9, 0
253; CHECK-O0: lhi %r3, 1
254; CHECK-O0: brasl %r14, foo_sret
255; CHECK-O0: lgr {{.*}}, %r9
256; CHECK-O0: cghi %r9, 0
257; CHECK-O0: jlh
258; Access part of the error object and save it to error_ref
259; CHECK-O0: lb %r0, 8(%r{{.*}})
260; CHECK-O0: stc %r0, 0(%r{{.*}})
261; reload from stack
262; CHECK-O0: lg %r2, {{.*}}(%r15)
263; CHECK-O0: brasl %r14, free
264entry:
265  %s = alloca %struct.S, align 8
266  %error_ptr_ref = alloca swifterror %swift_error*
267  store %swift_error* null, %swift_error** %error_ptr_ref
268  call void @foo_sret(%struct.S* sret(%struct.S) %s, i32 1, %swift_error** swifterror %error_ptr_ref)
269  %error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref
270  %had_error_from_foo = icmp ne %swift_error* %error_from_foo, null
271  %tmp = bitcast %swift_error* %error_from_foo to i8*
272  br i1 %had_error_from_foo, label %handler, label %cont
273cont:
274  %v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1
275  %t = load i8, i8* %v1
276  store i8 %t, i8* %error_ref
277  br label %handler
278handler:
279  call void @free(i8* %tmp)
280  ret float 1.0
281}
282
283; This is a caller with multiple swifterror values, it calls "foo" twice, each
284; time with a different swifterror value, from "alloca swifterror".
285define float @caller_with_multiple_swifterror_values(i8* %error_ref, i8* %error_ref2) {
286; CHECK-LABEL: caller_with_multiple_swifterror_values:
287; CHECK-DAG: lgr %r[[REG1:[0-9]+]], %r2
288; CHECK-DAG: lgr %r[[REG2:[0-9]+]], %r3
289; The first swifterror value:
290; CHECK: lghi %r9, 0
291; CHECK: brasl %r14, foo
292; CHECK: ltgr %r2, %r9
293; CHECK: jlh
294; Access part of the error object and save it to error_ref
295; CHECK: lb %r0, 8(%r2)
296; CHECK: stc %r0, 0(%r[[REG1]])
297; CHECK: brasl %r14, free
298
299; The second swifterror value:
300; CHECK: lghi %r9, 0
301; CHECK: brasl %r14, foo
302; CHECK: ltgr %r2, %r9
303; CHECK: jlh
304; Access part of the error object and save it to error_ref
305; CHECK: lb %r0, 8(%r2)
306; CHECK: stc %r0, 0(%r[[REG2]])
307; CHECK: brasl %r14, free
308
309; CHECK-O0-LABEL: caller_with_multiple_swifterror_values:
310
311; The first swifterror value:
312; CHECK-O0: lghi %r9, 0
313; CHECK-O0: brasl %r14, foo
314; CHECK-O0: jlh
315
316; The second swifterror value:
317; CHECK-O0: lghi %r9, 0
318; CHECK-O0: brasl %r14, foo
319; CHECK-O0: jlh
320entry:
321  %error_ptr_ref = alloca swifterror %swift_error*
322  store %swift_error* null, %swift_error** %error_ptr_ref
323  %call = call float @foo(%swift_error** swifterror %error_ptr_ref)
324  %error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref
325  %had_error_from_foo = icmp ne %swift_error* %error_from_foo, null
326  %tmp = bitcast %swift_error* %error_from_foo to i8*
327  br i1 %had_error_from_foo, label %handler, label %cont
328cont:
329  %v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1
330  %t = load i8, i8* %v1
331  store i8 %t, i8* %error_ref
332  br label %handler
333handler:
334  call void @free(i8* %tmp)
335
336  %error_ptr_ref2 = alloca swifterror %swift_error*
337  store %swift_error* null, %swift_error** %error_ptr_ref2
338  %call2 = call float @foo(%swift_error** swifterror %error_ptr_ref2)
339  %error_from_foo2 = load %swift_error*, %swift_error** %error_ptr_ref2
340  %had_error_from_foo2 = icmp ne %swift_error* %error_from_foo2, null
341  %bitcast2 = bitcast %swift_error* %error_from_foo2 to i8*
342  br i1 %had_error_from_foo2, label %handler2, label %cont2
343cont2:
344  %v2 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo2, i64 0, i32 1
345  %t2 = load i8, i8* %v2
346  store i8 %t2, i8* %error_ref2
347  br label %handler2
348handler2:
349  call void @free(i8* %bitcast2)
350
351  ret float 1.0
352}
353