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, 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, i128 *%bptr, i64 -8
32  %a = load i128, i128 *%aptr
33  %b = load i128, 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, i128 *%bptr, i64 -8
48  %a = load i128, i128 *%aptr
49  %b = load i128, 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: lay [[BASE:%r[1-5]]], 524280(%r2)
59; CHECK: slg {{%r[0-5]}}, 8([[BASE]])
60; CHECK: slbg {{%r[0-5]}}, 524280(%r2)
61; CHECK: br %r14
62  %addr = add i64 %base, 524280
63  %bptr = inttoptr i64 %addr to i128 *
64  %aptr = getelementptr i128, i128 *%bptr, i64 -8
65  %a = load i128, i128 *%aptr
66  %b = load i128, i128 *%bptr
67  %sub = sub i128 %a, %b
68  store i128 %sub, i128 *%aptr
69  ret void
70}
71
72; Test the next doubleword after that, which requires separate logic for
73; both instructions.
74define void @f5(i64 %base) {
75; CHECK-LABEL: f5:
76; CHECK: slg {{%r[0-5]}}, 8({{%r[1-5]}})
77; CHECK: slbg {{%r[0-5]}}, 0({{%r[1-5]}})
78; CHECK: br %r14
79  %addr = add i64 %base, 524288
80  %bptr = inttoptr i64 %addr to i128 *
81  %aptr = getelementptr i128, i128 *%bptr, i64 -8
82  %a = load i128, i128 *%aptr
83  %b = load i128, i128 *%bptr
84  %sub = sub i128 %a, %b
85  store i128 %sub, i128 *%aptr
86  ret void
87}
88
89; Test the lowest displacement that is in range of both SLG and SLBG.
90define void @f6(i64 %base) {
91; CHECK-LABEL: f6:
92; CHECK: slg {{%r[0-5]}}, -524280(%r2)
93; CHECK: slbg {{%r[0-5]}}, -524288(%r2)
94; CHECK: br %r14
95  %addr = add i64 %base, -524288
96  %bptr = inttoptr i64 %addr to i128 *
97  %aptr = getelementptr i128, i128 *%bptr, i64 -8
98  %a = load i128, i128 *%aptr
99  %b = load i128, i128 *%bptr
100  %sub = sub i128 %a, %b
101  store i128 %sub, i128 *%aptr
102  ret void
103}
104
105; Test the next doubleword down, which is out of range of the SLBG.
106define void @f7(i64 %base) {
107; CHECK-LABEL: f7:
108; CHECK: slg {{%r[0-5]}}, -524288(%r2)
109; CHECK: slbg {{%r[0-5]}}, 0({{%r[1-5]}})
110; CHECK: br %r14
111  %addr = add i64 %base, -524296
112  %bptr = inttoptr i64 %addr to i128 *
113  %aptr = getelementptr i128, i128 *%bptr, i64 -8
114  %a = load i128, i128 *%aptr
115  %b = load i128, i128 *%bptr
116  %sub = sub i128 %a, %b
117  store i128 %sub, i128 *%aptr
118  ret void
119}
120
121; Check that subtractions of spilled values can use SLG and SLBG rather than
122; SLGR and SLBGR.
123define void @f8(i128 *%ptr0) {
124; CHECK-LABEL: f8:
125; CHECK: brasl %r14, foo@PLT
126; CHECK: slg {{%r[0-9]+}}, {{[0-9]+}}(%r15)
127; CHECK: slbg {{%r[0-9]+}}, {{[0-9]+}}(%r15)
128; CHECK: br %r14
129  %ptr1 = getelementptr i128, i128 *%ptr0, i128 2
130  %ptr2 = getelementptr i128, i128 *%ptr0, i128 4
131  %ptr3 = getelementptr i128, i128 *%ptr0, i128 6
132  %ptr4 = getelementptr i128, i128 *%ptr0, i128 8
133  %ptr5 = getelementptr i128, i128 *%ptr0, i128 10
134
135  %val0 = load i128, i128 *%ptr0
136  %val1 = load i128, i128 *%ptr1
137  %val2 = load i128, i128 *%ptr2
138  %val3 = load i128, i128 *%ptr3
139  %val4 = load i128, i128 *%ptr4
140  %val5 = load i128, i128 *%ptr5
141
142  %retptr = call i128 *@foo()
143
144  %ret = load i128, 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  %sub5 = sub i128 %sub4, %val5
151  store i128 %sub5, i128 *%retptr
152
153  ret void
154}
155