diff options
Diffstat (limited to 'llvm/lib/CodeGen')
-rw-r--r-- | llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp | 28 | ||||
-rw-r--r-- | llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp | 52 |
2 files changed, 55 insertions, 25 deletions
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index 2b5ea545f02..b25a9ab854a 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -1162,10 +1162,30 @@ void SelectionDAGISel::DoInstructionSelection() { // we convert them to normal FP opcodes instead at this point. This // will allow them to be handled by existing target-specific instruction // selectors. - if (!TLI->isStrictFPEnabled() && Node->isStrictFPOpcode() && - (TLI->getOperationAction(Node->getOpcode(), Node->getValueType(0)) - == TargetLowering::Expand)) - Node = CurDAG->mutateStrictFPToFP(Node); + if (!TLI->isStrictFPEnabled() && Node->isStrictFPOpcode()) { + // For some opcodes, we need to call TLI->getOperationAction using + // the first operand type instead of the result type. Note that this + // must match what SelectionDAGLegalize::LegalizeOp is doing. + EVT ActionVT; + switch (Node->getOpcode()) { + case ISD::STRICT_SINT_TO_FP: + case ISD::STRICT_UINT_TO_FP: + case ISD::STRICT_LRINT: + case ISD::STRICT_LLRINT: + case ISD::STRICT_LROUND: + case ISD::STRICT_LLROUND: + case ISD::STRICT_FSETCC: + case ISD::STRICT_FSETCCS: + ActionVT = Node->getOperand(1).getValueType(); + break; + default: + ActionVT = Node->getValueType(0); + break; + } + if (TLI->getOperationAction(Node->getOpcode(), ActionVT) + == TargetLowering::Expand) + Node = CurDAG->mutateStrictFPToFP(Node); + } LLVM_DEBUG(dbgs() << "\nISEL: Starting selection on root node: "; Node->dump(CurDAG)); diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp index c3d6d329d67..3fc21547654 100644 --- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -6074,7 +6074,13 @@ bool TargetLowering::expandFP_TO_UINT(SDNode *Node, SDValue &Result, } SDValue Cst = DAG.getConstantFP(APF, dl, SrcVT); - SDValue Sel = DAG.getSetCC(dl, SetCCVT, Src, Cst, ISD::SETLT); + SDValue Sel; + + if (Node->isStrictFPOpcode()) + Sel = DAG.getSetCC(dl, SetCCVT, Src, Cst, ISD::SETLT, + Node->getOperand(0), /*IsSignaling*/ true); + else + Sel = DAG.getSetCC(dl, SetCCVT, Src, Cst, ISD::SETLT); bool Strict = Node->isStrictFPOpcode() || shouldUseStrictFP_TO_INT(SrcVT, DstVT, /*IsSigned*/ false); @@ -6149,13 +6155,16 @@ bool TargetLowering::expandUINT_TO_FP(SDNode *Node, SDValue &Result, // For unsigned conversions, convert them to signed conversions using the // algorithm from the x86_64 __floatundidf in compiler_rt. - SDValue Fast; - if (Node->isStrictFPOpcode()) { - Fast = DAG.getNode(ISD::STRICT_SINT_TO_FP, dl, {DstVT, MVT::Other}, - {Node->getOperand(0), Src}); - Chain = SDValue(Fast.getNode(), 1); - } else - Fast = DAG.getNode(ISD::SINT_TO_FP, dl, DstVT, Src); + + // TODO: This really should be implemented using a branch rather than a + // select. We happen to get lucky and machinesink does the right + // thing most of the time. This would be a good candidate for a + // pseudo-op, or, even better, for whole-function isel. + EVT SetCCVT = + getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), SrcVT); + + SDValue SignBitTest = DAG.getSetCC( + dl, SetCCVT, Src, DAG.getConstant(0, dl, SrcVT), ISD::SETLT); SDValue ShiftConst = DAG.getConstant(1, dl, ShiftVT); SDValue Shr = DAG.getNode(ISD::SRL, dl, SrcVT, Src, ShiftConst); @@ -6163,27 +6172,28 @@ bool TargetLowering::expandUINT_TO_FP(SDNode *Node, SDValue &Result, SDValue And = DAG.getNode(ISD::AND, dl, SrcVT, Src, AndConst); SDValue Or = DAG.getNode(ISD::OR, dl, SrcVT, And, Shr); - SDValue Slow; + SDValue Slow, Fast; if (Node->isStrictFPOpcode()) { - SDValue SignCvt = DAG.getNode(ISD::STRICT_SINT_TO_FP, dl, - {DstVT, MVT::Other}, {Chain, Or}); + // In strict mode, we must avoid spurious exceptions, and therefore + // must make sure to only emit a single STRICT_SINT_TO_FP. + SDValue InCvt = DAG.getSelect(dl, SrcVT, SignBitTest, Or, Src); + Fast = DAG.getNode(ISD::STRICT_SINT_TO_FP, dl, { DstVT, MVT::Other }, + { Node->getOperand(0), InCvt }); Slow = DAG.getNode(ISD::STRICT_FADD, dl, { DstVT, MVT::Other }, - { SignCvt.getValue(1), SignCvt, SignCvt }); + { Fast.getValue(1), Fast, Fast }); Chain = Slow.getValue(1); + // The STRICT_SINT_TO_FP inherits the exception mode from the + // incoming STRICT_UINT_TO_FP node; the STRICT_FADD node can + // never raise any exception. + SDNodeFlags Flags; + Flags.setFPExcept(Node->getFlags().hasFPExcept()); + Fast->setFlags(Flags); } else { SDValue SignCvt = DAG.getNode(ISD::SINT_TO_FP, dl, DstVT, Or); Slow = DAG.getNode(ISD::FADD, dl, DstVT, SignCvt, SignCvt); + Fast = DAG.getNode(ISD::SINT_TO_FP, dl, DstVT, Src); } - // TODO: This really should be implemented using a branch rather than a - // select. We happen to get lucky and machinesink does the right - // thing most of the time. This would be a good candidate for a - // pseudo-op, or, even better, for whole-function isel. - EVT SetCCVT = - getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), SrcVT); - - SDValue SignBitTest = DAG.getSetCC( - dl, SetCCVT, Src, DAG.getConstant(0, dl, SrcVT), ISD::SETLT); Result = DAG.getSelect(dl, DstVT, SignBitTest, Slow, Fast); return true; } |