From ffdc67646ac521c5f1f041a931e88a762ae8b828 Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Mon, 17 Dec 2018 20:02:16 +0000 Subject: [PATCH] Convert (CMP (srl/shl X, C), 0) to (CMP (and X, C'), 0) when only the zero flag is used. This allows a TEST to be used and can be combined with any AND that may already exist as an input to the shift. This was already done in EmitTest, but was easily tricked by multiple uses because the setcc might be used by multiple instructions. Once the SETCC and users are legalized then we can look for the shift to be used by a single CMP, but the CMP itself can have multiple users. This appears to fix the case in PR39968. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@349385 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/X86/X86ISelLowering.cpp | 72 +++++++++++++++++++++--------- test/CodeGen/X86/cmp.ll | 3 +- 2 files changed, 51 insertions(+), 24 deletions(-) diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp index 62972f58721..757fe86935c 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -18630,27 +18630,6 @@ static SDValue EmitTest(SDValue Op, unsigned X86CC, const SDLoc &dl, Opcode = X86ISD::ADD; NumOperands = 2; break; - case ISD::SHL: - case ISD::SRL: - // If we have a constant logical shift that's only used in a comparison - // against zero turn it into an equivalent AND. This allows turning it into - // a TEST instruction later. - if (ZeroCheck && Op->hasOneUse() && - isa(Op->getOperand(1)) && !hasNonFlagsUse(Op)) { - EVT VT = Op.getValueType(); - unsigned BitWidth = VT.getSizeInBits(); - unsigned ShAmt = Op->getConstantOperandVal(1); - if (ShAmt >= BitWidth) // Avoid undefined shifts. - break; - APInt Mask = ArithOp.getOpcode() == ISD::SRL - ? APInt::getHighBitsSet(BitWidth, BitWidth - ShAmt) - : APInt::getLowBitsSet(BitWidth, BitWidth - ShAmt); - if (!Mask.isSignedIntN(ShiftToAndMaxMaskWidth)) - break; - Op = DAG.getNode(ISD::AND, dl, VT, Op->getOperand(0), - DAG.getConstant(Mask, dl, VT)); - } - break; case ISD::AND: // If the primary 'and' result isn't used, don't bother using X86ISD::AND, @@ -39952,6 +39931,32 @@ static bool needCarryOrOverflowFlag(SDValue Flags) { return false; } +static bool onlyZeroFlagUsed(SDValue Flags) { + assert(Flags.getValueType() == MVT::i32 && "Unexpected VT!"); + + for (SDNode::use_iterator UI = Flags->use_begin(), UE = Flags->use_end(); + UI != UE; ++UI) { + SDNode *User = *UI; + + unsigned CCOpNo; + switch (User->getOpcode()) { + default: + // Be conservative. + return false; + case X86ISD::SETCC: CCOpNo = 0; break; + case X86ISD::SETCC_CARRY: CCOpNo = 0; break; + case X86ISD::BRCOND: CCOpNo = 2; break; + case X86ISD::CMOV: CCOpNo = 2; break; + } + + X86::CondCode CC = (X86::CondCode)User->getConstantOperandVal(CCOpNo); + if (CC != X86::COND_E && CC != X86::COND_NE) + return false; + } + + return true; +} + static SDValue combineCMP(SDNode *N, SelectionDAG &DAG) { // Only handle test patterns. if (!isNullConstant(N->getOperand(1))) @@ -39961,9 +39966,33 @@ static SDValue combineCMP(SDNode *N, SelectionDAG &DAG) { // and use its flags directly. // TODO: Maybe we should try promoting compares that only use the zero flag // first if we can prove the upper bits with computeKnownBits? + SDLoc dl(N); SDValue Op = N->getOperand(0); EVT VT = Op.getValueType(); + // If we have a constant logical shift that's only used in a comparison + // against zero turn it into an equivalent AND. This allows turning it into + // a TEST instruction later. + if ((Op.getOpcode() == ISD::SRL || Op.getOpcode() == ISD::SHL) && + Op.hasOneUse() && isa(Op.getOperand(1)) && + onlyZeroFlagUsed(SDValue(N, 0))) { + EVT VT = Op.getValueType(); + unsigned BitWidth = VT.getSizeInBits(); + unsigned ShAmt = Op.getConstantOperandVal(1); + if (ShAmt < BitWidth) { // Avoid undefined shifts. + APInt Mask = Op.getOpcode() == ISD::SRL + ? APInt::getHighBitsSet(BitWidth, BitWidth - ShAmt) + : APInt::getLowBitsSet(BitWidth, BitWidth - ShAmt); + if (Mask.isSignedIntN(32)) { + Op = DAG.getNode(ISD::AND, dl, VT, Op.getOperand(0), + DAG.getConstant(Mask, dl, VT)); + return DAG.getNode(X86ISD::CMP, dl, MVT::i32, Op, + DAG.getConstant(0, dl, VT)); + } + } + } + + // Look for a truncate with a single use. if (Op.getOpcode() != ISD::TRUNCATE || !Op.hasOneUse()) return SDValue(); @@ -40001,7 +40030,6 @@ static SDValue combineCMP(SDNode *N, SelectionDAG &DAG) { } // We found an op we can narrow. Truncate its inputs. - SDLoc dl(N); SDValue Op0 = DAG.getNode(ISD::TRUNCATE, dl, VT, Op.getOperand(0)); SDValue Op1 = DAG.getNode(ISD::TRUNCATE, dl, VT, Op.getOperand(1)); diff --git a/test/CodeGen/X86/cmp.ll b/test/CodeGen/X86/cmp.ll index a12d599a1de..2747eca6b9a 100644 --- a/test/CodeGen/X86/cmp.ll +++ b/test/CodeGen/X86/cmp.ll @@ -469,9 +469,8 @@ entry: define { i64, i64 } @pr39968(i64, i64, i32) { ; CHECK-LABEL: pr39968: ; CHECK: # %bb.0: -; CHECK-NEXT: andl $64, %edx # encoding: [0x83,0xe2,0x40] ; CHECK-NEXT: xorl %eax, %eax # encoding: [0x31,0xc0] -; CHECK-NEXT: shrl $6, %edx # encoding: [0xc1,0xea,0x06] +; CHECK-NEXT: testb $64, %dl # encoding: [0xf6,0xc2,0x40] ; CHECK-NEXT: cmovneq %rdi, %rsi # encoding: [0x48,0x0f,0x45,0xf7] ; CHECK-NEXT: cmovneq %rdi, %rax # encoding: [0x48,0x0f,0x45,0xc7] ; CHECK-NEXT: movq %rsi, %rdx # encoding: [0x48,0x89,0xf2] -- 2.50.1