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.fma.f64(double %f1, double %f2, double %f3)
7
8define double @f1(double %f1, double %f2, double %acc) {
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 = fsub double -0.0, %acc
15  %res = call double @llvm.fma.f64 (double %f1, double %f2, double %negacc)
16  ret double %res
17}
18
19define double @f2(double %f1, double *%ptr, double %acc) {
20; CHECK-LABEL: f2:
21; CHECK: msdb %f2, %f0, 0(%r2)
22; CHECK: ldr %f0, %f2
23; CHECK: br %r14
24  %f2 = load double , double *%ptr
25  %negacc = fsub double -0.0, %acc
26  %res = call double @llvm.fma.f64 (double %f1, double %f2, double %negacc)
27  ret double %res
28}
29
30define double @f3(double %f1, double *%base, double %acc) {
31; CHECK-LABEL: f3:
32; CHECK: msdb %f2, %f0, 4088(%r2)
33; CHECK: ldr %f0, %f2
34; CHECK: br %r14
35  %ptr = getelementptr double, double *%base, i64 511
36  %f2 = load double , double *%ptr
37  %negacc = fsub double -0.0, %acc
38  %res = call double @llvm.fma.f64 (double %f1, double %f2, double %negacc)
39  ret double %res
40}
41
42define double @f4(double %f1, double *%base, double %acc) {
43; The important thing here is that we don't generate an out-of-range
44; displacement.  Other sequences besides this one would be OK.
45;
46; CHECK-LABEL: f4:
47; CHECK: aghi %r2, 4096
48; CHECK: msdb %f2, %f0, 0(%r2)
49; CHECK: ldr %f0, %f2
50; CHECK: br %r14
51  %ptr = getelementptr double, double *%base, i64 512
52  %f2 = load double , double *%ptr
53  %negacc = fsub double -0.0, %acc
54  %res = call double @llvm.fma.f64 (double %f1, double %f2, double %negacc)
55  ret double %res
56}
57
58define double @f5(double %f1, double *%base, double %acc) {
59; Here too the important thing is that we don't generate an out-of-range
60; displacement.  Other sequences besides this one would be OK.
61;
62; CHECK-LABEL: f5:
63; CHECK: aghi %r2, -8
64; CHECK: msdb %f2, %f0, 0(%r2)
65; CHECK: ldr %f0, %f2
66; CHECK: br %r14
67  %ptr = getelementptr double, double *%base, i64 -1
68  %f2 = load double , double *%ptr
69  %negacc = fsub double -0.0, %acc
70  %res = call double @llvm.fma.f64 (double %f1, double %f2, double %negacc)
71  ret double %res
72}
73
74define double @f6(double %f1, double *%base, i64 %index, double %acc) {
75; CHECK-LABEL: f6:
76; CHECK: sllg %r1, %r3, 3
77; CHECK: msdb %f2, %f0, 0(%r1,%r2)
78; CHECK: ldr %f0, %f2
79; CHECK: br %r14
80  %ptr = getelementptr double, double *%base, i64 %index
81  %f2 = load double , double *%ptr
82  %negacc = fsub double -0.0, %acc
83  %res = call double @llvm.fma.f64 (double %f1, double %f2, double %negacc)
84  ret double %res
85}
86
87define double @f7(double %f1, double *%base, i64 %index, double %acc) {
88; CHECK-LABEL: f7:
89; CHECK: sllg %r1, %r3, 3
90; CHECK: msdb %f2, %f0, 4088({{%r1,%r2|%r2,%r1}})
91; CHECK: ldr %f0, %f2
92; CHECK: br %r14
93  %index2 = add i64 %index, 511
94  %ptr = getelementptr double, double *%base, i64 %index2
95  %f2 = load double , double *%ptr
96  %negacc = fsub double -0.0, %acc
97  %res = call double @llvm.fma.f64 (double %f1, double %f2, double %negacc)
98  ret double %res
99}
100
101define double @f8(double %f1, double *%base, i64 %index, double %acc) {
102; CHECK-LABEL: f8:
103; CHECK: sllg %r1, %r3, 3
104; CHECK: lay %r1, 4096({{%r1,%r2|%r2,%r1}})
105; CHECK: msdb %f2, %f0, 0(%r1)
106; CHECK: ldr %f0, %f2
107; CHECK: br %r14
108  %index2 = add i64 %index, 512
109  %ptr = getelementptr double, double *%base, i64 %index2
110  %f2 = load double , double *%ptr
111  %negacc = fsub double -0.0, %acc
112  %res = call double @llvm.fma.f64 (double %f1, double %f2, double %negacc)
113  ret double %res
114}
115