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