1; Test f64 conditional stores that are presented as selects.
2;
3; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
4
5declare void @foo(double *)
6
7; Test with the loaded value first.
8define void @f1(double *%ptr, double %alt, i32 %limit) {
9; CHECK-LABEL: f1:
10; CHECK-NOT: %r2
11; CHECK: jl [[LABEL:[^ ]*]]
12; CHECK-NOT: %r2
13; CHECK: std %f0, 0(%r2)
14; CHECK: [[LABEL]]:
15; CHECK: br %r14
16  %cond = icmp ult i32 %limit, 420
17  %orig = load double *%ptr
18  %res = select i1 %cond, double %orig, double %alt
19  store double %res, double *%ptr
20  ret void
21}
22
23; ...and with the loaded value second
24define void @f2(double *%ptr, double %alt, i32 %limit) {
25; CHECK-LABEL: f2:
26; CHECK-NOT: %r2
27; CHECK: jhe [[LABEL:[^ ]*]]
28; CHECK-NOT: %r2
29; CHECK: std %f0, 0(%r2)
30; CHECK: [[LABEL]]:
31; CHECK: br %r14
32  %cond = icmp ult i32 %limit, 420
33  %orig = load double *%ptr
34  %res = select i1 %cond, double %alt, double %orig
35  store double %res, double *%ptr
36  ret void
37}
38
39; Check the high end of the aligned STD range.
40define void @f3(double *%base, double %alt, i32 %limit) {
41; CHECK-LABEL: f3:
42; CHECK-NOT: %r2
43; CHECK: jl [[LABEL:[^ ]*]]
44; CHECK-NOT: %r2
45; CHECK: std %f0, 4088(%r2)
46; CHECK: [[LABEL]]:
47; CHECK: br %r14
48  %ptr = getelementptr double *%base, i64 511
49  %cond = icmp ult i32 %limit, 420
50  %orig = load double *%ptr
51  %res = select i1 %cond, double %orig, double %alt
52  store double %res, double *%ptr
53  ret void
54}
55
56; Check the next doubleword up, which should use STDY instead of STD.
57define void @f4(double *%base, double %alt, i32 %limit) {
58; CHECK-LABEL: f4:
59; CHECK-NOT: %r2
60; CHECK: jl [[LABEL:[^ ]*]]
61; CHECK-NOT: %r2
62; CHECK: stdy %f0, 4096(%r2)
63; CHECK: [[LABEL]]:
64; CHECK: br %r14
65  %ptr = getelementptr double *%base, i64 512
66  %cond = icmp ult i32 %limit, 420
67  %orig = load double *%ptr
68  %res = select i1 %cond, double %orig, double %alt
69  store double %res, double *%ptr
70  ret void
71}
72
73; Check the high end of the aligned STDY range.
74define void @f5(double *%base, double %alt, i32 %limit) {
75; CHECK-LABEL: f5:
76; CHECK-NOT: %r2
77; CHECK: jl [[LABEL:[^ ]*]]
78; CHECK-NOT: %r2
79; CHECK: stdy %f0, 524280(%r2)
80; CHECK: [[LABEL]]:
81; CHECK: br %r14
82  %ptr = getelementptr double *%base, i64 65535
83  %cond = icmp ult i32 %limit, 420
84  %orig = load double *%ptr
85  %res = select i1 %cond, double %orig, double %alt
86  store double %res, double *%ptr
87  ret void
88}
89
90; Check the next doubleword up, which needs separate address logic.
91; Other sequences besides this one would be OK.
92define void @f6(double *%base, double %alt, i32 %limit) {
93; CHECK-LABEL: f6:
94; CHECK-NOT: %r2
95; CHECK: jl [[LABEL:[^ ]*]]
96; CHECK-NOT: %r2
97; CHECK: agfi %r2, 524288
98; CHECK: std %f0, 0(%r2)
99; CHECK: [[LABEL]]:
100; CHECK: br %r14
101  %ptr = getelementptr double *%base, i64 65536
102  %cond = icmp ult i32 %limit, 420
103  %orig = load double *%ptr
104  %res = select i1 %cond, double %orig, double %alt
105  store double %res, double *%ptr
106  ret void
107}
108
109; Check the low end of the STDY range.
110define void @f7(double *%base, double %alt, i32 %limit) {
111; CHECK-LABEL: f7:
112; CHECK-NOT: %r2
113; CHECK: jl [[LABEL:[^ ]*]]
114; CHECK-NOT: %r2
115; CHECK: stdy %f0, -524288(%r2)
116; CHECK: [[LABEL]]:
117; CHECK: br %r14
118  %ptr = getelementptr double *%base, i64 -65536
119  %cond = icmp ult i32 %limit, 420
120  %orig = load double *%ptr
121  %res = select i1 %cond, double %orig, double %alt
122  store double %res, double *%ptr
123  ret void
124}
125
126; Check the next doubleword down, which needs separate address logic.
127; Other sequences besides this one would be OK.
128define void @f8(double *%base, double %alt, i32 %limit) {
129; CHECK-LABEL: f8:
130; CHECK-NOT: %r2
131; CHECK: jl [[LABEL:[^ ]*]]
132; CHECK-NOT: %r2
133; CHECK: agfi %r2, -524296
134; CHECK: std %f0, 0(%r2)
135; CHECK: [[LABEL]]:
136; CHECK: br %r14
137  %ptr = getelementptr double *%base, i64 -65537
138  %cond = icmp ult i32 %limit, 420
139  %orig = load double *%ptr
140  %res = select i1 %cond, double %orig, double %alt
141  store double %res, double *%ptr
142  ret void
143}
144
145; Check that STDY allows an index.
146define void @f9(i64 %base, i64 %index, double %alt, i32 %limit) {
147; CHECK-LABEL: f9:
148; CHECK-NOT: %r2
149; CHECK: jl [[LABEL:[^ ]*]]
150; CHECK-NOT: %r2
151; CHECK: stdy %f0, 524287(%r3,%r2)
152; CHECK: [[LABEL]]:
153; CHECK: br %r14
154  %add1 = add i64 %base, %index
155  %add2 = add i64 %add1, 524287
156  %ptr = inttoptr i64 %add2 to double *
157  %cond = icmp ult i32 %limit, 420
158  %orig = load double *%ptr
159  %res = select i1 %cond, double %orig, double %alt
160  store double %res, double *%ptr
161  ret void
162}
163
164; Check that volatile loads are not matched.
165define void @f10(double *%ptr, double %alt, i32 %limit) {
166; CHECK-LABEL: f10:
167; CHECK: ld {{%f[0-5]}}, 0(%r2)
168; CHECK: {{jl|jnl}} [[LABEL:[^ ]*]]
169; CHECK: [[LABEL]]:
170; CHECK: std {{%f[0-5]}}, 0(%r2)
171; CHECK: br %r14
172  %cond = icmp ult i32 %limit, 420
173  %orig = load volatile double *%ptr
174  %res = select i1 %cond, double %orig, double %alt
175  store double %res, double *%ptr
176  ret void
177}
178
179; ...likewise stores.  In this case we should have a conditional load into %f0.
180define void @f11(double *%ptr, double %alt, i32 %limit) {
181; CHECK-LABEL: f11:
182; CHECK: jhe [[LABEL:[^ ]*]]
183; CHECK: ld %f0, 0(%r2)
184; CHECK: [[LABEL]]:
185; CHECK: std %f0, 0(%r2)
186; CHECK: br %r14
187  %cond = icmp ult i32 %limit, 420
188  %orig = load double *%ptr
189  %res = select i1 %cond, double %orig, double %alt
190  store volatile double %res, double *%ptr
191  ret void
192}
193
194; Try a frame index base.
195define void @f12(double %alt, i32 %limit) {
196; CHECK-LABEL: f12:
197; CHECK: brasl %r14, foo@PLT
198; CHECK-NOT: %r15
199; CHECK: jl [[LABEL:[^ ]*]]
200; CHECK-NOT: %r15
201; CHECK: std {{%f[0-9]+}}, {{[0-9]+}}(%r15)
202; CHECK: [[LABEL]]:
203; CHECK: brasl %r14, foo@PLT
204; CHECK: br %r14
205  %ptr = alloca double
206  call void @foo(double *%ptr)
207  %cond = icmp ult i32 %limit, 420
208  %orig = load double *%ptr
209  %res = select i1 %cond, double %orig, double %alt
210  store double %res, double *%ptr
211  call void @foo(double *%ptr)
212  ret void
213}
214