@@ -6723,7 +6723,7 @@ Value *llvm::simplifyBinaryIntrinsic(Intrinsic::ID IID, Type *ReturnType,
67236723 // inserting an llvm.canonicalize to transform input sNaNs into qNaNs,
67246724 // or may assume all NaN inputs are qNaNs.
67256725
6726- // If the arguments are the same, this is a no-op.
6726+ // If the arguments are the same, this is a no-op (ignoring NaN quieting)
67276727 if (Op0 == Op1)
67286728 return Op0;
67296729
@@ -6735,54 +6735,139 @@ Value *llvm::simplifyBinaryIntrinsic(Intrinsic::ID IID, Type *ReturnType,
67356735 if (Q.isUndefValue (Op1))
67366736 return Op0;
67376737
6738- bool PropagateNaN = IID == Intrinsic::minimum || IID == Intrinsic::maximum;
6739- bool PropagateSNaN = IID == Intrinsic::minnum || IID == Intrinsic::maxnum;
6740- bool IsMin = IID == Intrinsic::minimum || IID == Intrinsic::minnum ||
6741- IID == Intrinsic::minimumnum;
6742-
6743- // minnum(x, qnan) -> x
6744- // maxnum(x, qnan) -> x
6745- // minnum(x, snan) -> qnan
6746- // maxnum(x, snan) -> qnan
6747- // minimum(X, nan) -> qnan
6748- // maximum(X, nan) -> qnan
6749- if (PropagateSNaN && match (Op1, m_sNaN ()))
6750- return propagateNaN (cast<Constant>(Op1));
6751- if (match (Op1, m_NaN ())) {
6752- if (PropagateNaN)
6753- return propagateNaN (cast<Constant>(Op1));
6754- // In cases like mixed <sNaN, qNaN> vectors, avoid the optimization to
6755- // allow correct sNaN propagation where necessary.
6756- else if (PropagateSNaN && !match (Op1, m_qNaN ()))
6757- break ;
6758- else
6759- return Op0;
6760- }
6738+ if (Constant *C = dyn_cast<Constant>(Op1)) {
6739+ bool PropagateNaN =
6740+ IID == Intrinsic::minimum || IID == Intrinsic::maximum;
6741+ bool PropagateSNaN = IID == Intrinsic::minnum || IID == Intrinsic::maxnum;
6742+ bool IsMin = IID == Intrinsic::minimum || IID == Intrinsic::minnum ||
6743+ IID == Intrinsic::minimumnum;
6744+
6745+ // Get the optimized value for a constant scalar input. The result may
6746+ // indicate either to use the non-const LHS value, or return a pointer
6747+ // to a new constant value to use instead of the input (after e.g.
6748+ // quieting NaNs). Returns empty optional value if it cannot be optimized.
6749+ typedef struct {
6750+ bool UseNonConstVal;
6751+ Constant *NewConstVal;
6752+ } OptResult;
6753+ auto GetOptResultFor = [PropagateNaN, PropagateSNaN, IsMin,
6754+ Call](Constant *C) -> std::optional<OptResult> {
6755+ auto UseNonConstVal = []() -> OptResult { return {true , nullptr }; };
6756+ auto UseConstVal = [](Constant *C) -> OptResult { return {false , C}; };
6757+
6758+ // min/max(opt, poison) -> poison
6759+ if (isa<UndefValue>(C))
6760+ return UseConstVal (C);
6761+
6762+ const ConstantFP *CFP = dyn_cast<ConstantFP>(C);
6763+ if (!CFP)
6764+ return {};
6765+ APFloat CAPF = CFP->getValueAPF ();
6766+
6767+ // minnum(x, qnan) -> x
6768+ // maxnum(x, qnan) -> x
6769+ // minnum(x, snan) -> qnan
6770+ // maxnum(x, snan) -> qnan
6771+ // minimum(X, nan) -> qnan
6772+ // maximum(X, nan) -> qnan
6773+ // minimumnum(X, nan) -> x
6774+ // maximumnum(X, nan) -> x
6775+ if (CAPF.isNaN ()) {
6776+ if (PropagateNaN || (PropagateSNaN && CAPF.isSignaling ()))
6777+ return UseConstVal (ConstantFP::get (C->getType (), CAPF.makeQuiet ()));
6778+ else
6779+ return UseNonConstVal ();
6780+ }
67616781
6762- // In the following folds, inf can be replaced with the largest finite
6763- // float, if the ninf flag is set.
6764- const APFloat *C;
6765- if (match (Op1, m_APFloat (C)) &&
6766- (C->isInfinity () || (Call && Call->hasNoInfs () && C->isLargest ()))) {
6767- // minnum(X, -inf) -> -inf (ignoring sNaN -> qNaN propagation)
6768- // maxnum(X, +inf) -> +inf (ignoring sNaN -> qNaN propagation)
6769- // minimum(X, -inf) -> -inf if nnan
6770- // maximum(X, +inf) -> +inf if nnan
6771- // minimumnum(X, -inf) -> -inf
6772- // maximumnum(X, +inf) -> +inf
6773- if (C->isNegative () == IsMin &&
6774- (!PropagateNaN || (Call && Call->hasNoNaNs ())))
6775- return ConstantFP::get (ReturnType, *C);
6776-
6777- // minnum(X, +inf) -> X if nnan
6778- // maxnum(X, -inf) -> X if nnan
6779- // minimum(X, +inf) -> X (ignoring quieting of sNaNs)
6780- // maximum(X, -inf) -> X (ignoring quieting of sNaNs)
6781- // maximumnum(X, -inf) -> X if nnan
6782- // minimumnum(X, +inf) -> X if nnan
6783- if (C->isNegative () != IsMin &&
6784- (PropagateNaN || (Call && Call->hasNoNaNs ())))
6785- return Op0;
6782+ if (CAPF.isInfinity () ||
6783+ (Call && Call->hasNoInfs () && CAPF.isLargest ())) {
6784+ // minnum(X, -inf) -> -inf (ignoring sNaN -> qNaN propagation)
6785+ // maxnum(X, +inf) -> +inf (ignoring sNaN -> qNaN propagation)
6786+ // minimum(X, -inf) -> -inf if nnan
6787+ // maximum(X, +inf) -> +inf if nnan
6788+ // minimumnum(X, -inf) -> -inf
6789+ // maximumnum(X, +inf) -> +inf
6790+ if (CAPF.isNegative () == IsMin &&
6791+ (!PropagateNaN || (Call && Call->hasNoNaNs ())))
6792+ return UseConstVal (C);
6793+
6794+ // minnum(X, +inf) -> X if nnan
6795+ // maxnum(X, -inf) -> X if nnan
6796+ // minimum(X, +inf) -> X (ignoring quieting of sNaNs)
6797+ // maximum(X, -inf) -> X (ignoring quieting of sNaNs)
6798+ // maximumnum(X, -inf) -> X if nnan
6799+ // minimumnum(X, +inf) -> X if nnan
6800+ if (CAPF.isNegative () != IsMin &&
6801+ (PropagateNaN || (Call && Call->hasNoNaNs ())))
6802+ return UseNonConstVal ();
6803+ }
6804+
6805+ // Cannot optimize this element
6806+ return {};
6807+ };
6808+
6809+ if (VectorType *VTy = dyn_cast<VectorType>(C->getType ())) {
6810+ // Handle splat vectors (including scalable vectors)
6811+ if (Constant *SplatVal = C->getSplatValue ()) {
6812+ std::optional<OptResult> OptSplatVal = GetOptResultFor (SplatVal);
6813+ if (OptSplatVal.has_value ()) {
6814+ if (OptSplatVal.value ().UseNonConstVal )
6815+ return Op0;
6816+ assert (OptSplatVal.value ().NewConstVal != nullptr );
6817+ return ConstantVector::getSplat (VTy->getElementCount (),
6818+ OptSplatVal.value ().NewConstVal );
6819+ }
6820+ }
6821+
6822+ // Check elementwise whether we can optimize to either a constant value
6823+ // or return the LHS value. We cannot mix and match LHS + constant
6824+ // elements, as this would require inserting a new VectorShuffle
6825+ // instruction, which is not allowed in simplifyBinOp, so bail early if
6826+ // any element cannot be optimized, or if lhs vs const optimizations
6827+ // start to mismatch. However, we can turn undef/poison into the LHS
6828+ // value, so only bail if we need at least 1 non undef/poison RHS const.
6829+ bool CanOptimize = true ;
6830+ bool AllConstValsAreUndef = true ;
6831+ if (auto *FVty = dyn_cast<FixedVectorType>(VTy)) {
6832+ unsigned NumElts = FVty->getNumElements ();
6833+ // Storage to build up the constant return value (possible altered
6834+ // from the input RHS value by quieting NaNs)
6835+ SmallVector<Constant *, 16 > NewC (NumElts);
6836+
6837+ bool NeedsConstElement = false ;
6838+ bool NeedsLHSElement = false ;
6839+ for (unsigned i = 0 ; i != NumElts; ++i) {
6840+ Constant *EltC = C->getAggregateElement (i);
6841+ std::optional<OptResult> OptElemVal = GetOptResultFor (EltC);
6842+ if (!OptElemVal.has_value ()) {
6843+ CanOptimize = false ;
6844+ break ;
6845+ }
6846+ if (OptElemVal.value ().UseNonConstVal ) {
6847+ NeedsLHSElement = true ;
6848+ if (NeedsConstElement && !AllConstValsAreUndef)
6849+ break ;
6850+ } else {
6851+ NeedsConstElement = true ;
6852+ assert (OptElemVal.value ().NewConstVal != nullptr );
6853+ NewC[i] = OptElemVal.value ().NewConstVal ;
6854+ AllConstValsAreUndef &= isa<UndefValue>(NewC[i]);
6855+ if (NeedsLHSElement && !AllConstValsAreUndef)
6856+ break ;
6857+ }
6858+ }
6859+
6860+ if (CanOptimize && (!NeedsLHSElement || AllConstValsAreUndef))
6861+ return NeedsLHSElement ? Op0 : ConstantVector::get (NewC);
6862+ }
6863+ } else {
6864+ // Handle scalar inputs
6865+ std::optional<OptResult> OptScalarVal = GetOptResultFor (C);
6866+ if (OptScalarVal.has_value ()) {
6867+ OptResult Res = OptScalarVal.value ();
6868+ return Res.UseNonConstVal ? Op0 : Res.NewConstVal ;
6869+ }
6870+ }
67866871 }
67876872
67886873 // Min/max of the same operation with common operand:
0 commit comments