[llvm] Intrinsic: introduce minimumnum and maximumnum for IR and SelectionDAG (PR #96649)
Matt Arsenault via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 25 01:36:58 PDT 2024
================
@@ -8531,6 +8531,70 @@ SDValue TargetLowering::expandFMINIMUM_FMAXIMUM(SDNode *N,
return MinMax;
}
+SDValue TargetLowering::expandFMINIMUMNUM_FMAXIMUMNUM(SDNode *Node,
+ SelectionDAG &DAG) const {
+ SDLoc dl(Node);
+ unsigned NewOp = Node->getOpcode() == ISD::FMINIMUMNUM ? ISD::FMINNUM_IEEE
+ : ISD::FMAXNUM_IEEE;
+ EVT VT = Node->getValueType(0);
+
+ if (VT.isScalableVector())
+ report_fatal_error(
+ "Expanding fminimumnum/fmaximumnum for scalable vectors is undefined.");
+
+ if (isOperationLegalOrCustom(NewOp, VT)) {
+ SDValue Quiet0 = Node->getOperand(0);
+ SDValue Quiet1 = Node->getOperand(1);
+
+ if (!Node->getFlags().hasNoNaNs()) {
+ // Insert canonicalizes if it's possible we need to quiet to get correct
+ // sNaN behavior.
+ if (!DAG.isKnownNeverSNaN(Quiet0)) {
+ Quiet0 =
+ DAG.getNode(ISD::FCANONICALIZE, dl, VT, Quiet0, Node->getFlags());
+ }
+ if (!DAG.isKnownNeverSNaN(Quiet1)) {
+ Quiet1 =
+ DAG.getNode(ISD::FCANONICALIZE, dl, VT, Quiet1, Node->getFlags());
+ }
+ }
+
+ return DAG.getNode(NewOp, dl, VT, Quiet0, Quiet1, Node->getFlags());
+ }
+
+ // FMINIMUM/FMAXIMUM always return NaN if either operand is NaN.
+ // It has same behavior about +0.0 vs -0.0.
+ if (Node->getFlags().hasNoNaNs() ||
+ (DAG.isKnownNeverNaN(Node->getOperand(0)) &&
+ DAG.isKnownNeverNaN(Node->getOperand(1)))) {
+ unsigned IEEE2019Op =
+ Node->getOpcode() == ISD::FMINIMUMNUM ? ISD::FMINIMUM : ISD::FMAXIMUM;
+ if (isOperationLegalOrCustom(IEEE2019Op, VT))
+ return DAG.getNode(IEEE2019Op, dl, VT, Node->getOperand(0),
+ Node->getOperand(1), Node->getFlags());
+ }
+
+ // FMINNUM/FMAXMUM returns qNaN if either operand is sNaN, and it may return
+ // either one for +0.0 vs -0.0.
+ // FIXME: maybe we need hasNoSNaNs().
+ if ((Node->getFlags().hasNoNaNs() ||
+ (DAG.isKnownNeverSNaN(Node->getOperand(0)) &&
+ DAG.isKnownNeverSNaN(Node->getOperand(1)))) &&
+ (Node->getFlags().hasNoSignedZeros() ||
+ DAG.isKnownNeverZeroFloat(Node->getOperand(0)) ||
+ DAG.isKnownNeverZeroFloat(Node->getOperand(1)))) {
+ unsigned IEEE2008Op =
+ Node->getOpcode() == ISD::FMINIMUMNUM ? ISD::FMINNUM : ISD::FMAXNUM;
+ if (isOperationLegalOrCustom(IEEE2008Op, VT))
+ return DAG.getNode(IEEE2008Op, dl, VT, Node->getOperand(0),
+ Node->getOperand(1), Node->getFlags());
+ }
+
+ // FIXME: we may use setCC/getSELECT to optimize it instead of fallback to
+ // libcall.
----------------
arsenm wrote:
This is the wrong way to structure it. TLI::expand* functions should always fully, and directly, expand in terms of other generic opcodes. It should not have a failure path, expecting other code to insert a libcall on failure. There should be no failure case here. Other code should explicitly choose to use the libcall
https://github.com/llvm/llvm-project/pull/96649
More information about the llvm-commits
mailing list