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.subborrow.64(i8, i64, i64) 5declare { i64, i1 } @llvm.usub.with.overflow.i64(i64, i64) 6 7define i128 @sub128(i128 %a, i128 %b) nounwind { 8; CHECK-LABEL: sub128: 9; CHECK: # %bb.0: # %entry 10; CHECK-NEXT: movq %rdi, %rax 11; CHECK-NEXT: subq %rdx, %rax 12; CHECK-NEXT: sbbq %rcx, %rsi 13; CHECK-NEXT: movq %rsi, %rdx 14; CHECK-NEXT: retq 15entry: 16 %0 = sub i128 %a, %b 17 ret i128 %0 18} 19 20define i256 @sub256(i256 %a, i256 %b) nounwind { 21; CHECK-LABEL: sub256: 22; CHECK: # %bb.0: # %entry 23; CHECK-NEXT: movq %rdi, %rax 24; CHECK-NEXT: subq %r9, %rsi 25; CHECK-NEXT: sbbq {{[0-9]+}}(%rsp), %rdx 26; CHECK-NEXT: sbbq {{[0-9]+}}(%rsp), %rcx 27; CHECK-NEXT: sbbq {{[0-9]+}}(%rsp), %r8 28; CHECK-NEXT: movq %rcx, 16(%rdi) 29; CHECK-NEXT: movq %rdx, 8(%rdi) 30; CHECK-NEXT: movq %rsi, (%rdi) 31; CHECK-NEXT: movq %r8, 24(%rdi) 32; CHECK-NEXT: retq 33entry: 34 %0 = sub i256 %a, %b 35 ret i256 %0 36} 37 38%S = type { [4 x i64] } 39 40define %S @negate(ptr nocapture readonly %this) { 41; CHECK-LABEL: negate: 42; CHECK: # %bb.0: # %entry 43; CHECK-NEXT: movq %rdi, %rax 44; CHECK-NEXT: xorl %ecx, %ecx 45; CHECK-NEXT: xorl %edx, %edx 46; CHECK-NEXT: subq (%rsi), %rdx 47; CHECK-NEXT: movl $0, %edi 48; CHECK-NEXT: sbbq 8(%rsi), %rdi 49; CHECK-NEXT: movl $0, %r8d 50; CHECK-NEXT: sbbq 16(%rsi), %r8 51; CHECK-NEXT: sbbq 24(%rsi), %rcx 52; CHECK-NEXT: movq %rdx, (%rax) 53; CHECK-NEXT: movq %rdi, 8(%rax) 54; CHECK-NEXT: movq %r8, 16(%rax) 55; CHECK-NEXT: movq %rcx, 24(%rax) 56; CHECK-NEXT: retq 57entry: 58 %0 = load i64, ptr %this, align 8 59 %1 = xor i64 %0, -1 60 %2 = zext i64 %1 to i128 61 %3 = add nuw nsw i128 %2, 1 62 %4 = trunc i128 %3 to i64 63 %5 = lshr i128 %3, 64 64 %6 = getelementptr inbounds %S, ptr %this, i64 0, i32 0, i64 1 65 %7 = load i64, ptr %6, align 8 66 %8 = xor i64 %7, -1 67 %9 = zext i64 %8 to i128 68 %10 = add nuw nsw i128 %5, %9 69 %11 = trunc i128 %10 to i64 70 %12 = lshr i128 %10, 64 71 %13 = getelementptr inbounds %S, ptr %this, i64 0, i32 0, i64 2 72 %14 = load i64, ptr %13, align 8 73 %15 = xor i64 %14, -1 74 %16 = zext i64 %15 to i128 75 %17 = add nuw nsw i128 %12, %16 76 %18 = lshr i128 %17, 64 77 %19 = trunc i128 %17 to i64 78 %20 = getelementptr inbounds %S, ptr %this, i64 0, i32 0, i64 3 79 %21 = load i64, ptr %20, align 8 80 %22 = xor i64 %21, -1 81 %23 = zext i64 %22 to i128 82 %24 = add nuw nsw i128 %18, %23 83 %25 = trunc i128 %24 to i64 84 %26 = insertvalue [4 x i64] undef, i64 %4, 0 85 %27 = insertvalue [4 x i64] %26, i64 %11, 1 86 %28 = insertvalue [4 x i64] %27, i64 %19, 2 87 %29 = insertvalue [4 x i64] %28, i64 %25, 3 88 %30 = insertvalue %S undef, [4 x i64] %29, 0 89 ret %S %30 90} 91 92define %S @sub(ptr nocapture readonly %this, %S %arg.b) { 93; CHECK-LABEL: sub: 94; CHECK: # %bb.0: # %entry 95; CHECK-NEXT: movq %rdi, %rax 96; CHECK-NEXT: movq (%rsi), %rdi 97; CHECK-NEXT: movq 8(%rsi), %r10 98; CHECK-NEXT: subq %rdx, %rdi 99; CHECK-NEXT: setae %dl 100; CHECK-NEXT: addb $-1, %dl 101; CHECK-NEXT: adcq $0, %r10 102; CHECK-NEXT: setb %dl 103; CHECK-NEXT: movzbl %dl, %edx 104; CHECK-NEXT: notq %rcx 105; CHECK-NEXT: addq %r10, %rcx 106; CHECK-NEXT: adcq 16(%rsi), %rdx 107; CHECK-NEXT: setb %r10b 108; CHECK-NEXT: movzbl %r10b, %r10d 109; CHECK-NEXT: notq %r8 110; CHECK-NEXT: addq %rdx, %r8 111; CHECK-NEXT: adcq 24(%rsi), %r10 112; CHECK-NEXT: notq %r9 113; CHECK-NEXT: addq %r10, %r9 114; CHECK-NEXT: movq %rdi, (%rax) 115; CHECK-NEXT: movq %rcx, 8(%rax) 116; CHECK-NEXT: movq %r8, 16(%rax) 117; CHECK-NEXT: movq %r9, 24(%rax) 118; CHECK-NEXT: retq 119entry: 120 %0 = extractvalue %S %arg.b, 0 121 %.elt6 = extractvalue [4 x i64] %0, 1 122 %.elt8 = extractvalue [4 x i64] %0, 2 123 %.elt10 = extractvalue [4 x i64] %0, 3 124 %.elt = extractvalue [4 x i64] %0, 0 125 %1 = load i64, ptr %this, align 8 126 %2 = zext i64 %1 to i128 127 %3 = add nuw nsw i128 %2, 1 128 %4 = xor i64 %.elt, -1 129 %5 = zext i64 %4 to i128 130 %6 = add nuw nsw i128 %3, %5 131 %7 = trunc i128 %6 to i64 132 %8 = lshr i128 %6, 64 133 %9 = getelementptr inbounds %S, ptr %this, i64 0, i32 0, i64 1 134 %10 = load i64, ptr %9, align 8 135 %11 = zext i64 %10 to i128 136 %12 = add nuw nsw i128 %8, %11 137 %13 = xor i64 %.elt6, -1 138 %14 = zext i64 %13 to i128 139 %15 = add nuw nsw i128 %12, %14 140 %16 = trunc i128 %15 to i64 141 %17 = lshr i128 %15, 64 142 %18 = getelementptr inbounds %S, ptr %this, i64 0, i32 0, i64 2 143 %19 = load i64, ptr %18, align 8 144 %20 = zext i64 %19 to i128 145 %21 = add nuw nsw i128 %17, %20 146 %22 = xor i64 %.elt8, -1 147 %23 = zext i64 %22 to i128 148 %24 = add nuw nsw i128 %21, %23 149 %25 = lshr i128 %24, 64 150 %26 = trunc i128 %24 to i64 151 %27 = getelementptr inbounds %S, ptr %this, i64 0, i32 0, i64 3 152 %28 = load i64, ptr %27, align 8 153 %29 = zext i64 %28 to i128 154 %30 = add nuw nsw i128 %25, %29 155 %31 = xor i64 %.elt10, -1 156 %32 = zext i64 %31 to i128 157 %33 = add nuw nsw i128 %30, %32 158 %34 = trunc i128 %33 to i64 159 %35 = insertvalue [4 x i64] undef, i64 %7, 0 160 %36 = insertvalue [4 x i64] %35, i64 %16, 1 161 %37 = insertvalue [4 x i64] %36, i64 %26, 2 162 %38 = insertvalue [4 x i64] %37, i64 %34, 3 163 %39 = insertvalue %S undef, [4 x i64] %38, 0 164 ret %S %39 165} 166 167declare {i64, i1} @llvm.uadd.with.overflow(i64, i64) 168declare {i64, i1} @llvm.usub.with.overflow(i64, i64) 169 170define i64 @sub_from_carry(i64 %x, i64 %y, ptr %valout, i64 %z) { 171; CHECK-LABEL: sub_from_carry: 172; CHECK: # %bb.0: 173; CHECK-NEXT: movq %rcx, %rax 174; CHECK-NEXT: negq %rax 175; CHECK-NEXT: addq %rsi, %rdi 176; CHECK-NEXT: movq %rdi, (%rdx) 177; CHECK-NEXT: adcq $0, %rax 178; CHECK-NEXT: retq 179 %agg = call {i64, i1} @llvm.uadd.with.overflow(i64 %x, i64 %y) 180 %val = extractvalue {i64, i1} %agg, 0 181 %ov = extractvalue {i64, i1} %agg, 1 182 store i64 %val, ptr %valout, align 4 183 %carry = zext i1 %ov to i64 184 %res = sub i64 %carry, %z 185 ret i64 %res 186} 187 188; basic test for combineCarryDiamond() 189define { i64, i64, i1 } @subcarry_2x64(i64 %x0, i64 %x1, i64 %y0, i64 %y1) nounwind { 190; CHECK-LABEL: subcarry_2x64: 191; CHECK: # %bb.0: 192; CHECK-NEXT: movq %rdi, %rax 193; CHECK-NEXT: subq %rdx, %rax 194; CHECK-NEXT: sbbq %rcx, %rsi 195; CHECK-NEXT: setb %cl 196; CHECK-NEXT: movq %rsi, %rdx 197; CHECK-NEXT: retq 198 %t0 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %x0, i64 %y0) 199 %s0 = extractvalue { i64, i1 } %t0, 0 200 %k0 = extractvalue { i64, i1 } %t0, 1 201 202 %t1 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %x1, i64 %y1) 203 %s1 = extractvalue { i64, i1 } %t1, 0 204 %k1 = extractvalue { i64, i1 } %t1, 1 205 206 %zk0 = zext i1 %k0 to i64 207 %t2 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %s1, i64 %zk0) 208 %s2 = extractvalue { i64, i1 } %t2, 0 209 %k2 = extractvalue { i64, i1 } %t2, 1 210 %k = or i1 %k1, %k2 211 212 %r0 = insertvalue { i64, i64, i1 } poison, i64 %s0, 0 213 %r1 = insertvalue { i64, i64, i1 } %r0, i64 %s2, 1 214 %r = insertvalue { i64, i64, i1 } %r1, i1 %k, 2 215 ret { i64, i64, i1 } %r 216} 217 218; basic test for combineCarryDiamond() with or operands reversed 219define { i64, i64, i1 } @subcarry_2x64_or_reversed(i64 %x0, i64 %x1, i64 %y0, i64 %y1) nounwind { 220; CHECK-LABEL: subcarry_2x64_or_reversed: 221; CHECK: # %bb.0: 222; CHECK-NEXT: movq %rdi, %rax 223; CHECK-NEXT: subq %rdx, %rax 224; CHECK-NEXT: sbbq %rcx, %rsi 225; CHECK-NEXT: setb %cl 226; CHECK-NEXT: movq %rsi, %rdx 227; CHECK-NEXT: retq 228 %t0 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %x0, i64 %y0) 229 %s0 = extractvalue { i64, i1 } %t0, 0 230 %k0 = extractvalue { i64, i1 } %t0, 1 231 232 %t1 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %x1, i64 %y1) 233 %s1 = extractvalue { i64, i1 } %t1, 0 234 %k1 = extractvalue { i64, i1 } %t1, 1 235 236 %zk0 = zext i1 %k0 to i64 237 %t2 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %s1, i64 %zk0) 238 %s2 = extractvalue { i64, i1 } %t2, 0 239 %k2 = extractvalue { i64, i1 } %t2, 1 240 %k = or i1 %k2, %k1 ; reverse natural order of operands 241 242 %r0 = insertvalue { i64, i64, i1 } poison, i64 %s0, 0 243 %r1 = insertvalue { i64, i64, i1 } %r0, i64 %s2, 1 244 %r = insertvalue { i64, i64, i1 } %r1, i1 %k, 2 245 ret { i64, i64, i1 } %r 246} 247 248; basic test for combineCarryDiamond() with xor operands reversed 249define { i64, i64, i1 } @subcarry_2x64_xor_reversed(i64 %x0, i64 %x1, i64 %y0, i64 %y1) nounwind { 250; CHECK-LABEL: subcarry_2x64_xor_reversed: 251; CHECK: # %bb.0: 252; CHECK-NEXT: movq %rdi, %rax 253; CHECK-NEXT: subq %rdx, %rax 254; CHECK-NEXT: sbbq %rcx, %rsi 255; CHECK-NEXT: setb %cl 256; CHECK-NEXT: movq %rsi, %rdx 257; CHECK-NEXT: retq 258 %t0 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %x0, i64 %y0) 259 %s0 = extractvalue { i64, i1 } %t0, 0 260 %k0 = extractvalue { i64, i1 } %t0, 1 261 262 %t1 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %x1, i64 %y1) 263 %s1 = extractvalue { i64, i1 } %t1, 0 264 %k1 = extractvalue { i64, i1 } %t1, 1 265 266 %zk0 = zext i1 %k0 to i64 267 %t2 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %s1, i64 %zk0) 268 %s2 = extractvalue { i64, i1 } %t2, 0 269 %k2 = extractvalue { i64, i1 } %t2, 1 270 %k = xor i1 %k2, %k1 ; reverse natural order of operands 271 272 %r0 = insertvalue { i64, i64, i1 } poison, i64 %s0, 0 273 %r1 = insertvalue { i64, i64, i1 } %r0, i64 %s2, 1 274 %r = insertvalue { i64, i64, i1 } %r1, i1 %k, 2 275 ret { i64, i64, i1 } %r 276} 277 278; basic test for combineCarryDiamond() with and operands reversed 279define { i64, i64, i1 } @subcarry_2x64_and_reversed(i64 %x0, i64 %x1, i64 %y0, i64 %y1) nounwind { 280; CHECK-LABEL: subcarry_2x64_and_reversed: 281; CHECK: # %bb.0: 282; CHECK-NEXT: movq %rdi, %rax 283; CHECK-NEXT: subq %rdx, %rax 284; CHECK-NEXT: sbbq %rcx, %rsi 285; CHECK-NEXT: movq %rsi, %rdx 286; CHECK-NEXT: xorl %ecx, %ecx 287; CHECK-NEXT: retq 288 %t0 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %x0, i64 %y0) 289 %s0 = extractvalue { i64, i1 } %t0, 0 290 %k0 = extractvalue { i64, i1 } %t0, 1 291 292 %t1 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %x1, i64 %y1) 293 %s1 = extractvalue { i64, i1 } %t1, 0 294 %k1 = extractvalue { i64, i1 } %t1, 1 295 296 %zk0 = zext i1 %k0 to i64 297 %t2 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %s1, i64 %zk0) 298 %s2 = extractvalue { i64, i1 } %t2, 0 299 %k2 = extractvalue { i64, i1 } %t2, 1 300 %k = and i1 %k2, %k1 ; reverse natural order of operands 301 302 %r0 = insertvalue { i64, i64, i1 } poison, i64 %s0, 0 303 %r1 = insertvalue { i64, i64, i1 } %r0, i64 %s2, 1 304 %r = insertvalue { i64, i64, i1 } %r1, i1 %k, 2 305 ret { i64, i64, i1 } %r 306} 307 308; basic test for combineCarryDiamond() with add operands reversed 309define { i64, i64, i1 } @subcarry_2x64_add_reversed(i64 %x0, i64 %x1, i64 %y0, i64 %y1) nounwind { 310; CHECK-LABEL: subcarry_2x64_add_reversed: 311; CHECK: # %bb.0: 312; CHECK-NEXT: movq %rdi, %rax 313; CHECK-NEXT: movq %rsi, %rdi 314; CHECK-NEXT: subq %rcx, %rdi 315; CHECK-NEXT: subq %rdx, %rax 316; CHECK-NEXT: sbbq $0, %rdi 317; CHECK-NEXT: setb %r8b 318; CHECK-NEXT: cmpq %rcx, %rsi 319; CHECK-NEXT: adcb $0, %r8b 320; CHECK-NEXT: movq %rdi, %rdx 321; CHECK-NEXT: movl %r8d, %ecx 322; CHECK-NEXT: retq 323 %t0 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %x0, i64 %y0) 324 %s0 = extractvalue { i64, i1 } %t0, 0 325 %k0 = extractvalue { i64, i1 } %t0, 1 326 327 %t1 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %x1, i64 %y1) 328 %s1 = extractvalue { i64, i1 } %t1, 0 329 %k1 = extractvalue { i64, i1 } %t1, 1 330 331 %zk0 = zext i1 %k0 to i64 332 %t2 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %s1, i64 %zk0) 333 %s2 = extractvalue { i64, i1 } %t2, 0 334 %k2 = extractvalue { i64, i1 } %t2, 1 335 %k = add i1 %k2, %k1 ; reverse natural order of operands 336 337 %r0 = insertvalue { i64, i64, i1 } poison, i64 %s0, 0 338 %r1 = insertvalue { i64, i64, i1 } %r0, i64 %s2, 1 339 %r = insertvalue { i64, i64, i1 } %r1, i1 %k, 2 340 ret { i64, i64, i1 } %r 341} 342 343; Here %carryin is considered as valid carry flag for combining into ADDCARRY 344; although %carryin does not come from any carry-producing instruction. 345define { i64, i1 } @subcarry_fake_carry(i64 %a, i64 %b, i1 %carryin) { 346; CHECK-LABEL: subcarry_fake_carry: 347; CHECK: # %bb.0: 348; CHECK-NEXT: movq %rdi, %rax 349; CHECK-NEXT: btl $0, %edx 350; CHECK-NEXT: sbbq %rsi, %rax 351; CHECK-NEXT: setb %dl 352; CHECK-NEXT: retq 353 %t1 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %a, i64 %b) 354 %partial = extractvalue { i64, i1 } %t1, 0 355 %k1 = extractvalue { i64, i1 } %t1, 1 356 357 %zcarryin = zext i1 %carryin to i64 358 %s = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %partial, i64 %zcarryin) 359 %k2 = extractvalue { i64, i1 } %s, 1 360 361 %carryout = or i1 %k1, %k2 362 363 %ret = insertvalue { i64, i1 } %s, i1 %carryout, 1 364 ret { i64, i1 } %ret 365} 366 367; negative test: %carryin does not look like carry 368define { i64, i1 } @subcarry_carry_not_zext(i64 %a, i64 %b, i64 %carryin) { 369; CHECK-LABEL: subcarry_carry_not_zext: 370; CHECK: # %bb.0: 371; CHECK-NEXT: movq %rdi, %rax 372; CHECK-NEXT: subq %rsi, %rax 373; CHECK-NEXT: setb %cl 374; CHECK-NEXT: subq %rdx, %rax 375; CHECK-NEXT: setb %dl 376; CHECK-NEXT: orb %cl, %dl 377; CHECK-NEXT: retq 378 %t1 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %a, i64 %b) 379 %partial = extractvalue { i64, i1 } %t1, 0 380 %k1 = extractvalue { i64, i1 } %t1, 1 381 382 %s = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %partial, i64 %carryin) 383 %k2 = extractvalue { i64, i1 } %s, 1 384 385 %carryout = or i1 %k1, %k2 386 387 %ret = insertvalue { i64, i1 } %s, i1 %carryout, 1 388 ret { i64, i1 } %ret 389} 390 391; negative test: %carryin does not look like carry 392define { i64, i1 } @subcarry_carry_not_i1(i64 %a, i64 %b, i8 %carryin) { 393; CHECK-LABEL: subcarry_carry_not_i1: 394; CHECK: # %bb.0: 395; CHECK-NEXT: movq %rdi, %rax 396; CHECK-NEXT: subq %rsi, %rax 397; CHECK-NEXT: setb %cl 398; CHECK-NEXT: movzbl %dl, %edx 399; CHECK-NEXT: subq %rdx, %rax 400; CHECK-NEXT: setb %dl 401; CHECK-NEXT: orb %cl, %dl 402; CHECK-NEXT: retq 403 %t1 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %a, i64 %b) 404 %partial = extractvalue { i64, i1 } %t1, 0 405 %k1 = extractvalue { i64, i1 } %t1, 1 406 407 %zcarryin = zext i8 %carryin to i64 408 %s = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %partial, i64 %zcarryin) 409 %k2 = extractvalue { i64, i1 } %s, 1 410 411 %carryout = or i1 %k1, %k2 412 413 %ret = insertvalue { i64, i1 } %s, i1 %carryout, 1 414 ret { i64, i1 } %ret 415} 416 417%struct.U320 = type { [5 x i64] } 418 419define i32 @sub_U320_without_i128_or(ptr nocapture dereferenceable(40) %0, i64 %1, i64 %2, i64 %3, i64 %4, i64 %5) { 420; CHECK-LABEL: sub_U320_without_i128_or: 421; CHECK: # %bb.0: 422; CHECK-NEXT: subq %rsi, (%rdi) 423; CHECK-NEXT: sbbq %rdx, 8(%rdi) 424; CHECK-NEXT: sbbq %rcx, 16(%rdi) 425; CHECK-NEXT: sbbq %r8, 24(%rdi) 426; CHECK-NEXT: sbbq %r9, 32(%rdi) 427; CHECK-NEXT: setb %al 428; CHECK-NEXT: movzbl %al, %eax 429; CHECK-NEXT: retq 430 %7 = load i64, ptr %0, align 8 431 %8 = getelementptr inbounds %struct.U320, ptr %0, i64 0, i32 0, i64 1 432 %9 = load i64, ptr %8, align 8 433 %10 = getelementptr inbounds %struct.U320, ptr %0, i64 0, i32 0, i64 2 434 %11 = load i64, ptr %10, align 8 435 %12 = getelementptr inbounds %struct.U320, ptr %0, i64 0, i32 0, i64 3 436 %13 = load i64, ptr %12, align 8 437 %14 = getelementptr inbounds %struct.U320, ptr %0, i64 0, i32 0, i64 4 438 %15 = load i64, ptr %14, align 8 439 %16 = sub i64 %7, %1 440 %17 = sub i64 %9, %2 441 %18 = icmp ult i64 %7, %1 442 %19 = zext i1 %18 to i64 443 %20 = sub i64 %17, %19 444 %21 = sub i64 %11, %3 445 %22 = icmp ult i64 %9, %2 446 %23 = icmp ult i64 %17, %19 447 %24 = or i1 %22, %23 448 %25 = zext i1 %24 to i64 449 %26 = sub i64 %21, %25 450 %27 = sub i64 %13, %4 451 %28 = icmp ult i64 %11, %3 452 %29 = icmp ult i64 %21, %25 453 %30 = or i1 %28, %29 454 %31 = zext i1 %30 to i64 455 %32 = sub i64 %27, %31 456 %33 = sub i64 %15, %5 457 %34 = icmp ult i64 %13, %4 458 %35 = icmp ult i64 %27, %31 459 %36 = or i1 %34, %35 460 %37 = zext i1 %36 to i64 461 %38 = sub i64 %33, %37 462 store i64 %16, ptr %0, align 8 463 store i64 %20, ptr %8, align 8 464 store i64 %26, ptr %10, align 8 465 store i64 %32, ptr %12, align 8 466 store i64 %38, ptr %14, align 8 467 %39 = icmp ult i64 %15, %5 468 %40 = icmp ult i64 %33, %37 469 %41 = or i1 %39, %40 470 %42 = zext i1 %41 to i32 471 ret i32 %42 472} 473 474define i32 @sub_U320_usubo(ptr nocapture dereferenceable(40) %0, i64 %1, i64 %2, i64 %3, i64 %4, i64 %5) { 475; CHECK-LABEL: sub_U320_usubo: 476; CHECK: # %bb.0: 477; CHECK-NEXT: subq %rsi, (%rdi) 478; CHECK-NEXT: sbbq %rdx, 8(%rdi) 479; CHECK-NEXT: sbbq %rcx, 16(%rdi) 480; CHECK-NEXT: sbbq %r8, 24(%rdi) 481; CHECK-NEXT: sbbq %r9, 32(%rdi) 482; CHECK-NEXT: setb %al 483; CHECK-NEXT: movzbl %al, %eax 484; CHECK-NEXT: retq 485 %7 = load i64, ptr %0, align 8 486 %8 = getelementptr inbounds %struct.U320, ptr %0, i64 0, i32 0, i64 1 487 %9 = load i64, ptr %8, align 8 488 %10 = getelementptr inbounds %struct.U320, ptr %0, i64 0, i32 0, i64 2 489 %11 = load i64, ptr %10, align 8 490 %12 = getelementptr inbounds %struct.U320, ptr %0, i64 0, i32 0, i64 3 491 %13 = load i64, ptr %12, align 8 492 %14 = getelementptr inbounds %struct.U320, ptr %0, i64 0, i32 0, i64 4 493 %15 = load i64, ptr %14, align 8 494 %16 = tail call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %7, i64 %1) 495 %17 = extractvalue { i64, i1 } %16, 1 496 %18 = extractvalue { i64, i1 } %16, 0 497 %19 = zext i1 %17 to i64 498 %20 = tail call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %9, i64 %2) 499 %21 = extractvalue { i64, i1 } %20, 1 500 %22 = extractvalue { i64, i1 } %20, 0 501 %23 = tail call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %22, i64 %19) 502 %24 = extractvalue { i64, i1 } %23, 1 503 %25 = extractvalue { i64, i1 } %23, 0 504 %26 = or i1 %21, %24 505 %27 = zext i1 %26 to i64 506 %28 = tail call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %11, i64 %3) 507 %29 = extractvalue { i64, i1 } %28, 1 508 %30 = extractvalue { i64, i1 } %28, 0 509 %31 = tail call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %30, i64 %27) 510 %32 = extractvalue { i64, i1 } %31, 1 511 %33 = extractvalue { i64, i1 } %31, 0 512 %34 = or i1 %29, %32 513 %35 = zext i1 %34 to i64 514 %36 = tail call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %13, i64 %4) 515 %37 = extractvalue { i64, i1 } %36, 1 516 %38 = extractvalue { i64, i1 } %36, 0 517 %39 = tail call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %38, i64 %35) 518 %40 = extractvalue { i64, i1 } %39, 1 519 %41 = extractvalue { i64, i1 } %39, 0 520 %42 = or i1 %37, %40 521 %43 = zext i1 %42 to i64 522 %44 = tail call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %15, i64 %5) 523 %45 = extractvalue { i64, i1 } %44, 1 524 %46 = extractvalue { i64, i1 } %44, 0 525 %47 = tail call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %46, i64 %43) 526 %48 = extractvalue { i64, i1 } %47, 1 527 %49 = extractvalue { i64, i1 } %47, 0 528 %50 = or i1 %45, %48 529 store i64 %18, ptr %0, align 8 530 store i64 %25, ptr %8, align 8 531 store i64 %33, ptr %10, align 8 532 store i64 %41, ptr %12, align 8 533 store i64 %49, ptr %14, align 8 534 %51 = zext i1 %50 to i32 535 ret i32 %51 536} 537 538%struct.U192 = type { [3 x i64] } 539 540define void @PR39464(ptr noalias nocapture sret(%struct.U192) %0, ptr nocapture readonly dereferenceable(24) %1, ptr nocapture readonly dereferenceable(24) %2) { 541; CHECK-LABEL: PR39464: 542; CHECK: # %bb.0: 543; CHECK-NEXT: movq %rdi, %rax 544; CHECK-NEXT: movq (%rsi), %rcx 545; CHECK-NEXT: subq (%rdx), %rcx 546; CHECK-NEXT: movq %rcx, (%rdi) 547; CHECK-NEXT: movq 8(%rsi), %rcx 548; CHECK-NEXT: sbbq 8(%rdx), %rcx 549; CHECK-NEXT: movq %rcx, 8(%rdi) 550; CHECK-NEXT: movq 16(%rsi), %rcx 551; CHECK-NEXT: sbbq 16(%rdx), %rcx 552; CHECK-NEXT: movq %rcx, 16(%rdi) 553; CHECK-NEXT: retq 554 %4 = load i64, ptr %1, align 8 555 %5 = load i64, ptr %2, align 8 556 %6 = tail call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %4, i64 %5) 557 %7 = extractvalue { i64, i1 } %6, 1 558 %8 = extractvalue { i64, i1 } %6, 0 559 %9 = zext i1 %7 to i64 560 store i64 %8, ptr %0, align 8 561 %10 = getelementptr inbounds %struct.U192, ptr %1, i64 0, i32 0, i64 1 562 %11 = load i64, ptr %10, align 8 563 %12 = getelementptr inbounds %struct.U192, ptr %2, i64 0, i32 0, i64 1 564 %13 = load i64, ptr %12, align 8 565 %14 = tail call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %11, i64 %13) 566 %15 = extractvalue { i64, i1 } %14, 1 567 %16 = extractvalue { i64, i1 } %14, 0 568 %17 = tail call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %16, i64 %9) 569 %18 = extractvalue { i64, i1 } %17, 1 570 %19 = extractvalue { i64, i1 } %17, 0 571 %20 = or i1 %15, %18 572 %21 = zext i1 %20 to i64 573 %22 = getelementptr inbounds %struct.U192, ptr %0, i64 0, i32 0, i64 1 574 store i64 %19, ptr %22, align 8 575 %23 = getelementptr inbounds %struct.U192, ptr %1, i64 0, i32 0, i64 2 576 %24 = load i64, ptr %23, align 8 577 %25 = getelementptr inbounds %struct.U192, ptr %2, i64 0, i32 0, i64 2 578 %26 = load i64, ptr %25, align 8 579 %27 = sub i64 %24, %26 580 %28 = sub i64 %27, %21 581 %29 = getelementptr inbounds %struct.U192, ptr %0, i64 0, i32 0, i64 2 582 store i64 %28, ptr %29, align 8 583 ret void 584} 585 586%uint128 = type { i64, i64 } 587%uint256 = type { %uint128, %uint128 } 588 589; The 256-bit subtraction implementation using two inlined usubo procedures for U128 type { i64, i64 }. 590; This is similar to how LLVM legalize types in CodeGen. 591define void @sub_U256_without_i128_or_recursive(ptr sret(%uint256) %0, ptr %1, ptr %2) nounwind { 592; CHECK-LABEL: sub_U256_without_i128_or_recursive: 593; CHECK: # %bb.0: 594; CHECK-NEXT: movq %rdi, %rax 595; CHECK-NEXT: movq (%rsi), %rcx 596; CHECK-NEXT: movq 8(%rsi), %rdi 597; CHECK-NEXT: movq 16(%rsi), %r8 598; CHECK-NEXT: movq 24(%rsi), %rsi 599; CHECK-NEXT: xorl %r9d, %r9d 600; CHECK-NEXT: subq 16(%rdx), %r8 601; CHECK-NEXT: setb %r9b 602; CHECK-NEXT: subq 24(%rdx), %rsi 603; CHECK-NEXT: subq (%rdx), %rcx 604; CHECK-NEXT: sbbq 8(%rdx), %rdi 605; CHECK-NEXT: sbbq $0, %r8 606; CHECK-NEXT: sbbq %r9, %rsi 607; CHECK-NEXT: movq %rcx, (%rax) 608; CHECK-NEXT: movq %rdi, 8(%rax) 609; CHECK-NEXT: movq %r8, 16(%rax) 610; CHECK-NEXT: movq %rsi, 24(%rax) 611; CHECK-NEXT: retq 612 %4 = load i64, ptr %1, align 8 613 %5 = getelementptr inbounds %uint256, ptr %1, i64 0, i32 0, i32 1 614 %6 = load i64, ptr %5, align 8 615 %7 = load i64, ptr %2, align 8 616 %8 = getelementptr inbounds %uint256, ptr %2, i64 0, i32 0, i32 1 617 %9 = load i64, ptr %8, align 8 618 %10 = sub i64 %4, %7 619 %11 = icmp ult i64 %4, %7 620 %12 = sub i64 %6, %9 621 %13 = icmp ult i64 %6, %9 622 %14 = zext i1 %11 to i64 623 %15 = sub i64 %12, %14 624 %16 = icmp ult i64 %12, %14 625 %17 = or i1 %13, %16 626 %18 = getelementptr inbounds %uint256, ptr %1, i64 0, i32 1, i32 0 627 %19 = load i64, ptr %18, align 8 628 %20 = getelementptr inbounds %uint256, ptr %1, i64 0, i32 1, i32 1 629 %21 = load i64, ptr %20, align 8 630 %22 = getelementptr inbounds %uint256, ptr %2, i64 0, i32 1, i32 0 631 %23 = load i64, ptr %22, align 8 632 %24 = getelementptr inbounds %uint256, ptr %2, i64 0, i32 1, i32 1 633 %25 = load i64, ptr %24, align 8 634 %26 = sub i64 %19, %23 635 %27 = icmp ult i64 %19, %23 636 %28 = sub i64 %21, %25 637 %29 = zext i1 %27 to i64 638 %30 = sub i64 %28, %29 639 %31 = zext i1 %17 to i64 640 %32 = sub i64 %26, %31 641 %33 = icmp ult i64 %26, %31 642 %34 = zext i1 %33 to i64 643 %35 = sub i64 %30, %34 644 store i64 %10, ptr %0, align 8 645 %36 = getelementptr inbounds %uint256, ptr %0, i64 0, i32 0, i32 1 646 store i64 %15, ptr %36, align 8 647 %37 = getelementptr inbounds %uint256, ptr %0, i64 0, i32 1, i32 0 648 store i64 %32, ptr %37, align 8 649 %38 = getelementptr inbounds %uint256, ptr %0, i64 0, i32 1, i32 1 650 store i64 %35, ptr %38, align 8 651 ret void 652} 653 654; unsigned less than of two 2x64 integers 655; TODO: This should be optimized to cmp + sbb. 656define i1 @subcarry_ult_2x64(i64 %x0, i64 %x1, i64 %y0, i64 %y1) nounwind { 657; CHECK-LABEL: subcarry_ult_2x64: 658; CHECK: # %bb.0: 659; CHECK-NEXT: subq %rcx, %rsi 660; CHECK-NEXT: setb %cl 661; CHECK-NEXT: cmpq %rdx, %rdi 662; CHECK-NEXT: sbbq $0, %rsi 663; CHECK-NEXT: setb %al 664; CHECK-NEXT: orb %cl, %al 665; CHECK-NEXT: retq 666 %b0 = icmp ult i64 %x0, %y0 667 %d1 = sub i64 %x1, %y1 668 %b10 = icmp ult i64 %x1, %y1 669 %b0z = zext i1 %b0 to i64 670 %b11 = icmp ult i64 %d1, %b0z 671 %b1 = or i1 %b10, %b11 672 ret i1 %b1 673} 674 675; New version of subcarry_ult_2x64 after the InstCombine change 676; https://github.com/llvm/llvm-project/commit/926e7312b2f20f2f7b0a3d5ddbd29da5625507f3 677; This is also the result of "naive" implementation (x1 < y1) | ((x0 < y0) & (x1 == y1)). 678; C source: https://godbolt.org/z/W1qqvqGbr 679; TODO: This should be optimized to cmp + sbb. 680define i1 @subcarry_ult_2x64_2(i64 %x0, i64 %x1, i64 %y0, i64 %y1) nounwind { 681; CHECK-LABEL: subcarry_ult_2x64_2: 682; CHECK: # %bb.0: # %entry 683; CHECK-NEXT: cmpq %rdx, %rdi 684; CHECK-NEXT: setb %dl 685; CHECK-NEXT: cmpq %rcx, %rsi 686; CHECK-NEXT: setb %cl 687; CHECK-NEXT: sete %al 688; CHECK-NEXT: andb %dl, %al 689; CHECK-NEXT: orb %cl, %al 690; CHECK-NEXT: retq 691entry: 692 %0 = icmp ult i64 %x0, %y0 693 %1 = icmp ult i64 %x1, %y1 694 %2 = icmp eq i64 %x1, %y1 695 %3 = and i1 %0, %2 696 %4 = or i1 %1, %3 697 ret i1 %4 698} 699 700; unsigned less than of 2x64 and i64 integers 701; The IR comes from C source that uses __builtin_subcl but also the naive version (x0 < y) & (x1 == 0). 702; https://godbolt.org/z/W1qqvqGbr 703; TODO: This should be optimized to cmp + sbb. 704define i1 @subcarry_ult_2x64_1x64(i64 %x0, i64 %x1, i64 %y) nounwind { 705; CHECK-LABEL: subcarry_ult_2x64_1x64: 706; CHECK: # %bb.0: # %entry 707; CHECK-NEXT: cmpq %rdx, %rdi 708; CHECK-NEXT: setb %cl 709; CHECK-NEXT: testq %rsi, %rsi 710; CHECK-NEXT: sete %al 711; CHECK-NEXT: andb %cl, %al 712; CHECK-NEXT: retq 713entry: 714 %0 = icmp ult i64 %x0, %y 715 %1 = icmp eq i64 %x1, 0 716 %2 = and i1 %1, %0 717 ret i1 %2 718} 719