brintos

brintos / llvm-project-archived public Read only

0
0
Text · 24.6 KiB · 7d5db07 Raw
714 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py2; RUN: llc < %s -mtriple=x86_64-unknown | FileCheck %s3 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: # %entry10; CHECK-NEXT:    movq %rdi, %rax11; CHECK-NEXT:    subq %rdx, %rax12; CHECK-NEXT:    sbbq %rcx, %rsi13; CHECK-NEXT:    movq %rsi, %rdx14; CHECK-NEXT:    retq15entry:16  %0 = sub i128 %a, %b17  ret i128 %018}19 20define i256 @sub256(i256 %a, i256 %b) nounwind {21; CHECK-LABEL: sub256:22; CHECK:       # %bb.0: # %entry23; CHECK-NEXT:    movq %rdi, %rax24; CHECK-NEXT:    subq %r9, %rsi25; CHECK-NEXT:    sbbq {{[0-9]+}}(%rsp), %rdx26; CHECK-NEXT:    sbbq {{[0-9]+}}(%rsp), %rcx27; CHECK-NEXT:    sbbq {{[0-9]+}}(%rsp), %r828; 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:    retq33entry:34  %0 = sub i256 %a, %b35  ret i256 %036}37 38%S = type { [4 x i64] }39 40define %S @negate(ptr nocapture readonly %this) {41; CHECK-LABEL: negate:42; CHECK:       # %bb.0: # %entry43; CHECK-NEXT:    movq %rdi, %rax44; CHECK-NEXT:    xorl %ecx, %ecx45; CHECK-NEXT:    xorl %edx, %edx46; CHECK-NEXT:    subq (%rsi), %rdx47; CHECK-NEXT:    movl $0, %edi48; CHECK-NEXT:    sbbq 8(%rsi), %rdi49; CHECK-NEXT:    movl $0, %r8d50; CHECK-NEXT:    sbbq 16(%rsi), %r851; CHECK-NEXT:    sbbq 24(%rsi), %rcx52; 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:    retq57entry:58  %0 = load i64, ptr %this, align 859  %1 = xor i64 %0, -160  %2 = zext i64 %1 to i12861  %3 = add nuw nsw i128 %2, 162  %4 = trunc i128 %3 to i6463  %5 = lshr i128 %3, 6464  %6 = getelementptr inbounds %S, ptr %this, i64 0, i32 0, i64 165  %7 = load i64, ptr %6, align 866  %8 = xor i64 %7, -167  %9 = zext i64 %8 to i12868  %10 = add nuw nsw i128 %5, %969  %11 = trunc i128 %10 to i6470  %12 = lshr i128 %10, 6471  %13 = getelementptr inbounds %S, ptr %this, i64 0, i32 0, i64 272  %14 = load i64, ptr %13, align 873  %15 = xor i64 %14, -174  %16 = zext i64 %15 to i12875  %17 = add nuw nsw i128 %12, %1676  %18 = lshr i128 %17, 6477  %19 = trunc i128 %17 to i6478  %20 = getelementptr inbounds %S, ptr %this, i64 0, i32 0, i64 379  %21 = load i64, ptr %20, align 880  %22 = xor i64 %21, -181  %23 = zext i64 %22 to i12882  %24 = add nuw nsw i128 %18, %2383  %25 = trunc i128 %24 to i6484  %26 = insertvalue [4 x i64] undef, i64 %4, 085  %27 = insertvalue [4 x i64] %26, i64 %11, 186  %28 = insertvalue [4 x i64] %27, i64 %19, 287  %29 = insertvalue [4 x i64] %28, i64 %25, 388  %30 = insertvalue %S undef, [4 x i64] %29, 089  ret %S %3090}91 92define %S @sub(ptr nocapture readonly %this, %S %arg.b) {93; CHECK-LABEL: sub:94; CHECK:       # %bb.0: # %entry95; CHECK-NEXT:    movq %rdi, %rax96; CHECK-NEXT:    movq (%rsi), %rdi97; CHECK-NEXT:    movq 8(%rsi), %r1098; CHECK-NEXT:    subq %rdx, %rdi99; CHECK-NEXT:    setae %dl100; CHECK-NEXT:    addb $-1, %dl101; CHECK-NEXT:    adcq $0, %r10102; CHECK-NEXT:    setb %dl103; CHECK-NEXT:    movzbl %dl, %edx104; CHECK-NEXT:    notq %rcx105; CHECK-NEXT:    addq %r10, %rcx106; CHECK-NEXT:    adcq 16(%rsi), %rdx107; CHECK-NEXT:    setb %r10b108; CHECK-NEXT:    movzbl %r10b, %r10d109; CHECK-NEXT:    notq %r8110; CHECK-NEXT:    addq %rdx, %r8111; CHECK-NEXT:    adcq 24(%rsi), %r10112; CHECK-NEXT:    notq %r9113; CHECK-NEXT:    addq %r10, %r9114; 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:    retq119entry:120  %0 = extractvalue %S %arg.b, 0121  %.elt6 = extractvalue [4 x i64] %0, 1122  %.elt8 = extractvalue [4 x i64] %0, 2123  %.elt10 = extractvalue [4 x i64] %0, 3124  %.elt = extractvalue [4 x i64] %0, 0125  %1 = load i64, ptr %this, align 8126  %2 = zext i64 %1 to i128127  %3 = add nuw nsw i128 %2, 1128  %4 = xor i64 %.elt, -1129  %5 = zext i64 %4 to i128130  %6 = add nuw nsw i128 %3, %5131  %7 = trunc i128 %6 to i64132  %8 = lshr i128 %6, 64133  %9 = getelementptr inbounds %S, ptr %this, i64 0, i32 0, i64 1134  %10 = load i64, ptr %9, align 8135  %11 = zext i64 %10 to i128136  %12 = add nuw nsw i128 %8, %11137  %13 = xor i64 %.elt6, -1138  %14 = zext i64 %13 to i128139  %15 = add nuw nsw i128 %12, %14140  %16 = trunc i128 %15 to i64141  %17 = lshr i128 %15, 64142  %18 = getelementptr inbounds %S, ptr %this, i64 0, i32 0, i64 2143  %19 = load i64, ptr %18, align 8144  %20 = zext i64 %19 to i128145  %21 = add nuw nsw i128 %17, %20146  %22 = xor i64 %.elt8, -1147  %23 = zext i64 %22 to i128148  %24 = add nuw nsw i128 %21, %23149  %25 = lshr i128 %24, 64150  %26 = trunc i128 %24 to i64151  %27 = getelementptr inbounds %S, ptr %this, i64 0, i32 0, i64 3152  %28 = load i64, ptr %27, align 8153  %29 = zext i64 %28 to i128154  %30 = add nuw nsw i128 %25, %29155  %31 = xor i64 %.elt10, -1156  %32 = zext i64 %31 to i128157  %33 = add nuw nsw i128 %30, %32158  %34 = trunc i128 %33 to i64159  %35 = insertvalue [4 x i64] undef, i64 %7, 0160  %36 = insertvalue [4 x i64] %35, i64 %16, 1161  %37 = insertvalue [4 x i64] %36, i64 %26, 2162  %38 = insertvalue [4 x i64] %37, i64 %34, 3163  %39 = insertvalue %S undef, [4 x i64] %38, 0164  ret %S %39165}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, %rax174; CHECK-NEXT:    negq %rax175; CHECK-NEXT:    addq %rsi, %rdi176; CHECK-NEXT:    movq %rdi, (%rdx)177; CHECK-NEXT:    adcq $0, %rax178; CHECK-NEXT:    retq179  %agg = call {i64, i1} @llvm.uadd.with.overflow(i64 %x, i64 %y)180  %val = extractvalue {i64, i1} %agg, 0181  %ov = extractvalue {i64, i1} %agg, 1182  store i64 %val, ptr %valout, align 4183  %carry = zext i1 %ov to i64184  %res = sub i64 %carry, %z185  ret i64 %res186}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, %rax193; CHECK-NEXT:    subq %rdx, %rax194; CHECK-NEXT:    sbbq %rcx, %rsi195; CHECK-NEXT:    setb %cl196; CHECK-NEXT:    movq %rsi, %rdx197; CHECK-NEXT:    retq198  %t0 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %x0, i64 %y0)199  %s0 = extractvalue { i64, i1 } %t0, 0200  %k0 = extractvalue { i64, i1 } %t0, 1201 202  %t1 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %x1, i64 %y1)203  %s1 = extractvalue { i64, i1 } %t1, 0204  %k1 = extractvalue { i64, i1 } %t1, 1205 206  %zk0 = zext i1 %k0 to i64207  %t2 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %s1, i64 %zk0)208  %s2 = extractvalue { i64, i1 } %t2, 0209  %k2 = extractvalue { i64, i1 } %t2, 1210  %k = or i1 %k1, %k2211 212  %r0 = insertvalue { i64, i64, i1 } poison, i64 %s0, 0213  %r1 = insertvalue { i64, i64, i1 } %r0, i64 %s2, 1214  %r = insertvalue { i64, i64, i1 } %r1, i1 %k, 2215  ret { i64, i64, i1 } %r216}217 218; basic test for combineCarryDiamond() with or operands reversed219define { 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, %rax223; CHECK-NEXT:    subq %rdx, %rax224; CHECK-NEXT:    sbbq %rcx, %rsi225; CHECK-NEXT:    setb %cl226; CHECK-NEXT:    movq %rsi, %rdx227; CHECK-NEXT:    retq228  %t0 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %x0, i64 %y0)229  %s0 = extractvalue { i64, i1 } %t0, 0230  %k0 = extractvalue { i64, i1 } %t0, 1231 232  %t1 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %x1, i64 %y1)233  %s1 = extractvalue { i64, i1 } %t1, 0234  %k1 = extractvalue { i64, i1 } %t1, 1235 236  %zk0 = zext i1 %k0 to i64237  %t2 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %s1, i64 %zk0)238  %s2 = extractvalue { i64, i1 } %t2, 0239  %k2 = extractvalue { i64, i1 } %t2, 1240  %k = or i1 %k2, %k1  ; reverse natural order of operands241 242  %r0 = insertvalue { i64, i64, i1 } poison, i64 %s0, 0243  %r1 = insertvalue { i64, i64, i1 } %r0, i64 %s2, 1244  %r = insertvalue { i64, i64, i1 } %r1, i1 %k, 2245  ret { i64, i64, i1 } %r246}247 248; basic test for combineCarryDiamond() with xor operands reversed249define { 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, %rax253; CHECK-NEXT:    subq %rdx, %rax254; CHECK-NEXT:    sbbq %rcx, %rsi255; CHECK-NEXT:    setb %cl256; CHECK-NEXT:    movq %rsi, %rdx257; CHECK-NEXT:    retq258  %t0 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %x0, i64 %y0)259  %s0 = extractvalue { i64, i1 } %t0, 0260  %k0 = extractvalue { i64, i1 } %t0, 1261 262  %t1 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %x1, i64 %y1)263  %s1 = extractvalue { i64, i1 } %t1, 0264  %k1 = extractvalue { i64, i1 } %t1, 1265 266  %zk0 = zext i1 %k0 to i64267  %t2 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %s1, i64 %zk0)268  %s2 = extractvalue { i64, i1 } %t2, 0269  %k2 = extractvalue { i64, i1 } %t2, 1270  %k = xor i1 %k2, %k1  ; reverse natural order of operands271 272  %r0 = insertvalue { i64, i64, i1 } poison, i64 %s0, 0273  %r1 = insertvalue { i64, i64, i1 } %r0, i64 %s2, 1274  %r = insertvalue { i64, i64, i1 } %r1, i1 %k, 2275  ret { i64, i64, i1 } %r276}277 278; basic test for combineCarryDiamond() with and operands reversed279define { 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, %rax283; CHECK-NEXT:    subq %rdx, %rax284; CHECK-NEXT:    sbbq %rcx, %rsi285; CHECK-NEXT:    movq %rsi, %rdx286; CHECK-NEXT:    xorl %ecx, %ecx287; CHECK-NEXT:    retq288  %t0 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %x0, i64 %y0)289  %s0 = extractvalue { i64, i1 } %t0, 0290  %k0 = extractvalue { i64, i1 } %t0, 1291 292  %t1 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %x1, i64 %y1)293  %s1 = extractvalue { i64, i1 } %t1, 0294  %k1 = extractvalue { i64, i1 } %t1, 1295 296  %zk0 = zext i1 %k0 to i64297  %t2 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %s1, i64 %zk0)298  %s2 = extractvalue { i64, i1 } %t2, 0299  %k2 = extractvalue { i64, i1 } %t2, 1300  %k = and i1 %k2, %k1  ; reverse natural order of operands301 302  %r0 = insertvalue { i64, i64, i1 } poison, i64 %s0, 0303  %r1 = insertvalue { i64, i64, i1 } %r0, i64 %s2, 1304  %r = insertvalue { i64, i64, i1 } %r1, i1 %k, 2305  ret { i64, i64, i1 } %r306}307 308; basic test for combineCarryDiamond() with add operands reversed309define { 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, %rax313; CHECK-NEXT:    subq %rdx, %rax314; CHECK-NEXT:    sbbq %rcx, %rsi315; CHECK-NEXT:    setb %cl316; CHECK-NEXT:    movq %rsi, %rdx317; CHECK-NEXT:    retq318  %t0 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %x0, i64 %y0)319  %s0 = extractvalue { i64, i1 } %t0, 0320  %k0 = extractvalue { i64, i1 } %t0, 1321 322  %t1 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %x1, i64 %y1)323  %s1 = extractvalue { i64, i1 } %t1, 0324  %k1 = extractvalue { i64, i1 } %t1, 1325 326  %zk0 = zext i1 %k0 to i64327  %t2 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %s1, i64 %zk0)328  %s2 = extractvalue { i64, i1 } %t2, 0329  %k2 = extractvalue { i64, i1 } %t2, 1330  %k = add i1 %k2, %k1  ; reverse natural order of operands331 332  %r0 = insertvalue { i64, i64, i1 } poison, i64 %s0, 0333  %r1 = insertvalue { i64, i64, i1 } %r0, i64 %s2, 1334  %r = insertvalue { i64, i64, i1 } %r1, i1 %k, 2335  ret { i64, i64, i1 } %r336}337 338; Here %carryin is considered as valid carry flag for combining into ADDCARRY339; although %carryin does not come from any carry-producing instruction.340define { i64, i1 } @subcarry_fake_carry(i64 %a, i64 %b, i1 %carryin) {341; CHECK-LABEL: subcarry_fake_carry:342; CHECK:       # %bb.0:343; CHECK-NEXT:    movq %rdi, %rax344; CHECK-NEXT:    btl $0, %edx345; CHECK-NEXT:    sbbq %rsi, %rax346; CHECK-NEXT:    setb %dl347; CHECK-NEXT:    retq348    %t1 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %a, i64 %b)349    %partial = extractvalue { i64, i1 } %t1, 0350    %k1 = extractvalue { i64, i1 } %t1, 1351 352    %zcarryin = zext i1 %carryin to i64353    %s = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %partial, i64 %zcarryin)354    %k2 = extractvalue { i64, i1 } %s, 1355 356    %carryout = or i1 %k1, %k2357 358    %ret = insertvalue { i64, i1 } %s, i1 %carryout, 1359    ret { i64, i1 } %ret360}361 362; negative test: %carryin does not look like carry363define { i64, i1 } @subcarry_carry_not_zext(i64 %a, i64 %b, i64 %carryin) {364; CHECK-LABEL: subcarry_carry_not_zext:365; CHECK:       # %bb.0:366; CHECK-NEXT:    movq %rdi, %rax367; CHECK-NEXT:    subq %rsi, %rax368; CHECK-NEXT:    setb %cl369; CHECK-NEXT:    subq %rdx, %rax370; CHECK-NEXT:    setb %dl371; CHECK-NEXT:    orb %cl, %dl372; CHECK-NEXT:    retq373    %t1 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %a, i64 %b)374    %partial = extractvalue { i64, i1 } %t1, 0375    %k1 = extractvalue { i64, i1 } %t1, 1376 377    %s = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %partial, i64 %carryin)378    %k2 = extractvalue { i64, i1 } %s, 1379 380    %carryout = or i1 %k1, %k2381 382    %ret = insertvalue { i64, i1 } %s, i1 %carryout, 1383    ret { i64, i1 } %ret384}385 386; negative test: %carryin does not look like carry387define { i64, i1 } @subcarry_carry_not_i1(i64 %a, i64 %b, i8 %carryin) {388; CHECK-LABEL: subcarry_carry_not_i1:389; CHECK:       # %bb.0:390; CHECK-NEXT:    movq %rdi, %rax391; CHECK-NEXT:    subq %rsi, %rax392; CHECK-NEXT:    setb %cl393; CHECK-NEXT:    movzbl %dl, %edx394; CHECK-NEXT:    subq %rdx, %rax395; CHECK-NEXT:    setb %dl396; CHECK-NEXT:    orb %cl, %dl397; CHECK-NEXT:    retq398    %t1 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %a, i64 %b)399    %partial = extractvalue { i64, i1 } %t1, 0400    %k1 = extractvalue { i64, i1 } %t1, 1401 402    %zcarryin = zext i8 %carryin to i64403    %s = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %partial, i64 %zcarryin)404    %k2 = extractvalue { i64, i1 } %s, 1405 406    %carryout = or i1 %k1, %k2407 408    %ret = insertvalue { i64, i1 } %s, i1 %carryout, 1409    ret { i64, i1 } %ret410}411 412%struct.U320 = type { [5 x i64] }413 414define i32 @sub_U320_without_i128_or(ptr nocapture dereferenceable(40) %0, i64 %1, i64 %2, i64 %3, i64 %4, i64 %5) {415; CHECK-LABEL: sub_U320_without_i128_or:416; CHECK:       # %bb.0:417; CHECK-NEXT:    subq %rsi, (%rdi)418; CHECK-NEXT:    sbbq %rdx, 8(%rdi)419; CHECK-NEXT:    sbbq %rcx, 16(%rdi)420; CHECK-NEXT:    sbbq %r8, 24(%rdi)421; CHECK-NEXT:    sbbq %r9, 32(%rdi)422; CHECK-NEXT:    setb %al423; CHECK-NEXT:    movzbl %al, %eax424; CHECK-NEXT:    retq425  %7 = load i64, ptr %0, align 8426  %8 = getelementptr inbounds %struct.U320, ptr %0, i64 0, i32 0, i64 1427  %9 = load i64, ptr %8, align 8428  %10 = getelementptr inbounds %struct.U320, ptr %0, i64 0, i32 0, i64 2429  %11 = load i64, ptr %10, align 8430  %12 = getelementptr inbounds %struct.U320, ptr %0, i64 0, i32 0, i64 3431  %13 = load i64, ptr %12, align 8432  %14 = getelementptr inbounds %struct.U320, ptr %0, i64 0, i32 0, i64 4433  %15 = load i64, ptr %14, align 8434  %16 = sub i64 %7, %1435  %17 = sub i64 %9, %2436  %18 = icmp ult i64 %7, %1437  %19 = zext i1 %18 to i64438  %20 = sub i64 %17, %19439  %21 = sub i64 %11, %3440  %22 = icmp ult i64 %9, %2441  %23 = icmp ult i64 %17, %19442  %24 = or i1 %22, %23443  %25 = zext i1 %24 to i64444  %26 = sub i64 %21, %25445  %27 = sub i64 %13, %4446  %28 = icmp ult i64 %11, %3447  %29 = icmp ult i64 %21, %25448  %30 = or i1 %28, %29449  %31 = zext i1 %30 to i64450  %32 = sub i64 %27, %31451  %33 = sub i64 %15, %5452  %34 = icmp ult i64 %13, %4453  %35 = icmp ult i64 %27, %31454  %36 = or i1 %34, %35455  %37 = zext i1 %36 to i64456  %38 = sub i64 %33, %37457  store i64 %16, ptr %0, align 8458  store i64 %20, ptr %8, align 8459  store i64 %26, ptr %10, align 8460  store i64 %32, ptr %12, align 8461  store i64 %38, ptr %14, align 8462  %39 = icmp ult i64 %15, %5463  %40 = icmp ult i64 %33, %37464  %41 = or i1 %39, %40465  %42 = zext i1 %41 to i32466  ret i32 %42467}468 469define i32 @sub_U320_usubo(ptr nocapture dereferenceable(40) %0, i64 %1, i64 %2, i64 %3, i64 %4, i64 %5) {470; CHECK-LABEL: sub_U320_usubo:471; CHECK:       # %bb.0:472; CHECK-NEXT:    subq %rsi, (%rdi)473; CHECK-NEXT:    sbbq %rdx, 8(%rdi)474; CHECK-NEXT:    sbbq %rcx, 16(%rdi)475; CHECK-NEXT:    sbbq %r8, 24(%rdi)476; CHECK-NEXT:    sbbq %r9, 32(%rdi)477; CHECK-NEXT:    setb %al478; CHECK-NEXT:    movzbl %al, %eax479; CHECK-NEXT:    retq480  %7 = load i64, ptr %0, align 8481  %8 = getelementptr inbounds %struct.U320, ptr %0, i64 0, i32 0, i64 1482  %9 = load i64, ptr %8, align 8483  %10 = getelementptr inbounds %struct.U320, ptr %0, i64 0, i32 0, i64 2484  %11 = load i64, ptr %10, align 8485  %12 = getelementptr inbounds %struct.U320, ptr %0, i64 0, i32 0, i64 3486  %13 = load i64, ptr %12, align 8487  %14 = getelementptr inbounds %struct.U320, ptr %0, i64 0, i32 0, i64 4488  %15 = load i64, ptr %14, align 8489  %16 = tail call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %7, i64 %1)490  %17 = extractvalue { i64, i1 } %16, 1491  %18 = extractvalue { i64, i1 } %16, 0492  %19 = zext i1 %17 to i64493  %20 = tail call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %9, i64 %2)494  %21 = extractvalue { i64, i1 } %20, 1495  %22 = extractvalue { i64, i1 } %20, 0496  %23 = tail call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %22, i64 %19)497  %24 = extractvalue { i64, i1 } %23, 1498  %25 = extractvalue { i64, i1 } %23, 0499  %26 = or i1 %21, %24500  %27 = zext i1 %26 to i64501  %28 = tail call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %11, i64 %3)502  %29 = extractvalue { i64, i1 } %28, 1503  %30 = extractvalue { i64, i1 } %28, 0504  %31 = tail call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %30, i64 %27)505  %32 = extractvalue { i64, i1 } %31, 1506  %33 = extractvalue { i64, i1 } %31, 0507  %34 = or i1 %29, %32508  %35 = zext i1 %34 to i64509  %36 = tail call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %13, i64 %4)510  %37 = extractvalue { i64, i1 } %36, 1511  %38 = extractvalue { i64, i1 } %36, 0512  %39 = tail call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %38, i64 %35)513  %40 = extractvalue { i64, i1 } %39, 1514  %41 = extractvalue { i64, i1 } %39, 0515  %42 = or i1 %37, %40516  %43 = zext i1 %42 to i64517  %44 = tail call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %15, i64 %5)518  %45 = extractvalue { i64, i1 } %44, 1519  %46 = extractvalue { i64, i1 } %44, 0520  %47 = tail call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %46, i64 %43)521  %48 = extractvalue { i64, i1 } %47, 1522  %49 = extractvalue { i64, i1 } %47, 0523  %50 = or i1 %45, %48524  store i64 %18, ptr %0, align 8525  store i64 %25, ptr %8, align 8526  store i64 %33, ptr %10, align 8527  store i64 %41, ptr %12, align 8528  store i64 %49, ptr %14, align 8529  %51 = zext i1 %50 to i32530  ret i32 %51531}532 533%struct.U192 = type { [3 x i64] }534 535define void @PR39464(ptr noalias nocapture sret(%struct.U192) %0, ptr nocapture readonly dereferenceable(24) %1, ptr nocapture readonly dereferenceable(24) %2) {536; CHECK-LABEL: PR39464:537; CHECK:       # %bb.0:538; CHECK-NEXT:    movq %rdi, %rax539; CHECK-NEXT:    movq (%rsi), %rcx540; CHECK-NEXT:    subq (%rdx), %rcx541; CHECK-NEXT:    movq %rcx, (%rdi)542; CHECK-NEXT:    movq 8(%rsi), %rcx543; CHECK-NEXT:    sbbq 8(%rdx), %rcx544; CHECK-NEXT:    movq %rcx, 8(%rdi)545; CHECK-NEXT:    movq 16(%rsi), %rcx546; CHECK-NEXT:    sbbq 16(%rdx), %rcx547; CHECK-NEXT:    movq %rcx, 16(%rdi)548; CHECK-NEXT:    retq549  %4 = load i64, ptr %1, align 8550  %5 = load i64, ptr %2, align 8551  %6 = tail call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %4, i64 %5)552  %7 = extractvalue { i64, i1 } %6, 1553  %8 = extractvalue { i64, i1 } %6, 0554  %9 = zext i1 %7 to i64555  store i64 %8, ptr %0, align 8556  %10 = getelementptr inbounds %struct.U192, ptr %1, i64 0, i32 0, i64 1557  %11 = load i64, ptr %10, align 8558  %12 = getelementptr inbounds %struct.U192, ptr %2, i64 0, i32 0, i64 1559  %13 = load i64, ptr %12, align 8560  %14 = tail call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %11, i64 %13)561  %15 = extractvalue { i64, i1 } %14, 1562  %16 = extractvalue { i64, i1 } %14, 0563  %17 = tail call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %16, i64 %9)564  %18 = extractvalue { i64, i1 } %17, 1565  %19 = extractvalue { i64, i1 } %17, 0566  %20 = or i1 %15, %18567  %21 = zext i1 %20 to i64568  %22 = getelementptr inbounds %struct.U192, ptr %0, i64 0, i32 0, i64 1569  store i64 %19, ptr %22, align 8570  %23 = getelementptr inbounds %struct.U192, ptr %1, i64 0, i32 0, i64 2571  %24 = load i64, ptr %23, align 8572  %25 = getelementptr inbounds %struct.U192, ptr %2, i64 0, i32 0, i64 2573  %26 = load i64, ptr %25, align 8574  %27 = sub i64 %24, %26575  %28 = sub i64 %27, %21576  %29 = getelementptr inbounds %struct.U192, ptr %0, i64 0, i32 0, i64 2577  store i64 %28, ptr %29, align 8578  ret void579}580 581%uint128 = type { i64, i64 }582%uint256 = type { %uint128, %uint128 }583 584; The 256-bit subtraction implementation using two inlined usubo procedures for U128 type { i64, i64 }.585; This is similar to how LLVM legalize types in CodeGen.586define void @sub_U256_without_i128_or_recursive(ptr sret(%uint256) %0, ptr %1, ptr %2) nounwind {587; CHECK-LABEL: sub_U256_without_i128_or_recursive:588; CHECK:       # %bb.0:589; CHECK-NEXT:    movq %rdi, %rax590; CHECK-NEXT:    movq (%rsi), %rcx591; CHECK-NEXT:    movq 8(%rsi), %rdi592; CHECK-NEXT:    movq 16(%rsi), %r8593; CHECK-NEXT:    movq 24(%rsi), %rsi594; CHECK-NEXT:    xorl %r9d, %r9d595; CHECK-NEXT:    subq 16(%rdx), %r8596; CHECK-NEXT:    setb %r9b597; CHECK-NEXT:    subq 24(%rdx), %rsi598; CHECK-NEXT:    subq (%rdx), %rcx599; CHECK-NEXT:    sbbq 8(%rdx), %rdi600; CHECK-NEXT:    sbbq $0, %r8601; CHECK-NEXT:    sbbq %r9, %rsi602; CHECK-NEXT:    movq %rcx, (%rax)603; CHECK-NEXT:    movq %rdi, 8(%rax)604; CHECK-NEXT:    movq %r8, 16(%rax)605; CHECK-NEXT:    movq %rsi, 24(%rax)606; CHECK-NEXT:    retq607  %4 = load i64, ptr %1, align 8608  %5 = getelementptr inbounds %uint256, ptr %1, i64 0, i32 0, i32 1609  %6 = load i64, ptr %5, align 8610  %7 = load i64, ptr %2, align 8611  %8 = getelementptr inbounds %uint256, ptr %2, i64 0, i32 0, i32 1612  %9 = load i64, ptr %8, align 8613  %10 = sub i64 %4, %7614  %11 = icmp ult i64 %4, %7615  %12 = sub i64 %6, %9616  %13 = icmp ult i64 %6, %9617  %14 = zext i1 %11 to i64618  %15 = sub i64 %12, %14619  %16 = icmp ult i64 %12, %14620  %17 = or i1 %13, %16621  %18 = getelementptr inbounds %uint256, ptr %1, i64 0, i32 1, i32 0622  %19 = load i64, ptr %18, align 8623  %20 = getelementptr inbounds %uint256, ptr %1, i64 0, i32 1, i32 1624  %21 = load i64, ptr %20, align 8625  %22 = getelementptr inbounds %uint256, ptr %2, i64 0, i32 1, i32 0626  %23 = load i64, ptr %22, align 8627  %24 = getelementptr inbounds %uint256, ptr %2, i64 0, i32 1, i32 1628  %25 = load i64, ptr %24, align 8629  %26 = sub i64 %19, %23630  %27 = icmp ult i64 %19, %23631  %28 = sub i64 %21, %25632  %29 = zext i1 %27 to i64633  %30 = sub i64 %28, %29634  %31 = zext i1 %17 to i64635  %32 = sub i64 %26, %31636  %33 = icmp ult i64 %26, %31637  %34 = zext i1 %33 to i64638  %35 = sub i64 %30, %34639  store i64 %10, ptr %0, align 8640  %36 = getelementptr inbounds %uint256, ptr %0, i64 0, i32 0, i32 1641  store i64 %15, ptr %36, align 8642  %37 = getelementptr inbounds %uint256, ptr %0, i64 0, i32 1, i32 0643  store i64 %32, ptr %37, align 8644  %38 = getelementptr inbounds %uint256, ptr %0, i64 0, i32 1, i32 1645  store i64 %35, ptr %38, align 8646  ret void647}648 649; unsigned less than of two 2x64 integers650; TODO: This should be optimized to cmp + sbb.651define i1 @subcarry_ult_2x64(i64 %x0, i64 %x1, i64 %y0, i64 %y1) nounwind {652; CHECK-LABEL: subcarry_ult_2x64:653; CHECK:       # %bb.0:654; CHECK-NEXT:    subq %rcx, %rsi655; CHECK-NEXT:    setb %cl656; CHECK-NEXT:    cmpq %rdx, %rdi657; CHECK-NEXT:    sbbq $0, %rsi658; CHECK-NEXT:    setb %al659; CHECK-NEXT:    orb %cl, %al660; CHECK-NEXT:    retq661  %b0 = icmp ult i64 %x0, %y0662  %d1 = sub i64 %x1, %y1663  %b10 = icmp ult i64 %x1, %y1664  %b0z = zext i1 %b0 to i64665  %b11 = icmp ult i64 %d1, %b0z666  %b1 = or i1 %b10, %b11667  ret i1 %b1668}669 670; New version of subcarry_ult_2x64 after the InstCombine change671; https://github.com/llvm/llvm-project/commit/926e7312b2f20f2f7b0a3d5ddbd29da5625507f3672; This is also the result of "naive" implementation (x1 < y1) | ((x0 < y0) & (x1 == y1)).673; C source: https://godbolt.org/z/W1qqvqGbr674; TODO: This should be optimized to cmp + sbb.675define i1 @subcarry_ult_2x64_2(i64 %x0, i64 %x1, i64 %y0, i64 %y1) nounwind {676; CHECK-LABEL: subcarry_ult_2x64_2:677; CHECK:       # %bb.0: # %entry678; CHECK-NEXT:    cmpq %rdx, %rdi679; CHECK-NEXT:    setb %dl680; CHECK-NEXT:    cmpq %rcx, %rsi681; CHECK-NEXT:    setb %cl682; CHECK-NEXT:    sete %al683; CHECK-NEXT:    andb %dl, %al684; CHECK-NEXT:    orb %cl, %al685; CHECK-NEXT:    retq686entry:687  %0 = icmp ult i64 %x0, %y0688  %1 = icmp ult i64 %x1, %y1689  %2 = icmp eq i64 %x1, %y1690  %3 = and i1 %0, %2691  %4 = or i1 %1, %3692  ret i1 %4693}694 695; unsigned less than of 2x64 and i64 integers696; The IR comes from C source that uses __builtin_subcl but also the naive version (x0 < y) & (x1 == 0).697; https://godbolt.org/z/W1qqvqGbr698; TODO: This should be optimized to cmp + sbb.699define i1 @subcarry_ult_2x64_1x64(i64 %x0, i64 %x1, i64 %y) nounwind {700; CHECK-LABEL: subcarry_ult_2x64_1x64:701; CHECK:       # %bb.0: # %entry702; CHECK-NEXT:    cmpq %rdx, %rdi703; CHECK-NEXT:    setb %cl704; CHECK-NEXT:    testq %rsi, %rsi705; CHECK-NEXT:    sete %al706; CHECK-NEXT:    andb %cl, %al707; CHECK-NEXT:    retq708entry:709  %0 = icmp ult i64 %x0, %y710  %1 = icmp eq i64 %x1, 0711  %2 = and i1 %1, %0712  ret i1 %2713}714