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