xref: /llvm-project/llvm/test/CodeGen/AArch64/i128-math.ll (revision e30a4fc3e20bf5d9cc2f5bfcb61b4eb0e686a193)
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2; RUN: llc < %s -mtriple=aarch64-- | FileCheck %s
3
4declare { i128, i1 } @llvm.uadd.with.overflow.i128(i128, i128)
5declare   i128       @llvm.uadd.sat.i128(i128, i128)
6
7declare { i128, i1 } @llvm.usub.with.overflow.i128(i128, i128)
8declare   i128       @llvm.usub.sat.i128(i128, i128)
9
10declare { i128, i1 } @llvm.umul.with.overflow.i128(i128, i128)
11declare   i128       @llvm.umul.sat.i128(i128, i128)
12
13declare { i128, i1 } @llvm.sadd.with.overflow.i128(i128, i128)
14declare   i128       @llvm.sadd.sat.i128(i128, i128)
15
16declare { i128, i1 } @llvm.ssub.with.overflow.i128(i128, i128)
17declare   i128       @llvm.ssub.sat.i128(i128, i128)
18
19declare { i128, i1 } @llvm.smul.with.overflow.i128(i128, i128)
20declare   i128       @llvm.smul.sat.i128(i128, i128)
21
22define i128 @u128_add(i128 %x, i128 %y) {
23; CHECK-LABEL: u128_add:
24; CHECK:       // %bb.0:
25; CHECK-NEXT:    adds x0, x0, x2
26; CHECK-NEXT:    adc x1, x1, x3
27; CHECK-NEXT:    ret
28  %1 = add i128 %x, %y
29  ret i128 %1
30}
31
32define { i128, i8 } @u128_checked_add(i128 %x, i128 %y) {
33; CHECK-LABEL: u128_checked_add:
34; CHECK:       // %bb.0:
35; CHECK-NEXT:    adds x0, x0, x2
36; CHECK-NEXT:    adcs x1, x1, x3
37; CHECK-NEXT:    cset w8, hs
38; CHECK-NEXT:    eor w2, w8, #0x1
39; CHECK-NEXT:    ret
40  %1 = tail call { i128, i1 } @llvm.uadd.with.overflow.i128(i128 %x, i128 %y)
41  %2 = extractvalue { i128, i1 } %1, 0
42  %3 = extractvalue { i128, i1 } %1, 1
43  %4 = xor i1 %3, true
44  %5 = zext i1 %4 to i8
45  %6 = insertvalue { i128, i8 } undef, i128 %2, 0
46  %7 = insertvalue { i128, i8 } %6, i8 %5, 1
47  ret { i128, i8 } %7
48}
49
50define { i128, i8 } @u128_overflowing_add(i128 %x, i128 %y) {
51; CHECK-LABEL: u128_overflowing_add:
52; CHECK:       // %bb.0:
53; CHECK-NEXT:    adds x0, x0, x2
54; CHECK-NEXT:    adcs x1, x1, x3
55; CHECK-NEXT:    cset w2, hs
56; CHECK-NEXT:    ret
57  %1 = tail call { i128, i1 } @llvm.uadd.with.overflow.i128(i128 %x, i128 %y)
58  %2 = extractvalue { i128, i1 } %1, 0
59  %3 = extractvalue { i128, i1 } %1, 1
60  %4 = zext i1 %3 to i8
61  %5 = insertvalue { i128, i8 } undef, i128 %2, 0
62  %6 = insertvalue { i128, i8 } %5, i8 %4, 1
63  ret { i128, i8 } %6
64}
65
66define i128 @u128_saturating_add(i128 %x, i128 %y) {
67; CHECK-LABEL: u128_saturating_add:
68; CHECK:       // %bb.0:
69; CHECK-NEXT:    adds x8, x0, x2
70; CHECK-NEXT:    adcs x9, x1, x3
71; CHECK-NEXT:    csinv x0, x8, xzr, lo
72; CHECK-NEXT:    csinv x1, x9, xzr, lo
73; CHECK-NEXT:    ret
74  %1 = tail call i128 @llvm.uadd.sat.i128(i128 %x, i128 %y)
75  ret i128 %1
76}
77
78define i128 @u128_sub(i128 %x, i128 %y) {
79; CHECK-LABEL: u128_sub:
80; CHECK:       // %bb.0:
81; CHECK-NEXT:    subs x0, x0, x2
82; CHECK-NEXT:    sbc x1, x1, x3
83; CHECK-NEXT:    ret
84  %1 = sub i128 %x, %y
85  ret i128 %1
86}
87
88define { i128, i8 } @u128_checked_sub(i128 %x, i128 %y) {
89; CHECK-LABEL: u128_checked_sub:
90; CHECK:       // %bb.0:
91; CHECK-NEXT:    subs x0, x0, x2
92; CHECK-NEXT:    sbcs x1, x1, x3
93; CHECK-NEXT:    cset w8, lo
94; CHECK-NEXT:    eor w2, w8, #0x1
95; CHECK-NEXT:    ret
96  %1 = tail call { i128, i1 } @llvm.usub.with.overflow.i128(i128 %x, i128 %y)
97  %2 = extractvalue { i128, i1 } %1, 0
98  %3 = extractvalue { i128, i1 } %1, 1
99  %4 = xor i1 %3, true
100  %5 = zext i1 %4 to i8
101  %6 = insertvalue { i128, i8 } undef, i128 %2, 0
102  %7 = insertvalue { i128, i8 } %6, i8 %5, 1
103  ret { i128, i8 } %7
104}
105
106define { i128, i8 } @u128_overflowing_sub(i128 %x, i128 %y) {
107; CHECK-LABEL: u128_overflowing_sub:
108; CHECK:       // %bb.0:
109; CHECK-NEXT:    subs x0, x0, x2
110; CHECK-NEXT:    sbcs x1, x1, x3
111; CHECK-NEXT:    cset w2, lo
112; CHECK-NEXT:    ret
113  %1 = tail call { i128, i1 } @llvm.usub.with.overflow.i128(i128 %x, i128 %y)
114  %2 = extractvalue { i128, i1 } %1, 0
115  %3 = extractvalue { i128, i1 } %1, 1
116  %4 = zext i1 %3 to i8
117  %5 = insertvalue { i128, i8 } undef, i128 %2, 0
118  %6 = insertvalue { i128, i8 } %5, i8 %4, 1
119  ret { i128, i8 } %6
120}
121
122define i128 @u128_saturating_sub(i128 %x, i128 %y) {
123; CHECK-LABEL: u128_saturating_sub:
124; CHECK:       // %bb.0:
125; CHECK-NEXT:    subs x8, x0, x2
126; CHECK-NEXT:    sbcs x9, x1, x3
127; CHECK-NEXT:    csel x0, xzr, x8, lo
128; CHECK-NEXT:    csel x1, xzr, x9, lo
129; CHECK-NEXT:    ret
130  %1 = tail call i128 @llvm.usub.sat.i128(i128 %x, i128 %y)
131  ret i128 %1
132}
133
134define i128 @i128_add(i128 %x, i128 %y) {
135; CHECK-LABEL: i128_add:
136; CHECK:       // %bb.0:
137; CHECK-NEXT:    adds x0, x0, x2
138; CHECK-NEXT:    adc x1, x1, x3
139; CHECK-NEXT:    ret
140  %1 = add i128 %x, %y
141  ret i128 %1
142}
143
144define { i128, i8 } @i128_checked_add(i128 %x, i128 %y) {
145; CHECK-LABEL: i128_checked_add:
146; CHECK:       // %bb.0:
147; CHECK-NEXT:    adds x0, x0, x2
148; CHECK-NEXT:    adcs x1, x1, x3
149; CHECK-NEXT:    cset w8, vs
150; CHECK-NEXT:    eor w2, w8, #0x1
151; CHECK-NEXT:    ret
152  %1 = tail call { i128, i1 } @llvm.sadd.with.overflow.i128(i128 %x, i128 %y)
153  %2 = extractvalue { i128, i1 } %1, 0
154  %3 = extractvalue { i128, i1 } %1, 1
155  %4 = xor i1 %3, true
156  %5 = zext i1 %4 to i8
157  %6 = insertvalue { i128, i8 } undef, i128 %2, 0
158  %7 = insertvalue { i128, i8 } %6, i8 %5, 1
159  ret { i128, i8 } %7
160}
161
162define { i128, i8 } @i128_overflowing_add(i128 %x, i128 %y) {
163; CHECK-LABEL: i128_overflowing_add:
164; CHECK:       // %bb.0:
165; CHECK-NEXT:    adds x0, x0, x2
166; CHECK-NEXT:    adcs x1, x1, x3
167; CHECK-NEXT:    cset w2, vs
168; CHECK-NEXT:    ret
169  %1 = tail call { i128, i1 } @llvm.sadd.with.overflow.i128(i128 %x, i128 %y)
170  %2 = extractvalue { i128, i1 } %1, 0
171  %3 = extractvalue { i128, i1 } %1, 1
172  %4 = zext i1 %3 to i8
173  %5 = insertvalue { i128, i8 } undef, i128 %2, 0
174  %6 = insertvalue { i128, i8 } %5, i8 %4, 1
175  ret { i128, i8 } %6
176}
177
178define i128 @i128_saturating_add(i128 %x, i128 %y) {
179; CHECK-LABEL: i128_saturating_add:
180; CHECK:       // %bb.0:
181; CHECK-NEXT:    adds x8, x0, x2
182; CHECK-NEXT:    adcs x9, x1, x3
183; CHECK-NEXT:    asr x10, x9, #63
184; CHECK-NEXT:    eor x11, x10, #0x8000000000000000
185; CHECK-NEXT:    csel x0, x10, x8, vs
186; CHECK-NEXT:    csel x1, x11, x9, vs
187; CHECK-NEXT:    ret
188  %1 = tail call i128 @llvm.sadd.sat.i128(i128 %x, i128 %y)
189  ret i128 %1
190}
191
192define i128 @i128_sub(i128 %x, i128 %y) {
193; CHECK-LABEL: i128_sub:
194; CHECK:       // %bb.0:
195; CHECK-NEXT:    subs x0, x0, x2
196; CHECK-NEXT:    sbc x1, x1, x3
197; CHECK-NEXT:    ret
198  %1 = sub i128 %x, %y
199  ret i128 %1
200}
201
202define { i128, i8 } @i128_checked_sub(i128 %x, i128 %y) {
203; CHECK-LABEL: i128_checked_sub:
204; CHECK:       // %bb.0:
205; CHECK-NEXT:    subs x0, x0, x2
206; CHECK-NEXT:    sbcs x1, x1, x3
207; CHECK-NEXT:    cset w8, vs
208; CHECK-NEXT:    eor w2, w8, #0x1
209; CHECK-NEXT:    ret
210  %1 = tail call { i128, i1 } @llvm.ssub.with.overflow.i128(i128 %x, i128 %y)
211  %2 = extractvalue { i128, i1 } %1, 0
212  %3 = extractvalue { i128, i1 } %1, 1
213  %4 = xor i1 %3, true
214  %5 = zext i1 %4 to i8
215  %6 = insertvalue { i128, i8 } undef, i128 %2, 0
216  %7 = insertvalue { i128, i8 } %6, i8 %5, 1
217  ret { i128, i8 } %7
218}
219
220define { i128, i8 } @i128_overflowing_sub(i128 %x, i128 %y) {
221; CHECK-LABEL: i128_overflowing_sub:
222; CHECK:       // %bb.0:
223; CHECK-NEXT:    subs x0, x0, x2
224; CHECK-NEXT:    sbcs x1, x1, x3
225; CHECK-NEXT:    cset w2, vs
226; CHECK-NEXT:    ret
227  %1 = tail call { i128, i1 } @llvm.ssub.with.overflow.i128(i128 %x, i128 %y)
228  %2 = extractvalue { i128, i1 } %1, 0
229  %3 = extractvalue { i128, i1 } %1, 1
230  %4 = zext i1 %3 to i8
231  %5 = insertvalue { i128, i8 } undef, i128 %2, 0
232  %6 = insertvalue { i128, i8 } %5, i8 %4, 1
233  ret { i128, i8 } %6
234}
235
236define i128 @i128_saturating_sub(i128 %x, i128 %y) {
237; CHECK-LABEL: i128_saturating_sub:
238; CHECK:       // %bb.0:
239; CHECK-NEXT:    subs x8, x0, x2
240; CHECK-NEXT:    sbcs x9, x1, x3
241; CHECK-NEXT:    asr x10, x9, #63
242; CHECK-NEXT:    eor x11, x10, #0x8000000000000000
243; CHECK-NEXT:    csel x0, x10, x8, vs
244; CHECK-NEXT:    csel x1, x11, x9, vs
245; CHECK-NEXT:    ret
246  %1 = tail call i128 @llvm.ssub.sat.i128(i128 %x, i128 %y)
247  ret i128 %1
248}
249
250define i128 @u128_mul(i128 %x, i128 %y) {
251; CHECK-LABEL: u128_mul:
252; CHECK:       // %bb.0:
253; CHECK-NEXT:    umulh x8, x0, x2
254; CHECK-NEXT:    madd x8, x0, x3, x8
255; CHECK-NEXT:    mul x0, x0, x2
256; CHECK-NEXT:    madd x1, x1, x2, x8
257; CHECK-NEXT:    ret
258  %1 = mul i128 %x, %y
259  ret i128 %1
260}
261
262define { i128, i8 } @u128_checked_mul(i128 %x, i128 %y) {
263; CHECK-LABEL: u128_checked_mul:
264; CHECK:       // %bb.0:
265; CHECK-NEXT:    mul x9, x3, x0
266; CHECK-NEXT:    cmp x1, #0
267; CHECK-NEXT:    ccmp x3, #0, #4, ne
268; CHECK-NEXT:    umulh x8, x1, x2
269; CHECK-NEXT:    umulh x10, x3, x0
270; CHECK-NEXT:    madd x9, x1, x2, x9
271; CHECK-NEXT:    ccmp xzr, x8, #0, eq
272; CHECK-NEXT:    umulh x11, x0, x2
273; CHECK-NEXT:    ccmp xzr, x10, #0, eq
274; CHECK-NEXT:    mul x0, x0, x2
275; CHECK-NEXT:    cset w8, ne
276; CHECK-NEXT:    adds x1, x11, x9
277; CHECK-NEXT:    csinc w8, w8, wzr, lo
278; CHECK-NEXT:    eor w2, w8, #0x1
279; CHECK-NEXT:    ret
280  %1 = tail call { i128, i1 } @llvm.umul.with.overflow.i128(i128 %x, i128 %y)
281  %2 = extractvalue { i128, i1 } %1, 0
282  %3 = extractvalue { i128, i1 } %1, 1
283  %4 = xor i1 %3, true
284  %5 = zext i1 %4 to i8
285  %6 = insertvalue { i128, i8 } undef, i128 %2, 0
286  %7 = insertvalue { i128, i8 } %6, i8 %5, 1
287  ret { i128, i8 } %7
288}
289
290define { i128, i8 } @u128_overflowing_mul(i128 %x, i128 %y) {
291; CHECK-LABEL: u128_overflowing_mul:
292; CHECK:       // %bb.0:
293; CHECK-NEXT:    mul x9, x3, x0
294; CHECK-NEXT:    cmp x1, #0
295; CHECK-NEXT:    ccmp x3, #0, #4, ne
296; CHECK-NEXT:    umulh x8, x1, x2
297; CHECK-NEXT:    umulh x10, x3, x0
298; CHECK-NEXT:    madd x9, x1, x2, x9
299; CHECK-NEXT:    ccmp xzr, x8, #0, eq
300; CHECK-NEXT:    umulh x11, x0, x2
301; CHECK-NEXT:    ccmp xzr, x10, #0, eq
302; CHECK-NEXT:    mul x0, x0, x2
303; CHECK-NEXT:    cset w8, ne
304; CHECK-NEXT:    adds x1, x11, x9
305; CHECK-NEXT:    csinc w2, w8, wzr, lo
306; CHECK-NEXT:    ret
307  %1 = tail call { i128, i1 } @llvm.umul.with.overflow.i128(i128 %x, i128 %y)
308  %2 = extractvalue { i128, i1 } %1, 0
309  %3 = extractvalue { i128, i1 } %1, 1
310  %4 = zext i1 %3 to i8
311  %5 = insertvalue { i128, i8 } undef, i128 %2, 0
312  %6 = insertvalue { i128, i8 } %5, i8 %4, 1
313  ret { i128, i8 } %6
314}
315
316define i128 @u128_saturating_mul(i128 %x, i128 %y) {
317; CHECK-LABEL: u128_saturating_mul:
318; CHECK:       // %bb.0:
319; CHECK-NEXT:    mul x9, x3, x0
320; CHECK-NEXT:    cmp x1, #0
321; CHECK-NEXT:    ccmp x3, #0, #4, ne
322; CHECK-NEXT:    umulh x8, x1, x2
323; CHECK-NEXT:    umulh x10, x3, x0
324; CHECK-NEXT:    madd x9, x1, x2, x9
325; CHECK-NEXT:    ccmp xzr, x8, #0, eq
326; CHECK-NEXT:    umulh x11, x0, x2
327; CHECK-NEXT:    ccmp xzr, x10, #0, eq
328; CHECK-NEXT:    mul x8, x0, x2
329; CHECK-NEXT:    cset w10, ne
330; CHECK-NEXT:    adds x9, x11, x9
331; CHECK-NEXT:    csinc w10, w10, wzr, lo
332; CHECK-NEXT:    cmp w10, #0
333; CHECK-NEXT:    csinv x0, x8, xzr, eq
334; CHECK-NEXT:    csinv x1, x9, xzr, eq
335; CHECK-NEXT:    ret
336  %1 = tail call { i128, i1 } @llvm.umul.with.overflow.i128(i128 %x, i128 %y)
337  %2 = extractvalue { i128, i1 } %1, 0
338  %3 = extractvalue { i128, i1 } %1, 1
339  %4 = select i1 %3, i128 -1, i128 %2
340  ret i128 %4
341}
342
343define i128 @i128_mul(i128 %x, i128 %y) {
344; CHECK-LABEL: i128_mul:
345; CHECK:       // %bb.0:
346; CHECK-NEXT:    umulh x8, x0, x2
347; CHECK-NEXT:    madd x8, x0, x3, x8
348; CHECK-NEXT:    mul x0, x0, x2
349; CHECK-NEXT:    madd x1, x1, x2, x8
350; CHECK-NEXT:    ret
351  %1 = mul i128 %x, %y
352  ret i128 %1
353}
354
355define { i128, i8 } @i128_checked_mul(i128 %x, i128 %y) {
356; CHECK-LABEL: i128_checked_mul:
357; CHECK:       // %bb.0:
358; CHECK-NEXT:    asr x9, x1, #63
359; CHECK-NEXT:    umulh x10, x0, x2
360; CHECK-NEXT:    asr x13, x3, #63
361; CHECK-NEXT:    mul x11, x1, x2
362; CHECK-NEXT:    umulh x8, x1, x2
363; CHECK-NEXT:    mul x9, x9, x2
364; CHECK-NEXT:    adds x10, x11, x10
365; CHECK-NEXT:    mul x14, x0, x3
366; CHECK-NEXT:    umulh x12, x0, x3
367; CHECK-NEXT:    adc x9, x8, x9
368; CHECK-NEXT:    mul x13, x0, x13
369; CHECK-NEXT:    adds x8, x14, x10
370; CHECK-NEXT:    mul x15, x1, x3
371; CHECK-NEXT:    smulh x10, x1, x3
372; CHECK-NEXT:    mov x1, x8
373; CHECK-NEXT:    adc x11, x12, x13
374; CHECK-NEXT:    asr x12, x9, #63
375; CHECK-NEXT:    asr x13, x11, #63
376; CHECK-NEXT:    adds x9, x9, x11
377; CHECK-NEXT:    asr x11, x8, #63
378; CHECK-NEXT:    mul x0, x0, x2
379; CHECK-NEXT:    adc x12, x12, x13
380; CHECK-NEXT:    adds x9, x15, x9
381; CHECK-NEXT:    adc x10, x10, x12
382; CHECK-NEXT:    cmp x9, x11
383; CHECK-NEXT:    ccmp x10, x11, #0, eq
384; CHECK-NEXT:    cset w2, eq
385; CHECK-NEXT:    ret
386  %1 = tail call { i128, i1 } @llvm.smul.with.overflow.i128(i128 %x, i128 %y)
387  %2 = extractvalue { i128, i1 } %1, 0
388  %3 = extractvalue { i128, i1 } %1, 1
389  %4 = xor i1 %3, true
390  %5 = zext i1 %4 to i8
391  %6 = insertvalue { i128, i8 } undef, i128 %2, 0
392  %7 = insertvalue { i128, i8 } %6, i8 %5, 1
393  ret { i128, i8 } %7
394}
395
396define { i128, i8 } @i128_overflowing_mul(i128 %x, i128 %y) {
397; CHECK-LABEL: i128_overflowing_mul:
398; CHECK:       // %bb.0:
399; CHECK-NEXT:    asr x9, x1, #63
400; CHECK-NEXT:    umulh x10, x0, x2
401; CHECK-NEXT:    asr x13, x3, #63
402; CHECK-NEXT:    mul x11, x1, x2
403; CHECK-NEXT:    umulh x8, x1, x2
404; CHECK-NEXT:    mul x9, x9, x2
405; CHECK-NEXT:    adds x10, x11, x10
406; CHECK-NEXT:    mul x14, x0, x3
407; CHECK-NEXT:    umulh x12, x0, x3
408; CHECK-NEXT:    adc x9, x8, x9
409; CHECK-NEXT:    mul x13, x0, x13
410; CHECK-NEXT:    adds x8, x14, x10
411; CHECK-NEXT:    mul x15, x1, x3
412; CHECK-NEXT:    smulh x10, x1, x3
413; CHECK-NEXT:    mov x1, x8
414; CHECK-NEXT:    adc x11, x12, x13
415; CHECK-NEXT:    asr x12, x9, #63
416; CHECK-NEXT:    asr x13, x11, #63
417; CHECK-NEXT:    adds x9, x9, x11
418; CHECK-NEXT:    asr x11, x8, #63
419; CHECK-NEXT:    mul x0, x0, x2
420; CHECK-NEXT:    adc x12, x12, x13
421; CHECK-NEXT:    adds x9, x15, x9
422; CHECK-NEXT:    adc x10, x10, x12
423; CHECK-NEXT:    cmp x9, x11
424; CHECK-NEXT:    ccmp x10, x11, #0, eq
425; CHECK-NEXT:    cset w2, ne
426; CHECK-NEXT:    ret
427  %1 = tail call { i128, i1 } @llvm.smul.with.overflow.i128(i128 %x, i128 %y)
428  %2 = extractvalue { i128, i1 } %1, 0
429  %3 = extractvalue { i128, i1 } %1, 1
430  %4 = zext i1 %3 to i8
431  %5 = insertvalue { i128, i8 } undef, i128 %2, 0
432  %6 = insertvalue { i128, i8 } %5, i8 %4, 1
433  ret { i128, i8 } %6
434}
435
436define i128 @i128_saturating_mul(i128 %x, i128 %y) {
437; CHECK-LABEL: i128_saturating_mul:
438; CHECK:       // %bb.0:
439; CHECK-NEXT:    asr x9, x1, #63
440; CHECK-NEXT:    umulh x10, x0, x2
441; CHECK-NEXT:    asr x13, x3, #63
442; CHECK-NEXT:    mul x11, x1, x2
443; CHECK-NEXT:    umulh x8, x1, x2
444; CHECK-NEXT:    mul x9, x9, x2
445; CHECK-NEXT:    adds x10, x11, x10
446; CHECK-NEXT:    mul x14, x0, x3
447; CHECK-NEXT:    umulh x12, x0, x3
448; CHECK-NEXT:    adc x8, x8, x9
449; CHECK-NEXT:    mul x13, x0, x13
450; CHECK-NEXT:    adds x9, x14, x10
451; CHECK-NEXT:    mul x11, x1, x3
452; CHECK-NEXT:    adc x10, x12, x13
453; CHECK-NEXT:    smulh x12, x1, x3
454; CHECK-NEXT:    asr x13, x8, #63
455; CHECK-NEXT:    asr x14, x10, #63
456; CHECK-NEXT:    adds x8, x8, x10
457; CHECK-NEXT:    adc x10, x13, x14
458; CHECK-NEXT:    adds x8, x11, x8
459; CHECK-NEXT:    asr x11, x9, #63
460; CHECK-NEXT:    mul x13, x0, x2
461; CHECK-NEXT:    adc x10, x12, x10
462; CHECK-NEXT:    eor x12, x3, x1
463; CHECK-NEXT:    eor x8, x8, x11
464; CHECK-NEXT:    eor x10, x10, x11
465; CHECK-NEXT:    asr x11, x12, #63
466; CHECK-NEXT:    orr x8, x8, x10
467; CHECK-NEXT:    eor x10, x11, #0x7fffffffffffffff
468; CHECK-NEXT:    cmp x8, #0
469; CHECK-NEXT:    csinv x0, x13, x11, eq
470; CHECK-NEXT:    csel x1, x10, x9, ne
471; CHECK-NEXT:    ret
472  %1 = tail call { i128, i1 } @llvm.smul.with.overflow.i128(i128 %x, i128 %y)
473  %2 = extractvalue { i128, i1 } %1, 0
474  %3 = extractvalue { i128, i1 } %1, 1
475  %4 = xor i128 %y, %x
476  %5 = icmp sgt i128 %4, -1
477  %6 = select i1 %5, i128 170141183460469231731687303715884105727, i128 -170141183460469231731687303715884105728
478  %7 = select i1 %3, i128 %6, i128 %2
479  ret i128 %7
480}
481
482define { i128, i1 } @saddo_not_1(i128 %x) nounwind {
483; CHECK-LABEL: saddo_not_1:
484; CHECK:       // %bb.0:
485; CHECK-NEXT:    negs x0, x0
486; CHECK-NEXT:    ngcs x1, x1
487; CHECK-NEXT:    cset w2, vs
488; CHECK-NEXT:    ret
489  %not = xor i128 %x, -1
490  %r = call { i128, i1 } @llvm.sadd.with.overflow.i128(i128 %not, i128 1)
491  ret { i128, i1 } %r
492}
493
494define { i128, i1 } @saddo_carry_not_1(i128 %x) nounwind {
495; CHECK-LABEL: saddo_carry_not_1:
496; CHECK:       // %bb.0:
497; CHECK-NEXT:    mov w8, #1 // =0x1
498; CHECK-NEXT:    negs x0, x0
499; CHECK-NEXT:    sbcs x1, x8, x1
500; CHECK-NEXT:    cset w2, vs
501; CHECK-NEXT:    ret
502  %not = xor i128 %x, -1
503  %r = call { i128, i1 } @llvm.sadd.with.overflow.i128(i128 %not, i128 u0x10000000000000001)
504  ret { i128, i1 } %r
505}
506