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