diff options
Diffstat (limited to 'llvm/lib/Target/ARM/ARMISelLowering.cpp')
| -rw-r--r-- | llvm/lib/Target/ARM/ARMISelLowering.cpp | 73 | 
1 files changed, 71 insertions, 2 deletions
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp index f72e2c28ac0..aeda7c06a27 100644 --- a/llvm/lib/Target/ARM/ARMISelLowering.cpp +++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp @@ -1041,7 +1041,7 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM,    if (!Subtarget->isThumb1Only())      setOperationAction(ISD::SETCCE, MVT::i32, Custom); -  setOperationAction(ISD::BRCOND,    MVT::Other, Expand); +  setOperationAction(ISD::BRCOND,    MVT::Other, Custom);    setOperationAction(ISD::BR_CC,     MVT::i32,   Custom);    setOperationAction(ISD::BR_CC,     MVT::f32,   Custom);    setOperationAction(ISD::BR_CC,     MVT::f64,   Custom); @@ -3894,6 +3894,10 @@ ARMTargetLowering::duplicateCmp(SDValue Cmp, SelectionDAG &DAG) const {    return DAG.getNode(ARMISD::FMSTAT, DL, MVT::Glue, Cmp);  } +// This function returns three things: the arithmetic computation itself +// (Value), a comparison (OverflowCmp), and a condition code (ARMcc).  The +// comparison and the condition code define the case in which the arithmetic +// computation *does not* overflow.  std::pair<SDValue, SDValue>  ARMTargetLowering::getARMXALUOOp(SDValue Op, SelectionDAG &DAG,                                   SDValue &ARMcc) const { @@ -3919,7 +3923,11 @@ ARMTargetLowering::getARMXALUOOp(SDValue Op, SelectionDAG &DAG,      break;    case ISD::UADDO:      ARMcc = DAG.getConstant(ARMCC::HS, dl, MVT::i32); -    Value = DAG.getNode(ISD::ADD, dl, Op.getValueType(), LHS, RHS); +    // We use ADDC here to correspond to its use in LowerUnsignedALUO. +    // We do not use it in the USUBO case as Value may not be used. +    Value = DAG.getNode(ARMISD::ADDC, dl, +                        DAG.getVTList(Op.getValueType(), MVT::i32), LHS, RHS) +                .getValue(0);      OverflowCmp = DAG.getNode(ARMISD::CMP, dl, MVT::Glue, Value, LHS);      break;    case ISD::SSUBO: @@ -4518,6 +4526,39 @@ ARMTargetLowering::OptimizeVFPBrcond(SDValue Op, SelectionDAG &DAG) const {    return SDValue();  } +SDValue ARMTargetLowering::LowerBRCOND(SDValue Op, SelectionDAG &DAG) const { +  SDValue Chain = Op.getOperand(0); +  SDValue Cond = Op.getOperand(1); +  SDValue Dest = Op.getOperand(2); +  SDLoc dl(Op); + +  // Optimize {s|u}{add|sub}.with.overflow feeding into a branch instruction. +  unsigned Opc = Cond.getOpcode(); +  if (Cond.getResNo() == 1 && (Opc == ISD::SADDO || Opc == ISD::UADDO || +                               Opc == ISD::SSUBO || Opc == ISD::USUBO)) { +    // Only lower legal XALUO ops. +    if (!DAG.getTargetLoweringInfo().isTypeLegal(Cond->getValueType(0))) +      return SDValue(); + +    // The actual operation with overflow check. +    SDValue Value, OverflowCmp; +    SDValue ARMcc; +    std::tie(Value, OverflowCmp) = getARMXALUOOp(Cond, DAG, ARMcc); + +    // Reverse the condition code. +    ARMCC::CondCodes CondCode = +        (ARMCC::CondCodes)cast<const ConstantSDNode>(ARMcc)->getZExtValue(); +    CondCode = ARMCC::getOppositeCondition(CondCode); +    ARMcc = DAG.getConstant(CondCode, SDLoc(ARMcc), MVT::i32); +    SDValue CCR = DAG.getRegister(ARM::CPSR, MVT::i32); + +    return DAG.getNode(ARMISD::BRCOND, dl, MVT::Other, Chain, Dest, ARMcc, CCR, +                       OverflowCmp); +  } + +  return SDValue(); +} +  SDValue ARMTargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const {    SDValue Chain = Op.getOperand(0);    ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(1))->get(); @@ -4538,6 +4579,33 @@ SDValue ARMTargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const {      }    } +  // Optimize {s|u}{add|sub}.with.overflow feeding into a branch instruction. +  unsigned Opc = LHS.getOpcode(); +  if (LHS.getResNo() == 1 && (isOneConstant(RHS) || isNullConstant(RHS)) && +      (Opc == ISD::SADDO || Opc == ISD::UADDO || Opc == ISD::SSUBO || +       Opc == ISD::USUBO) && (CC == ISD::SETEQ || CC == ISD::SETNE)) { +    // Only lower legal XALUO ops. +    if (!DAG.getTargetLoweringInfo().isTypeLegal(LHS->getValueType(0))) +      return SDValue(); + +    // The actual operation with overflow check. +    SDValue Value, OverflowCmp; +    SDValue ARMcc; +    std::tie(Value, OverflowCmp) = getARMXALUOOp(LHS.getValue(0), DAG, ARMcc); + +    if ((CC == ISD::SETNE) != isOneConstant(RHS)) { +      // Reverse the condition code. +      ARMCC::CondCodes CondCode = +          (ARMCC::CondCodes)cast<const ConstantSDNode>(ARMcc)->getZExtValue(); +      CondCode = ARMCC::getOppositeCondition(CondCode); +      ARMcc = DAG.getConstant(CondCode, SDLoc(ARMcc), MVT::i32); +    } +    SDValue CCR = DAG.getRegister(ARM::CPSR, MVT::i32); + +    return DAG.getNode(ARMISD::BRCOND, dl, MVT::Other, Chain, Dest, ARMcc, CCR, +                       OverflowCmp); +  } +    if (LHS.getValueType() == MVT::i32) {      SDValue ARMcc;      SDValue Cmp = getARMCmp(LHS, RHS, CC, ARMcc, DAG, dl); @@ -7793,6 +7861,7 @@ SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {    case ISD::GlobalTLSAddress: return LowerGlobalTLSAddress(Op, DAG);    case ISD::SELECT:        return LowerSELECT(Op, DAG);    case ISD::SELECT_CC:     return LowerSELECT_CC(Op, DAG); +  case ISD::BRCOND:        return LowerBRCOND(Op, DAG);    case ISD::BR_CC:         return LowerBR_CC(Op, DAG);    case ISD::BR_JT:         return LowerBR_JT(Op, DAG);    case ISD::VASTART:       return LowerVASTART(Op, DAG);  | 

