Index: llvm/lib/Target/X86/X86ISelLowering.cpp =================================================================== --- llvm/lib/Target/X86/X86ISelLowering.cpp +++ llvm/lib/Target/X86/X86ISelLowering.cpp @@ -44186,19 +44186,38 @@ } -/// Fold a xor(setcc cond, val), 1 --> setcc (inverted(cond), val) static SDValue foldXor1SetCC(SDNode *N, SelectionDAG &DAG) { - if (N->getOpcode() != ISD::XOR) + if (N->getOpcode() != ISD::XOR || !isOneConstant(N->getOperand(1))) return SDValue(); + // xor (setcc cond, val), 1 --> setcc (inverted(cond), val) SDValue LHS = N->getOperand(0); - if (!isOneConstant(N->getOperand(1)) || LHS->getOpcode() != X86ISD::SETCC) - return SDValue(); + if (LHS.getOpcode() == X86ISD::SETCC) { + X86::CondCode NewCC = X86::GetOppositeBranchCondition( + X86::CondCode(LHS->getConstantOperandVal(0))); + SDLoc DL(N); + return getSETCC(NewCC, LHS->getOperand(1), DL, DAG); + } - X86::CondCode NewCC = X86::GetOppositeBranchCondition( - X86::CondCode(LHS->getConstantOperandVal(0))); - SDLoc DL(N); - return getSETCC(NewCC, LHS->getOperand(1), DL, DAG); + // Peek through a truncate. + if (LHS.getOpcode() == ISD::TRUNCATE) + LHS = LHS.getOperand(0); + + // xor (trunc (xor i1 X, Y)), 1 --> zext (setcc (cmp eq X, Y)) + if (LHS.getOpcode() == ISD::XOR && LHS.hasOneUse()) { + SDValue X = LHS.getOperand(0), Y = LHS.getOperand(1); + // All bits except for least-significant-bit must be known zero. + KnownBits KnownX = DAG.computeKnownBits(X); + KnownBits KnownY = DAG.computeKnownBits(Y); + if (~(KnownX.Zero) == 1 && ~(KnownY.Zero) == 1) { + SDLoc DL(N); + SDValue Cmp = DAG.getNode(X86ISD::CMP, DL, X.getValueType(), X, Y); + SDValue Set = getSETCC(X86::CondCode::COND_E, Cmp, DL, DAG); + return DAG.getZExtOrTrunc(Set, DL, N->getValueType(0)); + } + } + + return SDValue(); } static SDValue combineXor(SDNode *N, SelectionDAG &DAG, Index: llvm/test/CodeGen/X86/xor-icmp.ll =================================================================== --- llvm/test/CodeGen/X86/xor-icmp.ll +++ llvm/test/CodeGen/X86/xor-icmp.ll @@ -95,16 +95,14 @@ ; X32-LABEL: xor_not_bools: ; X32: # %bb.0: ; X32-NEXT: movb {{[0-9]+}}(%esp), %al -; X32-NEXT: xorb {{[0-9]+}}(%esp), %al -; X32-NEXT: xorb $1, %al +; X32-NEXT: cmpb %al, {{[0-9]+}}(%esp) +; X32-NEXT: sete %al ; X32-NEXT: retl ; ; X64-LABEL: xor_not_bools: ; X64: # %bb.0: -; X64-NEXT: movl %edi, %eax -; X64-NEXT: xorl %esi, %eax -; X64-NEXT: xorb $1, %al -; X64-NEXT: # kill: def $al killed $al killed $eax +; X64-NEXT: cmpl %esi, %edi +; X64-NEXT: sete %al ; X64-NEXT: retq %xor = xor i1 %x, %y %not = xor i1 %xor, true @@ -117,21 +115,21 @@ ; X32-LABEL: xor_not_cmps: ; X32: # %bb.0: ; X32-NEXT: cmpl $42, {{[0-9]+}}(%esp) -; X32-NEXT: setne %cl +; X32-NEXT: setne %al ; X32-NEXT: cmpl $235, {{[0-9]+}}(%esp) +; X32-NEXT: sete %cl +; X32-NEXT: cmpb %cl, %al ; X32-NEXT: sete %al -; X32-NEXT: xorb %cl, %al -; X32-NEXT: xorb $1, %al ; X32-NEXT: retl ; ; X64-LABEL: xor_not_cmps: ; X64: # %bb.0: ; X64-NEXT: cmpl $42, %edi -; X64-NEXT: setne %cl +; X64-NEXT: setne %al ; X64-NEXT: cmpl $235, %esi +; X64-NEXT: sete %cl +; X64-NEXT: cmpb %cl, %al ; X64-NEXT: sete %al -; X64-NEXT: xorb %cl, %al -; X64-NEXT: xorb $1, %al ; X64-NEXT: retq %cmpx = icmp ne i32 %x, 42 %cmpy = icmp eq i32 %y, 235