xref: /llvm-project/llvm/test/CodeGen/SystemZ/int-mul-13.ll (revision a65ccc1b9fe740c9f65d9cf2b627de50278aad56)
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 3
2; Test high-part i64->i128 multiplications on z13.
3;
4; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z13 | FileCheck %s
5
6; Check zero-extended multiplication in which only the high part is used.
7define i64 @f1(i64 %dummy, i64 %a, i64 %b) {
8; CHECK-LABEL: f1:
9; CHECK:       # %bb.0:
10; CHECK-NEXT:    # kill: def $r3d killed $r3d def $r2q
11; CHECK-NEXT:    mlgr %r2, %r4
12; CHECK-NEXT:    # kill: def $r2d killed $r2d killed $r2q
13; CHECK-NEXT:    br %r14
14  %ax = zext i64 %a to i128
15  %bx = zext i64 %b to i128
16  %mulx = mul i128 %ax, %bx
17  %highx = lshr i128 %mulx, 64
18  %high = trunc i128 %highx to i64
19  ret i64 %high
20}
21
22; Check sign-extended multiplication in which only the high part is used.
23; This needs a rather convoluted sequence.
24define i64 @f2(i64 %dummy, i64 %a, i64 %b) {
25; CHECK-LABEL: f2:
26; CHECK:       # %bb.0:
27; CHECK-NEXT:    srag %r1, %r4, 63
28; CHECK-NEXT:    # kill: def $r3d killed $r3d def $r2q
29; CHECK-NEXT:    srag %r0, %r3, 63
30; CHECK-NEXT:    ngr %r1, %r3
31; CHECK-NEXT:    mlgr %r2, %r4
32; CHECK-NEXT:    ngr %r0, %r4
33; CHECK-NEXT:    agr %r0, %r1
34; CHECK-NEXT:    sgr %r2, %r0
35; CHECK-NEXT:    br %r14
36  %ax = sext i64 %a to i128
37  %bx = sext i64 %b to i128
38  %mulx = mul i128 %ax, %bx
39  %highx = lshr i128 %mulx, 64
40  %high = trunc i128 %highx to i64
41  ret i64 %high
42}
43
44; Check zero-extended multiplication in which only part of the high half
45; is used.
46define i64 @f3(i64 %dummy, i64 %a, i64 %b) {
47; CHECK-LABEL: f3:
48; CHECK:       # %bb.0:
49; CHECK-NEXT:    # kill: def $r3d killed $r3d def $r2q
50; CHECK-NEXT:    mlgr %r2, %r4
51; CHECK-NEXT:    srlg %r2, %r2, 3
52; CHECK-NEXT:    br %r14
53  %ax = zext i64 %a to i128
54  %bx = zext i64 %b to i128
55  %mulx = mul i128 %ax, %bx
56  %highx = lshr i128 %mulx, 67
57  %high = trunc i128 %highx to i64
58  ret i64 %high
59}
60
61; Check zero-extended multiplication in which the result is split into
62; high and low halves.
63define i64 @f4(i64 %dummy, i64 %a, i64 %b) {
64; CHECK-LABEL: f4:
65; CHECK:       # %bb.0:
66; CHECK-NEXT:    # kill: def $r3d killed $r3d def $r2q
67; CHECK-NEXT:    mlgr %r2, %r4
68; CHECK-NEXT:    ogr %r2, %r3
69; CHECK-NEXT:    br %r14
70  %ax = zext i64 %a to i128
71  %bx = zext i64 %b to i128
72  %mulx = mul i128 %ax, %bx
73  %highx = lshr i128 %mulx, 64
74  %high = trunc i128 %highx to i64
75  %low = trunc i128 %mulx to i64
76  %or = or i64 %high, %low
77  ret i64 %or
78}
79
80; Check division by a constant, which should use multiplication instead.
81define i64 @f5(i64 %dummy, i64 %a) {
82; CHECK-LABEL: f5:
83; CHECK:       # %bb.0:
84; CHECK-NEXT:    llihf %r0, 1782028570
85; CHECK-NEXT:    oilf %r0, 598650223
86; CHECK-NEXT:    # kill: def $r3d killed $r3d def $r2q
87; CHECK-NEXT:    mlgr %r2, %r0
88; CHECK-NEXT:    srlg %r2, %r2, 9
89; CHECK-NEXT:    br %r14
90  %res = udiv i64 %a, 1234
91  ret i64 %res
92}
93
94; Check MLG with no displacement.
95define i64 @f6(i64 %dummy, i64 %a, ptr %src) {
96; CHECK-LABEL: f6:
97; CHECK:       # %bb.0:
98; CHECK-NEXT:    # kill: def $r3d killed $r3d def $r2q
99; CHECK-NEXT:    mlg %r2, 0(%r4)
100; CHECK-NEXT:    # kill: def $r2d killed $r2d killed $r2q
101; CHECK-NEXT:    br %r14
102  %b = load i64, ptr %src
103  %ax = zext i64 %a to i128
104  %bx = zext i64 %b to i128
105  %mulx = mul i128 %ax, %bx
106  %highx = lshr i128 %mulx, 64
107  %high = trunc i128 %highx to i64
108  ret i64 %high
109}
110
111; Check the high end of the aligned MLG range.
112define i64 @f7(i64 %dummy, i64 %a, ptr %src) {
113; CHECK-LABEL: f7:
114; CHECK:       # %bb.0:
115; CHECK-NEXT:    # kill: def $r3d killed $r3d def $r2q
116; CHECK-NEXT:    mlg %r2, 524280(%r4)
117; CHECK-NEXT:    # kill: def $r2d killed $r2d killed $r2q
118; CHECK-NEXT:    br %r14
119  %ptr = getelementptr i64, ptr %src, i64 65535
120  %b = load i64, ptr %ptr
121  %ax = zext i64 %a to i128
122  %bx = zext i64 %b to i128
123  %mulx = mul i128 %ax, %bx
124  %highx = lshr i128 %mulx, 64
125  %high = trunc i128 %highx to i64
126  ret i64 %high
127}
128
129; Check the next doubleword up, which requires separate address logic.
130; Other sequences besides this one would be OK.
131define i64 @f8(i64 %dummy, i64 %a, ptr %src) {
132; CHECK-LABEL: f8:
133; CHECK:       # %bb.0:
134; CHECK-NEXT:    agfi %r4, 524288
135; CHECK-NEXT:    # kill: def $r3d killed $r3d def $r2q
136; CHECK-NEXT:    mlg %r2, 0(%r4)
137; CHECK-NEXT:    # kill: def $r2d killed $r2d killed $r2q
138; CHECK-NEXT:    br %r14
139  %ptr = getelementptr i64, ptr %src, i64 65536
140  %b = load i64, ptr %ptr
141  %ax = zext i64 %a to i128
142  %bx = zext i64 %b to i128
143  %mulx = mul i128 %ax, %bx
144  %highx = lshr i128 %mulx, 64
145  %high = trunc i128 %highx to i64
146  ret i64 %high
147}
148
149; Check the high end of the negative aligned MLG range.
150define i64 @f9(i64 %dummy, i64 %a, ptr %src) {
151; CHECK-LABEL: f9:
152; CHECK:       # %bb.0:
153; CHECK-NEXT:    # kill: def $r3d killed $r3d def $r2q
154; CHECK-NEXT:    mlg %r2, -8(%r4)
155; CHECK-NEXT:    # kill: def $r2d killed $r2d killed $r2q
156; CHECK-NEXT:    br %r14
157  %ptr = getelementptr i64, ptr %src, i64 -1
158  %b = load i64, ptr %ptr
159  %ax = zext i64 %a to i128
160  %bx = zext i64 %b to i128
161  %mulx = mul i128 %ax, %bx
162  %highx = lshr i128 %mulx, 64
163  %high = trunc i128 %highx to i64
164  ret i64 %high
165}
166
167; Check the low end of the MLG range.
168define i64 @f10(i64 %dummy, i64 %a, ptr %src) {
169; CHECK-LABEL: f10:
170; CHECK:       # %bb.0:
171; CHECK-NEXT:    # kill: def $r3d killed $r3d def $r2q
172; CHECK-NEXT:    mlg %r2, -524288(%r4)
173; CHECK-NEXT:    # kill: def $r2d killed $r2d killed $r2q
174; CHECK-NEXT:    br %r14
175  %ptr = getelementptr i64, ptr %src, i64 -65536
176  %b = load i64, ptr %ptr
177  %ax = zext i64 %a to i128
178  %bx = zext i64 %b to i128
179  %mulx = mul i128 %ax, %bx
180  %highx = lshr i128 %mulx, 64
181  %high = trunc i128 %highx to i64
182  ret i64 %high
183}
184
185; Check the next doubleword down, which needs separate address logic.
186; Other sequences besides this one would be OK.
187define i64 @f11(ptr %dest, i64 %a, ptr %src) {
188; CHECK-LABEL: f11:
189; CHECK:       # %bb.0:
190; CHECK-NEXT:    agfi %r4, -524296
191; CHECK-NEXT:    # kill: def $r3d killed $r3d def $r2q
192; CHECK-NEXT:    mlg %r2, 0(%r4)
193; CHECK-NEXT:    # kill: def $r2d killed $r2d killed $r2q
194; CHECK-NEXT:    br %r14
195  %ptr = getelementptr i64, ptr %src, i64 -65537
196  %b = load i64, ptr %ptr
197  %ax = zext i64 %a to i128
198  %bx = zext i64 %b to i128
199  %mulx = mul i128 %ax, %bx
200  %highx = lshr i128 %mulx, 64
201  %high = trunc i128 %highx to i64
202  ret i64 %high
203}
204
205; Check that MLG allows an index.
206define i64 @f12(ptr %dest, i64 %a, i64 %src, i64 %index) {
207; CHECK-LABEL: f12:
208; CHECK:       # %bb.0:
209; CHECK-NEXT:    # kill: def $r3d killed $r3d def $r2q
210; CHECK-NEXT:    mlg %r2, 524287(%r5,%r4)
211; CHECK-NEXT:    # kill: def $r2d killed $r2d killed $r2q
212; CHECK-NEXT:    br %r14
213  %add1 = add i64 %src, %index
214  %add2 = add i64 %add1, 524287
215  %ptr = inttoptr i64 %add2 to ptr
216  %b = load i64, ptr %ptr
217  %ax = zext i64 %a to i128
218  %bx = zext i64 %b to i128
219  %mulx = mul i128 %ax, %bx
220  %highx = lshr i128 %mulx, 64
221  %high = trunc i128 %highx to i64
222  ret i64 %high
223}
224
225