diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp --- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -3014,7 +3014,8 @@ return SDValue(); } -static SDValue getAsCarry(const TargetLowering &TLI, SDValue V) { +static SDValue getAsCarry(const TargetLowering &TLI, SDValue V, + bool ForceCarryReconstruction = false) { bool Masked = false; // First, peel away TRUNCATE/ZERO_EXTEND/AND nodes due to legalization. @@ -3030,20 +3031,25 @@ continue; } + if (ForceCarryReconstruction && V.getValueType() == MVT::i1) + return V; + break; } - // If this is not a carry, return. - if (V.getResNo() != 1) - return SDValue(); + if (!ForceCarryReconstruction) { + // If this is not a carry, return. + if (V.getResNo() != 1) + return SDValue(); - if (V.getOpcode() != ISD::UADDO_CARRY && V.getOpcode() != ISD::USUBO_CARRY && - V.getOpcode() != ISD::UADDO && V.getOpcode() != ISD::USUBO) - return SDValue(); + if (V.getOpcode() != ISD::UADDO_CARRY && V.getOpcode() != ISD::USUBO_CARRY && + V.getOpcode() != ISD::UADDO && V.getOpcode() != ISD::USUBO) + return SDValue(); - EVT VT = V->getValueType(0); - if (!TLI.isOperationLegalOrCustom(V.getOpcode(), VT)) - return SDValue(); + EVT VT = V->getValueType(0); + if (!TLI.isOperationLegalOrCustom(V.getOpcode(), VT)) + return SDValue(); + } // If the result is masked, then no matter what kind of bool it is we can // return. If it isn't, then we need to make sure the bool type is either 0 or @@ -3539,11 +3545,8 @@ return SDValue(); // Verify that the carry/borrow in is plausibly a carry/borrow bit. - // TODO: make getAsCarry() aware of how partial carries are merged. - if (CarryIn.getOpcode() != ISD::ZERO_EXTEND) - return SDValue(); - CarryIn = CarryIn.getOperand(0); - if (CarryIn.getValueType() != MVT::i1) + CarryIn = getAsCarry(TLI, CarryIn, true); + if (!CarryIn) return SDValue(); SDLoc DL(N); diff --git a/llvm/test/CodeGen/X86/addcarry.ll b/llvm/test/CodeGen/X86/addcarry.ll --- a/llvm/test/CodeGen/X86/addcarry.ll +++ b/llvm/test/CodeGen/X86/addcarry.ll @@ -637,7 +637,7 @@ ; CHECK-LABEL: addcarry_fake_carry: ; CHECK: # %bb.0: ; CHECK-NEXT: movq %rdi, %rax -; CHECK-NEXT: btl $0, %edx +; CHECK-NEXT: addl $-1, %edx ; CHECK-NEXT: adcq %rsi, %rax ; CHECK-NEXT: setb %dl ; CHECK-NEXT: retq @@ -660,11 +660,9 @@ ; CHECK-LABEL: addcarry_carry_not_zext: ; CHECK: # %bb.0: ; CHECK-NEXT: movq %rdi, %rax -; CHECK-NEXT: addq %rsi, %rax -; CHECK-NEXT: setb %cl -; CHECK-NEXT: addq %rdx, %rax +; CHECK-NEXT: addq $-1, %rdx +; CHECK-NEXT: adcq %rsi, %rax ; CHECK-NEXT: setb %dl -; CHECK-NEXT: orb %cl, %dl ; CHECK-NEXT: retq %t1 = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 %a, i64 %b) %partial = extractvalue { i64, i1 } %t1, 0 @@ -683,12 +681,10 @@ define { i64, i1 } @addcarry_carry_not_i1(i64 %a, i64 %b, i8 %carryin) nounwind { ; CHECK-LABEL: addcarry_carry_not_i1: ; CHECK: # %bb.0: -; CHECK-NEXT: addq %rsi, %rdi -; CHECK-NEXT: setb %cl -; CHECK-NEXT: movzbl %dl, %eax -; CHECK-NEXT: addq %rdi, %rax +; CHECK-NEXT: movq %rdi, %rax +; CHECK-NEXT: addl $-1, %edx +; CHECK-NEXT: adcq %rsi, %rax ; CHECK-NEXT: setb %dl -; CHECK-NEXT: orb %cl, %dl ; CHECK-NEXT: retq %t1 = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 %a, i64 %b) %partial = extractvalue { i64, i1 } %t1, 0