xref: /llvm-project/llvm/test/CodeGen/SystemZ/fp-strict-cmp-04.ll (revision 1d1893097a6319a6402331a54a588b1a5d961808)
1; Test that floating-point strict compares are omitted if CC already has the
2; right value.
3;
4; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z10 \
5; RUN:   -enable-misched=0 -no-integrated-as | FileCheck %s
6;
7; We need -enable-misched=0 to make sure f12 and following routines really
8; test the compare elimination pass.
9
10
11declare float @llvm.fabs.f32(float %f)
12
13; Test addition followed by EQ, which can use the CC result of the addition.
14define float @f1(float %a, float %b, ptr %dest) #0 {
15; CHECK-LABEL: f1:
16; CHECK: aebr %f0, %f2
17; CHECK-NEXT: ber %r14
18; CHECK: br %r14
19entry:
20  %res = call float @llvm.experimental.constrained.fadd.f32(
21                        float %a, float %b,
22                        metadata !"round.dynamic",
23                        metadata !"fpexcept.strict") #0
24  %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(
25                                               float %res, float 0.0,
26                                               metadata !"oeq",
27                                               metadata !"fpexcept.strict") #0
28  br i1 %cmp, label %exit, label %store
29
30store:
31  store float %b, ptr %dest
32  br label %exit
33
34exit:
35  ret float %res
36}
37
38; ...and again with LT.
39define float @f2(float %a, float %b, ptr %dest) #0 {
40; CHECK-LABEL: f2:
41; CHECK: aebr %f0, %f2
42; CHECK-NEXT: blr %r14
43; CHECK: br %r14
44entry:
45  %res = call float @llvm.experimental.constrained.fadd.f32(
46                        float %a, float %b,
47                        metadata !"round.dynamic",
48                        metadata !"fpexcept.strict") #0
49  %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(
50                                               float %res, float 0.0,
51                                               metadata !"olt",
52                                               metadata !"fpexcept.strict") #0
53  br i1 %cmp, label %exit, label %store
54
55store:
56  store float %b, ptr %dest
57  br label %exit
58
59exit:
60  ret float %res
61}
62
63; ...and again with GT.
64define float @f3(float %a, float %b, ptr %dest) #0 {
65; CHECK-LABEL: f3:
66; CHECK: aebr %f0, %f2
67; CHECK-NEXT: bhr %r14
68; CHECK: br %r14
69entry:
70  %res = call float @llvm.experimental.constrained.fadd.f32(
71                        float %a, float %b,
72                        metadata !"round.dynamic",
73                        metadata !"fpexcept.strict") #0
74  %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(
75                                               float %res, float 0.0,
76                                               metadata !"ogt",
77                                               metadata !"fpexcept.strict") #0
78  br i1 %cmp, label %exit, label %store
79
80store:
81  store float %b, ptr %dest
82  br label %exit
83
84exit:
85  ret float %res
86}
87
88; ...and again with UEQ.
89define float @f4(float %a, float %b, ptr %dest) #0 {
90; CHECK-LABEL: f4:
91; CHECK: aebr %f0, %f2
92; CHECK-NEXT: bnlhr %r14
93; CHECK: br %r14
94entry:
95  %res = call float @llvm.experimental.constrained.fadd.f32(
96                        float %a, float %b,
97                        metadata !"round.dynamic",
98                        metadata !"fpexcept.strict") #0
99  %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(
100                                               float %res, float 0.0,
101                                               metadata !"ueq",
102                                               metadata !"fpexcept.strict") #0
103  br i1 %cmp, label %exit, label %store
104
105store:
106  store float %b, ptr %dest
107  br label %exit
108
109exit:
110  ret float %res
111}
112
113; Subtraction also provides a zero-based CC value.
114define float @f5(float %a, float %b, ptr %dest) #0 {
115; CHECK-LABEL: f5:
116; CHECK: seb %f0, 0(%r2)
117; CHECK-NEXT: bnher %r14
118; CHECK: br %r14
119entry:
120  %cur = load float, ptr %dest
121  %res = call float @llvm.experimental.constrained.fsub.f32(
122                        float %a, float %cur,
123                        metadata !"round.dynamic",
124                        metadata !"fpexcept.strict") #0
125  %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(
126                                               float %res, float 0.0,
127                                               metadata !"ult",
128                                               metadata !"fpexcept.strict") #0
129  br i1 %cmp, label %exit, label %store
130
131store:
132  store float %b, ptr %dest
133  br label %exit
134
135exit:
136  ret float %res
137}
138
139; Test the result of LOAD POSITIVE.  We cannot omit the LTEBR.
140define float @f6(float %dummy, float %a, ptr %dest) #0 {
141; CHECK-LABEL: f6:
142; CHECK: lpdfr %f0, %f2
143; CHECK-NEXT: ltebr %f1, %f0
144; CHECK-NEXT: bhr %r14
145; CHECK: br %r14
146entry:
147  %res = call float @llvm.fabs.f32(float %a) #0
148  %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(
149                                               float %res, float 0.0,
150                                               metadata !"ogt",
151                                               metadata !"fpexcept.strict") #0
152  br i1 %cmp, label %exit, label %store
153
154store:
155  store float %res, ptr %dest
156  br label %exit
157
158exit:
159  ret float %res
160}
161
162; Test the result of LOAD NEGATIVE.  We cannot omit the LTEBR.
163define float @f7(float %dummy, float %a, ptr %dest) #0 {
164; CHECK-LABEL: f7:
165; CHECK: lndfr %f0, %f2
166; CHECK-NEXT: ltebr %f1, %f0
167; CHECK-NEXT: blr %r14
168; CHECK: br %r14
169entry:
170  %abs = call float @llvm.fabs.f32(float %a) #0
171  %res = fneg float %abs
172  %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(
173                                               float %res, float 0.0,
174                                               metadata !"olt",
175                                               metadata !"fpexcept.strict") #0
176  br i1 %cmp, label %exit, label %store
177
178store:
179  store float %res, ptr %dest
180  br label %exit
181
182exit:
183  ret float %res
184}
185
186; Test the result of LOAD COMPLEMENT.  We cannot omit the LTEBR.
187define float @f8(float %dummy, float %a, ptr %dest) #0 {
188; CHECK-LABEL: f8:
189; CHECK: lcdfr %f0, %f2
190; CHECK-NEXT: ltebr %f1, %f0
191; CHECK-NEXT: bler %r14
192; CHECK: br %r14
193entry:
194  %res = fneg float %a
195  %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(
196                                               float %res, float 0.0,
197                                               metadata !"ole",
198                                               metadata !"fpexcept.strict") #0
199  br i1 %cmp, label %exit, label %store
200
201store:
202  store float %res, ptr %dest
203  br label %exit
204
205exit:
206  ret float %res
207}
208
209; Multiplication (for example) does not modify CC.
210define float @f9(float %a, float %b, ptr %dest) #0 {
211; CHECK-LABEL: f9:
212; CHECK: meebr %f0, %f2
213; CHECK-NEXT: ltebr %f1, %f0
214; CHECK-NEXT: blhr %r14
215; CHECK: br %r14
216entry:
217  %res = call float @llvm.experimental.constrained.fmul.f32(
218                        float %a, float %b,
219                        metadata !"round.dynamic",
220                        metadata !"fpexcept.strict") #0
221  %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(
222                                               float %res, float 0.0,
223                                               metadata !"one",
224                                               metadata !"fpexcept.strict") #0
225  br i1 %cmp, label %exit, label %store
226
227store:
228  store float %b, ptr %dest
229  br label %exit
230
231exit:
232  ret float %res
233}
234
235; Test a combination involving a CC-setting instruction followed by
236; a non-CC-setting instruction.
237define float @f10(float %a, float %b, float %c, ptr %dest) #0 {
238; CHECK-LABEL: f10:
239; CHECK: aebr %f0, %f2
240; CHECK-NEXT: debr %f0, %f4
241; CHECK-NEXT: ltebr %f1, %f0
242; CHECK-NEXT: bner %r14
243; CHECK: br %r14
244entry:
245  %add = call float @llvm.experimental.constrained.fadd.f32(
246                        float %a, float %b,
247                        metadata !"round.dynamic",
248                        metadata !"fpexcept.strict") #0
249  %res = call float @llvm.experimental.constrained.fdiv.f32(
250                        float %add, float %c,
251                        metadata !"round.dynamic",
252                        metadata !"fpexcept.strict") #0
253  %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(
254                                               float %res, float 0.0,
255                                               metadata !"une",
256                                               metadata !"fpexcept.strict") #0
257  br i1 %cmp, label %exit, label %store
258
259store:
260  store float %b, ptr %dest
261  br label %exit
262
263exit:
264  ret float %res
265}
266
267; Test a case where CC is set based on a different register from the
268; compare input.
269define float @f11(float %a, float %b, float %c, ptr %dest1, ptr %dest2) #0 {
270; CHECK-LABEL: f11:
271; CHECK: aebr %f0, %f2
272; CHECK-NEXT: sebr %f4, %f0
273; CHECK-DAG: ste %f4, 0(%r2)
274; CHECK-DAG: ltebr %f1, %f0
275; CHECK-NEXT: ber %r14
276; CHECK: br %r14
277entry:
278  %add = call float @llvm.experimental.constrained.fadd.f32(
279                        float %a, float %b,
280                        metadata !"round.dynamic",
281                        metadata !"fpexcept.strict") #0
282  %sub = call float @llvm.experimental.constrained.fsub.f32(
283                        float %c, float %add,
284                        metadata !"round.dynamic",
285                        metadata !"fpexcept.strict") #0
286  store float %sub, ptr %dest1
287  %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(
288                                               float %add, float 0.0,
289                                               metadata !"oeq",
290                                               metadata !"fpexcept.strict") #0
291  br i1 %cmp, label %exit, label %store
292
293store:
294  store float %sub, ptr %dest2
295  br label %exit
296
297exit:
298  ret float %add
299}
300
301; Test that LER does not get converted to LTEBR as %f0 is live after it.
302define float @f12(float %dummy, float %val) #0 {
303; CHECK-LABEL: f12:
304; CHECK: ler %f0, %f2
305; CHECK-NEXT: #APP
306; CHECK-NEXT: blah %f0
307; CHECK-NEXT: #NO_APP
308; CHECK-NEXT: ltebr %f1, %f2
309; CHECK-NEXT: blr %r14
310; CHECK: br %r14
311entry:
312  %ret = call float asm "blah $1", "=f,{f0}"(float %val) #0
313  %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(
314                                               float %val, float 0.0,
315                                               metadata !"olt",
316                                               metadata !"fpexcept.strict") #0
317  br i1 %cmp, label %exit, label %store
318
319store:
320  call void asm sideeffect "blah", ""() #0
321  br label %exit
322
323exit:
324  ret float %ret
325}
326
327; Test that LDR does not get converted to LTDBR as %f0 is live after it.
328define double @f13(double %dummy, double %val) #0 {
329; CHECK-LABEL: f13:
330; CHECK: ldr %f0, %f2
331; CHECK-NEXT: #APP
332; CHECK-NEXT: blah %f0
333; CHECK-NEXT: #NO_APP
334; CHECK-NEXT: ltdbr %f1, %f2
335; CHECK-NEXT: blr %r14
336; CHECK: br %r14
337entry:
338  %ret = call double asm "blah $1", "=f,{f0}"(double %val) #0
339  %cmp = call i1 @llvm.experimental.constrained.fcmp.f64(
340                                               double %val, double 0.0,
341                                               metadata !"olt",
342                                               metadata !"fpexcept.strict") #0
343  br i1 %cmp, label %exit, label %store
344
345store:
346  call void asm sideeffect "blah", ""() #0
347  br label %exit
348
349exit:
350  ret double %ret
351}
352
353; Test that LXR does not get converted to LTXBR as %f4 is live after it.
354define void @f14(ptr %ptr1, ptr %ptr2) #0 {
355; CHECK-LABEL: f14:
356; CHECK: lxr
357; CHECK-NEXT: dxbr
358; CHECK-NEXT: std
359; CHECK-NEXT: std
360; CHECK-NEXT: mxbr
361; CHECK-NEXT: std
362; CHECK-NEXT: std
363; CHECK-NEXT: ltxbr
364; CHECK-NEXT: blr %r14
365; CHECK: br %r14
366entry:
367  %val1 = load fp128, ptr %ptr1
368  %val2 = load fp128, ptr %ptr2
369  %div = fdiv fp128 %val1, %val2
370  store fp128 %div, ptr %ptr1
371  %mul = fmul fp128 %val1, %val2
372  store fp128 %mul, ptr %ptr2
373  %cmp = call i1 @llvm.experimental.constrained.fcmp.f128(
374                                               fp128 %val1, fp128 0xL00000000000000000000000000000000,
375                                               metadata !"olt",
376                                               metadata !"fpexcept.strict") #0
377  br i1 %cmp, label %exit, label %store
378
379store:
380  call void asm sideeffect "blah", ""() #0
381  br label %exit
382
383exit:
384  ret void
385}
386
387; Test a case where it is the source rather than destination of LER that
388; we need, but cannot convert the LER.
389define float @f15(float %val, float %dummy) #0 {
390; CHECK-LABEL: f15:
391; CHECK: ler %f2, %f0
392; CHECK-NEXT: #APP
393; CHECK-NEXT: blah %f2
394; CHECK-NEXT: #NO_APP
395; CHECK-NEXT: ltebr %f1, %f2
396; CHECK-NEXT: blr %r14
397; CHECK: br %r14
398entry:
399  %ret = call float asm "blah $1", "=f,{f2}"(float %val) #0
400  %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(
401                                               float %val, float 0.0,
402                                               metadata !"olt",
403                                               metadata !"fpexcept.strict") #0
404  br i1 %cmp, label %exit, label %store
405
406store:
407  call void asm sideeffect "blah", ""() #0
408  br label %exit
409
410exit:
411  ret float %ret
412}
413
414; Test a case where it is the source rather than destination of LDR that
415; we need, but cannot convert the LDR.
416define double @f16(double %val, double %dummy) #0 {
417; CHECK-LABEL: f16:
418; CHECK: ldr %f2, %f0
419; CHECK-NEXT: #APP
420; CHECK-NEXT: blah %f2
421; CHECK-NEXT: #NO_APP
422; CHECK-NEXT: ltdbr %f1, %f2
423; CHECK-NEXT: blr %r14
424; CHECK: br %r14
425entry:
426  %ret = call double asm "blah $1", "=f,{f2}"(double %val) #0
427  %cmp = call i1 @llvm.experimental.constrained.fcmp.f64(
428                                               double %val, double 0.0,
429                                               metadata !"olt",
430                                               metadata !"fpexcept.strict") #0
431  br i1 %cmp, label %exit, label %store
432
433store:
434  call void asm sideeffect "blah", ""() #0
435  br label %exit
436
437exit:
438  ret double %ret
439}
440
441; Repeat f2 with a comparison against -0.
442define float @f17(float %a, float %b, ptr %dest) #0 {
443; CHECK-LABEL: f17:
444; CHECK: aebr %f0, %f2
445; CHECK-NEXT: blr %r14
446; CHECK: br %r14
447entry:
448  %res = call float @llvm.experimental.constrained.fadd.f32(
449                        float %a, float %b,
450                        metadata !"round.dynamic",
451                        metadata !"fpexcept.strict") #0
452  %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(
453                                               float %res, float -0.0,
454                                               metadata !"olt",
455                                               metadata !"fpexcept.strict") #0
456  br i1 %cmp, label %exit, label %store
457
458store:
459  store float %b, ptr %dest
460  br label %exit
461
462exit:
463  ret float %res
464}
465
466; Verify that we cannot omit the compare if there may be an intervening
467; change to the exception flags.
468define float @f18(float %a, float %b, ptr %dest) #0 {
469; CHECK-LABEL: f18:
470; CHECK: aebr %f0, %f2
471; CHECK: ltebr %f1, %f0
472; CHECK-NEXT: ber %r14
473; CHECK: br %r14
474entry:
475  %res = call float @llvm.experimental.constrained.fadd.f32(
476                        float %a, float %b,
477                        metadata !"round.dynamic",
478                        metadata !"fpexcept.strict") #0
479  call void asm sideeffect "blah", ""() #0
480  %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(
481                                               float %res, float 0.0,
482                                               metadata !"oeq",
483                                               metadata !"fpexcept.strict") #0
484  br i1 %cmp, label %exit, label %store
485
486store:
487  store float %b, ptr %dest
488  br label %exit
489
490exit:
491  ret float %res
492}
493
494; Verify that we cannot convert LER to LTEBR and omit the compare if
495; there may be an intervening change to the exception flags.
496define float @f19(float %dummy, float %val) #0 {
497; CHECK-LABEL: f19:
498; CHECK: ler %f0, %f2
499; CHECK-NEXT: #APP
500; CHECK-NEXT: blah %f0
501; CHECK-NEXT: #NO_APP
502; CHECK-NEXT: ltebr %f1, %f2
503; CHECK-NEXT: blr %r14
504; CHECK: br %r14
505entry:
506  %ret = call float asm sideeffect "blah $1", "=f,{f0}"(float %val) #0
507  %cmp = call i1 @llvm.experimental.constrained.fcmp.f32(
508                                               float %val, float 0.0,
509                                               metadata !"olt",
510                                               metadata !"fpexcept.strict") #0
511  br i1 %cmp, label %exit, label %store
512
513store:
514  call void asm sideeffect "blah", ""() #0
515  br label %exit
516
517exit:
518  ret float %ret
519}
520
521attributes #0 = { strictfp }
522
523declare float @llvm.experimental.constrained.fadd.f32(float, float, metadata, metadata)
524declare float @llvm.experimental.constrained.fsub.f32(float, float, metadata, metadata)
525declare float @llvm.experimental.constrained.fmul.f32(float, float, metadata, metadata)
526declare float @llvm.experimental.constrained.fdiv.f32(float, float, metadata, metadata)
527declare i1 @llvm.experimental.constrained.fcmp.f32(float, float, metadata, metadata)
528declare i1 @llvm.experimental.constrained.fcmp.f64(double, double, metadata, metadata)
529declare i1 @llvm.experimental.constrained.fcmp.f128(fp128, fp128, metadata, metadata)
530