Index: lib/Target/X86/X86ISelLowering.cpp =================================================================== --- lib/Target/X86/X86ISelLowering.cpp +++ lib/Target/X86/X86ISelLowering.cpp @@ -30939,11 +30939,43 @@ return true; } +// When legalizing carry, we create carries via add X, -1 +// If that comes from an actual carry, via setcc, we use the +// carry directly. +static SDValue combineCarryThroughADD(SDValue EFLAGS) { + if (EFLAGS.getOpcode() == X86ISD::ADD) { + if (isAllOnesConstant(EFLAGS.getOperand(1))) { + 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)))) + Carry = Carry.getOperand(0); + if (Carry.getOpcode() == X86ISD::SETCC || + Carry.getOpcode() == X86ISD::SETCC_CARRY) { + if (Carry.getConstantOperandVal(0) == X86::COND_B) + return Carry.getOperand(1); + } + } + } + + return SDValue(); +} + /// Optimize an EFLAGS definition used according to the condition code \p CC /// into a simpler EFLAGS value, potentially returning a new \p CC and replacing /// uses of chain values. static SDValue combineSetCCEFLAGS(SDValue EFLAGS, X86::CondCode &CC, SelectionDAG &DAG) { + // When legalizing carry, we create carries via add X, -1 + // If that comes from an actual carry, via setcc, we use the + // carry directly. + if (CC == X86::COND_B) + if (SDValue Flags = combineCarryThroughADD(EFLAGS)) + return Flags; + if (SDValue R = checkBoolTestSetCCCombine(EFLAGS, CC)) return R; return combineSetCCAtomicArith(EFLAGS, CC, DAG); @@ -34823,6 +34855,8 @@ if (SDValue Flags = combineSetCCEFLAGS(EFLAGS, CC, DAG)) return getSETCC(CC, Flags, DL, DAG); + + return SDValue(); } @@ -34987,27 +35021,16 @@ return SDValue(); } -// Optimize RES, EFLAGS = X86ISD::ADD LHS, RHS -static SDValue combineX86ADD(SDNode *N, SelectionDAG &DAG, - X86TargetLowering::DAGCombinerInfo &DCI) { +static SDValue combineX86SBB(SDNode *N, SelectionDAG &DAG) { // When legalizing carry, we create carries via add X, -1 // If that comes from an actual carry, via setcc, we use the // carry directly. - if (isAllOnesConstant(N->getOperand(1)) && N->hasAnyUseOfValue(1)) { - SDValue Carry = N->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)))) - Carry = Carry.getOperand(0); - - if (Carry.getOpcode() == X86ISD::SETCC || - Carry.getOpcode() == X86ISD::SETCC_CARRY) { - if (Carry.getConstantOperandVal(0) == X86::COND_B) - return DCI.CombineTo(N, SDValue(N, 0), Carry.getOperand(1)); - } + if (SDValue Flags = combineCarryThroughADD(N->getOperand(2))) { + MVT VT = N->getSimpleValueType(0); + SDVTList VTs = DAG.getVTList(VT, MVT::i32); + return DAG.getNode(X86ISD::SBB, SDLoc(N), VTs, + N->getOperand(0), N->getOperand(1), + Flags); } return SDValue(); @@ -35036,6 +35059,17 @@ return DCI.CombineTo(N, Res1, CarryOut); } + // When legalizing carry, we create carries via add X, -1 + // If that comes from an actual carry, via setcc, we use the + // carry directly. + if (SDValue Flags = combineCarryThroughADD(N->getOperand(2))) { + MVT VT = N->getSimpleValueType(0); + SDVTList VTs = DAG.getVTList(VT, MVT::i32); + return DAG.getNode(X86ISD::ADC, SDLoc(N), VTs, + N->getOperand(0), N->getOperand(1), + Flags); + } + return SDValue(); } @@ -35721,7 +35755,7 @@ case X86ISD::CMOV: return combineCMov(N, DAG, DCI, Subtarget); case ISD::ADD: return combineAdd(N, DAG, Subtarget); case ISD::SUB: return combineSub(N, DAG, Subtarget); - case X86ISD::ADD: return combineX86ADD(N, DAG, DCI); + case X86ISD::SBB: return combineX86SBB(N, DAG); case X86ISD::ADC: return combineADC(N, DAG, DCI); case ISD::MUL: return combineMul(N, DAG, DCI, Subtarget); case ISD::SHL: Index: test/CodeGen/X86/pr34381.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/pr34381.ll @@ -0,0 +1,43 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +;RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu | FileCheck %s + +@var_21 = external constant i32, align 4 +@var_29 = external constant i8, align 1 +@var_390 = external global i32, align 4 +@var_11 = external constant i8, align 1 +@var_370 = external global i8, align 1 + +; Function Attrs: noinline nounwind optnone uwtable +define void @_Z3foov() { +; CHECK-LABEL: _Z3foov: +; CHECK: # BB#0: # %entry +; CHECK-NEXT: movsbl {{.*}}(%rip), %eax +; CHECK-NEXT: negl %eax +; CHECK-NEXT: cmpl %eax, {{.*}}(%rip) +; CHECK-NEXT: setb %al +; CHECK-NEXT: xorl %ecx, %ecx +; CHECK-NEXT: decb %al +; CHECK-NEXT: sete %cl +; CHECK-NEXT: movl %ecx, {{.*}}(%rip) +; CHECK-NEXT: movb {{.*}}(%rip), %al +; CHECK-NEXT: movb %al, {{.*}}(%rip) +; CHECK-NEXT: retq +entry: + %0 = load i32, i32* @var_21, align 4 + %1 = load i8, i8* @var_29, align 1 + %conv = sext i8 %1 to i32 + %sub = sub nsw i32 0, %conv + %cmp = icmp ult i32 %0, %sub + %conv1 = zext i1 %cmp to i32 + %add = add nsw i32 %conv1, -1 + %conv2 = trunc i32 %add to i8 + %tobool = icmp ne i8 %conv2, 0 + %lnot = xor i1 %tobool, true + %conv3 = zext i1 %lnot to i32 + store i32 %conv3, i32* @var_390, align 4 + %2 = load i8, i8* @var_11, align 1 + %conv4 = sext i8 %2 to i16 + %conv5 = trunc i16 %conv4 to i8 + store i8 %conv5, i8* @var_370, align 1 + ret void +}