1; Test 8-bit conditional stores that are presented as selects.  The volatile
2; tests require z10, which use a branch instead of a LOCR.
3;
4; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z10 | FileCheck %s
5
6declare void @foo(i8 *)
7
8; Test the simple case, with the loaded value first.
9define void @f1(i8 *%ptr, i8 %alt, i32 %limit) {
10; CHECK-LABEL: f1:
11; CHECK-NOT: %r2
12; CHECK: jl [[LABEL:[^ ]*]]
13; CHECK-NOT: %r2
14; CHECK: stc %r3, 0(%r2)
15; CHECK: [[LABEL]]:
16; CHECK: br %r14
17  %cond = icmp ult i32 %limit, 420
18  %orig = load i8 *%ptr
19  %res = select i1 %cond, i8 %orig, i8 %alt
20  store i8 %res, i8 *%ptr
21  ret void
22}
23
24; ...and with the loaded value second
25define void @f2(i8 *%ptr, i8 %alt, i32 %limit) {
26; CHECK-LABEL: f2:
27; CHECK-NOT: %r2
28; CHECK: jhe [[LABEL:[^ ]*]]
29; CHECK-NOT: %r2
30; CHECK: stc %r3, 0(%r2)
31; CHECK: [[LABEL]]:
32; CHECK: br %r14
33  %cond = icmp ult i32 %limit, 420
34  %orig = load i8 *%ptr
35  %res = select i1 %cond, i8 %alt, i8 %orig
36  store i8 %res, i8 *%ptr
37  ret void
38}
39
40; Test cases where the value is explicitly sign-extended to 32 bits, with the
41; loaded value first.
42define void @f3(i8 *%ptr, i32 %alt, i32 %limit) {
43; CHECK-LABEL: f3:
44; CHECK-NOT: %r2
45; CHECK: jl [[LABEL:[^ ]*]]
46; CHECK-NOT: %r2
47; CHECK: stc %r3, 0(%r2)
48; CHECK: [[LABEL]]:
49; CHECK: br %r14
50  %cond = icmp ult i32 %limit, 420
51  %orig = load i8 *%ptr
52  %ext = sext i8 %orig to i32
53  %res = select i1 %cond, i32 %ext, i32 %alt
54  %trunc = trunc i32 %res to i8
55  store i8 %trunc, i8 *%ptr
56  ret void
57}
58
59; ...and with the loaded value second
60define void @f4(i8 *%ptr, i32 %alt, i32 %limit) {
61; CHECK-LABEL: f4:
62; CHECK-NOT: %r2
63; CHECK: jhe [[LABEL:[^ ]*]]
64; CHECK-NOT: %r2
65; CHECK: stc %r3, 0(%r2)
66; CHECK: [[LABEL]]:
67; CHECK: br %r14
68  %cond = icmp ult i32 %limit, 420
69  %orig = load i8 *%ptr
70  %ext = sext i8 %orig to i32
71  %res = select i1 %cond, i32 %alt, i32 %ext
72  %trunc = trunc i32 %res to i8
73  store i8 %trunc, i8 *%ptr
74  ret void
75}
76
77; Test cases where the value is explicitly zero-extended to 32 bits, with the
78; loaded value first.
79define void @f5(i8 *%ptr, i32 %alt, i32 %limit) {
80; CHECK-LABEL: f5:
81; CHECK-NOT: %r2
82; CHECK: jl [[LABEL:[^ ]*]]
83; CHECK-NOT: %r2
84; CHECK: stc %r3, 0(%r2)
85; CHECK: [[LABEL]]:
86; CHECK: br %r14
87  %cond = icmp ult i32 %limit, 420
88  %orig = load i8 *%ptr
89  %ext = zext i8 %orig to i32
90  %res = select i1 %cond, i32 %ext, i32 %alt
91  %trunc = trunc i32 %res to i8
92  store i8 %trunc, i8 *%ptr
93  ret void
94}
95
96; ...and with the loaded value second
97define void @f6(i8 *%ptr, i32 %alt, i32 %limit) {
98; CHECK-LABEL: f6:
99; CHECK-NOT: %r2
100; CHECK: jhe [[LABEL:[^ ]*]]
101; CHECK-NOT: %r2
102; CHECK: stc %r3, 0(%r2)
103; CHECK: [[LABEL]]:
104; CHECK: br %r14
105  %cond = icmp ult i32 %limit, 420
106  %orig = load i8 *%ptr
107  %ext = zext i8 %orig to i32
108  %res = select i1 %cond, i32 %alt, i32 %ext
109  %trunc = trunc i32 %res to i8
110  store i8 %trunc, i8 *%ptr
111  ret void
112}
113
114; Test cases where the value is explicitly sign-extended to 64 bits, with the
115; loaded value first.
116define void @f7(i8 *%ptr, i64 %alt, i32 %limit) {
117; CHECK-LABEL: f7:
118; CHECK-NOT: %r2
119; CHECK: jl [[LABEL:[^ ]*]]
120; CHECK-NOT: %r2
121; CHECK: stc %r3, 0(%r2)
122; CHECK: [[LABEL]]:
123; CHECK: br %r14
124  %cond = icmp ult i32 %limit, 420
125  %orig = load i8 *%ptr
126  %ext = sext i8 %orig to i64
127  %res = select i1 %cond, i64 %ext, i64 %alt
128  %trunc = trunc i64 %res to i8
129  store i8 %trunc, i8 *%ptr
130  ret void
131}
132
133; ...and with the loaded value second
134define void @f8(i8 *%ptr, i64 %alt, i32 %limit) {
135; CHECK-LABEL: f8:
136; CHECK-NOT: %r2
137; CHECK: jhe [[LABEL:[^ ]*]]
138; CHECK-NOT: %r2
139; CHECK: stc %r3, 0(%r2)
140; CHECK: [[LABEL]]:
141; CHECK: br %r14
142  %cond = icmp ult i32 %limit, 420
143  %orig = load i8 *%ptr
144  %ext = sext i8 %orig to i64
145  %res = select i1 %cond, i64 %alt, i64 %ext
146  %trunc = trunc i64 %res to i8
147  store i8 %trunc, i8 *%ptr
148  ret void
149}
150
151; Test cases where the value is explicitly zero-extended to 64 bits, with the
152; loaded value first.
153define void @f9(i8 *%ptr, i64 %alt, i32 %limit) {
154; CHECK-LABEL: f9:
155; CHECK-NOT: %r2
156; CHECK: jl [[LABEL:[^ ]*]]
157; CHECK-NOT: %r2
158; CHECK: stc %r3, 0(%r2)
159; CHECK: [[LABEL]]:
160; CHECK: br %r14
161  %cond = icmp ult i32 %limit, 420
162  %orig = load i8 *%ptr
163  %ext = zext i8 %orig to i64
164  %res = select i1 %cond, i64 %ext, i64 %alt
165  %trunc = trunc i64 %res to i8
166  store i8 %trunc, i8 *%ptr
167  ret void
168}
169
170; ...and with the loaded value second
171define void @f10(i8 *%ptr, i64 %alt, i32 %limit) {
172; CHECK-LABEL: f10:
173; CHECK-NOT: %r2
174; CHECK: jhe [[LABEL:[^ ]*]]
175; CHECK-NOT: %r2
176; CHECK: stc %r3, 0(%r2)
177; CHECK: [[LABEL]]:
178; CHECK: br %r14
179  %cond = icmp ult i32 %limit, 420
180  %orig = load i8 *%ptr
181  %ext = zext i8 %orig to i64
182  %res = select i1 %cond, i64 %alt, i64 %ext
183  %trunc = trunc i64 %res to i8
184  store i8 %trunc, i8 *%ptr
185  ret void
186}
187
188; Check the high end of the STC range.
189define void @f11(i8 *%base, i8 %alt, i32 %limit) {
190; CHECK-LABEL: f11:
191; CHECK-NOT: %r2
192; CHECK: jl [[LABEL:[^ ]*]]
193; CHECK-NOT: %r2
194; CHECK: stc %r3, 4095(%r2)
195; CHECK: [[LABEL]]:
196; CHECK: br %r14
197  %ptr = getelementptr i8 *%base, i64 4095
198  %cond = icmp ult i32 %limit, 420
199  %orig = load i8 *%ptr
200  %res = select i1 %cond, i8 %orig, i8 %alt
201  store i8 %res, i8 *%ptr
202  ret void
203}
204
205; Check the next byte up, which should use STCY instead of STC.
206define void @f12(i8 *%base, i8 %alt, i32 %limit) {
207; CHECK-LABEL: f12:
208; CHECK-NOT: %r2
209; CHECK: jl [[LABEL:[^ ]*]]
210; CHECK-NOT: %r2
211; CHECK: stcy %r3, 4096(%r2)
212; CHECK: [[LABEL]]:
213; CHECK: br %r14
214  %ptr = getelementptr i8 *%base, i64 4096
215  %cond = icmp ult i32 %limit, 420
216  %orig = load i8 *%ptr
217  %res = select i1 %cond, i8 %orig, i8 %alt
218  store i8 %res, i8 *%ptr
219  ret void
220}
221
222; Check the high end of the STCY range.
223define void @f13(i8 *%base, i8 %alt, i32 %limit) {
224; CHECK-LABEL: f13:
225; CHECK-NOT: %r2
226; CHECK: jl [[LABEL:[^ ]*]]
227; CHECK-NOT: %r2
228; CHECK: stcy %r3, 524287(%r2)
229; CHECK: [[LABEL]]:
230; CHECK: br %r14
231  %ptr = getelementptr i8 *%base, i64 524287
232  %cond = icmp ult i32 %limit, 420
233  %orig = load i8 *%ptr
234  %res = select i1 %cond, i8 %orig, i8 %alt
235  store i8 %res, i8 *%ptr
236  ret void
237}
238
239; Check the next byte up, which needs separate address logic.
240; Other sequences besides this one would be OK.
241define void @f14(i8 *%base, i8 %alt, i32 %limit) {
242; CHECK-LABEL: f14:
243; CHECK-NOT: %r2
244; CHECK: jl [[LABEL:[^ ]*]]
245; CHECK-NOT: %r2
246; CHECK: agfi %r2, 524288
247; CHECK: stc %r3, 0(%r2)
248; CHECK: [[LABEL]]:
249; CHECK: br %r14
250  %ptr = getelementptr i8 *%base, i64 524288
251  %cond = icmp ult i32 %limit, 420
252  %orig = load i8 *%ptr
253  %res = select i1 %cond, i8 %orig, i8 %alt
254  store i8 %res, i8 *%ptr
255  ret void
256}
257
258; Check the low end of the STCY range.
259define void @f15(i8 *%base, i8 %alt, i32 %limit) {
260; CHECK-LABEL: f15:
261; CHECK-NOT: %r2
262; CHECK: jl [[LABEL:[^ ]*]]
263; CHECK-NOT: %r2
264; CHECK: stcy %r3, -524288(%r2)
265; CHECK: [[LABEL]]:
266; CHECK: br %r14
267  %ptr = getelementptr i8 *%base, i64 -524288
268  %cond = icmp ult i32 %limit, 420
269  %orig = load i8 *%ptr
270  %res = select i1 %cond, i8 %orig, i8 %alt
271  store i8 %res, i8 *%ptr
272  ret void
273}
274
275; Check the next byte down, which needs separate address logic.
276; Other sequences besides this one would be OK.
277define void @f16(i8 *%base, i8 %alt, i32 %limit) {
278; CHECK-LABEL: f16:
279; CHECK-NOT: %r2
280; CHECK: jl [[LABEL:[^ ]*]]
281; CHECK-NOT: %r2
282; CHECK: agfi %r2, -524289
283; CHECK: stc %r3, 0(%r2)
284; CHECK: [[LABEL]]:
285; CHECK: br %r14
286  %ptr = getelementptr i8 *%base, i64 -524289
287  %cond = icmp ult i32 %limit, 420
288  %orig = load i8 *%ptr
289  %res = select i1 %cond, i8 %orig, i8 %alt
290  store i8 %res, i8 *%ptr
291  ret void
292}
293
294; Check that STCY allows an index.
295define void @f17(i64 %base, i64 %index, i8 %alt, i32 %limit) {
296; CHECK-LABEL: f17:
297; CHECK-NOT: %r2
298; CHECK: jl [[LABEL:[^ ]*]]
299; CHECK-NOT: %r2
300; CHECK: stcy %r4, 4096(%r3,%r2)
301; CHECK: [[LABEL]]:
302; CHECK: br %r14
303  %add1 = add i64 %base, %index
304  %add2 = add i64 %add1, 4096
305  %ptr = inttoptr i64 %add2 to i8 *
306  %cond = icmp ult i32 %limit, 420
307  %orig = load i8 *%ptr
308  %res = select i1 %cond, i8 %orig, i8 %alt
309  store i8 %res, i8 *%ptr
310  ret void
311}
312
313; Check that volatile loads are not matched.
314define void @f18(i8 *%ptr, i8 %alt, i32 %limit) {
315; CHECK-LABEL: f18:
316; CHECK: lb {{%r[0-5]}}, 0(%r2)
317; CHECK: {{jl|jnl}} [[LABEL:[^ ]*]]
318; CHECK: [[LABEL]]:
319; CHECK: stc {{%r[0-5]}}, 0(%r2)
320; CHECK: br %r14
321  %cond = icmp ult i32 %limit, 420
322  %orig = load volatile i8 *%ptr
323  %res = select i1 %cond, i8 %orig, i8 %alt
324  store i8 %res, i8 *%ptr
325  ret void
326}
327
328; ...likewise stores.  In this case we should have a conditional load into %r3.
329define void @f19(i8 *%ptr, i8 %alt, i32 %limit) {
330; CHECK-LABEL: f19:
331; CHECK: jhe [[LABEL:[^ ]*]]
332; CHECK: lb %r3, 0(%r2)
333; CHECK: [[LABEL]]:
334; CHECK: stc %r3, 0(%r2)
335; CHECK: br %r14
336  %cond = icmp ult i32 %limit, 420
337  %orig = load i8 *%ptr
338  %res = select i1 %cond, i8 %orig, i8 %alt
339  store volatile i8 %res, i8 *%ptr
340  ret void
341}
342
343; Check that atomic loads are not matched.  The transformation is OK for
344; the "unordered" case tested here, but since we don't try to handle atomic
345; operations at all in this context, it seems better to assert that than
346; to restrict the test to a stronger ordering.
347define void @f20(i8 *%ptr, i8 %alt, i32 %limit) {
348; FIXME: should use a normal load instead of CS.
349; CHECK-LABEL: f20:
350; CHECK: lb {{%r[0-9]+}}, 0(%r2)
351; CHECK: {{jl|jnl}} [[LABEL:[^ ]*]]
352; CHECK: [[LABEL]]:
353; CHECK: stc {{%r[0-9]+}}, 0(%r2)
354; CHECK: br %r14
355  %cond = icmp ult i32 %limit, 420
356  %orig = load atomic i8 *%ptr unordered, align 1
357  %res = select i1 %cond, i8 %orig, i8 %alt
358  store i8 %res, i8 *%ptr
359  ret void
360}
361
362; ...likewise stores.
363define void @f21(i8 *%ptr, i8 %alt, i32 %limit) {
364; FIXME: should use a normal store instead of CS.
365; CHECK-LABEL: f21:
366; CHECK: jhe [[LABEL:[^ ]*]]
367; CHECK: lb %r3, 0(%r2)
368; CHECK: [[LABEL]]:
369; CHECK: stc %r3, 0(%r2)
370; CHECK: br %r14
371  %cond = icmp ult i32 %limit, 420
372  %orig = load i8 *%ptr
373  %res = select i1 %cond, i8 %orig, i8 %alt
374  store atomic i8 %res, i8 *%ptr unordered, align 1
375  ret void
376}
377
378; Try a frame index base.
379define void @f22(i8 %alt, i32 %limit) {
380; CHECK-LABEL: f22:
381; CHECK: brasl %r14, foo@PLT
382; CHECK-NOT: %r15
383; CHECK: jl [[LABEL:[^ ]*]]
384; CHECK-NOT: %r15
385; CHECK: stc {{%r[0-9]+}}, {{[0-9]+}}(%r15)
386; CHECK: [[LABEL]]:
387; CHECK: brasl %r14, foo@PLT
388; CHECK: br %r14
389  %ptr = alloca i8
390  call void @foo(i8 *%ptr)
391  %cond = icmp ult i32 %limit, 420
392  %orig = load i8 *%ptr
393  %res = select i1 %cond, i8 %orig, i8 %alt
394  store i8 %res, i8 *%ptr
395  call void @foo(i8 *%ptr)
396  ret void
397}
398