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