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 @@ -2602,17 +2602,30 @@ break; } - // If this is not a carry, return. - if (V.getResNo() != 1) - return SDValue(); - - if (V.getOpcode() != ISD::ADDCARRY && V.getOpcode() != ISD::SUBCARRY && - V.getOpcode() != ISD::UADDO && V.getOpcode() != ISD::USUBO) - return SDValue(); + switch (V.getOpcode()) { + case ISD::ADDCARRY: + case ISD::SUBCARRY: + case ISD::UADDO: + case ISD::USUBO: { + // If this is not a carry, return. + if (V.getResNo() != 1) + return SDValue(); - EVT VT = V.getNode()->getValueType(0); - if (!TLI.isOperationLegalOrCustom(V.getOpcode(), VT)) + EVT VT = V.getNode()->getValueType(0); + if (!TLI.isOperationLegalOrCustom(V.getOpcode(), VT)) + return SDValue(); + break; + } + case ISD::SETCC: { + // Consider SETULT which affects carry flag only. + ISD::CondCode CC = cast(V.getOperand(2))->get(); + if (CC != ISD::SETULT) + return SDValue(); + break; + } + default: 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 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 @@ -420,44 +420,31 @@ define i32 @add_U320_without_i128_add(%struct.U320* nocapture dereferenceable(40) %0, i64 %1, i64 %2, i64 %3, i64 %4, i64 %5) { ; CHECK-LABEL: add_U320_without_i128_add: ; CHECK: # %bb.0: -; CHECK-NEXT: pushq %r14 -; CHECK-NEXT: .cfi_def_cfa_offset 16 -; CHECK-NEXT: pushq %rbx -; CHECK-NEXT: .cfi_def_cfa_offset 24 -; CHECK-NEXT: .cfi_offset %rbx, -24 -; CHECK-NEXT: .cfi_offset %r14, -16 -; CHECK-NEXT: movq 16(%rdi), %rax -; CHECK-NEXT: leaq (%rax,%rcx), %r10 +; CHECK-NEXT: movq 16(%rdi), %r10 +; CHECK-NEXT: xorl %r11d, %r11d +; CHECK-NEXT: movq %r10, %rax +; CHECK-NEXT: addq %rcx, %rax +; CHECK-NEXT: setb %r11b ; CHECK-NEXT: addq %rsi, (%rdi) ; CHECK-NEXT: adcq %rdx, 8(%rdi) -; CHECK-NEXT: movq %rax, %rdx -; CHECK-NEXT: adcq %rcx, %rdx -; CHECK-NEXT: movq 24(%rdi), %r11 -; CHECK-NEXT: leaq (%r8,%r11), %r14 -; CHECK-NEXT: xorl %ebx, %ebx -; CHECK-NEXT: cmpq %r10, %rdx -; CHECK-NEXT: setb %bl -; CHECK-NEXT: addq %rcx, %rax -; CHECK-NEXT: adcq %r14, %rbx -; CHECK-NEXT: movq 32(%rdi), %r10 -; CHECK-NEXT: leaq (%r9,%r10), %rcx -; CHECK-NEXT: xorl %esi, %esi -; CHECK-NEXT: cmpq %r14, %rbx -; CHECK-NEXT: setb %sil -; CHECK-NEXT: addq %r11, %r8 -; CHECK-NEXT: adcq %rcx, %rsi +; CHECK-NEXT: adcq %rcx, %r10 +; CHECK-NEXT: xorl %ecx, %ecx +; CHECK-NEXT: addq 24(%rdi), %r8 +; CHECK-NEXT: setb %cl +; CHECK-NEXT: cmpq %rax, %r10 +; CHECK-NEXT: adcq %r8, %r11 +; CHECK-NEXT: movq 32(%rdi), %rdx +; CHECK-NEXT: leaq (%r9,%rdx), %rsi +; CHECK-NEXT: cmpq %r8, %r11 +; CHECK-NEXT: adcq %rsi, %rcx ; CHECK-NEXT: xorl %eax, %eax -; CHECK-NEXT: cmpq %rcx, %rsi +; CHECK-NEXT: cmpq %rsi, %rcx ; CHECK-NEXT: setb %al -; CHECK-NEXT: addq %r10, %r9 -; CHECK-NEXT: movq %rdx, 16(%rdi) -; CHECK-NEXT: movq %rbx, 24(%rdi) -; CHECK-NEXT: movq %rsi, 32(%rdi) +; CHECK-NEXT: addq %rdx, %r9 +; CHECK-NEXT: movq %r10, 16(%rdi) +; CHECK-NEXT: movq %r11, 24(%rdi) +; CHECK-NEXT: movq %rcx, 32(%rdi) ; CHECK-NEXT: adcl $0, %eax -; CHECK-NEXT: popq %rbx -; CHECK-NEXT: .cfi_def_cfa_offset 16 -; CHECK-NEXT: popq %r14 -; CHECK-NEXT: .cfi_def_cfa_offset 8 ; CHECK-NEXT: retq %7 = getelementptr inbounds %struct.U320, %struct.U320* %0, i64 0, i32 0, i64 0 %8 = load i64, i64* %7, align 8 @@ -1037,11 +1024,9 @@ define i32 @addcarry_ult(i32 %a, i32 %b, i32 %x, i32 %y) { ; CHECK-LABEL: addcarry_ult: ; CHECK: # %bb.0: -; CHECK-NEXT: # kill: def $esi killed $esi def $rsi -; CHECK-NEXT: # kill: def $edi killed $edi def $rdi -; CHECK-NEXT: leal (%rdi,%rsi), %eax +; CHECK-NEXT: movl %edi, %eax ; CHECK-NEXT: cmpl %ecx, %edx -; CHECK-NEXT: adcl $0, %eax +; CHECK-NEXT: adcl %esi, %eax ; CHECK-NEXT: retq %s = add i32 %a, %b %k = icmp ult i32 %x, %y