1; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z10 \
2; RUN:   | FileCheck -check-prefix=CHECK -check-prefix=CHECK-SCALAR %s
3; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z13 \
4; RUN:   | FileCheck -check-prefix=CHECK -check-prefix=CHECK-VECTOR %s
5
6declare double @llvm.experimental.constrained.fma.f64(double %f1, double %f2, double %f3, metadata, metadata)
7
8define double @f1(double %f1, double %f2, double %acc) #0 {
9; CHECK-LABEL: f1:
10; CHECK-SCALAR: msdbr %f4, %f0, %f2
11; CHECK-SCALAR: ldr %f0, %f4
12; CHECK-VECTOR: wfmsdb %f0, %f0, %f2, %f4
13; CHECK: br %r14
14  %negacc = fneg double %acc
15  %res = call double @llvm.experimental.constrained.fma.f64 (
16                        double %f1, double %f2, double %negacc,
17                        metadata !"round.dynamic",
18                        metadata !"fpexcept.strict") #0
19  ret double %res
20}
21
22define double @f2(double %f1, double *%ptr, double %acc) #0 {
23; CHECK-LABEL: f2:
24; CHECK: msdb %f2, %f0, 0(%r2)
25; CHECK: ldr %f0, %f2
26; CHECK: br %r14
27  %f2 = load double, double *%ptr
28  %negacc = fneg double %acc
29  %res = call double @llvm.experimental.constrained.fma.f64 (
30                        double %f1, double %f2, double %negacc,
31                        metadata !"round.dynamic",
32                        metadata !"fpexcept.strict") #0
33  ret double %res
34}
35
36define double @f3(double %f1, double *%base, double %acc) #0 {
37; CHECK-LABEL: f3:
38; CHECK: msdb %f2, %f0, 4088(%r2)
39; CHECK: ldr %f0, %f2
40; CHECK: br %r14
41  %ptr = getelementptr double, double *%base, i64 511
42  %f2 = load double, double *%ptr
43  %negacc = fneg double %acc
44  %res = call double @llvm.experimental.constrained.fma.f64 (
45                        double %f1, double %f2, double %negacc,
46                        metadata !"round.dynamic",
47                        metadata !"fpexcept.strict") #0
48  ret double %res
49}
50
51define double @f4(double %f1, double *%base, double %acc) #0 {
52; The important thing here is that we don't generate an out-of-range
53; displacement.  Other sequences besides this one would be OK.
54;
55; CHECK-LABEL: f4:
56; CHECK: aghi %r2, 4096
57; CHECK: msdb %f2, %f0, 0(%r2)
58; CHECK: ldr %f0, %f2
59; CHECK: br %r14
60  %ptr = getelementptr double, double *%base, i64 512
61  %f2 = load double, double *%ptr
62  %negacc = fneg double %acc
63  %res = call double @llvm.experimental.constrained.fma.f64 (
64                        double %f1, double %f2, double %negacc,
65                        metadata !"round.dynamic",
66                        metadata !"fpexcept.strict") #0
67  ret double %res
68}
69
70define double @f5(double %f1, double *%base, double %acc) #0 {
71; Here too the important thing is that we don't generate an out-of-range
72; displacement.  Other sequences besides this one would be OK.
73;
74; CHECK-LABEL: f5:
75; CHECK: aghi %r2, -8
76; CHECK: msdb %f2, %f0, 0(%r2)
77; CHECK: ldr %f0, %f2
78; CHECK: br %r14
79  %ptr = getelementptr double, double *%base, i64 -1
80  %f2 = load double, double *%ptr
81  %negacc = fneg double %acc
82  %res = call double @llvm.experimental.constrained.fma.f64 (
83                        double %f1, double %f2, double %negacc,
84                        metadata !"round.dynamic",
85                        metadata !"fpexcept.strict") #0
86  ret double %res
87}
88
89define double @f6(double %f1, double *%base, i64 %index, double %acc) #0 {
90; CHECK-LABEL: f6:
91; CHECK: sllg %r1, %r3, 3
92; CHECK: msdb %f2, %f0, 0(%r1,%r2)
93; CHECK: ldr %f0, %f2
94; CHECK: br %r14
95  %ptr = getelementptr double, double *%base, i64 %index
96  %f2 = load double, double *%ptr
97  %negacc = fneg double %acc
98  %res = call double @llvm.experimental.constrained.fma.f64 (
99                        double %f1, double %f2, double %negacc,
100                        metadata !"round.dynamic",
101                        metadata !"fpexcept.strict") #0
102  ret double %res
103}
104
105define double @f7(double %f1, double *%base, i64 %index, double %acc) #0 {
106; CHECK-LABEL: f7:
107; CHECK: sllg %r1, %r3, 3
108; CHECK: msdb %f2, %f0, 4088({{%r1,%r2|%r2,%r1}})
109; CHECK: ldr %f0, %f2
110; CHECK: br %r14
111  %index2 = add i64 %index, 511
112  %ptr = getelementptr double, double *%base, i64 %index2
113  %f2 = load double, double *%ptr
114  %negacc = fneg double %acc
115  %res = call double @llvm.experimental.constrained.fma.f64 (
116                        double %f1, double %f2, double %negacc,
117                        metadata !"round.dynamic",
118                        metadata !"fpexcept.strict") #0
119  ret double %res
120}
121
122define double @f8(double %f1, double *%base, i64 %index, double %acc) #0 {
123; CHECK-LABEL: f8:
124; CHECK: sllg %r1, %r3, 3
125; CHECK: lay %r1, 4096({{%r1,%r2|%r2,%r1}})
126; CHECK: msdb %f2, %f0, 0(%r1)
127; CHECK: ldr %f0, %f2
128; CHECK: br %r14
129  %index2 = add i64 %index, 512
130  %ptr = getelementptr double, double *%base, i64 %index2
131  %f2 = load double, double *%ptr
132  %negacc = fneg double %acc
133  %res = call double @llvm.experimental.constrained.fma.f64 (
134                        double %f1, double %f2, double %negacc,
135                        metadata !"round.dynamic",
136                        metadata !"fpexcept.strict") #0
137  ret double %res
138}
139
140attributes #0 = { strictfp }
141