diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -44714,14 +44714,17 @@ static SDValue combineCarryThroughADD(SDValue EFLAGS, SelectionDAG &DAG) { if (EFLAGS.getOpcode() == X86ISD::ADD) { if (isAllOnesConstant(EFLAGS.getOperand(1))) { + bool FoundAndLSB = false; SDValue Carry = EFLAGS.getOperand(0); while (Carry.getOpcode() == ISD::TRUNCATE || Carry.getOpcode() == ISD::ZERO_EXTEND || Carry.getOpcode() == ISD::SIGN_EXTEND || Carry.getOpcode() == ISD::ANY_EXTEND || (Carry.getOpcode() == ISD::AND && - isOneConstant(Carry.getOperand(1)))) + isOneConstant(Carry.getOperand(1)))) { + FoundAndLSB |= Carry.getOpcode() == ISD::AND; Carry = Carry.getOperand(0); + } if (Carry.getOpcode() == X86ISD::SETCC || Carry.getOpcode() == X86ISD::SETCC_CARRY) { // TODO: Merge this code with equivalent in combineAddOrSubToADCOrSBB? @@ -44748,10 +44751,24 @@ } // If this is a check of the z flag of an add with 1, switch to the // C flag. - if (CarryCC == X86::COND_E && - CarryOp1.getOpcode() == X86ISD::ADD && + if (CarryCC == X86::COND_E && CarryOp1.getOpcode() == X86ISD::ADD && isOneConstant(CarryOp1.getOperand(1))) return CarryOp1; + } else if (FoundAndLSB) { + SDLoc DL(Carry); + SDValue BitNo = DAG.getConstant(0, DL, Carry.getValueType()); + if (Carry.getOpcode() == ISD::SRL) { + BitNo = Carry.getOperand(1); + Carry = Carry.getOperand(0); + } + if (Carry.getScalarValueSizeInBits() < 32) + Carry = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i32, Carry); + EVT CarryVT = Carry.getValueType(); + if (DAG.getTargetLoweringInfo().isTypeLegal(CarryVT)) { + if (CarryVT != BitNo.getValueType()) + BitNo = DAG.getNode(ISD::ANY_EXTEND, DL, CarryVT, BitNo); + return DAG.getNode(X86ISD::BT, DL, MVT::i32, Carry, BitNo); + } } } } 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 @@ -640,8 +640,7 @@ ; CHECK-LABEL: addcarry_fake_carry: ; CHECK: # %bb.0: ; CHECK-NEXT: movq %rdi, %rax -; CHECK-NEXT: andb $1, %dl -; CHECK-NEXT: addb $-1, %dl +; CHECK-NEXT: btl $0, %edx ; CHECK-NEXT: adcq %rsi, %rax ; CHECK-NEXT: setb %dl ; CHECK-NEXT: retq diff --git a/llvm/test/CodeGen/X86/combine-adc.ll b/llvm/test/CodeGen/X86/combine-adc.ll --- a/llvm/test/CodeGen/X86/combine-adc.ll +++ b/llvm/test/CodeGen/X86/combine-adc.ll @@ -68,23 +68,17 @@ } ; FIXME: Fail to add (non-overflowing) constants together -; FIXME: Fail to convert add+lshr+and to BT define i32 @adc_merge_constants(i32 %a0) nounwind { ; X86-LABEL: adc_merge_constants: ; X86: # %bb.0: -; X86-NEXT: movl {{[0-9]+}}(%esp), %eax -; X86-NEXT: shrl $11, %eax -; X86-NEXT: andb $1, %al -; X86-NEXT: addb $-1, %al +; X86-NEXT: btl $11, {{[0-9]+}}(%esp) ; X86-NEXT: movl $55, %eax ; X86-NEXT: adcl $-1, %eax ; X86-NEXT: retl ; ; X64-LABEL: adc_merge_constants: ; X64: # %bb.0: -; X64-NEXT: shrl $11, %edi -; X64-NEXT: andb $1, %dil -; X64-NEXT: addb $-1, %dil +; X64-NEXT: btl $11, %edi ; X64-NEXT: movl $55, %eax ; X64-NEXT: adcl $-1, %eax ; X64-NEXT: retq diff --git a/llvm/test/CodeGen/X86/subcarry.ll b/llvm/test/CodeGen/X86/subcarry.ll --- a/llvm/test/CodeGen/X86/subcarry.ll +++ b/llvm/test/CodeGen/X86/subcarry.ll @@ -349,8 +349,7 @@ ; CHECK-LABEL: subcarry_fake_carry: ; CHECK: # %bb.0: ; CHECK-NEXT: movq %rdi, %rax -; CHECK-NEXT: andb $1, %dl -; CHECK-NEXT: addb $-1, %dl +; CHECK-NEXT: btl $0, %edx ; CHECK-NEXT: sbbq %rsi, %rax ; CHECK-NEXT: setb %dl ; CHECK-NEXT: retq