@@ -6473,7 +6473,8 @@ static Value *foldMinMaxSharedOp(Intrinsic::ID IID, Value *Op0, Value *Op1) {
64736473static Value *foldMinimumMaximumSharedOp (Intrinsic::ID IID, Value *Op0,
64746474 Value *Op1) {
64756475 assert ((IID == Intrinsic::maxnum || IID == Intrinsic::minnum ||
6476- IID == Intrinsic::maximum || IID == Intrinsic::minimum) &&
6476+ IID == Intrinsic::maximum || IID == Intrinsic::minimum ||
6477+ IID == Intrinsic::maximumnum || IID == Intrinsic::minimumnum) &&
64776478 " Unsupported intrinsic" );
64786479
64796480 auto *M0 = dyn_cast<IntrinsicInst>(Op0);
@@ -6512,6 +6513,82 @@ static Value *foldMinimumMaximumSharedOp(Intrinsic::ID IID, Value *Op0,
65126513 return nullptr ;
65136514}
65146515
6516+ enum class MinMaxOptResult {
6517+ CannotOptimize = 0 ,
6518+ UseNewConstVal = 1 ,
6519+ UseOtherVal = 2 ,
6520+ // For undef/poison, we can choose to either propgate undef/poison or
6521+ // use the LHS value depending on what will allow more optimization.
6522+ UseEither = 3
6523+ };
6524+ // Get the optimized value for a min/max instruction with a single constant
6525+ // input (either undef or scalar constantFP). The result may indicate to
6526+ // use the non-const LHS value, use a new constant value instead (with NaNs
6527+ // quieted), or to choose either option in the case of undef/poison.
6528+ static MinMaxOptResult OptimizeConstMinMax (const Constant *RHSConst,
6529+ const Intrinsic::ID IID,
6530+ const CallBase *Call,
6531+ Constant **OutNewConstVal) {
6532+ assert (OutNewConstVal != nullptr );
6533+
6534+ bool PropagateNaN = IID == Intrinsic::minimum || IID == Intrinsic::maximum;
6535+ bool PropagateSNaN = IID == Intrinsic::minnum || IID == Intrinsic::maxnum;
6536+ bool IsMin = IID == Intrinsic::minimum || IID == Intrinsic::minnum ||
6537+ IID == Intrinsic::minimumnum;
6538+
6539+ // min/max(x, poison) -> either x or poison
6540+ if (isa<UndefValue>(RHSConst)) {
6541+ *OutNewConstVal = const_cast <Constant *>(RHSConst);
6542+ return MinMaxOptResult::UseEither;
6543+ }
6544+
6545+ const ConstantFP *CFP = dyn_cast<ConstantFP>(RHSConst);
6546+ if (!CFP)
6547+ return MinMaxOptResult::CannotOptimize;
6548+ APFloat CAPF = CFP->getValueAPF ();
6549+
6550+ // minnum(x, qnan) -> x
6551+ // maxnum(x, qnan) -> x
6552+ // minnum(x, snan) -> qnan
6553+ // maxnum(x, snan) -> qnan
6554+ // minimum(X, nan) -> qnan
6555+ // maximum(X, nan) -> qnan
6556+ // minimumnum(X, nan) -> x
6557+ // maximumnum(X, nan) -> x
6558+ if (CAPF.isNaN ()) {
6559+ if (PropagateNaN || (PropagateSNaN && CAPF.isSignaling ())) {
6560+ *OutNewConstVal = ConstantFP::get (CFP->getType (), CAPF.makeQuiet ());
6561+ return MinMaxOptResult::UseNewConstVal;
6562+ }
6563+ return MinMaxOptResult::UseOtherVal;
6564+ }
6565+
6566+ if (CAPF.isInfinity () || (Call && Call->hasNoInfs () && CAPF.isLargest ())) {
6567+ // minnum(X, -inf) -> -inf (ignoring sNaN -> qNaN propagation)
6568+ // maxnum(X, +inf) -> +inf (ignoring sNaN -> qNaN propagation)
6569+ // minimum(X, -inf) -> -inf if nnan
6570+ // maximum(X, +inf) -> +inf if nnan
6571+ // minimumnum(X, -inf) -> -inf
6572+ // maximumnum(X, +inf) -> +inf
6573+ if (CAPF.isNegative () == IsMin &&
6574+ (!PropagateNaN || (Call && Call->hasNoNaNs ()))) {
6575+ *OutNewConstVal = const_cast <Constant *>(RHSConst);
6576+ return MinMaxOptResult::UseNewConstVal;
6577+ }
6578+
6579+ // minnum(X, +inf) -> X if nnan
6580+ // maxnum(X, -inf) -> X if nnan
6581+ // minimum(X, +inf) -> X (ignoring quieting of sNaNs)
6582+ // maximum(X, -inf) -> X (ignoring quieting of sNaNs)
6583+ // minimumnum(X, +inf) -> X if nnan
6584+ // maximumnum(X, -inf) -> X if nnan
6585+ if (CAPF.isNegative () != IsMin &&
6586+ (PropagateNaN || (Call && Call->hasNoNaNs ())))
6587+ return MinMaxOptResult::UseOtherVal;
6588+ }
6589+ return MinMaxOptResult::CannotOptimize;
6590+ }
6591+
65156592Value *llvm::simplifyBinaryIntrinsic (Intrinsic::ID IID, Type *ReturnType,
65166593 Value *Op0, Value *Op1,
65176594 const SimplifyQuery &Q,
@@ -6780,49 +6857,73 @@ Value *llvm::simplifyBinaryIntrinsic(Intrinsic::ID IID, Type *ReturnType,
67806857 case Intrinsic::maxnum:
67816858 case Intrinsic::minnum:
67826859 case Intrinsic::maximum:
6783- case Intrinsic::minimum: {
6784- // If the arguments are the same, this is a no-op.
6860+ case Intrinsic::minimum:
6861+ case Intrinsic::maximumnum:
6862+ case Intrinsic::minimumnum: {
6863+ // In several cases here, we deviate from exact IEEE 754 semantics
6864+ // to enable optimizations (as allowed by the LLVM IR spec).
6865+ //
6866+ // For instance, we may return one of the arguments unmodified instead of
6867+ // inserting an llvm.canonicalize to transform input sNaNs into qNaNs,
6868+ // or may assume all NaN inputs are qNaNs.
6869+
6870+ // If the arguments are the same, this is a no-op (ignoring NaN quieting)
67856871 if (Op0 == Op1)
67866872 return Op0;
67876873
67886874 // Canonicalize constant operand as Op1.
67896875 if (isa<Constant>(Op0))
67906876 std::swap (Op0, Op1);
67916877
6792- // If an argument is undef, return the other argument.
6793- if (Q.isUndefValue (Op1))
6794- return Op0;
6878+ if (Constant *C = dyn_cast<Constant>(Op1)) {
6879+ MinMaxOptResult OptResult = MinMaxOptResult::CannotOptimize;
6880+ Constant *NewConst = nullptr ;
6881+
6882+ if (VectorType *VTy = dyn_cast<VectorType>(C->getType ())) {
6883+ ElementCount ElemCount = VTy->getElementCount ();
6884+
6885+ if (Constant *SplatVal = C->getSplatValue ()) {
6886+ // Handle splat vectors (including scalable vectors)
6887+ OptResult = OptimizeConstMinMax (SplatVal, IID, Call, &NewConst);
6888+ if (OptResult == MinMaxOptResult::UseNewConstVal)
6889+ NewConst = ConstantVector::getSplat (ElemCount, NewConst);
6890+
6891+ } else if (ElemCount.isFixed ()) {
6892+ // Storage to build up new const return value (with NaNs quieted)
6893+ SmallVector<Constant *, 16 > NewC (ElemCount.getFixedValue ());
6894+
6895+ // Check elementwise whether we can optimize to either a constant
6896+ // value or return the LHS value. We cannot mix and match LHS +
6897+ // constant elements, as this would require inserting a new
6898+ // VectorShuffle instruction, which is not allowed in simplifyBinOp.
6899+ OptResult = MinMaxOptResult::UseEither;
6900+ for (unsigned i = 0 ; i != ElemCount.getFixedValue (); ++i) {
6901+ auto ElemResult = OptimizeConstMinMax (C->getAggregateElement (i),
6902+ IID, Call, &NewConst);
6903+ if (ElemResult == MinMaxOptResult::CannotOptimize ||
6904+ (ElemResult != OptResult &&
6905+ OptResult != MinMaxOptResult::UseEither &&
6906+ ElemResult != MinMaxOptResult::UseEither)) {
6907+ OptResult = MinMaxOptResult::CannotOptimize;
6908+ break ;
6909+ }
6910+ NewC[i] = NewConst;
6911+ if (ElemResult != MinMaxOptResult::UseEither)
6912+ OptResult = ElemResult;
6913+ }
6914+ if (OptResult == MinMaxOptResult::UseNewConstVal)
6915+ NewConst = ConstantVector::get (NewC);
6916+ }
6917+ } else {
6918+ // Handle scalar inputs
6919+ OptResult = OptimizeConstMinMax (C, IID, Call, &NewConst);
6920+ }
67956921
6796- bool PropagateNaN = IID == Intrinsic::minimum || IID == Intrinsic::maximum;
6797- bool IsMin = IID == Intrinsic::minimum || IID == Intrinsic::minnum;
6798-
6799- // minnum(X, nan) -> X
6800- // maxnum(X, nan) -> X
6801- // minimum(X, nan) -> nan
6802- // maximum(X, nan) -> nan
6803- if (match (Op1, m_NaN ()))
6804- return PropagateNaN ? propagateNaN (cast<Constant>(Op1)) : Op0;
6805-
6806- // In the following folds, inf can be replaced with the largest finite
6807- // float, if the ninf flag is set.
6808- const APFloat *C;
6809- if (match (Op1, m_APFloat (C)) &&
6810- (C->isInfinity () || (Call && Call->hasNoInfs () && C->isLargest ()))) {
6811- // minnum(X, -inf) -> -inf
6812- // maxnum(X, +inf) -> +inf
6813- // minimum(X, -inf) -> -inf if nnan
6814- // maximum(X, +inf) -> +inf if nnan
6815- if (C->isNegative () == IsMin &&
6816- (!PropagateNaN || (Call && Call->hasNoNaNs ())))
6817- return ConstantFP::get (ReturnType, *C);
6818-
6819- // minnum(X, +inf) -> X if nnan
6820- // maxnum(X, -inf) -> X if nnan
6821- // minimum(X, +inf) -> X
6822- // maximum(X, -inf) -> X
6823- if (C->isNegative () != IsMin &&
6824- (PropagateNaN || (Call && Call->hasNoNaNs ())))
6825- return Op0;
6922+ if (OptResult == MinMaxOptResult::UseOtherVal ||
6923+ OptResult == MinMaxOptResult::UseEither)
6924+ return Op0; // Return the other arg (ignoring NaN quieting)
6925+ else if (OptResult == MinMaxOptResult::UseNewConstVal)
6926+ return NewConst;
68266927 }
68276928
68286929 // Min/max of the same operation with common operand:
0 commit comments