diff options
Diffstat (limited to 'llvm/lib')
| -rw-r--r-- | llvm/lib/Target/X86/X86ISelLowering.cpp | 49 | 
1 files changed, 43 insertions, 6 deletions
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp index c77355f9179..79e99db34bf 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -8283,7 +8283,18 @@ SDValue X86TargetLowering::EmitTest(SDValue Op, unsigned X86CC,    unsigned Opcode = 0;    unsigned NumOperands = 0; -  switch (Op.getNode()->getOpcode()) { + +  // Truncate operations may prevent the merge of the SETCC instruction +  // and the arithmetic intruction before it. Attempt to truncate the operands +  // of the arithmetic instruction and use a reduced bit-width instruction. +  bool NeedTruncation = false; +  unsigned InOpcode = Op.getNode()->getOpcode(); +  if (Op->getOpcode() == ISD::TRUNCATE && Op->hasOneUse()) { +    NeedTruncation = true; +    InOpcode = Op->getOperand(0)->getOpcode(); +  } + +  switch (InOpcode) {    case ISD::ADD:      // Due to an isel shortcoming, be conservative if this add is likely to be      // selected as part of a load-modify-store instruction. When the root node @@ -8339,7 +8350,7 @@ SDValue X86TargetLowering::EmitTest(SDValue Op, unsigned X86CC,        if (User->getOpcode() != ISD::BRCOND &&            User->getOpcode() != ISD::SETCC && -          (User->getOpcode() != ISD::SELECT || UOpNo != 0)) { +          !(User->getOpcode() == ISD::SELECT && UOpNo == 0)) {          NonFlagUse = true;          break;        } @@ -8360,11 +8371,9 @@ SDValue X86TargetLowering::EmitTest(SDValue Op, unsigned X86CC,          goto default_case;      // Otherwise use a regular EFLAGS-setting instruction. -    switch (Op.getNode()->getOpcode()) { +    switch (InOpcode) {      default: llvm_unreachable("unexpected operator!"); -    case ISD::SUB: -      Opcode = X86ISD::SUB; -      break; +    case ISD::SUB: Opcode = X86ISD::SUB; break;      case ISD::OR:  Opcode = X86ISD::OR;  break;      case ISD::XOR: Opcode = X86ISD::XOR; break;      case ISD::AND: Opcode = X86ISD::AND; break; @@ -8385,6 +8394,34 @@ SDValue X86TargetLowering::EmitTest(SDValue Op, unsigned X86CC,      break;    } +  if (NeedTruncation) { +    SDValue WideVal = Op->getOperand(0); +    EVT VT = Op.getValueType(); +    EVT WideVT = WideVal.getValueType(); +    unsigned ConvertedOp = 0; + +    // Use a target machine opcode to prevent further DAGCombine +    // optimizations that may separate the arithmetic operations from the +    // setcc node. +    switch (WideVal.getOpcode()) { +      default: break; +      case ISD::ADD: ConvertedOp = X86ISD::ADD; break; +      case ISD::SUB: ConvertedOp = X86ISD::SUB; break; +      case ISD::AND: ConvertedOp = X86ISD::AND; break; +      case ISD::OR:  ConvertedOp = X86ISD::OR;  break; +      case ISD::XOR: ConvertedOp = X86ISD::XOR; break; +    } + +    if (ConvertedOp && WideVal.hasOneUse()) { +      const TargetLowering &TLI = DAG.getTargetLoweringInfo(); +      if (TLI.isOperationLegal(WideVal.getOpcode(), WideVT)) { +        SDValue V0 = DAG.getNode(ISD::TRUNCATE, dl, VT, WideVal.getOperand(0)); +        SDValue V1 = DAG.getNode(ISD::TRUNCATE, dl, VT, WideVal.getOperand(1)); +        Op = DAG.getNode(ConvertedOp, dl, VT, V0, V1); +      } +    } +  } +    if (Opcode == 0)      // Emit a CMP with 0, which is the TEST pattern.      return DAG.getNode(X86ISD::CMP, dl, MVT::i32, Op,  | 

