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 @@ -49891,6 +49891,37 @@ return SDValue(); } +static SDValue combineAddOrSubToADCOrSBB(bool IsSub, const SDLoc &DL, EVT VT, + SDValue X, SDValue Y, + SelectionDAG &DAG, + bool ZeroSecondOpOnly = false); + +static SDValue combineOrXorWithSETCC(SDNode *N, SDValue N0, SDValue N1, + SelectionDAG &DAG) { + // Delegate to combineAddOrSubToADCOrSBB if we have: + // + // (xor/or (zero_extend (setcc)) imm) + // + // where imm is odd if and only if we have xor, in which case the XOR/OR are + // equivalent to a SUB/ADD, respectively. + if (N0.getOpcode() == ISD::ZERO_EXTEND && + N0.getOperand(0).getOpcode() == X86ISD::SETCC && + N0.hasOneUse()) { + if (ConstantSDNode *N1C = dyn_cast(N1)) { + bool IsSub = N->getOpcode() == ISD::XOR; + bool N1COdd = N1C->getZExtValue() & 1; + if (IsSub ? N1COdd : !N1COdd) { + SDLoc DL(N); + EVT VT = N->getValueType(0); + if (SDValue R = combineAddOrSubToADCOrSBB(IsSub, DL, VT, N1, N0, DAG)) + return R; + } + } + } + + return SDValue(); +} + static SDValue combineOr(SDNode *N, SelectionDAG &DAG, TargetLowering::DAGCombinerInfo &DCI, const X86Subtarget &Subtarget) { @@ -50038,6 +50069,9 @@ if (SDValue R = foldMaskedMerge(N, DAG)) return R; + if (SDValue R = combineOrXorWithSETCC(N, N0, N1, DAG)) + return R; + return SDValue(); } @@ -52513,6 +52547,9 @@ if (SDValue SetCC = foldXor1SetCC(N, DAG)) return SetCC; + if (SDValue R = combineOrXorWithSETCC(N, N0, N1, DAG)) + return R; + if (SDValue RV = foldXorTruncShiftIntoCmp(N, DAG)) return RV; @@ -54454,7 +54491,7 @@ static SDValue combineAddOrSubToADCOrSBB(bool IsSub, const SDLoc &DL, EVT VT, SDValue X, SDValue Y, SelectionDAG &DAG, - bool ZeroSecondOpOnly = false) { + bool ZeroSecondOpOnly) { if (!DAG.getTargetLoweringInfo().isTypeLegal(VT)) return SDValue(); 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 @@ -525,9 +525,8 @@ ; CHECK-LABEL: select_eq0_3_2: ; CHECK: # %bb.0: ; CHECK-NEXT: xorl %eax, %eax -; CHECK-NEXT: testl %edi, %edi -; CHECK-NEXT: sete %al -; CHECK-NEXT: orl $2, %eax +; CHECK-NEXT: cmpl $1, %edi +; CHECK-NEXT: adcl $2, %eax ; CHECK-NEXT: retq %cmp = icmp eq i32 %X, 0 %sel = select i1 %cmp, i32 3, i32 2 @@ -539,8 +538,7 @@ ; CHECK: # %bb.0: ; CHECK-NEXT: xorl %eax, %eax ; CHECK-NEXT: cmpl $4, %edi -; CHECK-NEXT: setae %al -; CHECK-NEXT: xorl $3, %eax +; CHECK-NEXT: adcl $2, %eax ; CHECK-NEXT: retq %cmp = icmp ugt i32 %X, 3 %sel = select i1 %cmp, i32 2, i32 3 @@ -552,8 +550,7 @@ ; CHECK: # %bb.0: ; CHECK-NEXT: xorl %eax, %eax ; CHECK-NEXT: cmpl $9, %edi -; CHECK-NEXT: setb %al -; CHECK-NEXT: orl $6, %eax +; CHECK-NEXT: adcl $6, %eax ; CHECK-NEXT: retq %cmp = icmp ult i32 %X, 9 %sel = select i1 %cmp, i32 7, i32 6 @@ -563,10 +560,9 @@ define i32 @select_ult2_2_3(i32 %X) { ; CHECK-LABEL: select_ult2_2_3: ; CHECK: # %bb.0: -; CHECK-NEXT: xorl %eax, %eax ; CHECK-NEXT: cmpl $2, %edi -; CHECK-NEXT: setb %al -; CHECK-NEXT: xorl $3, %eax +; CHECK-NEXT: movl $3, %eax +; CHECK-NEXT: sbbl $0, %eax ; CHECK-NEXT: retq %cmp = icmp ult i32 %X, 2 %cond = select i1 %cmp, i32 2, i32 3 @@ -576,10 +572,9 @@ define i32 @select_ugt2_3_2(i32 %X) { ; CHECK-LABEL: select_ugt2_3_2: ; CHECK: # %bb.0: -; CHECK-NEXT: xorl %eax, %eax ; CHECK-NEXT: cmpl $4, %edi -; CHECK-NEXT: setae %al -; CHECK-NEXT: orl $2, %eax +; CHECK-NEXT: movl $2, %eax +; CHECK-NEXT: sbbl $-1, %eax ; CHECK-NEXT: retq %cmp.inv = icmp ugt i32 %X, 3 %cond = select i1 %cmp.inv, i32 3, i32 2