1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2; RUN: llc < %s -mtriple=x86_64-unknown | FileCheck %s 3 4declare { i8, i64 } @llvm.x86.addcarry.64(i8, i64, i64) 5declare { i64, i1 } @llvm.uadd.with.overflow.i64(i64, i64) #1 6 7define i128 @add128(i128 %a, i128 %b) nounwind { 8; CHECK-LABEL: add128: 9; CHECK: # %bb.0: # %entry 10; CHECK-NEXT: movq %rdi, %rax 11; CHECK-NEXT: addq %rdx, %rax 12; CHECK-NEXT: adcq %rcx, %rsi 13; CHECK-NEXT: movq %rsi, %rdx 14; CHECK-NEXT: retq 15entry: 16 %0 = add i128 %a, %b 17 ret i128 %0 18} 19 20define void @add128_rmw(i128* %a, i128 %b) nounwind { 21; CHECK-LABEL: add128_rmw: 22; CHECK: # %bb.0: # %entry 23; CHECK-NEXT: addq %rsi, (%rdi) 24; CHECK-NEXT: adcq %rdx, 8(%rdi) 25; CHECK-NEXT: retq 26entry: 27 %0 = load i128, i128* %a 28 %1 = add i128 %0, %b 29 store i128 %1, i128* %a 30 ret void 31} 32 33define void @add128_rmw2(i128 %a, i128* %b) nounwind { 34; CHECK-LABEL: add128_rmw2: 35; CHECK: # %bb.0: # %entry 36; CHECK-NEXT: addq %rdi, (%rdx) 37; CHECK-NEXT: adcq %rsi, 8(%rdx) 38; CHECK-NEXT: retq 39entry: 40 %0 = load i128, i128* %b 41 %1 = add i128 %a, %0 42 store i128 %1, i128* %b 43 ret void 44} 45 46define i256 @add256(i256 %a, i256 %b) nounwind { 47; CHECK-LABEL: add256: 48; CHECK: # %bb.0: # %entry 49; CHECK-NEXT: movq %rdi, %rax 50; CHECK-NEXT: addq %r9, %rsi 51; CHECK-NEXT: adcq {{[0-9]+}}(%rsp), %rdx 52; CHECK-NEXT: adcq {{[0-9]+}}(%rsp), %rcx 53; CHECK-NEXT: adcq {{[0-9]+}}(%rsp), %r8 54; CHECK-NEXT: movq %rdx, 8(%rdi) 55; CHECK-NEXT: movq %rsi, (%rdi) 56; CHECK-NEXT: movq %rcx, 16(%rdi) 57; CHECK-NEXT: movq %r8, 24(%rdi) 58; CHECK-NEXT: retq 59entry: 60 %0 = add i256 %a, %b 61 ret i256 %0 62} 63 64define void @add256_rmw(i256* %a, i256 %b) nounwind { 65; CHECK-LABEL: add256_rmw: 66; CHECK: # %bb.0: # %entry 67; CHECK-NEXT: addq %rsi, (%rdi) 68; CHECK-NEXT: adcq %rdx, 8(%rdi) 69; CHECK-NEXT: adcq %rcx, 16(%rdi) 70; CHECK-NEXT: adcq %r8, 24(%rdi) 71; CHECK-NEXT: retq 72entry: 73 %0 = load i256, i256* %a 74 %1 = add i256 %0, %b 75 store i256 %1, i256* %a 76 ret void 77} 78 79define void @add256_rmw2(i256 %a, i256* %b) nounwind { 80; CHECK-LABEL: add256_rmw2: 81; CHECK: # %bb.0: # %entry 82; CHECK-NEXT: addq %rdi, (%r8) 83; CHECK-NEXT: adcq %rsi, 8(%r8) 84; CHECK-NEXT: adcq %rdx, 16(%r8) 85; CHECK-NEXT: adcq %rcx, 24(%r8) 86; CHECK-NEXT: retq 87entry: 88 %0 = load i256, i256* %b 89 %1 = add i256 %a, %0 90 store i256 %1, i256* %b 91 ret void 92} 93 94define void @a(i64* nocapture %s, i64* nocapture %t, i64 %a, i64 %b, i64 %c) nounwind { 95; CHECK-LABEL: a: 96; CHECK: # %bb.0: # %entry 97; CHECK-NEXT: addq %rcx, %rdx 98; CHECK-NEXT: adcq $0, %r8 99; CHECK-NEXT: movq %r8, (%rdi) 100; CHECK-NEXT: movq %rdx, (%rsi) 101; CHECK-NEXT: retq 102entry: 103 %0 = zext i64 %a to i128 104 %1 = zext i64 %b to i128 105 %2 = add i128 %1, %0 106 %3 = zext i64 %c to i128 107 %4 = shl i128 %3, 64 108 %5 = add i128 %4, %2 109 %6 = lshr i128 %5, 64 110 %7 = trunc i128 %6 to i64 111 store i64 %7, i64* %s, align 8 112 %8 = trunc i128 %2 to i64 113 store i64 %8, i64* %t, align 8 114 ret void 115} 116 117define void @b(i32* nocapture %r, i64 %a, i64 %b, i32 %c) nounwind { 118; CHECK-LABEL: b: 119; CHECK: # %bb.0: # %entry 120; CHECK-NEXT: addq %rdx, %rsi 121; CHECK-NEXT: adcl $0, %ecx 122; CHECK-NEXT: movl %ecx, (%rdi) 123; CHECK-NEXT: retq 124entry: 125 %0 = zext i64 %a to i128 126 %1 = zext i64 %b to i128 127 %2 = zext i32 %c to i128 128 %3 = add i128 %1, %0 129 %4 = lshr i128 %3, 64 130 %5 = add i128 %4, %2 131 %6 = trunc i128 %5 to i32 132 store i32 %6, i32* %r, align 4 133 ret void 134} 135 136define void @c(i16* nocapture %r, i64 %a, i64 %b, i16 %c) nounwind { 137; CHECK-LABEL: c: 138; CHECK: # %bb.0: # %entry 139; CHECK-NEXT: addq %rdx, %rsi 140; CHECK-NEXT: adcw $0, %cx 141; CHECK-NEXT: movw %cx, (%rdi) 142; CHECK-NEXT: retq 143entry: 144 %0 = zext i64 %a to i128 145 %1 = zext i64 %b to i128 146 %2 = zext i16 %c to i128 147 %3 = add i128 %1, %0 148 %4 = lshr i128 %3, 64 149 %5 = add i128 %4, %2 150 %6 = trunc i128 %5 to i16 151 store i16 %6, i16* %r, align 4 152 ret void 153} 154 155define void @d(i8* nocapture %r, i64 %a, i64 %b, i8 %c) nounwind { 156; CHECK-LABEL: d: 157; CHECK: # %bb.0: # %entry 158; CHECK-NEXT: addq %rdx, %rsi 159; CHECK-NEXT: adcb $0, %cl 160; CHECK-NEXT: movb %cl, (%rdi) 161; CHECK-NEXT: retq 162entry: 163 %0 = zext i64 %a to i128 164 %1 = zext i64 %b to i128 165 %2 = zext i8 %c to i128 166 %3 = add i128 %1, %0 167 %4 = lshr i128 %3, 64 168 %5 = add i128 %4, %2 169 %6 = trunc i128 %5 to i8 170 store i8 %6, i8* %r, align 4 171 ret void 172} 173 174define i8 @e(i32* nocapture %a, i32 %b) nounwind { 175; CHECK-LABEL: e: 176; CHECK: # %bb.0: 177; CHECK-NEXT: # kill: def $esi killed $esi def $rsi 178; CHECK-NEXT: movl (%rdi), %ecx 179; CHECK-NEXT: leal (%rsi,%rcx), %edx 180; CHECK-NEXT: addl %esi, %edx 181; CHECK-NEXT: setb %al 182; CHECK-NEXT: addl %esi, %ecx 183; CHECK-NEXT: movl %edx, (%rdi) 184; CHECK-NEXT: adcb $0, %al 185; CHECK-NEXT: retq 186 %1 = load i32, i32* %a, align 4 187 %2 = add i32 %1, %b 188 %3 = icmp ult i32 %2, %b 189 %4 = zext i1 %3 to i8 190 %5 = add i32 %2, %b 191 store i32 %5, i32* %a, align 4 192 %6 = icmp ult i32 %5, %b 193 %7 = zext i1 %6 to i8 194 %8 = add nuw nsw i8 %7, %4 195 ret i8 %8 196} 197 198%scalar = type { [4 x i64] } 199 200define %scalar @pr31719(%scalar* nocapture readonly %this, %scalar %arg.b) { 201; CHECK-LABEL: pr31719: 202; CHECK: # %bb.0: # %entry 203; CHECK-NEXT: movq %rdi, %rax 204; CHECK-NEXT: addq (%rsi), %rdx 205; CHECK-NEXT: adcq 8(%rsi), %rcx 206; CHECK-NEXT: adcq 16(%rsi), %r8 207; CHECK-NEXT: adcq 24(%rsi), %r9 208; CHECK-NEXT: movq %rdx, (%rdi) 209; CHECK-NEXT: movq %rcx, 8(%rdi) 210; CHECK-NEXT: movq %r8, 16(%rdi) 211; CHECK-NEXT: movq %r9, 24(%rdi) 212; CHECK-NEXT: retq 213entry: 214 %0 = extractvalue %scalar %arg.b, 0 215 %.elt = extractvalue [4 x i64] %0, 0 216 %.elt24 = extractvalue [4 x i64] %0, 1 217 %.elt26 = extractvalue [4 x i64] %0, 2 218 %.elt28 = extractvalue [4 x i64] %0, 3 219 %1 = getelementptr inbounds %scalar , %scalar* %this, i64 0, i32 0, i64 0 220 %2 = load i64, i64* %1, align 8 221 %3 = zext i64 %2 to i128 222 %4 = zext i64 %.elt to i128 223 %5 = add nuw nsw i128 %3, %4 224 %6 = trunc i128 %5 to i64 225 %7 = lshr i128 %5, 64 226 %8 = getelementptr inbounds %scalar , %scalar * %this, i64 0, i32 0, i64 1 227 %9 = load i64, i64* %8, align 8 228 %10 = zext i64 %9 to i128 229 %11 = zext i64 %.elt24 to i128 230 %12 = add nuw nsw i128 %10, %11 231 %13 = add nuw nsw i128 %12, %7 232 %14 = trunc i128 %13 to i64 233 %15 = lshr i128 %13, 64 234 %16 = getelementptr inbounds %scalar , %scalar* %this, i64 0, i32 0, i64 2 235 %17 = load i64, i64* %16, align 8 236 %18 = zext i64 %17 to i128 237 %19 = zext i64 %.elt26 to i128 238 %20 = add nuw nsw i128 %18, %19 239 %21 = add nuw nsw i128 %20, %15 240 %22 = trunc i128 %21 to i64 241 %23 = lshr i128 %21, 64 242 %24 = getelementptr inbounds %scalar , %scalar* %this, i64 0, i32 0, i64 3 243 %25 = load i64, i64* %24, align 8 244 %26 = zext i64 %25 to i128 245 %27 = zext i64 %.elt28 to i128 246 %28 = add nuw nsw i128 %26, %27 247 %29 = add nuw nsw i128 %28, %23 248 %30 = trunc i128 %29 to i64 249 %31 = insertvalue [4 x i64] undef, i64 %6, 0 250 %32 = insertvalue [4 x i64] %31, i64 %14, 1 251 %33 = insertvalue [4 x i64] %32, i64 %22, 2 252 %34 = insertvalue [4 x i64] %33, i64 %30, 3 253 %35 = insertvalue %scalar undef, [4 x i64] %34, 0 254 ret %scalar %35 255} 256 257%accumulator= type { i64, i64, i32 } 258 259define void @muladd(%accumulator* nocapture %this, i64 %arg.a, i64 %arg.b) { 260; CHECK-LABEL: muladd: 261; CHECK: # %bb.0: # %entry 262; CHECK-NEXT: movq %rdx, %rax 263; CHECK-NEXT: mulq %rsi 264; CHECK-NEXT: addq %rax, (%rdi) 265; CHECK-NEXT: adcq %rdx, 8(%rdi) 266; CHECK-NEXT: adcl $0, 16(%rdi) 267; CHECK-NEXT: retq 268entry: 269 %0 = zext i64 %arg.a to i128 270 %1 = zext i64 %arg.b to i128 271 %2 = mul nuw i128 %1, %0 272 %3 = getelementptr inbounds %accumulator, %accumulator* %this, i64 0, i32 0 273 %4 = load i64, i64* %3, align 8 274 %5 = zext i64 %4 to i128 275 %6 = add i128 %5, %2 276 %7 = trunc i128 %6 to i64 277 store i64 %7, i64* %3, align 8 278 %8 = lshr i128 %6, 64 279 %9 = getelementptr inbounds %accumulator, %accumulator* %this, i64 0, i32 1 280 %10 = load i64, i64* %9, align 8 281 %11 = zext i64 %10 to i128 282 %12 = add nuw nsw i128 %8, %11 283 %13 = trunc i128 %12 to i64 284 store i64 %13, i64* %9, align 8 285 %14 = lshr i128 %12, 64 286 %15 = getelementptr inbounds %accumulator, %accumulator* %this, i64 0, i32 2 287 %16 = load i32, i32* %15, align 4 288 %17 = zext i32 %16 to i128 289 %18 = add nuw nsw i128 %14, %17 290 %19 = trunc i128 %18 to i32 291 store i32 %19, i32* %15, align 4 292 ret void 293} 294 295define i64 @shiftadd(i64 %a, i64 %b, i64 %c, i64 %d) { 296; CHECK-LABEL: shiftadd: 297; CHECK: # %bb.0: # %entry 298; CHECK-NEXT: movq %rdx, %rax 299; CHECK-NEXT: addq %rsi, %rdi 300; CHECK-NEXT: adcq %rcx, %rax 301; CHECK-NEXT: retq 302entry: 303 %0 = zext i64 %a to i128 304 %1 = zext i64 %b to i128 305 %2 = add i128 %0, %1 306 %3 = lshr i128 %2, 64 307 %4 = trunc i128 %3 to i64 308 %5 = add i64 %c, %d 309 %6 = add i64 %4, %5 310 ret i64 %6 311} 312 313%S = type { [4 x i64] } 314 315define %S @readd(%S* nocapture readonly %this, %S %arg.b) { 316; CHECK-LABEL: readd: 317; CHECK: # %bb.0: # %entry 318; CHECK-NEXT: movq %rdi, %rax 319; CHECK-NEXT: addq (%rsi), %rdx 320; CHECK-NEXT: movq 8(%rsi), %r11 321; CHECK-NEXT: adcq $0, %r11 322; CHECK-NEXT: setb %r10b 323; CHECK-NEXT: movzbl %r10b, %edi 324; CHECK-NEXT: addq %rcx, %r11 325; CHECK-NEXT: adcq 16(%rsi), %rdi 326; CHECK-NEXT: setb %cl 327; CHECK-NEXT: movzbl %cl, %ecx 328; CHECK-NEXT: addq %r8, %rdi 329; CHECK-NEXT: adcq 24(%rsi), %rcx 330; CHECK-NEXT: addq %r9, %rcx 331; CHECK-NEXT: movq %rdx, (%rax) 332; CHECK-NEXT: movq %r11, 8(%rax) 333; CHECK-NEXT: movq %rdi, 16(%rax) 334; CHECK-NEXT: movq %rcx, 24(%rax) 335; CHECK-NEXT: retq 336entry: 337 %0 = extractvalue %S %arg.b, 0 338 %.elt6 = extractvalue [4 x i64] %0, 1 339 %.elt8 = extractvalue [4 x i64] %0, 2 340 %.elt10 = extractvalue [4 x i64] %0, 3 341 %.elt = extractvalue [4 x i64] %0, 0 342 %1 = getelementptr inbounds %S, %S* %this, i64 0, i32 0, i64 0 343 %2 = load i64, i64* %1, align 8 344 %3 = zext i64 %2 to i128 345 %4 = zext i64 %.elt to i128 346 %5 = add nuw nsw i128 %3, %4 347 %6 = trunc i128 %5 to i64 348 %7 = lshr i128 %5, 64 349 %8 = getelementptr inbounds %S, %S* %this, i64 0, i32 0, i64 1 350 %9 = load i64, i64* %8, align 8 351 %10 = zext i64 %9 to i128 352 %11 = add nuw nsw i128 %7, %10 353 %12 = zext i64 %.elt6 to i128 354 %13 = add nuw nsw i128 %11, %12 355 %14 = trunc i128 %13 to i64 356 %15 = lshr i128 %13, 64 357 %16 = getelementptr inbounds %S, %S* %this, i64 0, i32 0, i64 2 358 %17 = load i64, i64* %16, align 8 359 %18 = zext i64 %17 to i128 360 %19 = add nuw nsw i128 %15, %18 361 %20 = zext i64 %.elt8 to i128 362 %21 = add nuw nsw i128 %19, %20 363 %22 = lshr i128 %21, 64 364 %23 = trunc i128 %21 to i64 365 %24 = getelementptr inbounds %S, %S* %this, i64 0,i32 0, i64 3 366 %25 = load i64, i64* %24, align 8 367 %26 = zext i64 %25 to i128 368 %27 = add nuw nsw i128 %22, %26 369 %28 = zext i64 %.elt10 to i128 370 %29 = add nuw nsw i128 %27, %28 371 %30 = trunc i128 %29 to i64 372 %31 = insertvalue [4 x i64] undef, i64 %6, 0 373 %32 = insertvalue [4 x i64] %31, i64 %14, 1 374 %33 = insertvalue [4 x i64] %32, i64 %23, 2 375 %34 = insertvalue [4 x i64] %33, i64 %30, 3 376 %35 = insertvalue %S undef, [4 x i64] %34, 0 377 ret %S %35 378} 379 380define i128 @addcarry1_not(i128 %n) { 381; CHECK-LABEL: addcarry1_not: 382; CHECK: # %bb.0: 383; CHECK-NEXT: movq %rdi, %rax 384; CHECK-NEXT: xorl %edx, %edx 385; CHECK-NEXT: negq %rax 386; CHECK-NEXT: sbbq %rsi, %rdx 387; CHECK-NEXT: retq 388 %1 = xor i128 %n, -1 389 %2 = add i128 %1, 1 390 ret i128 %2 391} 392 393define i128 @addcarry_to_subcarry(i64 %a, i64 %b) { 394; CHECK-LABEL: addcarry_to_subcarry: 395; CHECK: # %bb.0: 396; CHECK-NEXT: movq %rdi, %rax 397; CHECK-NEXT: cmpq %rsi, %rdi 398; CHECK-NEXT: notq %rsi 399; CHECK-NEXT: setae %cl 400; CHECK-NEXT: addb $-1, %cl 401; CHECK-NEXT: adcq $0, %rax 402; CHECK-NEXT: setb %cl 403; CHECK-NEXT: movzbl %cl, %edx 404; CHECK-NEXT: addq %rsi, %rax 405; CHECK-NEXT: adcq $0, %rdx 406; CHECK-NEXT: retq 407 %notb = xor i64 %b, -1 408 %notb128 = zext i64 %notb to i128 409 %a128 = zext i64 %a to i128 410 %sum1 = add i128 %a128, 1 411 %sub1 = add i128 %sum1, %notb128 412 %hi = lshr i128 %sub1, 64 413 %sum2 = add i128 %hi, %a128 414 %sub2 = add i128 %sum2, %notb128 415 ret i128 %sub2 416} 417 418%struct.U320 = type { [5 x i64] } 419 420define i32 @add_U320_without_i128_add(%struct.U320* nocapture dereferenceable(40) %0, i64 %1, i64 %2, i64 %3, i64 %4, i64 %5) { 421; CHECK-LABEL: add_U320_without_i128_add: 422; CHECK: # %bb.0: 423; CHECK-NEXT: pushq %r14 424; CHECK-NEXT: .cfi_def_cfa_offset 16 425; CHECK-NEXT: pushq %rbx 426; CHECK-NEXT: .cfi_def_cfa_offset 24 427; CHECK-NEXT: .cfi_offset %rbx, -24 428; CHECK-NEXT: .cfi_offset %r14, -16 429; CHECK-NEXT: movq 16(%rdi), %rax 430; CHECK-NEXT: leaq (%rax,%rcx), %r10 431; CHECK-NEXT: addq %rsi, (%rdi) 432; CHECK-NEXT: adcq %rdx, 8(%rdi) 433; CHECK-NEXT: movq %rax, %rdx 434; CHECK-NEXT: adcq %rcx, %rdx 435; CHECK-NEXT: movq 24(%rdi), %r11 436; CHECK-NEXT: leaq (%r8,%r11), %r14 437; CHECK-NEXT: xorl %ebx, %ebx 438; CHECK-NEXT: cmpq %r10, %rdx 439; CHECK-NEXT: setb %bl 440; CHECK-NEXT: addq %rcx, %rax 441; CHECK-NEXT: adcq %r14, %rbx 442; CHECK-NEXT: movq 32(%rdi), %r10 443; CHECK-NEXT: leaq (%r9,%r10), %rcx 444; CHECK-NEXT: xorl %esi, %esi 445; CHECK-NEXT: cmpq %r14, %rbx 446; CHECK-NEXT: setb %sil 447; CHECK-NEXT: addq %r11, %r8 448; CHECK-NEXT: adcq %rcx, %rsi 449; CHECK-NEXT: xorl %eax, %eax 450; CHECK-NEXT: cmpq %rcx, %rsi 451; CHECK-NEXT: setb %al 452; CHECK-NEXT: addq %r10, %r9 453; CHECK-NEXT: movq %rdx, 16(%rdi) 454; CHECK-NEXT: movq %rbx, 24(%rdi) 455; CHECK-NEXT: movq %rsi, 32(%rdi) 456; CHECK-NEXT: adcl $0, %eax 457; CHECK-NEXT: popq %rbx 458; CHECK-NEXT: .cfi_def_cfa_offset 16 459; CHECK-NEXT: popq %r14 460; CHECK-NEXT: .cfi_def_cfa_offset 8 461; CHECK-NEXT: retq 462 %7 = getelementptr inbounds %struct.U320, %struct.U320* %0, i64 0, i32 0, i64 0 463 %8 = load i64, i64* %7, align 8 464 %9 = getelementptr inbounds %struct.U320, %struct.U320* %0, i64 0, i32 0, i64 1 465 %10 = load i64, i64* %9, align 8 466 %11 = getelementptr inbounds %struct.U320, %struct.U320* %0, i64 0, i32 0, i64 2 467 %12 = load i64, i64* %11, align 8 468 %13 = getelementptr inbounds %struct.U320, %struct.U320* %0, i64 0, i32 0, i64 3 469 %14 = load i64, i64* %13, align 8 470 %15 = getelementptr inbounds %struct.U320, %struct.U320* %0, i64 0, i32 0, i64 4 471 %16 = load i64, i64* %15, align 8 472 %17 = add i64 %8, %1 473 %18 = add i64 %10, %2 474 %19 = icmp ult i64 %17, %1 475 %20 = zext i1 %19 to i64 476 %21 = add i64 %18, %20 477 %22 = add i64 %12, %3 478 %23 = icmp ult i64 %18, %10 479 %24 = zext i1 %23 to i64 480 %25 = icmp ult i64 %21, %18 481 %26 = zext i1 %25 to i64 482 %27 = add i64 %22, %24 483 %28 = add i64 %27, %26 484 %29 = add i64 %14, %4 485 %30 = icmp ult i64 %22, %12 486 %31 = zext i1 %30 to i64 487 %32 = icmp ult i64 %28, %22 488 %33 = zext i1 %32 to i64 489 %34 = add i64 %29, %31 490 %35 = add i64 %34, %33 491 %36 = add i64 %16, %5 492 %37 = icmp ult i64 %29, %14 493 %38 = zext i1 %37 to i64 494 %39 = icmp ult i64 %35, %29 495 %40 = zext i1 %39 to i64 496 %41 = add i64 %36, %38 497 %42 = add i64 %41, %40 498 store i64 %17, i64* %7, align 8 499 store i64 %21, i64* %9, align 8 500 store i64 %28, i64* %11, align 8 501 store i64 %35, i64* %13, align 8 502 store i64 %42, i64* %15, align 8 503 %43 = icmp ult i64 %36, %16 504 %44 = zext i1 %43 to i32 505 %45 = icmp ult i64 %42, %36 506 %46 = zext i1 %45 to i32 507 %47 = add nuw nsw i32 %46, %44 508 ret i32 %47 509} 510 511define i32 @add_U320_without_i128_or(%struct.U320* nocapture dereferenceable(40) %0, i64 %1, i64 %2, i64 %3, i64 %4, i64 %5) { 512; CHECK-LABEL: add_U320_without_i128_or: 513; CHECK: # %bb.0: 514; CHECK-NEXT: addq %rsi, (%rdi) 515; CHECK-NEXT: adcq %rdx, 8(%rdi) 516; CHECK-NEXT: adcq %rcx, 16(%rdi) 517; CHECK-NEXT: adcq %r8, 24(%rdi) 518; CHECK-NEXT: adcq %r9, 32(%rdi) 519; CHECK-NEXT: setb %al 520; CHECK-NEXT: movzbl %al, %eax 521; CHECK-NEXT: retq 522 %7 = getelementptr inbounds %struct.U320, %struct.U320* %0, i64 0, i32 0, i64 0 523 %8 = load i64, i64* %7, align 8 524 %9 = getelementptr inbounds %struct.U320, %struct.U320* %0, i64 0, i32 0, i64 1 525 %10 = load i64, i64* %9, align 8 526 %11 = getelementptr inbounds %struct.U320, %struct.U320* %0, i64 0, i32 0, i64 2 527 %12 = load i64, i64* %11, align 8 528 %13 = getelementptr inbounds %struct.U320, %struct.U320* %0, i64 0, i32 0, i64 3 529 %14 = load i64, i64* %13, align 8 530 %15 = getelementptr inbounds %struct.U320, %struct.U320* %0, i64 0, i32 0, i64 4 531 %16 = load i64, i64* %15, align 8 532 %17 = add i64 %8, %1 533 %18 = add i64 %10, %2 534 %19 = icmp ult i64 %17, %1 535 %20 = zext i1 %19 to i64 536 %21 = add i64 %18, %20 537 %22 = add i64 %12, %3 538 %23 = icmp ult i64 %18, %10 539 %24 = icmp ult i64 %21, %18 540 %25 = or i1 %23, %24 541 %26 = zext i1 %25 to i64 542 %27 = add i64 %22, %26 543 %28 = add i64 %14, %4 544 %29 = icmp ult i64 %22, %12 545 %30 = icmp ult i64 %27, %22 546 %31 = or i1 %29, %30 547 %32 = zext i1 %31 to i64 548 %33 = add i64 %28, %32 549 %34 = add i64 %16, %5 550 %35 = icmp ult i64 %28, %14 551 %36 = icmp ult i64 %33, %28 552 %37 = or i1 %35, %36 553 %38 = zext i1 %37 to i64 554 %39 = add i64 %34, %38 555 store i64 %17, i64* %7, align 8 556 store i64 %21, i64* %9, align 8 557 store i64 %27, i64* %11, align 8 558 store i64 %33, i64* %13, align 8 559 store i64 %39, i64* %15, align 8 560 %40 = icmp ult i64 %34, %16 561 %41 = icmp ult i64 %39, %34 562 %42 = or i1 %40, %41 563 %43 = zext i1 %42 to i32 564 ret i32 %43 565} 566 567define i32 @add_U320_without_i128_xor(%struct.U320* nocapture dereferenceable(40) %0, i64 %1, i64 %2, i64 %3, i64 %4, i64 %5) { 568; CHECK-LABEL: add_U320_without_i128_xor: 569; CHECK: # %bb.0: 570; CHECK-NEXT: addq %rsi, (%rdi) 571; CHECK-NEXT: adcq %rdx, 8(%rdi) 572; CHECK-NEXT: adcq %rcx, 16(%rdi) 573; CHECK-NEXT: adcq %r8, 24(%rdi) 574; CHECK-NEXT: adcq %r9, 32(%rdi) 575; CHECK-NEXT: setb %al 576; CHECK-NEXT: movzbl %al, %eax 577; CHECK-NEXT: retq 578 %7 = getelementptr inbounds %struct.U320, %struct.U320* %0, i64 0, i32 0, i64 0 579 %8 = load i64, i64* %7, align 8 580 %9 = getelementptr inbounds %struct.U320, %struct.U320* %0, i64 0, i32 0, i64 1 581 %10 = load i64, i64* %9, align 8 582 %11 = getelementptr inbounds %struct.U320, %struct.U320* %0, i64 0, i32 0, i64 2 583 %12 = load i64, i64* %11, align 8 584 %13 = getelementptr inbounds %struct.U320, %struct.U320* %0, i64 0, i32 0, i64 3 585 %14 = load i64, i64* %13, align 8 586 %15 = getelementptr inbounds %struct.U320, %struct.U320* %0, i64 0, i32 0, i64 4 587 %16 = load i64, i64* %15, align 8 588 %17 = add i64 %8, %1 589 %18 = add i64 %10, %2 590 %19 = icmp ult i64 %17, %1 591 %20 = zext i1 %19 to i64 592 %21 = add i64 %18, %20 593 %22 = add i64 %12, %3 594 %23 = icmp ult i64 %18, %10 595 %24 = icmp ult i64 %21, %18 596 %25 = xor i1 %23, %24 597 %26 = zext i1 %25 to i64 598 %27 = add i64 %22, %26 599 %28 = add i64 %14, %4 600 %29 = icmp ult i64 %22, %12 601 %30 = icmp ult i64 %27, %22 602 %31 = xor i1 %29, %30 603 %32 = zext i1 %31 to i64 604 %33 = add i64 %28, %32 605 %34 = add i64 %16, %5 606 %35 = icmp ult i64 %28, %14 607 %36 = icmp ult i64 %33, %28 608 %37 = xor i1 %35, %36 609 %38 = zext i1 %37 to i64 610 %39 = add i64 %34, %38 611 store i64 %17, i64* %7, align 8 612 store i64 %21, i64* %9, align 8 613 store i64 %27, i64* %11, align 8 614 store i64 %33, i64* %13, align 8 615 store i64 %39, i64* %15, align 8 616 %40 = icmp ult i64 %34, %16 617 %41 = icmp ult i64 %39, %34 618 %42 = xor i1 %40, %41 619 %43 = zext i1 %42 to i32 620 ret i32 %43 621} 622 623; Either the primary addition can overflow or the addition of the carry, but 624; they cannot both overflow. 625define i32 @bogus_add_U320_without_i128_and(%struct.U320* nocapture dereferenceable(40) %0, i64 %1, i64 %2, i64 %3, i64 %4, i64 %5) { 626; CHECK-LABEL: bogus_add_U320_without_i128_and: 627; CHECK: # %bb.0: 628; CHECK-NEXT: addq %rsi, (%rdi) 629; CHECK-NEXT: adcq %rdx, 8(%rdi) 630; CHECK-NEXT: addq %rcx, 16(%rdi) 631; CHECK-NEXT: addq %r8, 24(%rdi) 632; CHECK-NEXT: addq %r9, 32(%rdi) 633; CHECK-NEXT: xorl %eax, %eax 634; CHECK-NEXT: retq 635 %7 = getelementptr inbounds %struct.U320, %struct.U320* %0, i64 0, i32 0, i64 0 636 %8 = load i64, i64* %7, align 8 637 %9 = getelementptr inbounds %struct.U320, %struct.U320* %0, i64 0, i32 0, i64 1 638 %10 = load i64, i64* %9, align 8 639 %11 = getelementptr inbounds %struct.U320, %struct.U320* %0, i64 0, i32 0, i64 2 640 %12 = load i64, i64* %11, align 8 641 %13 = getelementptr inbounds %struct.U320, %struct.U320* %0, i64 0, i32 0, i64 3 642 %14 = load i64, i64* %13, align 8 643 %15 = getelementptr inbounds %struct.U320, %struct.U320* %0, i64 0, i32 0, i64 4 644 %16 = load i64, i64* %15, align 8 645 %17 = add i64 %8, %1 646 %18 = add i64 %10, %2 647 %19 = icmp ult i64 %17, %1 648 %20 = zext i1 %19 to i64 649 %21 = add i64 %18, %20 650 %22 = add i64 %12, %3 651 %23 = icmp ult i64 %18, %10 652 %24 = icmp ult i64 %21, %18 653 %25 = and i1 %23, %24 654 %26 = zext i1 %25 to i64 655 %27 = add i64 %22, %26 656 %28 = add i64 %14, %4 657 %29 = icmp ult i64 %22, %12 658 %30 = icmp ult i64 %27, %22 659 %31 = and i1 %29, %30 660 %32 = zext i1 %31 to i64 661 %33 = add i64 %28, %32 662 %34 = add i64 %16, %5 663 %35 = icmp ult i64 %28, %14 664 %36 = icmp ult i64 %33, %28 665 %37 = and i1 %35, %36 666 %38 = zext i1 %37 to i64 667 %39 = add i64 %34, %38 668 store i64 %17, i64* %7, align 8 669 store i64 %21, i64* %9, align 8 670 store i64 %27, i64* %11, align 8 671 store i64 %33, i64* %13, align 8 672 store i64 %39, i64* %15, align 8 673 %40 = icmp ult i64 %34, %16 674 %41 = icmp ult i64 %39, %34 675 %42 = and i1 %40, %41 676 %43 = zext i1 %42 to i32 677 ret i32 %43 678} 679 680define void @add_U320_without_i128_or_no_ret(%struct.U320* nocapture dereferenceable(40) %0, i64 %1, i64 %2, i64 %3, i64 %4, i64 %5) { 681; CHECK-LABEL: add_U320_without_i128_or_no_ret: 682; CHECK: # %bb.0: 683; CHECK-NEXT: addq %rsi, (%rdi) 684; CHECK-NEXT: adcq %rdx, 8(%rdi) 685; CHECK-NEXT: adcq %rcx, 16(%rdi) 686; CHECK-NEXT: adcq %r8, 24(%rdi) 687; CHECK-NEXT: adcq %r9, 32(%rdi) 688; CHECK-NEXT: retq 689 %7 = getelementptr inbounds %struct.U320, %struct.U320* %0, i64 0, i32 0, i64 0 690 %8 = load i64, i64* %7, align 8 691 %9 = getelementptr inbounds %struct.U320, %struct.U320* %0, i64 0, i32 0, i64 1 692 %10 = load i64, i64* %9, align 8 693 %11 = getelementptr inbounds %struct.U320, %struct.U320* %0, i64 0, i32 0, i64 2 694 %12 = load i64, i64* %11, align 8 695 %13 = getelementptr inbounds %struct.U320, %struct.U320* %0, i64 0, i32 0, i64 3 696 %14 = load i64, i64* %13, align 8 697 %15 = getelementptr inbounds %struct.U320, %struct.U320* %0, i64 0, i32 0, i64 4 698 %16 = load i64, i64* %15, align 8 699 %17 = add i64 %8, %1 700 %18 = add i64 %10, %2 701 %19 = icmp ult i64 %17, %1 702 %20 = zext i1 %19 to i64 703 %21 = add i64 %18, %20 704 %22 = add i64 %12, %3 705 %23 = icmp ult i64 %18, %10 706 %24 = icmp ult i64 %21, %18 707 %25 = or i1 %23, %24 708 %26 = zext i1 %25 to i64 709 %27 = add i64 %22, %26 710 %28 = add i64 %14, %4 711 %29 = icmp ult i64 %22, %12 712 %30 = icmp ult i64 %27, %22 713 %31 = or i1 %29, %30 714 %32 = zext i1 %31 to i64 715 %33 = add i64 %28, %32 716 %34 = add i64 %16, %5 717 %35 = icmp ult i64 %28, %14 718 %36 = icmp ult i64 %33, %28 719 %37 = or i1 %35, %36 720 %38 = zext i1 %37 to i64 721 %39 = add i64 %34, %38 722 store i64 %17, i64* %7, align 8 723 store i64 %21, i64* %9, align 8 724 store i64 %27, i64* %11, align 8 725 store i64 %33, i64* %13, align 8 726 store i64 %39, i64* %15, align 8 727 ret void 728} 729 730define i32 @add_U320_uaddo(%struct.U320* nocapture dereferenceable(40) %0, i64 %1, i64 %2, i64 %3, i64 %4, i64 %5) { 731; CHECK-LABEL: add_U320_uaddo: 732; CHECK: # %bb.0: 733; CHECK-NEXT: addq %rsi, (%rdi) 734; CHECK-NEXT: adcq %rdx, 8(%rdi) 735; CHECK-NEXT: adcq %rcx, 16(%rdi) 736; CHECK-NEXT: adcq %r8, 24(%rdi) 737; CHECK-NEXT: adcq %r9, 32(%rdi) 738; CHECK-NEXT: setb %al 739; CHECK-NEXT: movzbl %al, %eax 740; CHECK-NEXT: retq 741 %7 = getelementptr inbounds %struct.U320, %struct.U320* %0, i64 0, i32 0, i64 0 742 %8 = load i64, i64* %7, align 8 743 %9 = getelementptr inbounds %struct.U320, %struct.U320* %0, i64 0, i32 0, i64 1 744 %10 = load i64, i64* %9, align 8 745 %11 = getelementptr inbounds %struct.U320, %struct.U320* %0, i64 0, i32 0, i64 2 746 %12 = load i64, i64* %11, align 8 747 %13 = getelementptr inbounds %struct.U320, %struct.U320* %0, i64 0, i32 0, i64 3 748 %14 = load i64, i64* %13, align 8 749 %15 = getelementptr inbounds %struct.U320, %struct.U320* %0, i64 0, i32 0, i64 4 750 %16 = load i64, i64* %15, align 8 751 %17 = tail call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 %8, i64 %1) 752 %18 = extractvalue { i64, i1 } %17, 1 753 %19 = extractvalue { i64, i1 } %17, 0 754 %20 = zext i1 %18 to i64 755 %21 = tail call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 %10, i64 %2) 756 %22 = extractvalue { i64, i1 } %21, 1 757 %23 = extractvalue { i64, i1 } %21, 0 758 %24 = tail call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 %23, i64 %20) 759 %25 = extractvalue { i64, i1 } %24, 1 760 %26 = extractvalue { i64, i1 } %24, 0 761 %27 = or i1 %22, %25 762 %28 = zext i1 %27 to i64 763 %29 = tail call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 %12, i64 %3) 764 %30 = extractvalue { i64, i1 } %29, 1 765 %31 = extractvalue { i64, i1 } %29, 0 766 %32 = tail call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 %31, i64 %28) 767 %33 = extractvalue { i64, i1 } %32, 1 768 %34 = extractvalue { i64, i1 } %32, 0 769 %35 = or i1 %30, %33 770 %36 = zext i1 %35 to i64 771 %37 = tail call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 %14, i64 %4) 772 %38 = extractvalue { i64, i1 } %37, 1 773 %39 = extractvalue { i64, i1 } %37, 0 774 %40 = tail call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 %39, i64 %36) 775 %41 = extractvalue { i64, i1 } %40, 1 776 %42 = extractvalue { i64, i1 } %40, 0 777 %43 = or i1 %38, %41 778 %44 = zext i1 %43 to i64 779 %45 = tail call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 %16, i64 %5) 780 %46 = extractvalue { i64, i1 } %45, 1 781 %47 = extractvalue { i64, i1 } %45, 0 782 %48 = tail call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 %47, i64 %44) 783 %49 = extractvalue { i64, i1 } %48, 1 784 %50 = extractvalue { i64, i1 } %48, 0 785 %51 = or i1 %46, %49 786 store i64 %19, i64* %7, align 8 787 store i64 %26, i64* %9, align 8 788 store i64 %34, i64* %11, align 8 789 store i64 %42, i64* %13, align 8 790 store i64 %50, i64* %15, align 8 791 %52 = zext i1 %51 to i32 792 ret i32 %52 793} 794 795%struct.U192 = type { [3 x i64] } 796 797define void @PR39464(%struct.U192* noalias nocapture sret(%struct.U192) %0, %struct.U192* nocapture readonly dereferenceable(24) %1, %struct.U192* nocapture readonly dereferenceable(24) %2) { 798; CHECK-LABEL: PR39464: 799; CHECK: # %bb.0: 800; CHECK-NEXT: movq %rdi, %rax 801; CHECK-NEXT: movq (%rsi), %rcx 802; CHECK-NEXT: addq (%rdx), %rcx 803; CHECK-NEXT: movq %rcx, (%rdi) 804; CHECK-NEXT: movq 8(%rsi), %rcx 805; CHECK-NEXT: adcq 8(%rdx), %rcx 806; CHECK-NEXT: movq %rcx, 8(%rdi) 807; CHECK-NEXT: movq 16(%rsi), %rcx 808; CHECK-NEXT: adcq 16(%rdx), %rcx 809; CHECK-NEXT: movq %rcx, 16(%rdi) 810; CHECK-NEXT: retq 811 %4 = getelementptr inbounds %struct.U192, %struct.U192* %1, i64 0, i32 0, i64 0 812 %5 = load i64, i64* %4, align 8 813 %6 = getelementptr inbounds %struct.U192, %struct.U192* %2, i64 0, i32 0, i64 0 814 %7 = load i64, i64* %6, align 8 815 %8 = tail call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 %5, i64 %7) 816 %9 = extractvalue { i64, i1 } %8, 1 817 %10 = extractvalue { i64, i1 } %8, 0 818 %11 = zext i1 %9 to i64 819 %12 = getelementptr inbounds %struct.U192, %struct.U192* %0, i64 0, i32 0, i64 0 820 store i64 %10, i64* %12, align 8 821 %13 = getelementptr inbounds %struct.U192, %struct.U192* %1, i64 0, i32 0, i64 1 822 %14 = load i64, i64* %13, align 8 823 %15 = getelementptr inbounds %struct.U192, %struct.U192* %2, i64 0, i32 0, i64 1 824 %16 = load i64, i64* %15, align 8 825 %17 = tail call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 %14, i64 %16) 826 %18 = extractvalue { i64, i1 } %17, 1 827 %19 = extractvalue { i64, i1 } %17, 0 828 %20 = tail call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 %19, i64 %11) 829 %21 = extractvalue { i64, i1 } %20, 1 830 %22 = extractvalue { i64, i1 } %20, 0 831 %23 = or i1 %18, %21 832 %24 = zext i1 %23 to i64 833 %25 = getelementptr inbounds %struct.U192, %struct.U192* %0, i64 0, i32 0, i64 1 834 store i64 %22, i64* %25, align 8 835 %26 = getelementptr inbounds %struct.U192, %struct.U192* %1, i64 0, i32 0, i64 2 836 %27 = load i64, i64* %26, align 8 837 %28 = getelementptr inbounds %struct.U192, %struct.U192* %2, i64 0, i32 0, i64 2 838 %29 = load i64, i64* %28, align 8 839 %30 = add i64 %27, %29 840 %31 = add i64 %30, %24 841 %32 = getelementptr inbounds %struct.U192, %struct.U192* %0, i64 0, i32 0, i64 2 842 store i64 %31, i64* %32, align 8 843 ret void 844} 845 846 847%uint128 = type { i64, i64 } 848 849define zeroext i1 @uaddo_U128_without_i128_or(i64 %0, i64 %1, i64 %2, i64 %3, %uint128* nocapture %4) nounwind { 850; CHECK-LABEL: uaddo_U128_without_i128_or: 851; CHECK: # %bb.0: 852; CHECK-NEXT: addq %rdx, %rdi 853; CHECK-NEXT: adcq %rcx, %rsi 854; CHECK-NEXT: setb %al 855; CHECK-NEXT: movq %rsi, (%r8) 856; CHECK-NEXT: movq %rdi, 8(%r8) 857; CHECK-NEXT: retq 858 %6 = add i64 %2, %0 859 %7 = icmp ult i64 %6, %0 860 %8 = add i64 %3, %1 861 %9 = icmp ult i64 %8, %1 862 %10 = zext i1 %7 to i64 863 %11 = add i64 %8, %10 864 %12 = icmp ult i64 %11, %8 865 %13 = or i1 %9, %12 866 %14 = getelementptr inbounds %uint128, %uint128* %4, i64 0, i32 0 867 store i64 %11, i64* %14, align 8 868 %15 = getelementptr inbounds %uint128, %uint128* %4, i64 0, i32 1 869 store i64 %6, i64* %15, align 8 870 ret i1 %13 871} 872 873 874%uint192 = type { i64, i64, i64 } 875 876define void @add_U192_without_i128_or(%uint192* sret(%uint192) %0, i64 %1, i64 %2, i64 %3, i64 %4, i64 %5, i64 %6) nounwind { 877; CHECK-LABEL: add_U192_without_i128_or: 878; CHECK: # %bb.0: 879; CHECK-NEXT: movq %rdi, %rax 880; CHECK-NEXT: addq %r8, %rsi 881; CHECK-NEXT: adcq %r9, %rdx 882; CHECK-NEXT: adcq {{[0-9]+}}(%rsp), %rcx 883; CHECK-NEXT: movq %rcx, (%rdi) 884; CHECK-NEXT: movq %rdx, 8(%rdi) 885; CHECK-NEXT: movq %rsi, 16(%rdi) 886; CHECK-NEXT: retq 887 %8 = add i64 %4, %1 888 %9 = icmp ult i64 %8, %1 889 %10 = add i64 %5, %2 890 %11 = icmp ult i64 %10, %2 891 %12 = zext i1 %9 to i64 892 %13 = add i64 %10, %12 893 %14 = icmp ult i64 %13, %10 894 %15 = or i1 %11, %14 895 %16 = add i64 %6, %3 896 %17 = zext i1 %15 to i64 897 %18 = add i64 %16, %17 898 %19 = getelementptr inbounds %uint192, %uint192* %0, i64 0, i32 0 899 store i64 %18, i64* %19, align 8 900 %20 = getelementptr inbounds %uint192, %uint192* %0, i64 0, i32 1 901 store i64 %13, i64* %20, align 8 902 %21 = getelementptr inbounds %uint192, %uint192* %0, i64 0, i32 2 903 store i64 %8, i64* %21, align 8 904 ret void 905} 906 907 908%uint256 = type { %uint128, %uint128 } 909 910; Classic unrolled 256-bit addition implementation using i64 as the word type. 911; It starts by adding least significant words and propagates carry to additions of the higher words. 912define void @add_U256_without_i128_or_by_i64_words(%uint256* sret(%uint256) %0, %uint256* %1, %uint256* %2) nounwind { 913; CHECK-LABEL: add_U256_without_i128_or_by_i64_words: 914; CHECK: # %bb.0: 915; CHECK-NEXT: movq %rdi, %rax 916; CHECK-NEXT: movq (%rdx), %r8 917; CHECK-NEXT: movq 8(%rdx), %rdi 918; CHECK-NEXT: addq (%rsi), %r8 919; CHECK-NEXT: adcq 8(%rsi), %rdi 920; CHECK-NEXT: movq 16(%rdx), %rcx 921; CHECK-NEXT: adcq 16(%rsi), %rcx 922; CHECK-NEXT: movq 24(%rdx), %rdx 923; CHECK-NEXT: adcq 24(%rsi), %rdx 924; CHECK-NEXT: movq %rdx, (%rax) 925; CHECK-NEXT: movq %rcx, 8(%rax) 926; CHECK-NEXT: movq %rdi, 16(%rax) 927; CHECK-NEXT: movq %r8, 24(%rax) 928; CHECK-NEXT: retq 929 %4 = getelementptr inbounds %uint256, %uint256* %1, i64 0, i32 0, i32 0 930 %5 = load i64, i64* %4, align 8 931 %6 = getelementptr inbounds %uint256, %uint256* %2, i64 0, i32 0, i32 0 932 %7 = load i64, i64* %6, align 8 933 %8 = add i64 %7, %5 934 %9 = icmp ult i64 %8, %5 935 %10 = getelementptr inbounds %uint256, %uint256* %1, i64 0, i32 0, i32 1 936 %11 = load i64, i64* %10, align 8 937 %12 = getelementptr inbounds %uint256, %uint256* %2, i64 0, i32 0, i32 1 938 %13 = load i64, i64* %12, align 8 939 %14 = add i64 %13, %11 940 %15 = icmp ult i64 %14, %11 941 %16 = zext i1 %9 to i64 942 %17 = add i64 %14, %16 943 %18 = icmp ult i64 %17, %16 944 %19 = or i1 %15, %18 945 %20 = getelementptr inbounds %uint256, %uint256* %1, i64 0, i32 1, i32 0 946 %21 = load i64, i64* %20, align 8 947 %22 = getelementptr inbounds %uint256, %uint256* %2, i64 0, i32 1, i32 0 948 %23 = load i64, i64* %22, align 8 949 %24 = add i64 %23, %21 950 %25 = icmp ult i64 %24, %21 951 %26 = zext i1 %19 to i64 952 %27 = add i64 %24, %26 953 %28 = icmp ult i64 %27, %26 954 %29 = or i1 %25, %28 955 %30 = getelementptr inbounds %uint256, %uint256* %1, i64 0, i32 1, i32 1 956 %31 = load i64, i64* %30, align 8 957 %32 = getelementptr inbounds %uint256, %uint256* %2, i64 0, i32 1, i32 1 958 %33 = load i64, i64* %32, align 8 959 %34 = add i64 %33, %31 960 %35 = zext i1 %29 to i64 961 %36 = add i64 %34, %35 962 %37 = getelementptr inbounds %uint256, %uint256* %0, i64 0, i32 0, i32 0 963 store i64 %36, i64* %37, align 8 964 %38 = getelementptr inbounds %uint256, %uint256* %0, i64 0, i32 0, i32 1 965 store i64 %27, i64* %38, align 8 966 %39 = getelementptr inbounds %uint256, %uint256* %0, i64 0, i32 1, i32 0 967 store i64 %17, i64* %39, align 8 968 %40 = getelementptr inbounds %uint256, %uint256* %0, i64 0, i32 1, i32 1 969 store i64 %8, i64* %40, align 8 970 ret void 971} 972 973; The 256-bit addition implementation using two inlined uaddo procedures for U128 type { i64, i64 }. 974; This is similar to how LLVM legalize types in CodeGen. 975define void @add_U256_without_i128_or_recursive(%uint256* sret(%uint256) %0, %uint256* %1, %uint256* %2) nounwind { 976; CHECK-LABEL: add_U256_without_i128_or_recursive: 977; CHECK: # %bb.0: 978; CHECK-NEXT: movq %rdi, %rax 979; CHECK-NEXT: movq (%rdx), %r8 980; CHECK-NEXT: movq 8(%rdx), %rdi 981; CHECK-NEXT: addq (%rsi), %r8 982; CHECK-NEXT: adcq 8(%rsi), %rdi 983; CHECK-NEXT: movq 16(%rdx), %rcx 984; CHECK-NEXT: movq 24(%rdx), %rdx 985; CHECK-NEXT: adcq 16(%rsi), %rcx 986; CHECK-NEXT: adcq 24(%rsi), %rdx 987; CHECK-NEXT: movq %r8, (%rax) 988; CHECK-NEXT: movq %rdi, 8(%rax) 989; CHECK-NEXT: movq %rcx, 16(%rax) 990; CHECK-NEXT: movq %rdx, 24(%rax) 991; CHECK-NEXT: retq 992 %4 = getelementptr inbounds %uint256, %uint256* %1, i64 0, i32 0, i32 0 993 %5 = load i64, i64* %4, align 8 994 %6 = getelementptr inbounds %uint256, %uint256* %1, i64 0, i32 0, i32 1 995 %7 = load i64, i64* %6, align 8 996 %8 = getelementptr inbounds %uint256, %uint256* %2, i64 0, i32 0, i32 0 997 %9 = load i64, i64* %8, align 8 998 %10 = getelementptr inbounds %uint256, %uint256* %2, i64 0, i32 0, i32 1 999 %11 = load i64, i64* %10, align 8 1000 %12 = add i64 %9, %5 1001 %13 = icmp ult i64 %12, %5 1002 %14 = add i64 %11, %7 1003 %15 = icmp ult i64 %14, %7 1004 %16 = zext i1 %13 to i64 1005 %17 = add i64 %14, %16 1006 %18 = icmp ult i64 %17, %14 1007 %19 = or i1 %15, %18 1008 %20 = getelementptr inbounds %uint256, %uint256* %1, i64 0, i32 1, i32 0 1009 %21 = load i64, i64* %20, align 8 1010 %22 = getelementptr inbounds %uint256, %uint256* %1, i64 0, i32 1, i32 1 1011 %23 = load i64, i64* %22, align 8 1012 %24 = getelementptr inbounds %uint256, %uint256* %2, i64 0, i32 1, i32 0 1013 %25 = load i64, i64* %24, align 8 1014 %26 = getelementptr inbounds %uint256, %uint256* %2, i64 0, i32 1, i32 1 1015 %27 = load i64, i64* %26, align 8 1016 %28 = add i64 %25, %21 1017 %29 = icmp ult i64 %28, %21 1018 %30 = add i64 %27, %23 1019 %31 = zext i1 %29 to i64 1020 %32 = add i64 %30, %31 1021 %33 = zext i1 %19 to i64 1022 %34 = add i64 %28, %33 1023 %35 = icmp ult i64 %34, %28 1024 %36 = zext i1 %35 to i64 1025 %37 = add i64 %32, %36 1026 %38 = getelementptr inbounds %uint256, %uint256* %0, i64 0, i32 0, i32 0 1027 store i64 %12, i64* %38, align 8 1028 %39 = getelementptr inbounds %uint256, %uint256* %0, i64 0, i32 0, i32 1 1029 store i64 %17, i64* %39, align 8 1030 %40 = getelementptr inbounds %uint256, %uint256* %0, i64 0, i32 1, i32 0 1031 store i64 %34, i64* %40, align 8 1032 %41 = getelementptr inbounds %uint256, %uint256* %0, i64 0, i32 1, i32 1 1033 store i64 %37, i64* %41, align 8 1034 ret void 1035} 1036