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