1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2; RUN: llc < %s -mtriple=x86_64-unknown | FileCheck %s
3
4; PR31754
5;
6; #include <x86intrin.h>
7; using u64 = unsigned long long;
8;
9; template<u64 K>
10; void test(u64& alo, u64& ahi)
11; {
12;     u64 blo = K;
13;     u64 bhi = 0;
14;     bool cf = (alo += blo) < blo;
15;     _addcarry_u64(cf, ahi, bhi, &ahi);
16; }
17;
18; template void test<0ull>(u64&, u64&);
19; template void test<1ull>(u64&, u64&);
20; template void test<2ull>(u64&, u64&);
21; template void test<3ull>(u64&, u64&);
22; template void test<4ull>(u64&, u64&);
23; template void test<0x7fffffffffffffffull>(u64&, u64&);
24; template void test<0x8000000000000000ull>(u64&, u64&);
25; template void test<0x8000000000000001ull>(u64&, u64&);
26; template void test<0xffffffff80000000ull>(u64&, u64&);
27; template void test<0xfffffffffffffffdull>(u64&, u64&);
28; template void test<0xfffffffffffffffeull>(u64&, u64&);
29; template void test<0xffffffffffffffffull>(u64&, u64&);
30
31define void @test_0(i64*, i64*) {
32; CHECK-LABEL: test_0:
33; CHECK:       # %bb.0:
34; CHECK-NEXT:    retq
35  %3 = load i64, i64* %1, align 8
36  %4 = tail call { i8, i64 } @llvm.x86.addcarry.64(i8 0, i64 %3, i64 0)
37  %5 = extractvalue { i8, i64 } %4, 1
38  store i64 %5, i64* %1, align 8
39  ret void
40}
41
42define void @test_1(i64*, i64*) {
43; CHECK-LABEL: test_1:
44; CHECK:       # %bb.0:
45; CHECK-NEXT:    addq $1, (%rdi)
46; CHECK-NEXT:    adcq $0, (%rsi)
47; CHECK-NEXT:    retq
48  %3 = load i64, i64* %0, align 8
49  %4 = add i64 %3, 1
50  store i64 %4, i64* %0, align 8
51  %5 = icmp eq i64 %4, 0
52  %6 = zext i1 %5 to i8
53  %7 = load i64, i64* %1, align 8
54  %8 = tail call { i8, i64 } @llvm.x86.addcarry.64(i8 %6, i64 %7, i64 0)
55  %9 = extractvalue { i8, i64 } %8, 1
56  store i64 %9, i64* %1, align 8
57  ret void
58}
59
60define void @test_2(i64*, i64*) {
61; CHECK-LABEL: test_2:
62; CHECK:       # %bb.0:
63; CHECK-NEXT:    addq $2, (%rdi)
64; CHECK-NEXT:    adcq $0, (%rsi)
65; CHECK-NEXT:    retq
66  %3 = load i64, i64* %0, align 8
67  %4 = add i64 %3, 2
68  store i64 %4, i64* %0, align 8
69  %5 = icmp ult i64 %4, 2
70  %6 = zext i1 %5 to i8
71  %7 = load i64, i64* %1, align 8
72  %8 = tail call { i8, i64 } @llvm.x86.addcarry.64(i8 %6, i64 %7, i64 0)
73  %9 = extractvalue { i8, i64 } %8, 1
74  store i64 %9, i64* %1, align 8
75  ret void
76}
77
78define void @test_3(i64*, i64*) {
79; CHECK-LABEL: test_3:
80; CHECK:       # %bb.0:
81; CHECK-NEXT:    addq $3, (%rdi)
82; CHECK-NEXT:    adcq $0, (%rsi)
83; CHECK-NEXT:    retq
84  %3 = load i64, i64* %0, align 8
85  %4 = add i64 %3, 3
86  store i64 %4, i64* %0, align 8
87  %5 = icmp ult i64 %4, 3
88  %6 = zext i1 %5 to i8
89  %7 = load i64, i64* %1, align 8
90  %8 = tail call { i8, i64 } @llvm.x86.addcarry.64(i8 %6, i64 %7, i64 0)
91  %9 = extractvalue { i8, i64 } %8, 1
92  store i64 %9, i64* %1, align 8
93  ret void
94}
95
96define void @test_4(i64*, i64*) {
97; CHECK-LABEL: test_4:
98; CHECK:       # %bb.0:
99; CHECK-NEXT:    addq $4, (%rdi)
100; CHECK-NEXT:    adcq $0, (%rsi)
101; CHECK-NEXT:    retq
102  %3 = load i64, i64* %0, align 8
103  %4 = add i64 %3, 4
104  store i64 %4, i64* %0, align 8
105  %5 = icmp ult i64 %4, 4
106  %6 = zext i1 %5 to i8
107  %7 = load i64, i64* %1, align 8
108  %8 = tail call { i8, i64 } @llvm.x86.addcarry.64(i8 %6, i64 %7, i64 0)
109  %9 = extractvalue { i8, i64 } %8, 1
110  store i64 %9, i64* %1, align 8
111  ret void
112}
113
114define void @test_9223372036854775807(i64*, i64*) {
115; CHECK-LABEL: test_9223372036854775807:
116; CHECK:       # %bb.0:
117; CHECK-NEXT:    movabsq $9223372036854775807, %rax # imm = 0x7FFFFFFFFFFFFFFF
118; CHECK-NEXT:    addq %rax, (%rdi)
119; CHECK-NEXT:    adcq $0, (%rsi)
120; CHECK-NEXT:    retq
121  %3 = load i64, i64* %0, align 8
122  %4 = add i64 %3, 9223372036854775807
123  store i64 %4, i64* %0, align 8
124  %5 = icmp ult i64 %4, 9223372036854775807
125  %6 = zext i1 %5 to i8
126  %7 = load i64, i64* %1, align 8
127  %8 = tail call { i8, i64 } @llvm.x86.addcarry.64(i8 %6, i64 %7, i64 0)
128  %9 = extractvalue { i8, i64 } %8, 1
129  store i64 %9, i64* %1, align 8
130  ret void
131}
132
133define void @test_9223372036854775808(i64*, i64*) {
134; CHECK-LABEL: test_9223372036854775808:
135; CHECK:       # %bb.0:
136; CHECK-NEXT:    movq (%rdi), %rax
137; CHECK-NEXT:    movabsq $-9223372036854775808, %rcx # imm = 0x8000000000000000
138; CHECK-NEXT:    xorq %rax, %rcx
139; CHECK-NEXT:    movq %rcx, (%rdi)
140; CHECK-NEXT:    shrq $63, %rax
141; CHECK-NEXT:    addb $-1, %al
142; CHECK-NEXT:    adcq $0, (%rsi)
143; CHECK-NEXT:    retq
144  %3 = load i64, i64* %0, align 8
145  %4 = xor i64 %3, -9223372036854775808
146  store i64 %4, i64* %0, align 8
147  %5 = lshr i64 %3, 63
148  %6 = trunc i64 %5 to i8
149  %7 = load i64, i64* %1, align 8
150  %8 = tail call { i8, i64 } @llvm.x86.addcarry.64(i8 %6, i64 %7, i64 0)
151  %9 = extractvalue { i8, i64 } %8, 1
152  store i64 %9, i64* %1, align 8
153  ret void
154}
155
156define void @test_9223372036854775809(i64*, i64*) {
157; CHECK-LABEL: test_9223372036854775809:
158; CHECK:       # %bb.0:
159; CHECK-NEXT:    movabsq $-9223372036854775807, %rax # imm = 0x8000000000000001
160; CHECK-NEXT:    addq %rax, (%rdi)
161; CHECK-NEXT:    adcq $0, (%rsi)
162; CHECK-NEXT:    retq
163  %3 = load i64, i64* %0, align 8
164  %4 = add i64 %3, -9223372036854775807
165  store i64 %4, i64* %0, align 8
166  %5 = icmp ult i64 %4, -9223372036854775807
167  %6 = zext i1 %5 to i8
168  %7 = load i64, i64* %1, align 8
169  %8 = tail call { i8, i64 } @llvm.x86.addcarry.64(i8 %6, i64 %7, i64 0)
170  %9 = extractvalue { i8, i64 } %8, 1
171  store i64 %9, i64* %1, align 8
172  ret void
173}
174
175define void @test_18446744071562067968(i64*, i64*) {
176; CHECK-LABEL: test_18446744071562067968:
177; CHECK:       # %bb.0:
178; CHECK-NEXT:    addq $-2147483648, (%rdi) # imm = 0x80000000
179; CHECK-NEXT:    adcq $0, (%rsi)
180; CHECK-NEXT:    retq
181  %3 = load i64, i64* %0, align 8
182  %4 = add i64 %3, -2147483648
183  store i64 %4, i64* %0, align 8
184  %5 = icmp ult i64 %4, -2147483648
185  %6 = zext i1 %5 to i8
186  %7 = load i64, i64* %1, align 8
187  %8 = tail call { i8, i64 } @llvm.x86.addcarry.64(i8 %6, i64 %7, i64 0)
188  %9 = extractvalue { i8, i64 } %8, 1
189  store i64 %9, i64* %1, align 8
190  ret void
191}
192
193define void @test_18446744073709551613(i64*, i64*) {
194; CHECK-LABEL: test_18446744073709551613:
195; CHECK:       # %bb.0:
196; CHECK-NEXT:    addq $-3, (%rdi)
197; CHECK-NEXT:    adcq $0, (%rsi)
198; CHECK-NEXT:    retq
199  %3 = load i64, i64* %0, align 8
200  %4 = add i64 %3, -3
201  store i64 %4, i64* %0, align 8
202  %5 = icmp ult i64 %4, -3
203  %6 = zext i1 %5 to i8
204  %7 = load i64, i64* %1, align 8
205  %8 = tail call { i8, i64 } @llvm.x86.addcarry.64(i8 %6, i64 %7, i64 0)
206  %9 = extractvalue { i8, i64 } %8, 1
207  store i64 %9, i64* %1, align 8
208  ret void
209}
210
211define void @test_18446744073709551614(i64*, i64*) {
212; CHECK-LABEL: test_18446744073709551614:
213; CHECK:       # %bb.0:
214; CHECK-NEXT:    addq $-2, (%rdi)
215; CHECK-NEXT:    adcq $0, (%rsi)
216; CHECK-NEXT:    retq
217  %3 = load i64, i64* %0, align 8
218  %4 = add i64 %3, -2
219  store i64 %4, i64* %0, align 8
220  %5 = icmp ult i64 %4, -2
221  %6 = zext i1 %5 to i8
222  %7 = load i64, i64* %1, align 8
223  %8 = tail call { i8, i64 } @llvm.x86.addcarry.64(i8 %6, i64 %7, i64 0)
224  %9 = extractvalue { i8, i64 } %8, 1
225  store i64 %9, i64* %1, align 8
226  ret void
227}
228
229define void @test_18446744073709551615(i64*, i64*) {
230; CHECK-LABEL: test_18446744073709551615:
231; CHECK:       # %bb.0:
232; CHECK-NEXT:    addq $-1, (%rdi)
233; CHECK-NEXT:    adcq $0, (%rsi)
234; CHECK-NEXT:    retq
235  %3 = load i64, i64* %0, align 8
236  %4 = add i64 %3, -1
237  store i64 %4, i64* %0, align 8
238  %5 = icmp ne i64 %3, 0
239  %6 = zext i1 %5 to i8
240  %7 = load i64, i64* %1, align 8
241  %8 = tail call { i8, i64 } @llvm.x86.addcarry.64(i8 %6, i64 %7, i64 0)
242  %9 = extractvalue { i8, i64 } %8, 1
243  store i64 %9, i64* %1, align 8
244  ret void
245}
246
247define i1 @illegal_type(i17 %x, i17* %p) {
248; CHECK-LABEL: illegal_type:
249; CHECK:       # %bb.0:
250; CHECK-NEXT:    addl $29, %edi
251; CHECK-NEXT:    movw %di, (%rsi)
252; CHECK-NEXT:    andl $131071, %edi # imm = 0x1FFFF
253; CHECK-NEXT:    movl %edi, %eax
254; CHECK-NEXT:    shrl $16, %eax
255; CHECK-NEXT:    movb %al, 2(%rsi)
256; CHECK-NEXT:    cmpl $29, %edi
257; CHECK-NEXT:    setb %al
258; CHECK-NEXT:    retq
259  %a = add i17 %x, 29
260  store i17 %a, i17* %p
261  %ov = icmp ult i17 %a, 29
262  ret i1 %ov
263}
264
265; The overflow check may be against the input rather than the sum.
266
267define i1 @uaddo_i64_increment_alt(i64 %x, i64* %p) {
268; CHECK-LABEL: uaddo_i64_increment_alt:
269; CHECK:       # %bb.0:
270; CHECK-NEXT:    incq %rdi
271; CHECK-NEXT:    sete %al
272; CHECK-NEXT:    movq %rdi, (%rsi)
273; CHECK-NEXT:    retq
274  %a = add i64 %x, 1
275  store i64 %a, i64* %p
276  %ov = icmp eq i64 %x, -1
277  ret i1 %ov
278}
279
280; Make sure insertion is done correctly based on dominance.
281
282define i1 @uaddo_i64_increment_alt_dom(i64 %x, i64* %p) {
283; CHECK-LABEL: uaddo_i64_increment_alt_dom:
284; CHECK:       # %bb.0:
285; CHECK-NEXT:    incq %rdi
286; CHECK-NEXT:    sete %al
287; CHECK-NEXT:    movq %rdi, (%rsi)
288; CHECK-NEXT:    retq
289  %ov = icmp eq i64 %x, -1
290  %a = add i64 %x, 1
291  store i64 %a, i64* %p
292  ret i1 %ov
293}
294
295; The overflow check may be against the input rather than the sum.
296
297define i1 @uaddo_i64_decrement_alt(i64 %x, i64* %p) {
298; CHECK-LABEL: uaddo_i64_decrement_alt:
299; CHECK:       # %bb.0:
300; CHECK-NEXT:    addq $-1, %rdi
301; CHECK-NEXT:    setb %al
302; CHECK-NEXT:    movq %rdi, (%rsi)
303; CHECK-NEXT:    retq
304  %a = add i64 %x, -1
305  store i64 %a, i64* %p
306  %ov = icmp ne i64 %x, 0
307  ret i1 %ov
308}
309
310; Make sure insertion is done correctly based on dominance.
311
312define i1 @uaddo_i64_decrement_alt_dom(i64 %x, i64* %p) {
313; CHECK-LABEL: uaddo_i64_decrement_alt_dom:
314; CHECK:       # %bb.0:
315; CHECK-NEXT:    addq $-1, %rdi
316; CHECK-NEXT:    setb %al
317; CHECK-NEXT:    movq %rdi, (%rsi)
318; CHECK-NEXT:    retq
319  %ov = icmp ne i64 %x, 0
320  %a = add i64 %x, -1
321  store i64 %a, i64* %p
322  ret i1 %ov
323}
324
325declare { i8, i64 } @llvm.x86.addcarry.64(i8, i64, i64)
326