[llvm] [InstSimplify] Optimize maximumnum and minimumnum (PR #139581)

Matt Arsenault via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 19 08:58:04 PDT 2025


================
@@ -6715,36 +6725,138 @@ Value *llvm::simplifyBinaryIntrinsic(Intrinsic::ID IID, Type *ReturnType,
     if (Q.isUndefValue(Op1))
       return Op0;
 
-    bool PropagateNaN = IID == Intrinsic::minimum || IID == Intrinsic::maximum;
-    bool IsMin = IID == Intrinsic::minimum || IID == Intrinsic::minnum;
-
-    // minnum(X, nan) -> X
-    // maxnum(X, nan) -> X
-    // minimum(X, nan) -> nan
-    // maximum(X, nan) -> nan
-    if (match(Op1, m_NaN()))
-      return PropagateNaN ? propagateNaN(cast<Constant>(Op1)) : Op0;
-
-    // In the following folds, inf can be replaced with the largest finite
-    // float, if the ninf flag is set.
-    const APFloat *C;
-    if (match(Op1, m_APFloat(C)) &&
-        (C->isInfinity() || (Call && Call->hasNoInfs() && C->isLargest()))) {
-      // minnum(X, -inf) -> -inf
-      // maxnum(X, +inf) -> +inf
-      // minimum(X, -inf) -> -inf if nnan
-      // maximum(X, +inf) -> +inf if nnan
-      if (C->isNegative() == IsMin &&
-          (!PropagateNaN || (Call && Call->hasNoNaNs())))
-        return ConstantFP::get(ReturnType, *C);
-
-      // minnum(X, +inf) -> X if nnan
-      // maxnum(X, -inf) -> X if nnan
-      // minimum(X, +inf) -> X
-      // maximum(X, -inf) -> X
-      if (C->isNegative() != IsMin &&
-          (PropagateNaN || (Call && Call->hasNoNaNs())))
-        return Op0;
+    if (Constant *C = dyn_cast<Constant>(Op1)) {
+      bool PropagateNaN =
+          IID == Intrinsic::minimum || IID == Intrinsic::maximum;
+      bool PropagateSNaN = IID == Intrinsic::minnum || IID == Intrinsic::maxnum;
+      bool IsMin = IID == Intrinsic::minimum || IID == Intrinsic::minnum ||
+                   IID == Intrinsic::minimumnum;
+
+      // Get the optimized value for a constant scalar input. The result may
+      // indicate either to use the non-const LHS value, or return a pointer
+      // to a new constant value to use instead of the input (after e.g.
+      // quieting NaNs). Returns empty optional value if it cannot be optimized.
+      typedef struct {
+        bool UseNonConstVal;
+        Constant *NewConstVal;
+      } OptResult;
+      auto GetOptResultFor = [PropagateNaN, PropagateSNaN, IsMin,
+                              Call](Constant *C) -> std::optional<OptResult> {
+        auto UseNonConstVal = []() -> OptResult { return {true, nullptr}; };
+        auto UseConstVal = [](Constant *C) -> OptResult { return {false, C}; };
+
+        // min/max(opt, poison) -> poison
+        if (isa<UndefValue>(C))
+          return UseConstVal(C);
+
+        const ConstantFP *CFP = dyn_cast<ConstantFP>(C);
+        if (!CFP)
+          return {};
+        APFloat CAPF = CFP->getValueAPF();
+
+        // minnum(x, qnan) -> x
+        // maxnum(x, qnan) -> x
+        // minnum(x, snan) -> qnan
+        // maxnum(x, snan) -> qnan
+        // minimum(X, nan) -> qnan
+        // maximum(X, nan) -> qnan
+        // minimumnum(X, nan) -> x
+        // maximumnum(X, nan) -> x
+        if (CAPF.isNaN()) {
+          if (PropagateNaN || (PropagateSNaN && CAPF.isSignaling()))
+            return UseConstVal(ConstantFP::get(C->getType(), CAPF.makeQuiet()));
+          else
+            return UseNonConstVal();
+        }
+
+        if (CAPF.isInfinity() ||
+            (Call && Call->hasNoInfs() && CAPF.isLargest())) {
+          // minnum(X, -inf) -> -inf (ignoring sNaN -> qNaN propagation)
+          // maxnum(X, +inf) -> +inf (ignoring sNaN -> qNaN propagation)
+          // minimum(X, -inf) -> -inf if nnan
+          // maximum(X, +inf) -> +inf if nnan
+          // minimumnum(X, -inf) -> -inf
+          // maximumnum(X, +inf) -> +inf
+          if (CAPF.isNegative() == IsMin &&
+              (!PropagateNaN || (Call && Call->hasNoNaNs())))
+            return UseConstVal(C);
+
+          // minnum(X, +inf) -> X if nnan
+          // maxnum(X, -inf) -> X if nnan
+          // minimum(X, +inf) -> X (ignoring quieting of sNaNs)
+          // maximum(X, -inf) -> X (ignoring quieting of sNaNs)
+          // minimumnum(X, +inf) -> X if nnan
+          // maximumnum(X, -inf) -> X if nnan
+          if (CAPF.isNegative() != IsMin &&
+              (PropagateNaN || (Call && Call->hasNoNaNs())))
+            return UseNonConstVal();
+        }
+
+        // Cannot optimize this element
+        return {};
+      };
+
+      if (VectorType *VTy = dyn_cast<VectorType>(C->getType())) {
+        // Handle splat vectors (including scalable vectors)
+        if (Constant *SplatVal = C->getSplatValue()) {
+          std::optional<OptResult> OptSplatVal = GetOptResultFor(SplatVal);
+          if (OptSplatVal.has_value()) {
+            if (OptSplatVal.value().UseNonConstVal)
+              return Op0;
+            assert(OptSplatVal.value().NewConstVal != nullptr);
+            return ConstantVector::getSplat(VTy->getElementCount(),
+                                            OptSplatVal.value().NewConstVal);
+          }
+        } else if (auto *FVty = dyn_cast<FixedVectorType>(VTy)) {
+          // Check elementwise whether we can optimize to either a constant
+          // value or return the LHS value. We cannot mix and match LHS +
+          // constant elements, as this would require inserting a new
+          // VectorShuffle instruction, which is not allowed in simplifyBinOp,
+          // so bail early if any element cannot be optimized, or if lhs vs
+          // const optimizations start to mismatch. However, we can turn
+          // undef/poison into the LHS value, so only bail if we need at least 1
+          // non undef/poison RHS const.
+          bool CanOptimize = true;
+          bool AllConstValsAreUndef = true;
+          unsigned NumElts = FVty->getNumElements();
+          // Storage to build up the constant return value (possible altered
+          // from the input RHS value by quieting NaNs)
+          SmallVector<Constant *, 16> NewC(NumElts);
+
+          bool NeedsConstElement = false;
+          bool NeedsLHSElement = false;
+          for (unsigned i = 0; i != NumElts; ++i) {
----------------
arsenm wrote:

We have a few too many places doing the same thing over fixed constant vectors 

https://github.com/llvm/llvm-project/pull/139581


More information about the llvm-commits mailing list