1; Test that floating-point compares are omitted if CC already has the
2; right value.
3;
4; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z10 -no-integrated-as | FileCheck %s
5
6declare float @llvm.fabs.f32(float %f)
7
8; Test addition followed by EQ, which can use the CC result of the addition.
9define float @f1(float %a, float %b, float *%dest) {
10; CHECK-LABEL: f1:
11; CHECK: aebr %f0, %f2
12; CHECK-NEXT: je .L{{.*}}
13; CHECK: br %r14
14entry:
15  %res = fadd float %a, %b
16  %cmp = fcmp oeq float %res, 0.0
17  br i1 %cmp, label %exit, label %store
18
19store:
20  store float %b, float *%dest
21  br label %exit
22
23exit:
24  ret float %res
25}
26
27; ...and again with LT.
28define float @f2(float %a, float %b, float *%dest) {
29; CHECK-LABEL: f2:
30; CHECK: aebr %f0, %f2
31; CHECK-NEXT: jl .L{{.*}}
32; CHECK: br %r14
33entry:
34  %res = fadd float %a, %b
35  %cmp = fcmp olt float %res, 0.0
36  br i1 %cmp, label %exit, label %store
37
38store:
39  store float %b, float *%dest
40  br label %exit
41
42exit:
43  ret float %res
44}
45
46; ...and again with GT.
47define float @f3(float %a, float %b, float *%dest) {
48; CHECK-LABEL: f3:
49; CHECK: aebr %f0, %f2
50; CHECK-NEXT: jh .L{{.*}}
51; CHECK: br %r14
52entry:
53  %res = fadd float %a, %b
54  %cmp = fcmp ogt float %res, 0.0
55  br i1 %cmp, label %exit, label %store
56
57store:
58  store float %b, float *%dest
59  br label %exit
60
61exit:
62  ret float %res
63}
64
65; ...and again with UEQ.
66define float @f4(float %a, float %b, float *%dest) {
67; CHECK-LABEL: f4:
68; CHECK: aebr %f0, %f2
69; CHECK-NEXT: jnlh .L{{.*}}
70; CHECK: br %r14
71entry:
72  %res = fadd float %a, %b
73  %cmp = fcmp ueq float %res, 0.0
74  br i1 %cmp, label %exit, label %store
75
76store:
77  store float %b, float *%dest
78  br label %exit
79
80exit:
81  ret float %res
82}
83
84; Subtraction also provides a zero-based CC value.
85define float @f5(float %a, float %b, float *%dest) {
86; CHECK-LABEL: f5:
87; CHECK: seb %f0, 0(%r2)
88; CHECK-NEXT: jnhe .L{{.*}}
89; CHECK: br %r14
90entry:
91  %cur = load float , float *%dest
92  %res = fsub float %a, %cur
93  %cmp = fcmp ult float %res, 0.0
94  br i1 %cmp, label %exit, label %store
95
96store:
97  store float %b, float *%dest
98  br label %exit
99
100exit:
101  ret float %res
102}
103
104; Test the result of LOAD POSITIVE.
105define float @f6(float %dummy, float %a, float *%dest) {
106; CHECK-LABEL: f6:
107; CHECK: lpebr %f0, %f2
108; CHECK-NEXT: jh .L{{.*}}
109; CHECK: br %r14
110entry:
111  %res = call float @llvm.fabs.f32(float %a)
112  %cmp = fcmp ogt float %res, 0.0
113  br i1 %cmp, label %exit, label %store
114
115store:
116  store float %res, float *%dest
117  br label %exit
118
119exit:
120  ret float %res
121}
122
123; Test the result of LOAD NEGATIVE.
124define float @f7(float %dummy, float %a, float *%dest) {
125; CHECK-LABEL: f7:
126; CHECK: lnebr %f0, %f2
127; CHECK-NEXT: jl .L{{.*}}
128; CHECK: br %r14
129entry:
130  %abs = call float @llvm.fabs.f32(float %a)
131  %res = fsub float -0.0, %abs
132  %cmp = fcmp olt float %res, 0.0
133  br i1 %cmp, label %exit, label %store
134
135store:
136  store float %res, float *%dest
137  br label %exit
138
139exit:
140  ret float %res
141}
142
143; Test the result of LOAD COMPLEMENT.
144define float @f8(float %dummy, float %a, float *%dest) {
145; CHECK-LABEL: f8:
146; CHECK: lcebr %f0, %f2
147; CHECK-NEXT: jle .L{{.*}}
148; CHECK: br %r14
149entry:
150  %res = fsub float -0.0, %a
151  %cmp = fcmp ole float %res, 0.0
152  br i1 %cmp, label %exit, label %store
153
154store:
155  store float %res, float *%dest
156  br label %exit
157
158exit:
159  ret float %res
160}
161
162; Multiplication (for example) does not modify CC.
163define float @f9(float %a, float %b, float *%dest) {
164; CHECK-LABEL: f9:
165; CHECK: meebr %f0, %f2
166; CHECK-NEXT: ltebr %f0, %f0
167; CHECK-NEXT: jlh .L{{.*}}
168; CHECK: br %r14
169entry:
170  %res = fmul float %a, %b
171  %cmp = fcmp one float %res, 0.0
172  br i1 %cmp, label %exit, label %store
173
174store:
175  store float %b, float *%dest
176  br label %exit
177
178exit:
179  ret float %res
180}
181
182; Test a combination involving a CC-setting instruction followed by
183; a non-CC-setting instruction.
184define float @f10(float %a, float %b, float %c, float *%dest) {
185; CHECK-LABEL: f10:
186; CHECK: aebr %f0, %f2
187; CHECK-NEXT: debr %f0, %f4
188; CHECK-NEXT: ltebr %f0, %f0
189; CHECK-NEXT: jne .L{{.*}}
190; CHECK: br %r14
191entry:
192  %add = fadd float %a, %b
193  %res = fdiv float %add, %c
194  %cmp = fcmp une float %res, 0.0
195  br i1 %cmp, label %exit, label %store
196
197store:
198  store float %b, float *%dest
199  br label %exit
200
201exit:
202  ret float %res
203}
204
205; Test a case where CC is set based on a different register from the
206; compare input.
207define float @f11(float %a, float %b, float %c, float *%dest1, float *%dest2) {
208; CHECK-LABEL: f11:
209; CHECK: aebr %f0, %f2
210; CHECK-NEXT: sebr %f4, %f0
211; CHECK-NEXT: ste %f4, 0(%r2)
212; CHECK-NEXT: ltebr %f0, %f0
213; CHECK-NEXT: je .L{{.*}}
214; CHECK: br %r14
215entry:
216  %add = fadd float %a, %b
217  %sub = fsub float %c, %add
218  store float %sub, float *%dest1
219  %cmp = fcmp oeq float %add, 0.0
220  br i1 %cmp, label %exit, label %store
221
222store:
223  store float %sub, float *%dest2
224  br label %exit
225
226exit:
227  ret float %add
228}
229
230; Test that LER gets converted to LTEBR where useful.
231define float @f12(float %dummy, float %val, float *%dest) {
232; CHECK-LABEL: f12:
233; CHECK: ltebr %f0, %f2
234; CHECK-NEXT: #APP
235; CHECK-NEXT: blah %f0
236; CHECK-NEXT: #NO_APP
237; CHECK-NEXT: jl .L{{.*}}
238; CHECK: br %r14
239entry:
240  call void asm sideeffect "blah $0", "{f0}"(float %val)
241  %cmp = fcmp olt float %val, 0.0
242  br i1 %cmp, label %exit, label %store
243
244store:
245  store float %val, float *%dest
246  br label %exit
247
248exit:
249  ret float %val
250}
251
252; Test that LDR gets converted to LTDBR where useful.
253define double @f13(double %dummy, double %val, double *%dest) {
254; CHECK-LABEL: f13:
255; CHECK: ltdbr %f0, %f2
256; CHECK-NEXT: #APP
257; CHECK-NEXT: blah %f0
258; CHECK-NEXT: #NO_APP
259; CHECK-NEXT: jl .L{{.*}}
260; CHECK: br %r14
261entry:
262  call void asm sideeffect "blah $0", "{f0}"(double %val)
263  %cmp = fcmp olt double %val, 0.0
264  br i1 %cmp, label %exit, label %store
265
266store:
267  store double %val, double *%dest
268  br label %exit
269
270exit:
271  ret double %val
272}
273
274; Test that LXR gets converted to LTXBR where useful.
275define void @f14(fp128 *%ptr1, fp128 *%ptr2) {
276; CHECK-LABEL: f14:
277; CHECK: ltxbr
278; CHECK-NEXT: dxbr
279; CHECK-NEXT: std
280; CHECK-NEXT: std
281; CHECK-NEXT: mxbr
282; CHECK-NEXT: std
283; CHECK-NEXT: std
284; CHECK-NEXT: jl .L{{.*}}
285; CHECK: br %r14
286entry:
287  %val1 = load fp128 , fp128 *%ptr1
288  %val2 = load fp128 , fp128 *%ptr2
289  %div = fdiv fp128 %val1, %val2
290  store fp128 %div, fp128 *%ptr1
291  %mul = fmul fp128 %val1, %val2
292  store fp128 %mul, fp128 *%ptr2
293  %cmp = fcmp olt fp128 %val1, 0xL00000000000000000000000000000000
294  br i1 %cmp, label %exit, label %store
295
296store:
297  call void asm sideeffect "blah", ""()
298  br label %exit
299
300exit:
301  ret void
302}
303
304; Test a case where it is the source rather than destination of LER that
305; we need.
306define float @f15(float %val, float %dummy, float *%dest) {
307; CHECK-LABEL: f15:
308; CHECK: ltebr %f2, %f0
309; CHECK-NEXT: #APP
310; CHECK-NEXT: blah %f2
311; CHECK-NEXT: #NO_APP
312; CHECK-NEXT: jl .L{{.*}}
313; CHECK: br %r14
314entry:
315  call void asm sideeffect "blah $0", "{f2}"(float %val)
316  %cmp = fcmp olt float %val, 0.0
317  br i1 %cmp, label %exit, label %store
318
319store:
320  store float %val, float *%dest
321  br label %exit
322
323exit:
324  ret float %val
325}
326
327; Test a case where it is the source rather than destination of LDR that
328; we need.
329define double @f16(double %val, double %dummy, double *%dest) {
330; CHECK-LABEL: f16:
331; CHECK: ltdbr %f2, %f0
332; CHECK-NEXT: #APP
333; CHECK-NEXT: blah %f2
334; CHECK-NEXT: #NO_APP
335; CHECK-NEXT: jl .L{{.*}}
336; CHECK: br %r14
337entry:
338  call void asm sideeffect "blah $0", "{f2}"(double %val)
339  %cmp = fcmp olt double %val, 0.0
340  br i1 %cmp, label %exit, label %store
341
342store:
343  store double %val, double *%dest
344  br label %exit
345
346exit:
347  ret double %val
348}
349
350; Repeat f2 with a comparison against -0.
351define float @f17(float %a, float %b, float *%dest) {
352; CHECK-LABEL: f17:
353; CHECK: aebr %f0, %f2
354; CHECK-NEXT: jl .L{{.*}}
355; CHECK: br %r14
356entry:
357  %res = fadd float %a, %b
358  %cmp = fcmp olt float %res, -0.0
359  br i1 %cmp, label %exit, label %store
360
361store:
362  store float %b, float *%dest
363  br label %exit
364
365exit:
366  ret float %res
367}
368
369; Test another form of f7 in which the condition is based on the unnegated
370; result.  This is what InstCombine would produce.
371define float @f18(float %dummy, float %a, float *%dest) {
372; CHECK-LABEL: f18:
373; CHECK: lnebr %f0, %f2
374; CHECK-NEXT: jl .L{{.*}}
375; CHECK: br %r14
376entry:
377  %abs = call float @llvm.fabs.f32(float %a)
378  %res = fsub float -0.0, %abs
379  %cmp = fcmp ogt float %abs, 0.0
380  br i1 %cmp, label %exit, label %store
381
382store:
383  store float %res, float *%dest
384  br label %exit
385
386exit:
387  ret float %res
388}
389
390; Similarly for f8.
391define float @f19(float %dummy, float %a, float *%dest) {
392; CHECK-LABEL: f19:
393; CHECK: lcebr %f0, %f2
394; CHECK-NEXT: jle .L{{.*}}
395; CHECK: br %r14
396entry:
397  %res = fsub float -0.0, %a
398  %cmp = fcmp oge float %a, 0.0
399  br i1 %cmp, label %exit, label %store
400
401store:
402  store float %res, float *%dest
403  br label %exit
404
405exit:
406  ret float %res
407}
408