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 @@ -55480,6 +55480,33 @@ return DAG.getNode(ISD::ADD, DL, VT, N0, Cmov); } +static SDValue combineSubSetcc(SDNode *N, SelectionDAG &DAG) { + SDValue Op0 = N->getOperand(0); + SDValue Op1 = N->getOperand(1); + + // (sub C (zero_extend (setcc))) + // => + // (add (zero_extend (setcc inverted) C-1)) if C is a nonzero immediate + // Don't disturb (sub 0 setcc), which is easily done with neg. + EVT VT = N->getValueType(0); + auto *Op0C = dyn_cast(Op0); + if (Op1.getOpcode() == ISD::ZERO_EXTEND && Op1.hasOneUse() && Op0C && + !Op0C->isZero() && Op1.getOperand(0).getOpcode() == X86ISD::SETCC && + Op1.getOperand(0).hasOneUse()) { + SDValue SetCC = Op1.getOperand(0); + X86::CondCode CC = (X86::CondCode)SetCC.getConstantOperandVal(0); + X86::CondCode NewCC = X86::GetOppositeBranchCondition(CC); + uint64_t NewImm = Op0C->getZExtValue() - 1; + SDLoc DL(Op1); + SDValue NewSetCC = getSETCC(NewCC, SetCC.getOperand(1), DL, DAG); + NewSetCC = DAG.getNode(ISD::ZERO_EXTEND, DL, VT, NewSetCC); + return DAG.getNode(X86ISD::ADD, DL, DAG.getVTList(VT, VT), NewSetCC, + DAG.getConstant(NewImm, DL, VT)); + } + + return SDValue(); +} + static SDValue combineSub(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const X86Subtarget &Subtarget) { @@ -55540,7 +55567,10 @@ if (SDValue V = combineXorSubCTLZ(N, DAG, Subtarget)) return V; - return combineAddOrSubToADCOrSBB(N, DAG); + if (SDValue V = combineAddOrSubToADCOrSBB(N, DAG)) + return V; + + return combineSubSetcc(N, DAG); } static SDValue combineVectorCompare(SDNode *N, SelectionDAG &DAG, diff --git a/llvm/test/CodeGen/X86/select-constant-xor.ll b/llvm/test/CodeGen/X86/select-constant-xor.ll --- a/llvm/test/CodeGen/X86/select-constant-xor.ll +++ b/llvm/test/CodeGen/X86/select-constant-xor.ll @@ -30,11 +30,10 @@ define i32 @selecti64i32(i64 %a) { ; CHECK-LABEL: selecti64i32: ; CHECK: # %bb.0: -; CHECK-NEXT: xorl %ecx, %ecx +; CHECK-NEXT: xorl %eax, %eax ; CHECK-NEXT: testq %rdi, %rdi -; CHECK-NEXT: setns %cl -; CHECK-NEXT: movl $-2147483648, %eax # imm = 0x80000000 -; CHECK-NEXT: subl %ecx, %eax +; CHECK-NEXT: sets %al +; CHECK-NEXT: addl $2147483647, %eax # imm = 0x7FFFFFFF ; CHECK-NEXT: retq %c = icmp sgt i64 %a, -1 %s = select i1 %c, i32 2147483647, i32 -2147483648 diff --git a/llvm/test/CodeGen/X86/select_const.ll b/llvm/test/CodeGen/X86/select_const.ll --- a/llvm/test/CodeGen/X86/select_const.ll +++ b/llvm/test/CodeGen/X86/select_const.ll @@ -584,11 +584,10 @@ define i32 @select_eq_1_2(i32 %a, i32 %b) { ; CHECK-LABEL: select_eq_1_2: ; CHECK: # %bb.0: -; CHECK-NEXT: xorl %ecx, %ecx +; CHECK-NEXT: xorl %eax, %eax ; CHECK-NEXT: cmpl %esi, %edi -; CHECK-NEXT: sete %cl -; CHECK-NEXT: movl $2, %eax -; CHECK-NEXT: subl %ecx, %eax +; CHECK-NEXT: setne %al +; CHECK-NEXT: incl %eax ; CHECK-NEXT: retq %cmp = icmp eq i32 %a, %b