1; Test 128-bit subtraction in which the second operand is variable.
2;
3; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z10 | FileCheck %s
4; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z196 | FileCheck %s
5
6declare i128 *@foo()
7
8; Test register addition.
9define void @f1(i128 *%ptr, i64 %high, i64 %low) {
10; CHECK-LABEL: f1:
11; CHECK: slgr {{%r[0-5]}}, %r4
12; CHECK: slbgr {{%r[0-5]}}, %r3
13; CHECK: br %r14
14  %a = load i128 *%ptr
15  %highx = zext i64 %high to i128
16  %lowx = zext i64 %low to i128
17  %bhigh = shl i128 %highx, 64
18  %b = or i128 %bhigh, %lowx
19  %sub = sub i128 %a, %b
20  store i128 %sub, i128 *%ptr
21  ret void
22}
23
24; Test memory addition with no offset.
25define void @f2(i64 %addr) {
26; CHECK-LABEL: f2:
27; CHECK: slg {{%r[0-5]}}, 8(%r2)
28; CHECK: slbg {{%r[0-5]}}, 0(%r2)
29; CHECK: br %r14
30  %bptr = inttoptr i64 %addr to i128 *
31  %aptr = getelementptr i128 *%bptr, i64 -8
32  %a = load i128 *%aptr
33  %b = load i128 *%bptr
34  %sub = sub i128 %a, %b
35  store i128 %sub, i128 *%aptr
36  ret void
37}
38
39; Test the highest aligned offset that is in range of both SLG and SLBG.
40define void @f3(i64 %base) {
41; CHECK-LABEL: f3:
42; CHECK: slg {{%r[0-5]}}, 524280(%r2)
43; CHECK: slbg {{%r[0-5]}}, 524272(%r2)
44; CHECK: br %r14
45  %addr = add i64 %base, 524272
46  %bptr = inttoptr i64 %addr to i128 *
47  %aptr = getelementptr i128 *%bptr, i64 -8
48  %a = load i128 *%aptr
49  %b = load i128 *%bptr
50  %sub = sub i128 %a, %b
51  store i128 %sub, i128 *%aptr
52  ret void
53}
54
55; Test the next doubleword up, which requires separate address logic for SLG.
56define void @f4(i64 %base) {
57; CHECK-LABEL: f4:
58; CHECK: lgr [[BASE:%r[1-5]]], %r2
59; CHECK: agfi [[BASE]], 524288
60; CHECK: slg {{%r[0-5]}}, 0([[BASE]])
61; CHECK: slbg {{%r[0-5]}}, 524280(%r2)
62; CHECK: br %r14
63  %addr = add i64 %base, 524280
64  %bptr = inttoptr i64 %addr to i128 *
65  %aptr = getelementptr i128 *%bptr, i64 -8
66  %a = load i128 *%aptr
67  %b = load i128 *%bptr
68  %sub = sub i128 %a, %b
69  store i128 %sub, i128 *%aptr
70  ret void
71}
72
73; Test the next doubleword after that, which requires separate logic for
74; both instructions.  It would be better to create an anchor at 524288
75; that both instructions can use, but that isn't implemented yet.
76define void @f5(i64 %base) {
77; CHECK-LABEL: f5:
78; CHECK: slg {{%r[0-5]}}, 0({{%r[1-5]}})
79; CHECK: slbg {{%r[0-5]}}, 0({{%r[1-5]}})
80; CHECK: br %r14
81  %addr = add i64 %base, 524288
82  %bptr = inttoptr i64 %addr to i128 *
83  %aptr = getelementptr i128 *%bptr, i64 -8
84  %a = load i128 *%aptr
85  %b = load i128 *%bptr
86  %sub = sub i128 %a, %b
87  store i128 %sub, i128 *%aptr
88  ret void
89}
90
91; Test the lowest displacement that is in range of both SLG and SLBG.
92define void @f6(i64 %base) {
93; CHECK-LABEL: f6:
94; CHECK: slg {{%r[0-5]}}, -524280(%r2)
95; CHECK: slbg {{%r[0-5]}}, -524288(%r2)
96; CHECK: br %r14
97  %addr = add i64 %base, -524288
98  %bptr = inttoptr i64 %addr to i128 *
99  %aptr = getelementptr i128 *%bptr, i64 -8
100  %a = load i128 *%aptr
101  %b = load i128 *%bptr
102  %sub = sub i128 %a, %b
103  store i128 %sub, i128 *%aptr
104  ret void
105}
106
107; Test the next doubleword down, which is out of range of the SLBG.
108define void @f7(i64 %base) {
109; CHECK-LABEL: f7:
110; CHECK: slg {{%r[0-5]}}, -524288(%r2)
111; CHECK: slbg {{%r[0-5]}}, 0({{%r[1-5]}})
112; CHECK: br %r14
113  %addr = add i64 %base, -524296
114  %bptr = inttoptr i64 %addr to i128 *
115  %aptr = getelementptr i128 *%bptr, i64 -8
116  %a = load i128 *%aptr
117  %b = load i128 *%bptr
118  %sub = sub i128 %a, %b
119  store i128 %sub, i128 *%aptr
120  ret void
121}
122
123; Check that subtractions of spilled values can use SLG and SLBG rather than
124; SLGR and SLBGR.
125define void @f8(i128 *%ptr0) {
126; CHECK-LABEL: f8:
127; CHECK: brasl %r14, foo@PLT
128; CHECK: slg {{%r[0-9]+}}, {{[0-9]+}}(%r15)
129; CHECK: slbg {{%r[0-9]+}}, {{[0-9]+}}(%r15)
130; CHECK: br %r14
131  %ptr1 = getelementptr i128 *%ptr0, i128 2
132  %ptr2 = getelementptr i128 *%ptr0, i128 4
133  %ptr3 = getelementptr i128 *%ptr0, i128 6
134  %ptr4 = getelementptr i128 *%ptr0, i128 8
135
136  %val0 = load i128 *%ptr0
137  %val1 = load i128 *%ptr1
138  %val2 = load i128 *%ptr2
139  %val3 = load i128 *%ptr3
140  %val4 = load i128 *%ptr4
141
142  %retptr = call i128 *@foo()
143
144  %ret = load i128 *%retptr
145  %sub0 = sub i128 %ret, %val0
146  %sub1 = sub i128 %sub0, %val1
147  %sub2 = sub i128 %sub1, %val2
148  %sub3 = sub i128 %sub2, %val3
149  %sub4 = sub i128 %sub3, %val4
150  store i128 %sub4, i128 *%retptr
151
152  ret void
153}
154