@@ -6473,7 +6473,8 @@ static Value *foldMinMaxSharedOp(Intrinsic::ID IID, Value *Op0, Value *Op1) {
6473
6473
static Value *foldMinimumMaximumSharedOp (Intrinsic::ID IID, Value *Op0,
6474
6474
Value *Op1) {
6475
6475
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) &&
6477
6478
" Unsupported intrinsic" );
6478
6479
6479
6480
auto *M0 = dyn_cast<IntrinsicInst>(Op0);
@@ -6512,6 +6513,82 @@ static Value *foldMinimumMaximumSharedOp(Intrinsic::ID IID, Value *Op0,
6512
6513
return nullptr ;
6513
6514
}
6514
6515
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
+
6515
6592
Value *llvm::simplifyBinaryIntrinsic (Intrinsic::ID IID, Type *ReturnType,
6516
6593
Value *Op0, Value *Op1,
6517
6594
const SimplifyQuery &Q,
@@ -6780,49 +6857,73 @@ Value *llvm::simplifyBinaryIntrinsic(Intrinsic::ID IID, Type *ReturnType,
6780
6857
case Intrinsic::maxnum:
6781
6858
case Intrinsic::minnum:
6782
6859
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)
6785
6871
if (Op0 == Op1)
6786
6872
return Op0;
6787
6873
6788
6874
// Canonicalize constant operand as Op1.
6789
6875
if (isa<Constant>(Op0))
6790
6876
std::swap (Op0, Op1);
6791
6877
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
+ }
6795
6921
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;
6826
6927
}
6827
6928
6828
6929
// Min/max of the same operation with common operand:
0 commit comments