1; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers | FileCheck %s
2
3; Test that basic 128-bit integer operations assemble as expected.
4
5target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
6target triple = "wasm32-unknown-unknown"
7
8declare i128 @llvm.ctlz.i128(i128, i1)
9declare i128 @llvm.cttz.i128(i128, i1)
10declare i128 @llvm.ctpop.i128(i128)
11
12; CHECK-LABEL: add128:
13; CHECK-NEXT: .functype add128 (i32, i64, i64, i64, i64) -> (){{$}}
14; CHECK-NOT:  .result
15; CHECK:      i64.add
16; CHECK:      i64.store
17; CHECK:      i64.add
18; CHECK:      i64.store
19; CHECK-NEXT: return{{$}}
20define i128 @add128(i128 %x, i128 %y) {
21  %a = add i128 %x, %y
22  ret i128 %a
23}
24
25; CHECK-LABEL: sub128:
26; CHECK-NEXT: .functype sub128 (i32, i64, i64, i64, i64) -> (){{$}}
27; CHECK:      i64.sub
28; CHECK:      i64.store
29; CHECK:      i64.sub
30; CHECK:      i64.store
31; CHECK-NEXT: return{{$}}
32define i128 @sub128(i128 %x, i128 %y) {
33  %a = sub i128 %x, %y
34  ret i128 %a
35}
36
37; CHECK-LABEL: mul128:
38; CHECK-NEXT: .functype mul128 (i32, i64, i64, i64, i64) -> (){{$}}
39; CHECK: call __multi3, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}{{$}}
40; CHECK: return{{$}}
41define i128 @mul128(i128 %x, i128 %y) {
42  %a = mul i128 %x, %y
43  ret i128 %a
44}
45
46; CHECK-LABEL: sdiv128:
47; CHECK-NEXT: .functype sdiv128 (i32, i64, i64, i64, i64) -> (){{$}}
48; CHECK: call __divti3, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}{{$}}
49; CHECK: return{{$}}
50define i128 @sdiv128(i128 %x, i128 %y) {
51  %a = sdiv i128 %x, %y
52  ret i128 %a
53}
54
55; CHECK-LABEL: udiv128:
56; CHECK-NEXT: .functype udiv128 (i32, i64, i64, i64, i64) -> (){{$}}
57; CHECK: call __udivti3, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}{{$}}
58; CHECK: return{{$}}
59define i128 @udiv128(i128 %x, i128 %y) {
60  %a = udiv i128 %x, %y
61  ret i128 %a
62}
63
64; CHECK-LABEL: srem128:
65; CHECK-NEXT: .functype srem128 (i32, i64, i64, i64, i64) -> (){{$}}
66; CHECK: call __modti3, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}{{$}}
67; CHECK: return{{$}}
68define i128 @srem128(i128 %x, i128 %y) {
69  %a = srem i128 %x, %y
70  ret i128 %a
71}
72
73; CHECK-LABEL: urem128:
74; CHECK-NEXT: .functype urem128 (i32, i64, i64, i64, i64) -> (){{$}}
75; CHECK: call __umodti3, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}{{$}}
76; CHECK: return{{$}}
77define i128 @urem128(i128 %x, i128 %y) {
78  %a = urem i128 %x, %y
79  ret i128 %a
80}
81
82; CHECK-LABEL: and128:
83; CHECK-NEXT: .functype and128 (i32, i64, i64, i64, i64) -> (){{$}}
84; CHECK-NOT:  .result
85; CHECK:      i64.and
86; CHECK:      i64.store
87; CHECK:      i64.and
88; CHECK:      i64.store
89; CHECK-NEXT: return{{$}}
90define i128 @and128(i128 %x, i128 %y) {
91  %a = and i128 %x, %y
92  ret i128 %a
93}
94
95; CHECK-LABEL: or128:
96; CHECK-NEXT: .functype or128 (i32, i64, i64, i64, i64) -> (){{$}}
97; CHECK:      i64.or
98; CHECK:      i64.store
99; CHECK:      i64.or
100; CHECK:      i64.store
101; CHECK-NEXT: return{{$}}
102define i128 @or128(i128 %x, i128 %y) {
103  %a = or i128 %x, %y
104  ret i128 %a
105}
106
107; CHECK-LABEL: xor128:
108; CHECK-NEXT: .functype xor128 (i32, i64, i64, i64, i64) -> (){{$}}
109; CHECK:      i64.xor
110; CHECK:      i64.store
111; CHECK:      i64.xor
112; CHECK:      i64.store
113; CHECK-NEXT: return{{$}}
114define i128 @xor128(i128 %x, i128 %y) {
115  %a = xor i128 %x, %y
116  ret i128 %a
117}
118
119; CHECK-LABEL: shl128:
120; CHECK-NEXT: .functype shl128 (i32, i64, i64, i64, i64) -> (){{$}}
121; CHECK: call __ashlti3, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}{{$}}
122; CHECK: return{{$}}
123define i128 @shl128(i128 %x, i128 %y) {
124  %a = shl i128 %x, %y
125  ret i128 %a
126}
127
128; CHECK-LABEL: shr128:
129; CHECK-NEXT: .functype shr128 (i32, i64, i64, i64, i64) -> (){{$}}
130; CHECK: call __lshrti3, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}{{$}}
131; CHECK: return{{$}}
132define i128 @shr128(i128 %x, i128 %y) {
133  %a = lshr i128 %x, %y
134  ret i128 %a
135}
136
137; CHECK-LABEL: sar128:
138; CHECK-NEXT: .functype sar128 (i32, i64, i64, i64, i64) -> (){{$}}
139; CHECK: call __ashrti3, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}{{$}}
140; CHECK: return{{$}}
141define i128 @sar128(i128 %x, i128 %y) {
142  %a = ashr i128 %x, %y
143  ret i128 %a
144}
145
146; CHECK-LABEL: clz128:
147; CHECK-NEXT: .functype clz128 (i32, i64, i64) -> (){{$}}
148; CHECK-NOT:  .result
149; CHECK:      i64.clz
150; CHECK:      i64.clz
151; CHECK:      return{{$}}
152define i128 @clz128(i128 %x) {
153  %a = call i128 @llvm.ctlz.i128(i128 %x, i1 false)
154  ret i128 %a
155}
156
157; CHECK-LABEL: clz128_zero_undef:
158; CHECK-NEXT: .functype clz128_zero_undef (i32, i64, i64) -> (){{$}}
159; CHECK:      i64.clz
160; CHECK:      i64.clz
161; CHECK:      return{{$}}
162define i128 @clz128_zero_undef(i128 %x) {
163  %a = call i128 @llvm.ctlz.i128(i128 %x, i1 true)
164  ret i128 %a
165}
166
167; CHECK-LABEL: ctz128:
168; CHECK-NEXT: .functype ctz128 (i32, i64, i64) -> (){{$}}
169; CHECK:      i64.ctz
170; CHECK:      i64.ctz
171; CHECK:      return{{$}}
172define i128 @ctz128(i128 %x) {
173  %a = call i128 @llvm.cttz.i128(i128 %x, i1 false)
174  ret i128 %a
175}
176
177; CHECK-LABEL: ctz128_zero_undef:
178; CHECK-NEXT: .functype ctz128_zero_undef (i32, i64, i64) -> (){{$}}
179; CHECK:      i64.ctz
180; CHECK:      i64.ctz
181; CHECK:      return{{$}}
182define i128 @ctz128_zero_undef(i128 %x) {
183  %a = call i128 @llvm.cttz.i128(i128 %x, i1 true)
184  ret i128 %a
185}
186
187; CHECK-LABEL: popcnt128:
188; CHECK-NEXT: .functype popcnt128 (i32, i64, i64) -> (){{$}}
189; CHECK:      i64.popcnt
190; CHECK:      i64.popcnt
191; CHECK:      return{{$}}
192define i128 @popcnt128(i128 %x) {
193  %a = call i128 @llvm.ctpop.i128(i128 %x)
194  ret i128 %a
195}
196
197; CHECK-LABEL: eqz128:
198; CHECK-NEXT: .functype eqz128 (i64, i64) -> (i32){{$}}
199; CHECK:     i64.or
200; CHECK:     i64.eqz
201; CHECK:     return $
202define i32 @eqz128(i128 %x) {
203  %a = icmp eq i128 %x, 0
204  %b = zext i1 %a to i32
205  ret i32 %b
206}
207
208; CHECK-LABEL: rotl:
209; CHECK-NEXT: .functype rotl (i32, i64, i64, i64, i64) -> (){{$}}
210; CHECK: call __ashlti3, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}{{$}}
211; CHECK: call __lshrti3, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}{{$}}
212; CHECK: return{{$}}
213define i128 @rotl(i128 %x, i128 %y) {
214  %z = sub i128 128, %y
215  %b = shl i128 %x, %y
216  %c = lshr i128 %x, %z
217  %d = or i128 %b, %c
218  ret i128 %d
219}
220
221; CHECK-LABEL: masked_rotl:
222; CHECK-NEXT: .functype masked_rotl (i32, i64, i64, i64, i64) -> (){{$}}
223; CHECK: call __ashlti3, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}{{$}}
224; CHECK: call __lshrti3, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}{{$}}
225; CHECK: return{{$}}
226define i128 @masked_rotl(i128 %x, i128 %y) {
227  %a = and i128 %y, 127
228  %z = sub i128 128, %a
229  %b = shl i128 %x, %a
230  %c = lshr i128 %x, %z
231  %d = or i128 %b, %c
232  ret i128 %d
233}
234
235; CHECK-LABEL: rotr:
236; CHECK-NEXT: .functype rotr (i32, i64, i64, i64, i64) -> (){{$}}
237; CHECK: call __lshrti3, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}{{$}}
238; CHECK: call __ashlti3, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}{{$}}
239; CHECK: return{{$}}
240define i128 @rotr(i128 %x, i128 %y) {
241  %z = sub i128 128, %y
242  %b = lshr i128 %x, %y
243  %c = shl i128 %x, %z
244  %d = or i128 %b, %c
245  ret i128 %d
246}
247
248; CHECK-LABEL: masked_rotr:
249; CHECK-NEXT: .functype masked_rotr (i32, i64, i64, i64, i64) -> (){{$}}
250; CHECK: call __lshrti3, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}{{$}}
251; CHECK: call __ashlti3, ${{.+}}, ${{.+}}, ${{.+}}, ${{.+}}{{$}}
252; CHECK: return{{$}}
253define i128 @masked_rotr(i128 %x, i128 %y) {
254  %a = and i128 %y, 127
255  %z = sub i128 128, %a
256  %b = lshr i128 %x, %a
257  %c = shl i128 %x, %z
258  %d = or i128 %b, %c
259  ret i128 %d
260}
261