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 @@ -5829,6 +5829,32 @@ if (SDValue Load = MatchLoadCombine(N)) return Load; + // TODO(chfast): Move to visitORCommutative() + // TODO(chfast): Generalize for other opcodes. + + if (auto Carry0 = getAsCarry(TLI, N0)) { + if (Carry0.getOpcode() == ISD::UADDO && Carry0.hasOneUse()) { + if (auto Carry1 = getAsCarry(TLI, N1)) { + if (Carry1.getOpcode() == Carry0.getOpcode() && Carry1.hasOneUse()) { + if (auto Carry2 = getAsCarry(TLI, Carry1.getOperand(1))) { + if (Carry2.getOpcode() == Carry0.getOpcode() && + Carry2.hasOneUse()) { + if (TLI.isOperationLegalOrCustom(ISD::ADDCARRY, + Carry1->getValueType(0))) { + // TODO: The ADDCARRY node should replace the Carry1 node, + // but this happens in other place in the DAG combiner. + auto AddcarryN = + DAG.getNode(ISD::ADDCARRY, SDLoc{N0}, N0->getVTList(), + N0->getOperand(0), N0->getOperand(1), Carry2); + return CombineTo(N, AddcarryN.getValue(1)); + } + } + } + } + } + } + } + // Simplify the operands using demanded-bits information. if (SimplifyDemandedBits(SDValue(N, 0))) return SDValue(N, 0); 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 @@ -418,12 +418,9 @@ define zeroext i1 @uaddo128(i64 %0, i64 %1, i64 %2, i64 %3, %uint128* nocapture %4) nounwind { ; CHECK-LABEL: uaddo128: ; CHECK: # %bb.0: -; CHECK-NEXT: addq %rcx, %rsi -; CHECK-NEXT: setb %cl ; CHECK-NEXT: addq %rdx, %rdi -; CHECK-NEXT: adcq $0, %rsi +; CHECK-NEXT: adcq %rcx, %rsi ; CHECK-NEXT: setb %al -; CHECK-NEXT: orb %cl, %al ; CHECK-NEXT: movq %rsi, (%r8) ; CHECK-NEXT: movq %rdi, 8(%r8) ; CHECK-NEXT: retq @@ -449,18 +446,12 @@ ; CHECK-LABEL: add192: ; CHECK: # %bb.0: ; CHECK-NEXT: movq %rdi, %rax -; CHECK-NEXT: addq %r9, %rdx -; CHECK-NEXT: setb %dil ; CHECK-NEXT: addq %r8, %rsi -; CHECK-NEXT: adcq $0, %rdx -; CHECK-NEXT: setb %r8b -; CHECK-NEXT: orb %dil, %r8b -; CHECK-NEXT: addq {{[0-9]+}}(%rsp), %rcx -; CHECK-NEXT: movzbl %r8b, %edi -; CHECK-NEXT: addq %rcx, %rdi -; CHECK-NEXT: movq %rdi, (%rax) -; CHECK-NEXT: movq %rdx, 8(%rax) -; CHECK-NEXT: movq %rsi, 16(%rax) +; CHECK-NEXT: adcq %r9, %rdx +; CHECK-NEXT: adcq {{[0-9]+}}(%rsp), %rcx +; CHECK-NEXT: movq %rcx, (%rdi) +; CHECK-NEXT: movq %rdx, 8(%rdi) +; CHECK-NEXT: movq %rsi, 16(%rdi) ; CHECK-NEXT: retq %8 = add i64 %4, %1 %9 = icmp ult i64 %8, %1