diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp --- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -1345,29 +1345,38 @@ return TLO.CombineTo(Op, TLO.DAG.getNode(ISD::OR, dl, VT, Op0, Op1)); ConstantSDNode* C = isConstOrConstSplat(Op1, DemandedElts); - if (C) { - // If one side is a constant, and all of the set bits in the constant are - // also known set on the other side, turn this into an AND, as we know - // the bits will be cleared. - // e.g. (X | C1) ^ C2 --> (X | C1) & ~C2 iff (C1&C2) == C2 - // NB: it is okay if more bits are known than are requested - if (C->getAPIntValue() == Known2.One) { - SDValue ANDC = - TLO.DAG.getConstant(~C->getAPIntValue() & DemandedBits, dl, VT); - return TLO.CombineTo(Op, TLO.DAG.getNode(ISD::AND, dl, VT, Op0, ANDC)); - } + if (C && (Op0.getOpcode() == ISD::OR || Op0.getOpcode() == ISD::AND)) { + ConstantSDNode *C1 = isConstOrConstSplat(Op0.getOperand(1), DemandedElts); + if (C1) { + // (X | C) ^ C -> X & ~C + if (Op0.getOpcode() == ISD::OR && + !((C->getAPIntValue() ^ C1->getAPIntValue()) & DemandedBits)) { + SDValue NOTC = + TLO.DAG.getConstant(~C->getAPIntValue() & DemandedBits, dl, VT); + return TLO.CombineTo( + Op, TLO.DAG.getNode(ISD::AND, dl, VT, Op0.getOperand(0), NOTC)); + } - // If the RHS is a constant, see if we can change it. Don't alter a -1 - // constant because that's a 'not' op, and that is better for combining - // and codegen. - if (!C->isAllOnesValue() && - DemandedBits.isSubsetOf(C->getAPIntValue())) { - // We're flipping all demanded bits. Flip the undemanded bits too. - SDValue New = TLO.DAG.getNOT(dl, Op0, VT); - return TLO.CombineTo(Op, New); + // (X & ~C) ^ C -> X | C + // TODO do this for the non-constant case too? I.e. (X & Y) ^ Z -> X | Z + // when all demanded bits of Y and Z are known to be different + if (Op0.getOpcode() == ISD::AND && + DemandedBits.isSubsetOf(C->getAPIntValue() ^ C1->getAPIntValue())) + return TLO.CombineTo( + Op, TLO.DAG.getNode(ISD::AND, dl, VT, Op0.getOperand(0), Op1)); } } + // If the RHS is a constant, see if we can change it. Don't alter a -1 + // constant because that's a 'not' op, and that is better for combining + // and codegen. + if (C && !C->isAllOnesValue() && + DemandedBits.isSubsetOf(C->getAPIntValue())) { + // We're flipping all demanded bits. Flip the undemanded bits too. + SDValue New = TLO.DAG.getNOT(dl, Op0, VT); + return TLO.CombineTo(Op, New); + } + // If we can't turn this into a 'not', try to shrink the constant. if (!C || !C->isAllOnesValue()) if (ShrinkDemandedConstant(Op, DemandedBits, DemandedElts, TLO)) diff --git a/llvm/test/CodeGen/X86/2012-08-07-CmpISelBug.ll b/llvm/test/CodeGen/X86/2012-08-07-CmpISelBug.ll --- a/llvm/test/CodeGen/X86/2012-08-07-CmpISelBug.ll +++ b/llvm/test/CodeGen/X86/2012-08-07-CmpISelBug.ll @@ -13,8 +13,8 @@ ; CHECK-NEXT: leal 13(%rdi), %eax ; CHECK-NEXT: xorb $-14, %al ; CHECK-NEXT: addb $82, %al -; CHECK-NEXT: movzbl %al, %eax ; CHECK-NEXT: testl %esi, %edi +; CHECK-NEXT: movzbl %al, %eax ; CHECK-NEXT: movl $1, %ecx ; CHECK-NEXT: cmovnel %eax, %ecx ; CHECK-NEXT: xorb $81, %cl