1; Test STOCs that are presented as selects.
2;
3; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z196 | FileCheck %s
4
5declare void @foo(i32 *)
6
7; Test the simple case, with the loaded value first.
8define void @f1(i32 *%ptr, i32 %alt, i32 %limit) {
9; CHECK-LABEL: f1:
10; CHECK: clfi %r4, 42
11; CHECK: stoche %r3, 0(%r2)
12; CHECK: br %r14
13  %cond = icmp ult i32 %limit, 42
14  %orig = load i32 *%ptr
15  %res = select i1 %cond, i32 %orig, i32 %alt
16  store i32 %res, i32 *%ptr
17  ret void
18}
19
20; ...and with the loaded value second
21define void @f2(i32 *%ptr, i32 %alt, i32 %limit) {
22; CHECK-LABEL: f2:
23; CHECK: clfi %r4, 42
24; CHECK: stocl %r3, 0(%r2)
25; CHECK: br %r14
26  %cond = icmp ult i32 %limit, 42
27  %orig = load i32 *%ptr
28  %res = select i1 %cond, i32 %alt, i32 %orig
29  store i32 %res, i32 *%ptr
30  ret void
31}
32
33; Test cases where the value is explicitly sign-extended to 64 bits, with the
34; loaded value first.
35define void @f3(i32 *%ptr, i64 %alt, i32 %limit) {
36; CHECK-LABEL: f3:
37; CHECK: clfi %r4, 42
38; CHECK: stoche %r3, 0(%r2)
39; CHECK: br %r14
40  %cond = icmp ult i32 %limit, 42
41  %orig = load i32 *%ptr
42  %ext = sext i32 %orig to i64
43  %res = select i1 %cond, i64 %ext, i64 %alt
44  %trunc = trunc i64 %res to i32
45  store i32 %trunc, i32 *%ptr
46  ret void
47}
48
49; ...and with the loaded value second
50define void @f4(i32 *%ptr, i64 %alt, i32 %limit) {
51; CHECK-LABEL: f4:
52; CHECK: clfi %r4, 42
53; CHECK: stocl %r3, 0(%r2)
54; CHECK: br %r14
55  %cond = icmp ult i32 %limit, 42
56  %orig = load i32 *%ptr
57  %ext = sext i32 %orig to i64
58  %res = select i1 %cond, i64 %alt, i64 %ext
59  %trunc = trunc i64 %res to i32
60  store i32 %trunc, i32 *%ptr
61  ret void
62}
63
64; Test cases where the value is explicitly zero-extended to 32 bits, with the
65; loaded value first.
66define void @f5(i32 *%ptr, i64 %alt, i32 %limit) {
67; CHECK-LABEL: f5:
68; CHECK: clfi %r4, 42
69; CHECK: stoche %r3, 0(%r2)
70; CHECK: br %r14
71  %cond = icmp ult i32 %limit, 42
72  %orig = load i32 *%ptr
73  %ext = zext i32 %orig to i64
74  %res = select i1 %cond, i64 %ext, i64 %alt
75  %trunc = trunc i64 %res to i32
76  store i32 %trunc, i32 *%ptr
77  ret void
78}
79
80; ...and with the loaded value second
81define void @f6(i32 *%ptr, i64 %alt, i32 %limit) {
82; CHECK-LABEL: f6:
83; CHECK: clfi %r4, 42
84; CHECK: stocl %r3, 0(%r2)
85; CHECK: br %r14
86  %cond = icmp ult i32 %limit, 42
87  %orig = load i32 *%ptr
88  %ext = zext i32 %orig to i64
89  %res = select i1 %cond, i64 %alt, i64 %ext
90  %trunc = trunc i64 %res to i32
91  store i32 %trunc, i32 *%ptr
92  ret void
93}
94
95; Check the high end of the aligned STOC range.
96define void @f7(i32 *%base, i32 %alt, i32 %limit) {
97; CHECK-LABEL: f7:
98; CHECK: clfi %r4, 42
99; CHECK: stoche %r3, 524284(%r2)
100; CHECK: br %r14
101  %ptr = getelementptr i32 *%base, i64 131071
102  %cond = icmp ult i32 %limit, 42
103  %orig = load i32 *%ptr
104  %res = select i1 %cond, i32 %orig, i32 %alt
105  store i32 %res, i32 *%ptr
106  ret void
107}
108
109; Check the next word up.  Other sequences besides this one would be OK.
110define void @f8(i32 *%base, i32 %alt, i32 %limit) {
111; CHECK-LABEL: f8:
112; CHECK: agfi %r2, 524288
113; CHECK: clfi %r4, 42
114; CHECK: stoche %r3, 0(%r2)
115; CHECK: br %r14
116  %ptr = getelementptr i32 *%base, i64 131072
117  %cond = icmp ult i32 %limit, 42
118  %orig = load i32 *%ptr
119  %res = select i1 %cond, i32 %orig, i32 %alt
120  store i32 %res, i32 *%ptr
121  ret void
122}
123
124; Check the low end of the STOC range.
125define void @f9(i32 *%base, i32 %alt, i32 %limit) {
126; CHECK-LABEL: f9:
127; CHECK: clfi %r4, 42
128; CHECK: stoche %r3, -524288(%r2)
129; CHECK: br %r14
130  %ptr = getelementptr i32 *%base, i64 -131072
131  %cond = icmp ult i32 %limit, 42
132  %orig = load i32 *%ptr
133  %res = select i1 %cond, i32 %orig, i32 %alt
134  store i32 %res, i32 *%ptr
135  ret void
136}
137
138; Check the next word down, with the same comments as f8.
139define void @f10(i32 *%base, i32 %alt, i32 %limit) {
140; CHECK-LABEL: f10:
141; CHECK: agfi %r2, -524292
142; CHECK: clfi %r4, 42
143; CHECK: stoche %r3, 0(%r2)
144; CHECK: br %r14
145  %ptr = getelementptr i32 *%base, i64 -131073
146  %cond = icmp ult i32 %limit, 42
147  %orig = load i32 *%ptr
148  %res = select i1 %cond, i32 %orig, i32 %alt
149  store i32 %res, i32 *%ptr
150  ret void
151}
152
153; Try a frame index base.
154define void @f11(i32 %alt, i32 %limit) {
155; CHECK-LABEL: f11:
156; CHECK: brasl %r14, foo@PLT
157; CHECK: stoche {{%r[0-9]+}}, {{[0-9]+}}(%r15)
158; CHECK: brasl %r14, foo@PLT
159; CHECK: br %r14
160  %ptr = alloca i32
161  call void @foo(i32 *%ptr)
162  %cond = icmp ult i32 %limit, 42
163  %orig = load i32 *%ptr
164  %res = select i1 %cond, i32 %orig, i32 %alt
165  store i32 %res, i32 *%ptr
166  call void @foo(i32 *%ptr)
167  ret void
168}
169
170; Test that conditionally-executed stores do not use STOC, since STOC
171; is allowed to trap even when the condition is false.
172define void @f12(i32 %a, i32 %b, i32 *%dest) {
173; CHECK-LABEL: f12:
174; CHECK-NOT: stoc
175; CHECK: br %r14
176entry:
177  %cmp = icmp ule i32 %a, %b
178  br i1 %cmp, label %store, label %exit
179
180store:
181  store i32 %b, i32 *%dest
182  br label %exit
183
184exit:
185  ret void
186}
187