diff options
Diffstat (limited to 'llvm/lib/Target/X86/X86ISelDAGToDAG.cpp')
| -rw-r--r-- | llvm/lib/Target/X86/X86ISelDAGToDAG.cpp | 75 |
1 files changed, 72 insertions, 3 deletions
diff --git a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp index 90fc39f97a4..7e171d77033 100644 --- a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp +++ b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp @@ -473,6 +473,7 @@ namespace { bool tryOptimizeRem8Extend(SDNode *N); + bool onlyUsesZeroFlag(SDValue Flags) const; bool hasNoSignFlagUses(SDValue Flags) const; bool hasNoCarryFlagUses(SDValue Flags) const; }; @@ -2250,6 +2251,42 @@ static X86::CondCode getCondFromOpc(unsigned Opc) { return CC; } +/// Test whether the given X86ISD::CMP node has any users that use a flag +/// other than ZF. +bool X86DAGToDAGISel::onlyUsesZeroFlag(SDValue Flags) const { + // Examine each user of the node. + for (SDNode::use_iterator UI = Flags->use_begin(), UE = Flags->use_end(); + UI != UE; ++UI) { + // Only check things that use the flags. + if (UI.getUse().getResNo() != Flags.getResNo()) + continue; + // Only examine CopyToReg uses that copy to EFLAGS. + if (UI->getOpcode() != ISD::CopyToReg || + cast<RegisterSDNode>(UI->getOperand(1))->getReg() != X86::EFLAGS) + return false; + // Examine each user of the CopyToReg use. + for (SDNode::use_iterator FlagUI = UI->use_begin(), + FlagUE = UI->use_end(); FlagUI != FlagUE; ++FlagUI) { + // Only examine the Flag result. + if (FlagUI.getUse().getResNo() != 1) continue; + // Anything unusual: assume conservatively. + if (!FlagUI->isMachineOpcode()) return false; + // Examine the condition code of the user. + X86::CondCode CC = getCondFromOpc(FlagUI->getMachineOpcode()); + + switch (CC) { + // Comparisons which only use the zero flag. + case X86::COND_E: case X86::COND_NE: + continue; + // Anything else: assume conservatively. + default: + return false; + } + } + } + return true; +} + /// Test whether the given X86ISD::CMP node has any uses which require the SF /// flag to be accurate. bool X86DAGToDAGISel::hasNoSignFlagUses(SDValue Flags) const { @@ -3685,6 +3722,10 @@ void X86DAGToDAGISel::Select(SDNode *Node) { SDValue N0 = Node->getOperand(0); SDValue N1 = Node->getOperand(1); + // Optimizations for TEST compares. + if (!isNullConstant(N1)) + break; + // Save the original VT of the compare. MVT CmpVT = N0.getSimpleValueType(); @@ -3692,7 +3733,7 @@ void X86DAGToDAGISel::Select(SDNode *Node) { // by a test instruction. The test should be removed later by // analyzeCompare if we are using only the zero flag. // TODO: Should we check the users and use the BEXTR flags directly? - if (isNullConstant(N1) && N0.getOpcode() == ISD::AND && N0.hasOneUse()) { + if (N0.getOpcode() == ISD::AND && N0.hasOneUse()) { if (MachineSDNode *NewNode = matchBEXTRFromAndImm(N0.getNode())) { unsigned TestOpc = CmpVT == MVT::i64 ? X86::TEST64rr : X86::TEST32rr; @@ -3713,12 +3754,40 @@ void X86DAGToDAGISel::Select(SDNode *Node) { // Look past the truncate if CMP is the only use of it. if (N0.getOpcode() == ISD::AND && N0.getNode()->hasOneUse() && - N0.getValueType() != MVT::i8 && - isNullConstant(N1)) { + N0.getValueType() != MVT::i8) { ConstantSDNode *C = dyn_cast<ConstantSDNode>(N0.getOperand(1)); if (!C) break; uint64_t Mask = C->getZExtValue(); + // Check if we can replace AND+IMM64 with a shift. This is possible for + // masks/ like 0xFF000000 or 0x00FFFFFF and if we care only about the zero + // flag. + if (CmpVT == MVT::i64 && !isInt<32>(Mask) && + onlyUsesZeroFlag(SDValue(Node, 0))) { + if (isMask_64(~Mask)) { + unsigned TrailingZeros = countTrailingZeros(Mask); + SDValue Imm = CurDAG->getTargetConstant(TrailingZeros, dl, MVT::i64); + SDValue Shift = + SDValue(CurDAG->getMachineNode(X86::SHR64ri, dl, MVT::i64, + N0.getOperand(0), Imm), 0); + MachineSDNode *Test = CurDAG->getMachineNode(X86::TEST64rr, dl, + MVT::i32, Shift, Shift); + ReplaceNode(Node, Test); + return; + } + if (isMask_64(Mask)) { + unsigned LeadingZeros = countLeadingZeros(Mask); + SDValue Imm = CurDAG->getTargetConstant(LeadingZeros, dl, MVT::i64); + SDValue Shift = + SDValue(CurDAG->getMachineNode(X86::SHL64ri, dl, MVT::i64, + N0.getOperand(0), Imm), 0); + MachineSDNode *Test = CurDAG->getMachineNode(X86::TEST64rr, dl, + MVT::i32, Shift, Shift); + ReplaceNode(Node, Test); + return; + } + } + MVT VT; int SubRegOp; unsigned ROpc, MOpc; |

