Index: llvm/trunk/include/llvm/CodeGen/SelectionDAGNodes.h =================================================================== --- llvm/trunk/include/llvm/CodeGen/SelectionDAGNodes.h +++ llvm/trunk/include/llvm/CodeGen/SelectionDAGNodes.h @@ -1358,6 +1358,9 @@ bool isAllOnesConstant(SDValue V); /// Returns true if \p V is a constant integer one. bool isOneConstant(SDValue V); +/// Returns true if \p V is a bitwise not operation. Assumes that an all ones +/// constant is canonicalized to be operand 1. +bool isBitwiseNot(SDValue V); class GlobalAddressSDNode : public SDNode { const GlobalValue *TheGlobal; Index: llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAG.cpp =================================================================== --- llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ llvm/trunk/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -6708,6 +6708,10 @@ return Const != nullptr && Const->isOne(); } +bool llvm::isBitwiseNot(SDValue V) { + return V.getOpcode() == ISD::XOR && isAllOnesConstant(V.getOperand(1)); +} + HandleSDNode::~HandleSDNode() { DropOperands(); } Index: llvm/trunk/lib/Target/X86/X86ISelLowering.cpp =================================================================== --- llvm/trunk/lib/Target/X86/X86ISelLowering.cpp +++ llvm/trunk/lib/Target/X86/X86ISelLowering.cpp @@ -14677,10 +14677,20 @@ break; case ISD::AND: - // If the primary and result isn't used, don't bother using X86ISD::AND, + // If the primary 'and' result isn't used, don't bother using X86ISD::AND, // because a TEST instruction will be better. - if (!hasNonFlagsUse(Op)) - break; + if (!hasNonFlagsUse(Op)) { + SDValue Op0 = ArithOp->getOperand(0); + SDValue Op1 = ArithOp->getOperand(1); + EVT VT = ArithOp.getValueType(); + bool isAndn = isBitwiseNot(Op0) || isBitwiseNot(Op1); + bool isLegalAndnType = VT == MVT::i32 || VT == MVT::i64; + + // But if we can combine this into an ANDN operation, then create an AND + // now and allow it to be pattern matched into an ANDN. + if (!Subtarget.hasBMI() || !isAndn || !isLegalAndnType) + break; + } // FALL THROUGH case ISD::SUB: case ISD::OR: Index: llvm/trunk/test/CodeGen/X86/bmi.ll =================================================================== --- llvm/trunk/test/CodeGen/X86/bmi.ll +++ llvm/trunk/test/CodeGen/X86/bmi.ll @@ -136,12 +136,11 @@ ret i64 %tmp2 } -; FIXME: Don't choose a 'test' if an 'andn' can be used. +; Don't choose a 'test' if an 'andn' can be used. define i1 @andn_cmp(i32 %x, i32 %y) { ; CHECK-LABEL: andn_cmp: ; CHECK: # BB#0: -; CHECK-NEXT: notl %edi -; CHECK-NEXT: testl %esi, %edi +; CHECK-NEXT: andnl %esi, %edi, %eax ; CHECK-NEXT: sete %al ; CHECK-NEXT: retq ; @@ -151,12 +150,11 @@ ret i1 %cmp } -; FIXME: Don't choose a 'test' if an 'andn' can be used. +; Don't choose a 'test' if an 'andn' can be used. define i1 @andn_cmp_swap_ops(i64 %x, i64 %y) { ; CHECK-LABEL: andn_cmp_swap_ops: ; CHECK: # BB#0: -; CHECK-NEXT: notq %rdi -; CHECK-NEXT: testq %rdi, %rsi +; CHECK-NEXT: andnq %rsi, %rdi, %rax ; CHECK-NEXT: sete %al ; CHECK-NEXT: retq ;