@@ -6415,7 +6415,8 @@ static Value *foldMinMaxSharedOp(Intrinsic::ID IID, Value *Op0, Value *Op1) {
64156415static Value *foldMinimumMaximumSharedOp (Intrinsic::ID IID, Value *Op0,
64166416 Value *Op1) {
64176417 assert ((IID == Intrinsic::maxnum || IID == Intrinsic::minnum ||
6418- IID == Intrinsic::maximum || IID == Intrinsic::minimum) &&
6418+ IID == Intrinsic::maximum || IID == Intrinsic::minimum ||
6419+ IID == Intrinsic::maximumnum || IID == Intrinsic::minimumnum) &&
64196420 " Unsupported intrinsic" );
64206421
64216422 auto *M0 = dyn_cast<IntrinsicInst>(Op0);
@@ -6711,7 +6712,16 @@ Value *llvm::simplifyBinaryIntrinsic(Intrinsic::ID IID, Type *ReturnType,
67116712 case Intrinsic::maxnum:
67126713 case Intrinsic::minnum:
67136714 case Intrinsic::maximum:
6714- case Intrinsic::minimum: {
6715+ case Intrinsic::minimum:
6716+ case Intrinsic::maximumnum:
6717+ case Intrinsic::minimumnum: {
6718+ // In several cases here, we deviate from exact IEEE 754 semantics
6719+ // to enable optimizations (as allowed by the LLVM IR spec).
6720+ //
6721+ // For instance, we often return one of the arguments unmodified instead of
6722+ // inserting an llvm.canonicalize to transform input sNaNs into qNaNs or to
6723+ // respect any FTZ semantics, and sometimes assume all NaN inputs are qNaNs.
6724+
67156725 // If the arguments are the same, this is a no-op.
67166726 if (Op0 == Op1)
67176727 return Op0;
@@ -6725,32 +6735,43 @@ Value *llvm::simplifyBinaryIntrinsic(Intrinsic::ID IID, Type *ReturnType,
67256735 return Op0;
67266736
67276737 bool PropagateNaN = IID == Intrinsic::minimum || IID == Intrinsic::maximum;
6728- bool IsMin = IID == Intrinsic::minimum || IID == Intrinsic::minnum;
6729-
6730- // minnum(X, nan) -> X
6731- // maxnum(X, nan) -> X
6732- // minimum(X, nan) -> nan
6733- // maximum(X, nan) -> nan
6734- if (match (Op1, m_NaN ()))
6735- return PropagateNaN ? propagateNaN (cast<Constant>(Op1)) : Op0;
6738+ bool PropagateSNaN = IID == Intrinsic::minnum || IID == Intrinsic::maxnum;
6739+ bool IsMin = IID == Intrinsic::minimum || IID == Intrinsic::minnum ||
6740+ IID == Intrinsic::minimumnum;
6741+
6742+ // minnum(x, qnan) -> x
6743+ // maxnum(x, qnan) -> x
6744+ // minnum(x, snan) -> qnan
6745+ // maxnum(x, snan) -> qnan
6746+ // minimum(X, nan) -> qnan
6747+ // maximum(X, nan) -> qnan
6748+ if (match (Op1, m_NaN ())) {
6749+ if (PropagateNaN || (PropagateSNaN && match (Op1, m_sNaN ())))
6750+ return propagateNaN (cast<Constant>(Op1));
6751+ return Op0;
6752+ }
67366753
67376754 // In the following folds, inf can be replaced with the largest finite
67386755 // float, if the ninf flag is set.
67396756 const APFloat *C;
67406757 if (match (Op1, m_APFloat (C)) &&
67416758 (C->isInfinity () || (Call && Call->hasNoInfs () && C->isLargest ()))) {
6742- // minnum(X, -inf) -> -inf
6743- // maxnum(X, +inf) -> +inf
6759+ // minnum(X, -inf) -> -inf (ignoring sNaN -> qNaN propagation)
6760+ // maxnum(X, +inf) -> +inf (ignoring sNaN -> qNaN propagation)
67446761 // minimum(X, -inf) -> -inf if nnan
67456762 // maximum(X, +inf) -> +inf if nnan
6763+ // minimumnum(X, -inf) -> -inf
6764+ // maximumnum(X, +inf) -> +inf
67466765 if (C->isNegative () == IsMin &&
67476766 (!PropagateNaN || (Call && Call->hasNoNaNs ())))
67486767 return ConstantFP::get (ReturnType, *C);
67496768
67506769 // minnum(X, +inf) -> X if nnan
67516770 // maxnum(X, -inf) -> X if nnan
6752- // minimum(X, +inf) -> X
6753- // maximum(X, -inf) -> X
6771+ // minimum(X, +inf) -> X (ignoring quieting of sNaNs)
6772+ // maximum(X, -inf) -> X (ignoring quieting of sNaNs)
6773+ // maximumnum(X, -inf) -> X if nnan
6774+ // minimumnum(X, +inf) -> X if nnan
67546775 if (C->isNegative () != IsMin &&
67556776 (PropagateNaN || (Call && Call->hasNoNaNs ())))
67566777 return Op0;
0 commit comments