@@ -6456,6 +6456,82 @@ static Value *foldMinimumMaximumSharedOp(Intrinsic::ID IID, Value *Op0,
64566456 return nullptr ;
64576457}
64586458
6459+ enum class MinMaxOptResult {
6460+ CannotOptimize = 0 ,
6461+ UseNewConstVal = 1 ,
6462+ UseOtherVal = 2 ,
6463+ // For undef/poison, we can choose to either propgate undef/poison or
6464+ // use the LHS value depending on what will allow more optimization.
6465+ UseEither = 3
6466+ };
6467+ // Get the optimized value for a min/max instruction with a single constant
6468+ // input (either undef or scalar constantFP). The result may indicate to
6469+ // use the non-const LHS value, use a new constant value instead (with NaNs
6470+ // quieted), or to choose either option in the case of undef/poison.
6471+ static MinMaxOptResult OptimizeConstMinMax (const Constant *RHSConst,
6472+ const Intrinsic::ID IID,
6473+ const CallBase *Call,
6474+ Constant **OutNewConstVal) {
6475+ assert (OutNewConstVal != nullptr );
6476+
6477+ bool PropagateNaN = IID == Intrinsic::minimum || IID == Intrinsic::maximum;
6478+ bool PropagateSNaN = IID == Intrinsic::minnum || IID == Intrinsic::maxnum;
6479+ bool IsMin = IID == Intrinsic::minimum || IID == Intrinsic::minnum ||
6480+ IID == Intrinsic::minimumnum;
6481+
6482+ // min/max(x, poison) -> either x or poison
6483+ if (isa<UndefValue>(RHSConst)) {
6484+ *OutNewConstVal = const_cast <Constant *>(RHSConst);
6485+ return MinMaxOptResult::UseEither;
6486+ }
6487+
6488+ const ConstantFP *CFP = dyn_cast<ConstantFP>(RHSConst);
6489+ if (!CFP)
6490+ return MinMaxOptResult::CannotOptimize;
6491+ APFloat CAPF = CFP->getValueAPF ();
6492+
6493+ // minnum(x, qnan) -> x
6494+ // maxnum(x, qnan) -> x
6495+ // minnum(x, snan) -> qnan
6496+ // maxnum(x, snan) -> qnan
6497+ // minimum(X, nan) -> qnan
6498+ // maximum(X, nan) -> qnan
6499+ // minimumnum(X, nan) -> x
6500+ // maximumnum(X, nan) -> x
6501+ if (CAPF.isNaN ()) {
6502+ if (PropagateNaN || (PropagateSNaN && CAPF.isSignaling ())) {
6503+ *OutNewConstVal = ConstantFP::get (CFP->getType (), CAPF.makeQuiet ());
6504+ return MinMaxOptResult::UseNewConstVal;
6505+ }
6506+ return MinMaxOptResult::UseOtherVal;
6507+ }
6508+
6509+ if (CAPF.isInfinity () || (Call && Call->hasNoInfs () && CAPF.isLargest ())) {
6510+ // minnum(X, -inf) -> -inf (ignoring sNaN -> qNaN propagation)
6511+ // maxnum(X, +inf) -> +inf (ignoring sNaN -> qNaN propagation)
6512+ // minimum(X, -inf) -> -inf if nnan
6513+ // maximum(X, +inf) -> +inf if nnan
6514+ // minimumnum(X, -inf) -> -inf
6515+ // maximumnum(X, +inf) -> +inf
6516+ if (CAPF.isNegative () == IsMin &&
6517+ (!PropagateNaN || (Call && Call->hasNoNaNs ()))) {
6518+ *OutNewConstVal = const_cast <Constant *>(RHSConst);
6519+ return MinMaxOptResult::UseNewConstVal;
6520+ }
6521+
6522+ // minnum(X, +inf) -> X if nnan
6523+ // maxnum(X, -inf) -> X if nnan
6524+ // minimum(X, +inf) -> X (ignoring quieting of sNaNs)
6525+ // maximum(X, -inf) -> X (ignoring quieting of sNaNs)
6526+ // minimumnum(X, +inf) -> X if nnan
6527+ // maximumnum(X, -inf) -> X if nnan
6528+ if (CAPF.isNegative () != IsMin &&
6529+ (PropagateNaN || (Call && Call->hasNoNaNs ())))
6530+ return MinMaxOptResult::UseOtherVal;
6531+ }
6532+ return MinMaxOptResult::CannotOptimize;
6533+ }
6534+
64596535Value *llvm::simplifyBinaryIntrinsic (Intrinsic::ID IID, Type *ReturnType,
64606536 Value *Op0, Value *Op1,
64616537 const SimplifyQuery &Q,
@@ -6721,142 +6797,55 @@ Value *llvm::simplifyBinaryIntrinsic(Intrinsic::ID IID, Type *ReturnType,
67216797 if (isa<Constant>(Op0))
67226798 std::swap (Op0, Op1);
67236799
6724- // If an argument is undef, return the other argument.
6725- if (Q.isUndefValue (Op1))
6726- return Op0;
6727-
67286800 if (Constant *C = dyn_cast<Constant>(Op1)) {
6729- bool PropagateNaN =
6730- IID == Intrinsic::minimum || IID == Intrinsic::maximum;
6731- bool PropagateSNaN = IID == Intrinsic::minnum || IID == Intrinsic::maxnum;
6732- bool IsMin = IID == Intrinsic::minimum || IID == Intrinsic::minnum ||
6733- IID == Intrinsic::minimumnum;
6734-
6735- // Get the optimized value for a constant scalar input. The result may
6736- // indicate either to use the non-const LHS value, or return a pointer
6737- // to a new constant value to use instead of the input (after e.g.
6738- // quieting NaNs). Returns empty optional value if it cannot be optimized.
6739- typedef struct {
6740- bool UseNonConstVal;
6741- Constant *NewConstVal;
6742- } OptResult;
6743- auto GetOptResultFor = [PropagateNaN, PropagateSNaN, IsMin,
6744- Call](Constant *C) -> std::optional<OptResult> {
6745- auto UseNonConstVal = []() -> OptResult { return {true , nullptr }; };
6746- auto UseConstVal = [](Constant *C) -> OptResult { return {false , C}; };
6747-
6748- // min/max(opt, poison) -> poison
6749- if (isa<UndefValue>(C))
6750- return UseConstVal (C);
6751-
6752- const ConstantFP *CFP = dyn_cast<ConstantFP>(C);
6753- if (!CFP)
6754- return {};
6755- APFloat CAPF = CFP->getValueAPF ();
6756-
6757- // minnum(x, qnan) -> x
6758- // maxnum(x, qnan) -> x
6759- // minnum(x, snan) -> qnan
6760- // maxnum(x, snan) -> qnan
6761- // minimum(X, nan) -> qnan
6762- // maximum(X, nan) -> qnan
6763- // minimumnum(X, nan) -> x
6764- // maximumnum(X, nan) -> x
6765- if (CAPF.isNaN ()) {
6766- if (PropagateNaN || (PropagateSNaN && CAPF.isSignaling ()))
6767- return UseConstVal (ConstantFP::get (C->getType (), CAPF.makeQuiet ()));
6768- else
6769- return UseNonConstVal ();
6770- }
6771-
6772- if (CAPF.isInfinity () ||
6773- (Call && Call->hasNoInfs () && CAPF.isLargest ())) {
6774- // minnum(X, -inf) -> -inf (ignoring sNaN -> qNaN propagation)
6775- // maxnum(X, +inf) -> +inf (ignoring sNaN -> qNaN propagation)
6776- // minimum(X, -inf) -> -inf if nnan
6777- // maximum(X, +inf) -> +inf if nnan
6778- // minimumnum(X, -inf) -> -inf
6779- // maximumnum(X, +inf) -> +inf
6780- if (CAPF.isNegative () == IsMin &&
6781- (!PropagateNaN || (Call && Call->hasNoNaNs ())))
6782- return UseConstVal (C);
6783-
6784- // minnum(X, +inf) -> X if nnan
6785- // maxnum(X, -inf) -> X if nnan
6786- // minimum(X, +inf) -> X (ignoring quieting of sNaNs)
6787- // maximum(X, -inf) -> X (ignoring quieting of sNaNs)
6788- // minimumnum(X, +inf) -> X if nnan
6789- // maximumnum(X, -inf) -> X if nnan
6790- if (CAPF.isNegative () != IsMin &&
6791- (PropagateNaN || (Call && Call->hasNoNaNs ())))
6792- return UseNonConstVal ();
6793- }
6794-
6795- // Cannot optimize this element
6796- return {};
6797- };
6801+ MinMaxOptResult OptResult = MinMaxOptResult::CannotOptimize;
6802+ Constant *NewConst = nullptr ;
67986803
67996804 if (VectorType *VTy = dyn_cast<VectorType>(C->getType ())) {
6800- // Handle splat vectors (including scalable vectors)
6805+ ElementCount ElemCount = VTy->getElementCount ();
6806+
68016807 if (Constant *SplatVal = C->getSplatValue ()) {
6802- std::optional<OptResult> OptSplatVal = GetOptResultFor (SplatVal);
6803- if (OptSplatVal.has_value ()) {
6804- if (OptSplatVal.value ().UseNonConstVal )
6805- return Op0;
6806- assert (OptSplatVal.value ().NewConstVal != nullptr );
6807- return ConstantVector::getSplat (VTy->getElementCount (),
6808- OptSplatVal.value ().NewConstVal );
6809- }
6808+ // Handle splat vectors (including scalable vectors)
6809+ OptResult = OptimizeConstMinMax (SplatVal, IID, Call, &NewConst);
6810+ if (OptResult == MinMaxOptResult::UseNewConstVal)
6811+ NewConst = ConstantVector::getSplat (ElemCount, NewConst);
6812+
68106813 } else if (auto *FVty = dyn_cast<FixedVectorType>(VTy)) {
6814+ // Storage to build up new const return value (with NaNs quieted)
6815+ SmallVector<Constant *, 16 > NewC (ElemCount.getFixedValue ());
6816+
68116817 // Check elementwise whether we can optimize to either a constant
68126818 // value or return the LHS value. We cannot mix and match LHS +
68136819 // constant elements, as this would require inserting a new
6814- // VectorShuffle instruction, which is not allowed in simplifyBinOp,
6815- // so bail early if any element cannot be optimized, or if lhs vs
6816- // const optimizations start to mismatch. However, we can turn
6817- // undef/poison into the LHS value, so only bail if we need at least 1
6818- // non undef/poison RHS const.
6819- bool CanOptimize = true ;
6820- bool AllConstValsAreUndef = true ;
6821- unsigned NumElts = FVty->getNumElements ();
6822- // Storage to build up the constant return value (possible altered
6823- // from the input RHS value by quieting NaNs)
6824- SmallVector<Constant *, 16 > NewC (NumElts);
6825-
6826- bool NeedsConstElement = false ;
6827- bool NeedsLHSElement = false ;
6828- for (unsigned i = 0 ; i != NumElts; ++i) {
6829- Constant *EltC = C->getAggregateElement (i);
6830- std::optional<OptResult> OptElemVal = GetOptResultFor (EltC);
6831- if (!OptElemVal.has_value ()) {
6832- CanOptimize = false ;
6820+ // VectorShuffle instruction, which is not allowed in simplifyBinOp.
6821+ OptResult = MinMaxOptResult::UseEither;
6822+ for (unsigned i = 0 ; i != ElemCount.getFixedValue (); ++i) {
6823+ auto ElemResult = OptimizeConstMinMax (C->getAggregateElement (i),
6824+ IID, Call, &NewConst);
6825+ if (ElemResult == MinMaxOptResult::CannotOptimize ||
6826+ (ElemResult != OptResult &&
6827+ OptResult != MinMaxOptResult::UseEither &&
6828+ ElemResult != MinMaxOptResult::UseEither)) {
6829+ OptResult = MinMaxOptResult::CannotOptimize;
68336830 break ;
68346831 }
6835- if (OptElemVal.value ().UseNonConstVal ) {
6836- NeedsLHSElement = true ;
6837- if (NeedsConstElement && !AllConstValsAreUndef)
6838- break ;
6839- } else {
6840- NeedsConstElement = true ;
6841- assert (OptElemVal.value ().NewConstVal != nullptr );
6842- NewC[i] = OptElemVal.value ().NewConstVal ;
6843- AllConstValsAreUndef &= isa<UndefValue>(NewC[i]);
6844- if (NeedsLHSElement && !AllConstValsAreUndef)
6845- break ;
6846- }
6832+ NewC[i] = NewConst;
6833+ if (ElemResult != MinMaxOptResult::UseEither)
6834+ OptResult = ElemResult;
68476835 }
6848-
6849- if (CanOptimize && (!NeedsLHSElement || AllConstValsAreUndef))
6850- return NeedsLHSElement ? Op0 : ConstantVector::get (NewC);
6836+ if (OptResult == MinMaxOptResult::UseNewConstVal)
6837+ NewConst = ConstantVector::get (NewC);
68516838 }
68526839 } else {
68536840 // Handle scalar inputs
6854- std::optional<OptResult> OptScalarVal = GetOptResultFor (C);
6855- if (OptScalarVal.has_value ()) {
6856- OptResult Res = OptScalarVal.value ();
6857- return Res.UseNonConstVal ? Op0 : Res.NewConstVal ;
6858- }
6841+ OptResult = OptimizeConstMinMax (C, IID, Call, &NewConst);
68596842 }
6843+
6844+ if (OptResult == MinMaxOptResult::UseOtherVal ||
6845+ OptResult == MinMaxOptResult::UseEither)
6846+ return Op0; // Return the other arg (ignoring NaN quieting)
6847+ else if (OptResult == MinMaxOptResult::UseNewConstVal)
6848+ return NewConst;
68606849 }
68616850
68626851 // Min/max of the same operation with common operand:
0 commit comments