1; Test transactional-execution intrinsics.
2;
3; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=zEC12 | FileCheck %s
4
5declare i32 @llvm.s390.tbegin(i8 *, i32)
6declare i32 @llvm.s390.tbegin.nofloat(i8 *, i32)
7declare void @llvm.s390.tbeginc(i8 *, i32)
8declare i32 @llvm.s390.tend()
9declare void @llvm.s390.tabort(i64)
10declare void @llvm.s390.ntstg(i64, i64 *)
11declare i32 @llvm.s390.etnd()
12declare void @llvm.s390.ppa.txassist(i32)
13
14; TBEGIN.
15define void @test_tbegin() {
16; CHECK-LABEL: test_tbegin:
17; CHECK-NOT: stmg
18; CHECK: std %f8,
19; CHECK: std %f9,
20; CHECK: std %f10,
21; CHECK: std %f11,
22; CHECK: std %f12,
23; CHECK: std %f13,
24; CHECK: std %f14,
25; CHECK: std %f15,
26; CHECK: tbegin 0, 65292
27; CHECK: ld %f8,
28; CHECK: ld %f9,
29; CHECK: ld %f10,
30; CHECK: ld %f11,
31; CHECK: ld %f12,
32; CHECK: ld %f13,
33; CHECK: ld %f14,
34; CHECK: ld %f15,
35; CHECK: br %r14
36  call i32 @llvm.s390.tbegin(i8 *null, i32 65292)
37  ret void
38}
39
40; TBEGIN (nofloat).
41define void @test_tbegin_nofloat1() {
42; CHECK-LABEL: test_tbegin_nofloat1:
43; CHECK-NOT: stmg
44; CHECK-NOT: std
45; CHECK: tbegin 0, 65292
46; CHECK: br %r14
47  call i32 @llvm.s390.tbegin.nofloat(i8 *null, i32 65292)
48  ret void
49}
50
51; TBEGIN (nofloat) with integer CC return value.
52define i32 @test_tbegin_nofloat2() {
53; CHECK-LABEL: test_tbegin_nofloat2:
54; CHECK-NOT: stmg
55; CHECK-NOT: std
56; CHECK: tbegin 0, 65292
57; CHECK: ipm %r2
58; CHECK: srl %r2, 28
59; CHECK: br %r14
60  %res = call i32 @llvm.s390.tbegin.nofloat(i8 *null, i32 65292)
61  ret i32 %res
62}
63
64; TBEGIN (nofloat) with implicit CC check.
65define void @test_tbegin_nofloat3(i32 *%ptr) {
66; CHECK-LABEL: test_tbegin_nofloat3:
67; CHECK-NOT: stmg
68; CHECK-NOT: std
69; CHECK: tbegin 0, 65292
70; CHECK: bnhr %r14
71; CHECK: mvhi 0(%r2), 0
72; CHECK: br %r14
73  %res = call i32 @llvm.s390.tbegin.nofloat(i8 *null, i32 65292)
74  %cmp = icmp eq i32 %res, 2
75  br i1 %cmp, label %if.then, label %if.end
76
77if.then:                                          ; preds = %entry
78  store i32 0, i32* %ptr, align 4
79  br label %if.end
80
81if.end:                                           ; preds = %if.then, %entry
82  ret void
83}
84
85; TBEGIN (nofloat) with dual CC use.
86define i32 @test_tbegin_nofloat4(i32 %pad, i32 *%ptr) {
87; CHECK-LABEL: test_tbegin_nofloat4:
88; CHECK-NOT: stmg
89; CHECK-NOT: std
90; CHECK: tbegin 0, 65292
91; CHECK: ipm %r2
92; CHECK: srl %r2, 28
93; CHECK: ciblh %r2, 2, 0(%r14)
94; CHECK: mvhi 0(%r3), 0
95; CHECK: br %r14
96  %res = call i32 @llvm.s390.tbegin.nofloat(i8 *null, i32 65292)
97  %cmp = icmp eq i32 %res, 2
98  br i1 %cmp, label %if.then, label %if.end
99
100if.then:                                          ; preds = %entry
101  store i32 0, i32* %ptr, align 4
102  br label %if.end
103
104if.end:                                           ; preds = %if.then, %entry
105  ret i32 %res
106}
107
108; TBEGIN (nofloat) with register.
109define void @test_tbegin_nofloat5(i8 *%ptr) {
110; CHECK-LABEL: test_tbegin_nofloat5:
111; CHECK-NOT: stmg
112; CHECK-NOT: std
113; CHECK: tbegin 0(%r2), 65292
114; CHECK: br %r14
115  call i32 @llvm.s390.tbegin.nofloat(i8 *%ptr, i32 65292)
116  ret void
117}
118
119; TBEGIN (nofloat) with GRSM 0x0f00.
120define void @test_tbegin_nofloat6() {
121; CHECK-LABEL: test_tbegin_nofloat6:
122; CHECK: stmg %r6, %r15,
123; CHECK-NOT: std
124; CHECK: tbegin 0, 3840
125; CHECK: br %r14
126  call i32 @llvm.s390.tbegin.nofloat(i8 *null, i32 3840)
127  ret void
128}
129
130; TBEGIN (nofloat) with GRSM 0xf100.
131define void @test_tbegin_nofloat7() {
132; CHECK-LABEL: test_tbegin_nofloat7:
133; CHECK: stmg %r8, %r15,
134; CHECK-NOT: std
135; CHECK: tbegin 0, 61696
136; CHECK: br %r14
137  call i32 @llvm.s390.tbegin.nofloat(i8 *null, i32 61696)
138  ret void
139}
140
141; TBEGIN (nofloat) with GRSM 0xfe00 -- stack pointer added automatically.
142define void @test_tbegin_nofloat8() {
143; CHECK-LABEL: test_tbegin_nofloat8:
144; CHECK-NOT: stmg
145; CHECK-NOT: std
146; CHECK: tbegin 0, 65280
147; CHECK: br %r14
148  call i32 @llvm.s390.tbegin.nofloat(i8 *null, i32 65024)
149  ret void
150}
151
152; TBEGIN (nofloat) with GRSM 0xfb00 -- no frame pointer needed.
153define void @test_tbegin_nofloat9() {
154; CHECK-LABEL: test_tbegin_nofloat9:
155; CHECK: stmg %r10, %r15,
156; CHECK-NOT: std
157; CHECK: tbegin 0, 64256
158; CHECK: br %r14
159  call i32 @llvm.s390.tbegin.nofloat(i8 *null, i32 64256)
160  ret void
161}
162
163; TBEGIN (nofloat) with GRSM 0xfb00 -- frame pointer added automatically.
164define void @test_tbegin_nofloat10(i64 %n) {
165; CHECK-LABEL: test_tbegin_nofloat10:
166; CHECK: stmg %r11, %r15,
167; CHECK-NOT: std
168; CHECK: tbegin 0, 65280
169; CHECK: br %r14
170  %buf = alloca i8, i64 %n
171  call i32 @llvm.s390.tbegin.nofloat(i8 *null, i32 64256)
172  ret void
173}
174
175; TBEGINC.
176define void @test_tbeginc() {
177; CHECK-LABEL: test_tbeginc:
178; CHECK-NOT: stmg
179; CHECK-NOT: std
180; CHECK: tbeginc 0, 65288
181; CHECK: br %r14
182  call void @llvm.s390.tbeginc(i8 *null, i32 65288)
183  ret void
184}
185
186; TEND with integer CC return value.
187define i32 @test_tend1() {
188; CHECK-LABEL: test_tend1:
189; CHECK: tend
190; CHECK: ipm %r2
191; CHECK: srl %r2, 28
192; CHECK: br %r14
193  %res = call i32 @llvm.s390.tend()
194  ret i32 %res
195}
196
197; TEND with implicit CC check.
198define void @test_tend3(i32 *%ptr) {
199; CHECK-LABEL: test_tend3:
200; CHECK: tend
201; CHECK: ber %r14
202; CHECK: mvhi 0(%r2), 0
203; CHECK: br %r14
204  %res = call i32 @llvm.s390.tend()
205  %cmp = icmp eq i32 %res, 2
206  br i1 %cmp, label %if.then, label %if.end
207
208if.then:                                          ; preds = %entry
209  store i32 0, i32* %ptr, align 4
210  br label %if.end
211
212if.end:                                           ; preds = %if.then, %entry
213  ret void
214}
215
216; TEND with dual CC use.
217define i32 @test_tend2(i32 %pad, i32 *%ptr) {
218; CHECK-LABEL: test_tend2:
219; CHECK: tend
220; CHECK: ipm %r2
221; CHECK: srl %r2, 28
222; CHECK: ciblh %r2, 2, 0(%r14)
223; CHECK: mvhi 0(%r3), 0
224; CHECK: br %r14
225  %res = call i32 @llvm.s390.tend()
226  %cmp = icmp eq i32 %res, 2
227  br i1 %cmp, label %if.then, label %if.end
228
229if.then:                                          ; preds = %entry
230  store i32 0, i32* %ptr, align 4
231  br label %if.end
232
233if.end:                                           ; preds = %if.then, %entry
234  ret i32 %res
235}
236
237; TABORT with register only.
238define void @test_tabort1(i64 %val) {
239; CHECK-LABEL: test_tabort1:
240; CHECK: tabort 0(%r2)
241; CHECK: br %r14
242  call void @llvm.s390.tabort(i64 %val)
243  ret void
244}
245
246; TABORT with immediate only.
247define void @test_tabort2(i64 %val) {
248; CHECK-LABEL: test_tabort2:
249; CHECK: tabort 1234
250; CHECK: br %r14
251  call void @llvm.s390.tabort(i64 1234)
252  ret void
253}
254
255; TABORT with register + immediate.
256define void @test_tabort3(i64 %val) {
257; CHECK-LABEL: test_tabort3:
258; CHECK: tabort 1234(%r2)
259; CHECK: br %r14
260  %sum = add i64 %val, 1234
261  call void @llvm.s390.tabort(i64 %sum)
262  ret void
263}
264
265; TABORT with out-of-range immediate.
266define void @test_tabort4(i64 %val) {
267; CHECK-LABEL: test_tabort4:
268; CHECK: tabort 0({{%r[1-5]}})
269; CHECK: br %r14
270  call void @llvm.s390.tabort(i64 4096)
271  ret void
272}
273
274; NTSTG with base pointer only.
275define void @test_ntstg1(i64 *%ptr, i64 %val) {
276; CHECK-LABEL: test_ntstg1:
277; CHECK: ntstg %r3, 0(%r2)
278; CHECK: br %r14
279  call void @llvm.s390.ntstg(i64 %val, i64 *%ptr)
280  ret void
281}
282
283; NTSTG with base and index.
284; Check that VSTL doesn't allow an index.
285define void @test_ntstg2(i64 *%base, i64 %index, i64 %val) {
286; CHECK-LABEL: test_ntstg2:
287; CHECK: sllg [[REG:%r[1-5]]], %r3, 3
288; CHECK: ntstg %r4, 0([[REG]],%r2)
289; CHECK: br %r14
290  %ptr = getelementptr i64, i64 *%base, i64 %index
291  call void @llvm.s390.ntstg(i64 %val, i64 *%ptr)
292  ret void
293}
294
295; NTSTG with the highest in-range displacement.
296define void @test_ntstg3(i64 *%base, i64 %val) {
297; CHECK-LABEL: test_ntstg3:
298; CHECK: ntstg %r3, 524280(%r2)
299; CHECK: br %r14
300  %ptr = getelementptr i64, i64 *%base, i64 65535
301  call void @llvm.s390.ntstg(i64 %val, i64 *%ptr)
302  ret void
303}
304
305; NTSTG with an out-of-range positive displacement.
306define void @test_ntstg4(i64 *%base, i64 %val) {
307; CHECK-LABEL: test_ntstg4:
308; CHECK: ntstg %r3, 0({{%r[1-5]}})
309; CHECK: br %r14
310  %ptr = getelementptr i64, i64 *%base, i64 65536
311  call void @llvm.s390.ntstg(i64 %val, i64 *%ptr)
312  ret void
313}
314
315; NTSTG with the lowest in-range displacement.
316define void @test_ntstg5(i64 *%base, i64 %val) {
317; CHECK-LABEL: test_ntstg5:
318; CHECK: ntstg %r3, -524288(%r2)
319; CHECK: br %r14
320  %ptr = getelementptr i64, i64 *%base, i64 -65536
321  call void @llvm.s390.ntstg(i64 %val, i64 *%ptr)
322  ret void
323}
324
325; NTSTG with an out-of-range negative displacement.
326define void @test_ntstg6(i64 *%base, i64 %val) {
327; CHECK-LABEL: test_ntstg6:
328; CHECK: ntstg %r3, 0({{%r[1-5]}})
329; CHECK: br %r14
330  %ptr = getelementptr i64, i64 *%base, i64 -65537
331  call void @llvm.s390.ntstg(i64 %val, i64 *%ptr)
332  ret void
333}
334
335; ETND.
336define i32 @test_etnd() {
337; CHECK-LABEL: test_etnd:
338; CHECK: etnd %r2
339; CHECK: br %r14
340  %res = call i32 @llvm.s390.etnd()
341  ret i32 %res
342}
343
344; PPA (Transaction-Abort Assist)
345define void @test_ppa_txassist(i32 %val) {
346; CHECK-LABEL: test_ppa_txassist:
347; CHECK: ppa %r2, 0, 1
348; CHECK: br %r14
349  call void @llvm.s390.ppa.txassist(i32 %val)
350  ret void
351}
352
353