diff options
Diffstat (limited to 'llvm/lib')
| -rw-r--r-- | llvm/lib/Target/X86/X86ISelDAGToDAG.cpp | 75 | ||||
| -rw-r--r-- | llvm/lib/Target/X86/X86ISelLowering.cpp | 55 | 
2 files changed, 75 insertions, 55 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; diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp index c2230ee598c..85bcb8d2803 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -18690,59 +18690,10 @@ static SDValue EmitTest(SDValue Op, unsigned X86CC, const SDLoc &dl,    case ISD::AND:      // If the primary 'and' result isn't used, don't bother using X86ISD::AND, -    // because a TEST instruction will be better. However, AND should be -    // preferred if the instruction can be combined into ANDN. -    if (!hasNonFlagsUse(Op)) { -      SDValue Op0 = ArithOp->getOperand(0); -      SDValue Op1 = ArithOp->getOperand(1); -      EVT VT = ArithOp.getValueType(); - -      // Check if we can replace AND+IMM64 with a shift before giving up. This -      // is possible for masks/ like 0xFF000000 or 0x00FFFFFF and if we care -      // only about the zero flag. -      if (!ZeroCheck) -        break; - -      // And with constant should be canonicalized unless we're dealing -      // with opaque constants. -      assert((!isa<ConstantSDNode>(Op0) || -              (isa<ConstantSDNode>(Op1) && -               (cast<ConstantSDNode>(Op0)->isOpaque() || -                cast<ConstantSDNode>(Op1)->isOpaque()))) && -             "AND node isn't canonicalized"); -      auto *CN = dyn_cast<ConstantSDNode>(Op1); -      if (!CN) -        break; - -      const APInt &Mask = CN->getAPIntValue(); -      if (Mask.isSignedIntN(ShiftToAndMaxMaskWidth)) -        break; // Prefer TEST instruction. - -      unsigned BitWidth = Mask.getBitWidth(); -      unsigned LeadingOnes = Mask.countLeadingOnes(); -      unsigned TrailingZeros = Mask.countTrailingZeros(); - -      if (LeadingOnes + TrailingZeros == BitWidth) { -        assert(TrailingZeros < VT.getSizeInBits() && -               "Shift amount should be less than the type width"); -        SDValue ShAmt = DAG.getConstant(TrailingZeros, dl, MVT::i8); -        Op = DAG.getNode(ISD::SRL, dl, VT, Op0, ShAmt); -        break; -      } - -      unsigned LeadingZeros = Mask.countLeadingZeros(); -      unsigned TrailingOnes = Mask.countTrailingOnes(); - -      if (LeadingZeros + TrailingOnes == BitWidth) { -        assert(LeadingZeros < VT.getSizeInBits() && -               "Shift amount should be less than the type width"); -        SDValue ShAmt = DAG.getConstant(LeadingZeros, dl, MVT::i8); -        Op = DAG.getNode(ISD::SHL, dl, VT, Op0, ShAmt); -        break; -      } - +    // because a TEST instruction will be better. +    if (!hasNonFlagsUse(Op))        break; -    } +      LLVM_FALLTHROUGH;    case ISD::SUB:    case ISD::OR: | 

