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 @@ -55560,6 +55560,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) { @@ -55620,7 +55647,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 @@ -47,20 +47,18 @@ define i32 @selecti64i32(i64 %a) { ; X86-LABEL: selecti64i32: ; X86: # %bb.0: -; X86-NEXT: xorl %ecx, %ecx +; X86-NEXT: xorl %eax, %eax ; X86-NEXT: cmpl $0, {{[0-9]+}}(%esp) -; X86-NEXT: setns %cl -; X86-NEXT: movl $-2147483648, %eax # imm = 0x80000000 -; X86-NEXT: subl %ecx, %eax +; X86-NEXT: sets %al +; X86-NEXT: addl $2147483647, %eax # imm = 0x7FFFFFFF ; X86-NEXT: retl ; ; X64-LABEL: selecti64i32: ; X64: # %bb.0: -; X64-NEXT: xorl %ecx, %ecx +; X64-NEXT: xorl %eax, %eax ; X64-NEXT: testq %rdi, %rdi -; X64-NEXT: setns %cl -; X64-NEXT: movl $-2147483648, %eax # imm = 0x80000000 -; X64-NEXT: subl %ecx, %eax +; X64-NEXT: sets %al +; X64-NEXT: addl $2147483647, %eax # imm = 0x7FFFFFFF ; X64-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 @@ -1062,27 +1062,30 @@ define i32 @select_eq_1_2(i32 %a, i32 %b) { ; X86-LABEL: select_eq_1_2: ; X86: # %bb.0: -; X86-NEXT: movl {{[0-9]+}}(%esp), %eax -; X86-NEXT: xorl %ecx, %ecx -; X86-NEXT: cmpl {{[0-9]+}}(%esp), %eax -; X86-NEXT: sete %cl -; X86-NEXT: movl $2, %eax -; X86-NEXT: subl %ecx, %eax +; X86-NEXT: movl {{[0-9]+}}(%esp), %ecx +; X86-NEXT: xorl %eax, %eax +; X86-NEXT: cmpl {{[0-9]+}}(%esp), %ecx +; X86-NEXT: setne %al +; X86-NEXT: incl %eax ; X86-NEXT: retl ; -; X64-LABEL: select_eq_1_2: -; X64: # %bb.0: -; X64-NEXT: xorl %ecx, %ecx -; X64-NEXT: cmpl %esi, %edi -; X64-NEXT: sete %cl -; X64-NEXT: movl $2, %eax -; X64-NEXT: subl %ecx, %eax -; X64-NEXT: retq +; X64-FASTINC-LABEL: select_eq_1_2: +; X64-FASTINC: # %bb.0: +; X64-FASTINC-NEXT: xorl %eax, %eax +; X64-FASTINC-NEXT: cmpl %esi, %edi +; X64-FASTINC-NEXT: setne %al +; X64-FASTINC-NEXT: incl %eax +; X64-FASTINC-NEXT: retq +; +; X64-SLOWINC-LABEL: select_eq_1_2: +; X64-SLOWINC: # %bb.0: +; X64-SLOWINC-NEXT: xorl %eax, %eax +; X64-SLOWINC-NEXT: cmpl %esi, %edi +; X64-SLOWINC-NEXT: setne %al +; X64-SLOWINC-NEXT: addl $1, %eax +; X64-SLOWINC-NEXT: retq %cmp = icmp eq i32 %a, %b %cond = select i1 %cmp, i32 1, i32 2 ret i32 %cond } -;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: -; X64-FASTINC: {{.*}} -; X64-SLOWINC: {{.*}}