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

Lewis Crawford via llvm-commits llvm-commits at lists.llvm.org
Tue May 13 02:55:19 PDT 2025


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

>From 2248c989fde34f7c95202850b6a36c424f62a02f Mon Sep 17 00:00:00 2001
From: Lewis Crawford <lcrawford at nvidia.com>
Date: Tue, 13 May 2025 09:23:03 +0000
Subject: [PATCH] [InstSimplify] Optimize maximumnum and minimumnum

Add support for the new maximumnum and minimumnum intrinsics in various optimizations in InstSimplify.

Also, change the behavior of optimizing maxnum(sNaN, x) to simplify to qNaN instead of x to better match the LLVM IR spec, and add more tests for sNaN behavior for all 3 max/min intrinsic types.
---
 llvm/include/llvm/IR/PatternMatch.h           |  15 +
 llvm/lib/Analysis/InstructionSimplify.cpp     |  49 +-
 llvm/lib/Analysis/ValueTracking.cpp           |   2 +
 .../Transforms/InstSimplify/fminmax-folds.ll  | 963 +++++++++++++++++-
 4 files changed, 1008 insertions(+), 21 deletions(-)

diff --git a/llvm/include/llvm/IR/PatternMatch.h b/llvm/include/llvm/IR/PatternMatch.h
index 6242a686e7bc0..c4d1bd095847d 100644
--- a/llvm/include/llvm/IR/PatternMatch.h
+++ b/llvm/include/llvm/IR/PatternMatch.h
@@ -707,10 +707,25 @@ m_SpecificInt_ICMP(ICmpInst::Predicate Predicate, const APInt &Threshold) {
 struct is_nan {
   bool isValue(const APFloat &C) const { return C.isNaN(); }
 };
+
+struct is_snan {
+  bool isValue(const APFloat &C) const { return C.isSignaling(); }
+};
+
+struct is_qnan {
+  bool isValue(const APFloat &C) const { return C.isNaN() && !C.isSignaling(); }
+};
+
 /// Match an arbitrary NaN constant. This includes quiet and signalling nans.
 /// For vectors, this includes constants with undefined elements.
 inline cstfp_pred_ty<is_nan> m_NaN() { return cstfp_pred_ty<is_nan>(); }
 
+/// Match quiet NaN constants, including vectors with undefined elements.
+inline cstfp_pred_ty<is_qnan> m_qNaN() { return cstfp_pred_ty<is_qnan>(); }
+
+/// Match signalling NaN constants, including vectors with undefined elements.
+inline cstfp_pred_ty<is_snan> m_sNaN() { return cstfp_pred_ty<is_snan>(); }
+
 struct is_nonnan {
   bool isValue(const APFloat &C) const { return !C.isNaN(); }
 };
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 85e3be9cc45c3..49774bcb45585 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -6415,7 +6415,8 @@ static Value *foldMinMaxSharedOp(Intrinsic::ID IID, Value *Op0, Value *Op1) {
 static Value *foldMinimumMaximumSharedOp(Intrinsic::ID IID, Value *Op0,
                                          Value *Op1) {
   assert((IID == Intrinsic::maxnum || IID == Intrinsic::minnum ||
-          IID == Intrinsic::maximum || IID == Intrinsic::minimum) &&
+          IID == Intrinsic::maximum || IID == Intrinsic::minimum ||
+          IID == Intrinsic::maximumnum || IID == Intrinsic::minimumnum) &&
          "Unsupported intrinsic");
 
   auto *M0 = dyn_cast<IntrinsicInst>(Op0);
@@ -6711,7 +6712,16 @@ Value *llvm::simplifyBinaryIntrinsic(Intrinsic::ID IID, Type *ReturnType,
   case Intrinsic::maxnum:
   case Intrinsic::minnum:
   case Intrinsic::maximum:
-  case Intrinsic::minimum: {
+  case Intrinsic::minimum:
+  case Intrinsic::maximumnum:
+  case Intrinsic::minimumnum: {
+    // In several cases here, we deviate from exact IEEE 754 semantics
+    // to enable optimizations (as allowed by the LLVM IR spec).
+    //
+    // For instance, we often return one of the arguments unmodified instead of
+    // inserting an llvm.canonicalize to transform input sNaNs into qNaNs or to
+    // respect any FTZ semantics, and sometimes assume all NaN inputs are qNaNs.
+
     // If the arguments are the same, this is a no-op.
     if (Op0 == Op1)
       return Op0;
@@ -6725,32 +6735,43 @@ Value *llvm::simplifyBinaryIntrinsic(Intrinsic::ID IID, Type *ReturnType,
       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;
+    bool PropagateSNaN = IID == Intrinsic::minnum || IID == Intrinsic::maxnum;
+    bool IsMin = IID == Intrinsic::minimum || IID == Intrinsic::minnum ||
+                 IID == Intrinsic::minimumnum;
+
+    // minnum(x, qnan) -> x
+    // maxnum(x, qnan) -> x
+    // minnum(x, snan) -> qnan
+    // maxnum(x, snan) -> qnan
+    // minimum(X, nan) -> qnan
+    // maximum(X, nan) -> qnan
+    if (match(Op1, m_NaN())) {
+      if (PropagateNaN || (PropagateSNaN && match(Op1, m_sNaN())))
+        return propagateNaN(cast<Constant>(Op1));
+      return 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
+      // 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 (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
+      // minimum(X, +inf) -> X (ignoring quieting of sNaNs)
+      // maximum(X, -inf) -> X (ignoring quieting of sNaNs)
+      // maximumnum(X, -inf) -> X if nnan
+      // minimumnum(X, +inf) -> X if nnan
       if (C->isNegative() != IsMin &&
           (PropagateNaN || (Call && Call->hasNoNaNs())))
         return Op0;
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 3d403531cea2f..c01ebbce15804 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -9310,6 +9310,8 @@ Intrinsic::ID llvm::getInverseMinMaxIntrinsic(Intrinsic::ID MinMaxID) {
   case Intrinsic::minimum: return Intrinsic::maximum;
   case Intrinsic::maxnum: return Intrinsic::minnum;
   case Intrinsic::minnum: return Intrinsic::maxnum;
+  case Intrinsic::maximumnum: return Intrinsic::minimumnum;
+  case Intrinsic::minimumnum: return Intrinsic::maximumnum;
   default: llvm_unreachable("Unexpected intrinsic");
   }
 }
diff --git a/llvm/test/Transforms/InstSimplify/fminmax-folds.ll b/llvm/test/Transforms/InstSimplify/fminmax-folds.ll
index fff6cfd8a3b4b..60d4fa531f1f5 100644
--- a/llvm/test/Transforms/InstSimplify/fminmax-folds.ll
+++ b/llvm/test/Transforms/InstSimplify/fminmax-folds.ll
@@ -54,6 +54,70 @@ define float @test_minimum_const_nan(float %x) {
   ret float %r
 }
 
+define float @test_maximumnum_const_nan(float %x) {
+; CHECK-LABEL: @test_maximumnum_const_nan(
+; CHECK-NEXT:    ret float [[R:%.*]]
+;
+  %r = call float @llvm.maximumnum.f32(float %x, float 0x7fff000000000000)
+  ret float %r
+}
+
+define float @test_minimumnum_const_nan(float %x) {
+; CHECK-LABEL: @test_minimumnum_const_nan(
+; CHECK-NEXT:    ret float [[R:%.*]]
+;
+  %r = call float @llvm.minimumnum.f32(float %x, float 0x7fff000000000000)
+  ret float %r
+}
+
+define float @test_minnum_const_snan(float %x) {
+; CHECK-LABEL: @test_minnum_const_snan(
+; CHECK-NEXT:    ret float 0x7FFC000000000000
+;
+  %r = call float @llvm.minnum.f32(float %x, float 0x7ff4000000000000)
+  ret float %r
+}
+
+define float @test_maxnum_const_snan(float %x) {
+; CHECK-LABEL: @test_maxnum_const_snan(
+; CHECK-NEXT:    ret float 0x7FFC000000000000
+;
+  %r = call float @llvm.maxnum.f32(float %x, float 0x7ff4000000000000)
+  ret float %r
+}
+
+define float @test_maximum_const_snan(float %x) {
+; CHECK-LABEL: @test_maximum_const_snan(
+; CHECK-NEXT:    ret float 0x7FFC000000000000
+;
+  %r = call float @llvm.maximum.f32(float %x, float 0x7ff4000000000000)
+  ret float %r
+}
+
+define float @test_minimum_const_snan(float %x) {
+; CHECK-LABEL: @test_minimum_const_snan(
+; CHECK-NEXT:    ret float 0x7FFC000000000000
+;
+  %r = call float @llvm.minimum.f32(float %x, float 0x7ff4000000000000)
+  ret float %r
+}
+
+define float @test_maximumnum_const_snan(float %x) {
+; CHECK-LABEL: @test_maximumnum_const_snan(
+; CHECK-NEXT:    ret float [[X:%.*]]
+;
+  %r = call float @llvm.maximumnum.f32(float %x, float 0x7ff4000000000000)
+  ret float %r
+}
+
+define float @test_minimumnum_const_snan(float %x) {
+; CHECK-LABEL: @test_minimumnum_const_snan(
+; CHECK-NEXT:    ret float [[X:%.*]]
+;
+  %r = call float @llvm.minimumnum.f32(float %x, float 0x7ff4000000000000)
+  ret float %r
+}
+
 define float @test_minnum_const_inf(float %x) {
 ; CHECK-LABEL: @test_minnum_const_inf(
 ; CHECK-NEXT:    [[R:%.*]] = call float @llvm.minnum.f32(float [[X:%.*]], float 0x7FF0000000000000)
@@ -88,6 +152,23 @@ define float @test_minimum_const_inf(float %x) {
   ret float %r
 }
 
+define float @test_maximumnum_const_inf(float %x) {
+; CHECK-LABEL: @test_maximumnum_const_inf(
+; CHECK-NEXT:    ret float 0x7FF0000000000000
+;
+  %r = call float @llvm.maximumnum.f32(float %x, float 0x7ff0000000000000)
+  ret float %r
+}
+
+define float @test_minimumnum_const_inf(float %x) {
+; CHECK-LABEL: @test_minimumnum_const_inf(
+; CHECK-NEXT:    [[R:%.*]] = call float @llvm.minimumnum.f32(float [[X:%.*]], float 0x7FF0000000000000)
+; CHECK-NEXT:    ret float [[R]]
+;
+  %r = call float @llvm.minimumnum.f32(float %x, float 0x7ff0000000000000)
+  ret float %r
+}
+
 define float @test_minnum_const_neg_inf(float %x) {
 ; CHECK-LABEL: @test_minnum_const_neg_inf(
 ; CHECK-NEXT:    ret float 0xFFF0000000000000
@@ -122,6 +203,23 @@ define float @test_minimum_const_neg_inf(float %x) {
   ret float %r
 }
 
+define float @test_maximumnum_const_neg_inf(float %x) {
+; CHECK-LABEL: @test_maximumnum_const_neg_inf(
+; CHECK-NEXT:    [[X:%.*]] = call float @llvm.maximumnum.f32(float [[X1:%.*]], float 0xFFF0000000000000)
+; CHECK-NEXT:    ret float [[X]]
+;
+  %r = call float @llvm.maximumnum.f32(float %x, float 0xfff0000000000000)
+  ret float %r
+}
+
+define float @test_minimumnum_const_neg_inf(float %x) {
+; CHECK-LABEL: @test_minimumnum_const_neg_inf(
+; CHECK-NEXT:    ret float 0xFFF0000000000000
+;
+  %r = call float @llvm.minimumnum.f32(float %x, float 0xfff0000000000000)
+  ret float %r
+}
+
 define float @test_minnum_const_inf_nnan(float %x) {
 ; CHECK-LABEL: @test_minnum_const_inf_nnan(
 ; CHECK-NEXT:    ret float [[X:%.*]]
@@ -154,6 +252,22 @@ define float @test_minimum_const_inf_nnan(float %x) {
   ret float %r
 }
 
+define float @test_maximumnum_const_inf_nnan(float %x) {
+; CHECK-LABEL: @test_maximumnum_const_inf_nnan(
+; CHECK-NEXT:    ret float 0x7FF0000000000000
+;
+  %r = call nnan float @llvm.maximumnum.f32(float %x, float 0x7ff0000000000000)
+  ret float %r
+}
+
+define float @test_minimumnum_const_inf_nnan(float %x) {
+; CHECK-LABEL: @test_minimumnum_const_inf_nnan(
+; CHECK-NEXT:    ret float [[X:%.*]]
+;
+  %r = call nnan float @llvm.minimumnum.f32(float %x, float 0x7ff0000000000000)
+  ret float %r
+}
+
 define float @test_minnum_const_inf_nnan_comm(float %x) {
 ; CHECK-LABEL: @test_minnum_const_inf_nnan_comm(
 ; CHECK-NEXT:    ret float [[X:%.*]]
@@ -186,6 +300,22 @@ define float @test_minimum_const_inf_nnan_comm(float %x) {
   ret float %r
 }
 
+define float @test_maximumnum_const_inf_nnan_comm(float %x) {
+; CHECK-LABEL: @test_maximumnum_const_inf_nnan_comm(
+; CHECK-NEXT:    ret float 0x7FF0000000000000
+;
+  %r = call nnan float @llvm.maximumnum.f32(float 0x7ff0000000000000, float %x)
+  ret float %r
+}
+
+define float @test_minimumnum_const_inf_nnan_comm(float %x) {
+; CHECK-LABEL: @test_minimumnum_const_inf_nnan_comm(
+; CHECK-NEXT:    ret float [[X:%.*]]
+;
+  %r = call nnan float @llvm.minimumnum.f32(float 0x7ff0000000000000, float %x)
+  ret float %r
+}
+
 define <2 x float> @test_minnum_const_inf_nnan_comm_vec(<2 x float> %x) {
 ; CHECK-LABEL: @test_minnum_const_inf_nnan_comm_vec(
 ; CHECK-NEXT:    ret <2 x float> [[X:%.*]]
@@ -218,6 +348,22 @@ define <2 x float> @test_minimum_const_inf_nnan_comm_vec(<2 x float> %x) {
   ret <2 x float> %r
 }
 
+define <2 x float> @test_maximumnum_const_inf_nnan_comm_vec(<2 x float> %x) {
+; CHECK-LABEL: @test_maximumnum_const_inf_nnan_comm_vec(
+; CHECK-NEXT:    ret <2 x float> splat (float 0x7FF0000000000000)
+;
+  %r = call nnan <2 x float> @llvm.maximumnum.v2f32(<2 x float> <float 0x7ff0000000000000, float 0x7ff0000000000000>, <2 x float> %x)
+  ret <2 x float> %r
+}
+
+define <2 x float> @test_minimumnum_const_inf_nnan_comm_vec(<2 x float> %x) {
+; CHECK-LABEL: @test_minimumnum_const_inf_nnan_comm_vec(
+; CHECK-NEXT:    ret <2 x float> [[X:%.*]]
+;
+  %r = call nnan <2 x float> @llvm.minimumnum.v2f32(<2 x float> <float 0x7ff0000000000000, float 0x7ff0000000000000>, <2 x float> %x)
+  ret <2 x float> %r
+}
+
 define float @test_minnum_const_neg_inf_nnan(float %x) {
 ; CHECK-LABEL: @test_minnum_const_neg_inf_nnan(
 ; CHECK-NEXT:    ret float 0xFFF0000000000000
@@ -250,6 +396,22 @@ define float @test_minimum_const_neg_inf_nnan(float %x) {
   ret float %r
 }
 
+define float @test_maximumnum_const_neg_inf_nnan(float %x) {
+; CHECK-LABEL: @test_maximumnum_const_neg_inf_nnan(
+; CHECK-NEXT:    ret float [[X:%.*]]
+;
+  %r = call nnan float @llvm.maximumnum.f32(float %x, float 0xfff0000000000000)
+  ret float %r
+}
+
+define float @test_minimumnum_const_neg_inf_nnan(float %x) {
+; CHECK-LABEL: @test_minimumnum_const_neg_inf_nnan(
+; CHECK-NEXT:    ret float 0xFFF0000000000000
+;
+  %r = call nnan float @llvm.minimumnum.f32(float %x, float 0xfff0000000000000)
+  ret float %r
+}
+
 define float @test_minnum_const_max(float %x) {
 ; CHECK-LABEL: @test_minnum_const_max(
 ; CHECK-NEXT:    [[R:%.*]] = call float @llvm.minnum.f32(float [[X:%.*]], float 0x47EFFFFFE0000000)
@@ -286,6 +448,24 @@ define float @test_minimum_const_max(float %x) {
   ret float %r
 }
 
+define float @test_maximumnum_const_max(float %x) {
+; CHECK-LABEL: @test_maximumnum_const_max(
+; CHECK-NEXT:    [[R:%.*]] = call float @llvm.maximumnum.f32(float [[X:%.*]], float 0x47EFFFFFE0000000)
+; CHECK-NEXT:    ret float [[R]]
+;
+  %r = call float @llvm.maximumnum.f32(float %x, float 0x47efffffe0000000)
+  ret float %r
+}
+
+define float @test_minimumnum_const_max(float %x) {
+; CHECK-LABEL: @test_minimumnum_const_max(
+; CHECK-NEXT:    [[R:%.*]] = call float @llvm.minimumnum.f32(float [[X:%.*]], float 0x47EFFFFFE0000000)
+; CHECK-NEXT:    ret float [[R]]
+;
+  %r = call float @llvm.minimumnum.f32(float %x, float 0x47efffffe0000000)
+  ret float %r
+}
+
 define float @test_minnum_const_neg_max(float %x) {
 ; CHECK-LABEL: @test_minnum_const_neg_max(
 ; CHECK-NEXT:    [[R:%.*]] = call float @llvm.minnum.f32(float [[X:%.*]], float 0xC7EFFFFFE0000000)
@@ -322,6 +502,24 @@ define float @test_minimum_const_neg_max(float %x) {
   ret float %r
 }
 
+define float @test_maximumnum_const_neg_max(float %x) {
+; CHECK-LABEL: @test_maximumnum_const_neg_max(
+; CHECK-NEXT:    [[R:%.*]] = call float @llvm.maximumnum.f32(float [[X:%.*]], float 0xC7EFFFFFE0000000)
+; CHECK-NEXT:    ret float [[R]]
+;
+  %r = call float @llvm.maximumnum.f32(float %x, float 0xc7efffffe0000000)
+  ret float %r
+}
+
+define float @test_minimumnum_const_neg_max(float %x) {
+; CHECK-LABEL: @test_minimumnum_const_neg_max(
+; CHECK-NEXT:    [[R:%.*]] = call float @llvm.minimumnum.f32(float [[X:%.*]], float 0xC7EFFFFFE0000000)
+; CHECK-NEXT:    ret float [[R]]
+;
+  %r = call float @llvm.minimumnum.f32(float %x, float 0xc7efffffe0000000)
+  ret float %r
+}
+
 define float @test_minnum_const_max_ninf(float %x) {
 ; CHECK-LABEL: @test_minnum_const_max_ninf(
 ; CHECK-NEXT:    [[R:%.*]] = call ninf float @llvm.minnum.f32(float [[X:%.*]], float 0x47EFFFFFE0000000)
@@ -356,6 +554,23 @@ define float @test_minimum_const_max_ninf(float %x) {
   ret float %r
 }
 
+define float @test_maximumnum_const_max_ninf(float %x) {
+; CHECK-LABEL: @test_maximumnum_const_max_ninf(
+; CHECK-NEXT:    ret float 0x47EFFFFFE0000000
+;
+  %r = call ninf float @llvm.maximumnum.f32(float %x, float 0x47efffffe0000000)
+  ret float %r
+}
+
+define float @test_minimumnum_const_max_ninf(float %x) {
+; CHECK-LABEL: @test_minimumnum_const_max_ninf(
+; CHECK-NEXT:    [[R:%.*]] = call ninf float @llvm.minimumnum.f32(float [[X:%.*]], float 0x47EFFFFFE0000000)
+; CHECK-NEXT:    ret float [[R]]
+;
+  %r = call ninf float @llvm.minimumnum.f32(float %x, float 0x47efffffe0000000)
+  ret float %r
+}
+
 define float @test_minnum_const_neg_max_ninf(float %x) {
 ; CHECK-LABEL: @test_minnum_const_neg_max_ninf(
 ; CHECK-NEXT:    ret float 0xC7EFFFFFE0000000
@@ -390,6 +605,23 @@ define float @test_minimum_const_neg_max_ninf(float %x) {
   ret float %r
 }
 
+define float @test_maximumnum_const_neg_max_ninf(float %x) {
+; CHECK-LABEL: @test_maximumnum_const_neg_max_ninf(
+; CHECK-NEXT:    [[X:%.*]] = call ninf float @llvm.maximumnum.f32(float [[X1:%.*]], float 0xC7EFFFFFE0000000)
+; CHECK-NEXT:    ret float [[X]]
+;
+  %r = call ninf float @llvm.maximumnum.f32(float %x, float 0xc7efffffe0000000)
+  ret float %r
+}
+
+define float @test_minimumnum_const_neg_max_ninf(float %x) {
+; CHECK-LABEL: @test_minimumnum_const_neg_max_ninf(
+; CHECK-NEXT:    ret float 0xC7EFFFFFE0000000
+;
+  %r = call ninf float @llvm.minimumnum.f32(float %x, float 0xc7efffffe0000000)
+  ret float %r
+}
+
 define float @test_minnum_const_max_nnan_ninf(float %x) {
 ; CHECK-LABEL: @test_minnum_const_max_nnan_ninf(
 ; CHECK-NEXT:    ret float [[X:%.*]]
@@ -422,6 +654,22 @@ define float @test_minimum_const_max_nnan_ninf(float %x) {
   ret float %r
 }
 
+define float @test_maximumnum_const_max_nnan_ninf(float %x) {
+; CHECK-LABEL: @test_maximumnum_const_max_nnan_ninf(
+; CHECK-NEXT:    ret float 0x47EFFFFFE0000000
+;
+  %r = call nnan ninf float @llvm.maximumnum.f32(float %x, float 0x47efffffe0000000)
+  ret float %r
+}
+
+define float @test_minimumnum_const_max_nnan_ninf(float %x) {
+; CHECK-LABEL: @test_minimumnum_const_max_nnan_ninf(
+; CHECK-NEXT:    ret float [[X:%.*]]
+;
+  %r = call nnan ninf float @llvm.minimumnum.f32(float %x, float 0x47efffffe0000000)
+  ret float %r
+}
+
 define float @test_minnum_const_neg_max_nnan_ninf(float %x) {
 ; CHECK-LABEL: @test_minnum_const_neg_max_nnan_ninf(
 ; CHECK-NEXT:    ret float 0xC7EFFFFFE0000000
@@ -454,8 +702,24 @@ define float @test_minimum_const_neg_max_nnan_ninf(float %x) {
   ret float %r
 }
 
+define float @test_maximumnum_const_neg_max_nnan_ninf(float %x) {
+; CHECK-LABEL: @test_maximumnum_const_neg_max_nnan_ninf(
+; CHECK-NEXT:    ret float [[X:%.*]]
+;
+  %r = call nnan ninf float @llvm.maximumnum.f32(float %x, float 0xc7efffffe0000000)
+  ret float %r
+}
+
+define float @test_minimumnum_const_neg_max_nnan_ninf(float %x) {
+; CHECK-LABEL: @test_minimumnum_const_neg_max_nnan_ninf(
+; CHECK-NEXT:    ret float 0xC7EFFFFFE0000000
+;
+  %r = call nnan ninf float @llvm.minimumnum.f32(float %x, float 0xc7efffffe0000000)
+  ret float %r
+}
+
 ; From the LangRef for minnum/maxnum:
-; "If either operand is a NaN, returns the other non-NaN operand."
+; "If either operand is a qNaN, returns the other non-NaN operand. Returns NaN only if both operands are NaN or if either operand is sNaN."
 
 define double @maxnum_nan_op0(double %x) {
 ; CHECK-LABEL: @maxnum_nan_op0(
@@ -521,6 +785,70 @@ define <2 x double> @minnum_nan_op1_vec(<2 x double> %x) {
   ret <2 x double> %r
 }
 
+define double @maxnum_snan_op0(double %x) {
+; CHECK-LABEL: @maxnum_snan_op0(
+; CHECK-NEXT:    ret double 0x7FFC000000000000
+;
+  %r = call double @llvm.maxnum.f64(double 0x7ff4000000000000, double %x)
+  ret double %r
+}
+
+define double @maxnum_snan_op1(double %x) {
+; CHECK-LABEL: @maxnum_snan_op1(
+; CHECK-NEXT:    ret double 0x7FFC00000000DEAD
+;
+  %r = call double @llvm.maxnum.f64(double %x, double 0x7ff400000000dead)
+  ret double %r
+}
+
+define double @minnum_snan_op0(double %x) {
+; CHECK-LABEL: @minnum_snan_op0(
+; CHECK-NEXT:    ret double 0x7FFC000DEAD00000
+;
+  %r = call double @llvm.minnum.f64(double 0x7ff4000dead00000, double %x)
+  ret double %r
+}
+
+define double @minnum_snan_op1(double %x) {
+; CHECK-LABEL: @minnum_snan_op1(
+; CHECK-NEXT:    ret double 0x7FFC00DEAD00DEAD
+;
+  %r = call double @llvm.minnum.f64(double %x, double 0x7ff400dead00dead)
+  ret double %r
+}
+
+define <2 x double> @maxnum_snan_op0_vec(<2 x double> %x) {
+; CHECK-LABEL: @maxnum_snan_op0_vec(
+; CHECK-NEXT:    ret <2 x double> <double 0x7FFC000000000000, double poison>
+;
+  %r = call <2 x double> @llvm.maxnum.v2f64(<2 x double> <double 0x7ff4000000000000, double poison>, <2 x double> %x)
+  ret <2 x double> %r
+}
+
+define <2 x double> @maxnum_snan_op1_vec(<2 x double> %x) {
+; CHECK-LABEL: @maxnum_snan_op1_vec(
+; CHECK-NEXT:    ret <2 x double> <double 0x7FFC00000000DEAD, double 0x7FFCFFFFFFFFFFFF>
+;
+  %r = call <2 x double> @llvm.maxnum.v2f64(<2 x double> %x, <2 x double> <double 0x7ff400000000dead, double 0x7ff4ffffffffffff>)
+  ret <2 x double> %r
+}
+
+define <2 x double> @minnum_snan_op0_vec(<2 x double> %x) {
+; CHECK-LABEL: @minnum_snan_op0_vec(
+; CHECK-NEXT:    ret <2 x double> <double poison, double 0x7FFC000DEAD00000>
+;
+  %r = call <2 x double> @llvm.minnum.v2f64(<2 x double> <double poison, double 0x7ff4000dead00000>, <2 x double> %x)
+  ret <2 x double> %r
+}
+
+define <2 x double> @minnum_snan_op1_vec(<2 x double> %x) {
+; CHECK-LABEL: @minnum_snan_op1_vec(
+; CHECK-NEXT:    ret <2 x double> splat (double 0x7FFC00DEAD00DEAD)
+;
+  %r = call <2 x double> @llvm.minnum.v2f64(<2 x double> %x, <2 x double> <double 0x7ff400dead00dead, double 0x7ff400dead00dead>)
+  ret <2 x double> %r
+}
+
 define float @maxnum_undef_op1(float %x) {
 ; CHECK-LABEL: @maxnum_undef_op1(
 ; CHECK-NEXT:    ret float [[X:%.*]]
@@ -743,6 +1071,7 @@ define float @minnum_inf(float %x) {
   %val = call float @llvm.minnum.f32(float 0x7FF0000000000000, float %x)
   ret float %val
 }
+
 define float @maxnum_x_maxnum_x_y(float %x, float %y) {
 ; CHECK-LABEL: @maxnum_x_maxnum_x_y(
 ; CHECK-NEXT:    [[A:%.*]] = call float @llvm.maxnum.f32(float [[X:%.*]], float [[Y:%.*]])
@@ -921,6 +1250,86 @@ define <2 x double> @minimum_nan_op1_vec(<2 x double> %x) {
   ret <2 x double> %r
 }
 
+define double @maximum_snan_op0(double %x) {
+; CHECK-LABEL: @maximum_snan_op0(
+; CHECK-NEXT:    ret double 0x7FFC000000000000
+;
+  %r = call double @llvm.maximum.f64(double 0x7ff4000000000000, double %x)
+  ret double %r
+}
+
+define double @maximum_snan_op1(double %x) {
+; CHECK-LABEL: @maximum_snan_op1(
+; CHECK-NEXT:    ret double 0x7FFC00000000DEAD
+;
+  %r = call double @llvm.maximum.f64(double %x, double 0x7ff400000000dead)
+  ret double %r
+}
+
+define double @minimum_snan_op0(double %x) {
+; CHECK-LABEL: @minimum_snan_op0(
+; CHECK-NEXT:    ret double 0x7FFC000DEAD00000
+;
+  %r = call double @llvm.minimum.f64(double 0x7ff4000dead00000, double %x)
+  ret double %r
+}
+
+define double @minimum_snan_op1(double %x) {
+; CHECK-LABEL: @minimum_snan_op1(
+; CHECK-NEXT:    ret double 0x7FFC00DEAD00DEAD
+;
+  %r = call double @llvm.minimum.f64(double %x, double 0x7ff400dead00dead)
+  ret double %r
+}
+
+define <2 x double> @maximum_snan_op0_vec_partial_poison(<2 x double> %x) {
+; CHECK-LABEL: @maximum_snan_op0_vec_partial_poison(
+; CHECK-NEXT:    ret <2 x double> <double 0x7FFC000000000000, double poison>
+;
+  %r = call <2 x double> @llvm.maximum.v2f64(<2 x double> <double 0x7ff4000000000000, double poison>, <2 x double> %x)
+  ret <2 x double> %r
+}
+
+define <2 x double> @maximum_snan_op1_vec_partial_poison(<2 x double> %x) {
+; CHECK-LABEL: @maximum_snan_op1_vec_partial_poison(
+; CHECK-NEXT:    ret <2 x double> <double 0x7FFC000000000000, double poison>
+;
+  %r = call <2 x double> @llvm.maximum.v2f64(<2 x double> %x, <2 x double> <double 0x7ff4000000000000, double poison>)
+  ret <2 x double> %r
+}
+
+define <2 x double> @maximum_snan_op1_vec(<2 x double> %x) {
+; CHECK-LABEL: @maximum_snan_op1_vec(
+; CHECK-NEXT:    ret <2 x double> <double 0x7FFC00000000DEAD, double 0x7FFCFFFFFFFFFFFF>
+;
+  %r = call <2 x double> @llvm.maximum.v2f64(<2 x double> %x, <2 x double> <double 0x7ff400000000dead, double 0x7ff4ffffffffffff>)
+  ret <2 x double> %r
+}
+
+define <2 x double> @minimum_snan_op0_vec_partial_poison(<2 x double> %x) {
+; CHECK-LABEL: @minimum_snan_op0_vec_partial_poison(
+; CHECK-NEXT:    ret <2 x double> <double poison, double 0x7FFC000DEAD00000>
+;
+  %r = call <2 x double> @llvm.minimum.v2f64(<2 x double> <double poison, double 0x7ff4000dead00000>, <2 x double> %x)
+  ret <2 x double> %r
+}
+
+define <2 x double> @minimum_snan_op1_vec_partial_poison(<2 x double> %x) {
+; CHECK-LABEL: @minimum_snan_op1_vec_partial_poison(
+; CHECK-NEXT:    ret <2 x double> <double poison, double 0x7FFC000DEAD00000>
+;
+  %r = call <2 x double> @llvm.minimum.v2f64(<2 x double> %x, <2 x double> <double poison, double 0x7ff4000dead00000>)
+  ret <2 x double> %r
+}
+
+define <2 x double> @minimum_snan_op1_vec(<2 x double> %x) {
+; CHECK-LABEL: @minimum_snan_op1_vec(
+; CHECK-NEXT:    ret <2 x double> splat (double 0x7FFC00DEAD00DEAD)
+;
+  %r = call <2 x double> @llvm.minimum.v2f64(<2 x double> %x, <2 x double> <double 0x7ff400dead00dead, double 0x7ff400dead00dead>)
+  ret <2 x double> %r
+}
+
 define float @maximum_undef_op1(float %x) {
 ; CHECK-LABEL: @maximum_undef_op1(
 ; CHECK-NEXT:    ret float [[X:%.*]]
@@ -1171,8 +1580,6 @@ define <2 x double> @minimum_neginf_commute_vec(<2 x double> %x) {
   ret <2 x double> %r
 }
 
-; TODO: minimum(INF, X) --> X
-
 define float @minimum_inf(float %x) {
 ; CHECK-LABEL: @minimum_inf(
 ; CHECK-NEXT:    ret float [[X:%.*]]
@@ -1317,8 +1724,8 @@ define <2 x float> @maxnum_minnum_maxnum(<2 x float> %x, <2 x float> %y) {
   ret <2 x float> %val
 }
 
-define <2 x double> @maxnum_minnum_minmum(<2 x double> %x, <2 x double> %y) {
-; CHECK-LABEL: @maxnum_minnum_minmum(
+define <2 x double> @maxnum_minnum_minnum(<2 x double> %x, <2 x double> %y) {
+; CHECK-LABEL: @maxnum_minnum_minnum(
 ; CHECK-NEXT:    [[MIN1:%.*]] = call <2 x double> @llvm.minnum.v2f64(<2 x double> [[X:%.*]], <2 x double> [[Y:%.*]])
 ; CHECK-NEXT:    [[MIN2:%.*]] = call <2 x double> @llvm.minnum.v2f64(<2 x double> [[X]], <2 x double> [[Y]])
 ; CHECK-NEXT:    [[VAL:%.*]] = call <2 x double> @llvm.maxnum.v2f64(<2 x double> [[MIN1]], <2 x double> [[MIN2]])
@@ -1376,8 +1783,8 @@ define <2 x float> @minnum_maxnum_maxnum(<2 x float> %x, <2 x float> %y) {
   ret <2 x float> %val
 }
 
-define <2 x double> @minnum_minnum_minmum(<2 x double> %x, <2 x double> %y) {
-; CHECK-LABEL: @minnum_minnum_minmum(
+define <2 x double> @minnum_minnum_minnum(<2 x double> %x, <2 x double> %y) {
+; CHECK-LABEL: @minnum_minnum_minnum(
 ; CHECK-NEXT:    [[MIN1:%.*]] = call <2 x double> @llvm.minnum.v2f64(<2 x double> [[X:%.*]], <2 x double> [[Y:%.*]])
 ; CHECK-NEXT:    ret <2 x double> [[MIN1]]
 ;
@@ -1386,3 +1793,545 @@ define <2 x double> @minnum_minnum_minmum(<2 x double> %x, <2 x double> %y) {
   %val = call <2 x double> @llvm.minnum.v2f64(<2 x double> %min1, <2 x double> %min2)
   ret <2 x double> %val
 }
+
+; From the LangRef for minimumnum/maximumnum:
+; "If both operands are NaNs (including sNaN), returns qNaN.
+;  If one operand is NaN (including sNaN) and another operand is a number, return the number."
+
+define double @maximumnum_nan_op0(double %x) {
+; CHECK-LABEL: @maximumnum_nan_op0(
+; CHECK-NEXT:    ret double [[X:%.*]]
+;
+  %r = call double @llvm.maximumnum.f64(double 0x7ff8000000000000, double %x)
+  ret double %r
+}
+
+define double @maximumnum_nan_op1(double %x) {
+; CHECK-LABEL: @maximumnum_nan_op1(
+; CHECK-NEXT:    ret double [[X:%.*]]
+;
+  %r = call double @llvm.maximumnum.f64(double %x, double 0x7ff800000000dead)
+  ret double %r
+}
+
+define double @minimumnum_nan_op0(double %x) {
+; CHECK-LABEL: @minimumnum_nan_op0(
+; CHECK-NEXT:    ret double [[X:%.*]]
+;
+  %r = call double @llvm.minimumnum.f64(double 0x7ff8000dead00000, double %x)
+  ret double %r
+}
+
+define double @minimumnum_nan_op1(double %x) {
+; CHECK-LABEL: @minimumnum_nan_op1(
+; CHECK-NEXT:    ret double [[X:%.*]]
+;
+  %r = call double @llvm.minimumnum.f64(double %x, double 0x7ff800dead00dead)
+  ret double %r
+}
+
+define <2 x double> @maximumnum_nan_op0_vec(<2 x double> %x) {
+; CHECK-LABEL: @maximumnum_nan_op0_vec(
+; CHECK-NEXT:    ret <2 x double> [[X:%.*]]
+;
+  %r = call <2 x double> @llvm.maximumnum.v2f64(<2 x double> <double 0x7ff8000000000000, double poison>, <2 x double> %x)
+  ret <2 x double> %r
+}
+
+define <2 x double> @maximumnum_nan_op1_vec(<2 x double> %x) {
+; CHECK-LABEL: @maximumnum_nan_op1_vec(
+; CHECK-NEXT:    ret <2 x double> [[X:%.*]]
+;
+  %r = call <2 x double> @llvm.maximumnum.v2f64(<2 x double> %x, <2 x double> <double 0x7ff800000000dead, double 0x7ff8ffffffffffff>)
+  ret <2 x double> %r
+}
+
+define <2 x double> @minimumnum_nan_op0_vec(<2 x double> %x) {
+; CHECK-LABEL: @minimumnum_nan_op0_vec(
+; CHECK-NEXT:    ret <2 x double> [[X:%.*]]
+;
+  %r = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> <double poison, double 0x7ff8000dead00000>, <2 x double> %x)
+  ret <2 x double> %r
+}
+
+define <2 x double> @minimumnum_nan_op1_vec(<2 x double> %x) {
+; CHECK-LABEL: @minimumnum_nan_op1_vec(
+; CHECK-NEXT:    ret <2 x double> [[X:%.*]]
+;
+  %r = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> %x, <2 x double> <double 0x7ff800dead00dead, double 0x7ff800dead00dead>)
+  ret <2 x double> %r
+}
+
+define double @maximumnum_snan_op0(double %x) {
+; CHECK-LABEL: @maximumnum_snan_op0(
+; CHECK-NEXT:    ret double [[X:%.*]]
+;
+  %r = call double @llvm.maximumnum.f64(double 0x7ff4000000000000, double %x)
+  ret double %r
+}
+
+define double @maximumnum_snan_op1(double %x) {
+; CHECK-LABEL: @maximumnum_snan_op1(
+; CHECK-NEXT:    ret double [[X:%.*]]
+;
+  %r = call double @llvm.maximumnum.f64(double %x, double 0x7ff400000000dead)
+  ret double %r
+}
+
+define double @minimumnum_snan_op0(double %x) {
+; CHECK-LABEL: @minimumnum_snan_op0(
+; CHECK-NEXT:    ret double [[X:%.*]]
+;
+  %r = call double @llvm.minimumnum.f64(double 0x7ff4000dead00000, double %x)
+  ret double %r
+}
+
+define double @minimumnum_snan_op1(double %x) {
+; CHECK-LABEL: @minimumnum_snan_op1(
+; CHECK-NEXT:    ret double [[X:%.*]]
+;
+  %r = call double @llvm.minimumnum.f64(double %x, double 0x7ff400dead00dead)
+  ret double %r
+}
+
+define <2 x double> @maximumnum_snan_op0_vec(<2 x double> %x) {
+; CHECK-LABEL: @maximumnum_snan_op0_vec(
+; CHECK-NEXT:    ret <2 x double> [[X:%.*]]
+;
+  %r = call <2 x double> @llvm.maximumnum.v2f64(<2 x double> <double 0x7ff4000000000000, double poison>, <2 x double> %x)
+  ret <2 x double> %r
+}
+
+define <2 x double> @maximumnum_snan_op1_vec(<2 x double> %x) {
+; CHECK-LABEL: @maximumnum_snan_op1_vec(
+; CHECK-NEXT:    ret <2 x double> [[X:%.*]]
+;
+  %r = call <2 x double> @llvm.maximumnum.v2f64(<2 x double> %x, <2 x double> <double 0x7ff400000000dead, double 0x7ff4ffffffffffff>)
+  ret <2 x double> %r
+}
+
+define <2 x double> @minimumnum_snan_op0_vec(<2 x double> %x) {
+; CHECK-LABEL: @minimumnum_snan_op0_vec(
+; CHECK-NEXT:    ret <2 x double> [[X:%.*]]
+;
+  %r = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> <double poison, double 0x7ff4000dead00000>, <2 x double> %x)
+  ret <2 x double> %r
+}
+
+define <2 x double> @minimumnum_snan_op1_vec(<2 x double> %x) {
+; CHECK-LABEL: @minimumnum_snan_op1_vec(
+; CHECK-NEXT:    ret <2 x double> [[X:%.*]]
+;
+  %r = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> %x, <2 x double> <double 0x7ff400dead00dead, double 0x7ff400dead00dead>)
+  ret <2 x double> %r
+}
+
+define float @maximumnum_undef_op1(float %x) {
+; CHECK-LABEL: @maximumnum_undef_op1(
+; CHECK-NEXT:    ret float [[X:%.*]]
+;
+  %val = call float @llvm.maximumnum.f32(float %x, float undef)
+  ret float %val
+}
+
+define float @maximumnum_poison_op1(float %x) {
+; CHECK-LABEL: @maximumnum_poison_op1(
+; CHECK-NEXT:    ret float [[X:%.*]]
+;
+  %val = call float @llvm.maximumnum.f32(float %x, float poison)
+  ret float %val
+}
+
+define float @maximumnum_undef_op0(float %x) {
+; CHECK-LABEL: @maximumnum_undef_op0(
+; CHECK-NEXT:    ret float [[X:%.*]]
+;
+  %val = call float @llvm.maximumnum.f32(float undef, float %x)
+  ret float %val
+}
+
+define float @maximumnum_poison_op0(float %x) {
+; CHECK-LABEL: @maximumnum_poison_op0(
+; CHECK-NEXT:    ret float [[X:%.*]]
+;
+  %val = call float @llvm.maximumnum.f32(float poison, float %x)
+  ret float %val
+}
+
+define float @minimumnum_undef_op1(float %x) {
+; CHECK-LABEL: @minimumnum_undef_op1(
+; CHECK-NEXT:    ret float [[X:%.*]]
+;
+  %val = call float @llvm.minimumnum.f32(float %x, float undef)
+  ret float %val
+}
+
+define float @minimumnum_poison_op1(float %x) {
+; CHECK-LABEL: @minimumnum_poison_op1(
+; CHECK-NEXT:    ret float [[X:%.*]]
+;
+  %val = call float @llvm.minimumnum.f32(float %x, float poison)
+  ret float %val
+}
+
+define float @minimumnum_undef_op0(float %x) {
+; CHECK-LABEL: @minimumnum_undef_op0(
+; CHECK-NEXT:    ret float [[X:%.*]]
+;
+  %val = call float @llvm.minimumnum.f32(float undef, float %x)
+  ret float %val
+}
+
+define float @minimumnum_poison_op0(float %x) {
+; CHECK-LABEL: @minimumnum_poison_op0(
+; CHECK-NEXT:    ret float [[X:%.*]]
+;
+  %val = call float @llvm.minimumnum.f32(float poison, float %x)
+  ret float %val
+}
+
+define float @minimumnum_undef_undef(float %x) {
+; CHECK-LABEL: @minimumnum_undef_undef(
+; CHECK-NEXT:    ret float undef
+;
+  %val = call float @llvm.minimumnum.f32(float undef, float undef)
+  ret float %val
+}
+
+define float @minimumnum_poison_undef(float %x) {
+; CHECK-LABEL: @minimumnum_poison_undef(
+; CHECK-NEXT:    ret float undef
+;
+  %val = call float @llvm.minimumnum.f32(float poison, float undef)
+  ret float %val
+}
+
+define float @minimumnum_undef_poison(float %x) {
+; CHECK-LABEL: @minimumnum_undef_poison(
+; CHECK-NEXT:    ret float poison
+;
+  %val = call float @llvm.minimumnum.f32(float undef, float poison)
+  ret float %val
+}
+
+define float @maximumnum_undef_undef(float %x) {
+; CHECK-LABEL: @maximumnum_undef_undef(
+; CHECK-NEXT:    ret float undef
+;
+  %val = call float @llvm.maximumnum.f32(float undef, float undef)
+  ret float %val
+}
+
+define float @maximumnum_poison_undef(float %x) {
+; CHECK-LABEL: @maximumnum_poison_undef(
+; CHECK-NEXT:    ret float undef
+;
+  %val = call float @llvm.maximumnum.f32(float poison, float undef)
+  ret float %val
+}
+
+define float @maximumnum_undef_poison(float %x) {
+; CHECK-LABEL: @maximumnum_undef_poison(
+; CHECK-NEXT:    ret float poison
+;
+  %val = call float @llvm.maximumnum.f32(float undef, float poison)
+  ret float %val
+}
+
+define float @minimumnum_same_args(float %x) {
+; CHECK-LABEL: @minimumnum_same_args(
+; CHECK-NEXT:    ret float [[X:%.*]]
+;
+  %y = call float @llvm.minimumnum.f32(float %x, float %x)
+  ret float %y
+}
+
+define float @maximumnum_same_args(float %x) {
+; CHECK-LABEL: @maximumnum_same_args(
+; CHECK-NEXT:    ret float [[X:%.*]]
+;
+  %y = call float @llvm.maximumnum.f32(float %x, float %x)
+  ret float %y
+}
+
+define float @minimumnum_x_minimumnum_x_y(float %x, float %y) {
+; CHECK-LABEL: @minimumnum_x_minimumnum_x_y(
+; CHECK-NEXT:    [[A:%.*]] = call float @llvm.minimumnum.f32(float [[X:%.*]], float [[Y:%.*]])
+; CHECK-NEXT:    ret float [[A]]
+;
+  %a = call float @llvm.minimumnum.f32(float %x, float %y)
+  %b = call float @llvm.minimumnum.f32(float %x, float %a)
+  ret float %b
+}
+
+define float @minimumnum_y_minimumnum_x_y(float %x, float %y) {
+; CHECK-LABEL: @minimumnum_y_minimumnum_x_y(
+; CHECK-NEXT:    [[A:%.*]] = call float @llvm.minimumnum.f32(float [[X:%.*]], float [[Y:%.*]])
+; CHECK-NEXT:    ret float [[A]]
+;
+  %a = call float @llvm.minimumnum.f32(float %x, float %y)
+  %b = call float @llvm.minimumnum.f32(float %y, float %a)
+  ret float %b
+}
+
+define float @minimumnum_x_y_minimumnum_x(float %x, float %y) {
+; CHECK-LABEL: @minimumnum_x_y_minimumnum_x(
+; CHECK-NEXT:    [[A:%.*]] = call float @llvm.minimumnum.f32(float [[X:%.*]], float [[Y:%.*]])
+; CHECK-NEXT:    ret float [[A]]
+;
+  %a = call float @llvm.minimumnum.f32(float %x, float %y)
+  %b = call float @llvm.minimumnum.f32(float %a, float %x)
+  ret float %b
+}
+
+define float @minimumnum_x_y_minimumnum_y(float %x, float %y) {
+; CHECK-LABEL: @minimumnum_x_y_minimumnum_y(
+; CHECK-NEXT:    [[A:%.*]] = call float @llvm.minimumnum.f32(float [[X:%.*]], float [[Y:%.*]])
+; CHECK-NEXT:    ret float [[A]]
+;
+  %a = call float @llvm.minimumnum.f32(float %x, float %y)
+  %b = call float @llvm.minimumnum.f32(float %a, float %y)
+  ret float %b
+}
+
+; negative test
+
+define float @minimumnum_z_minimumnum_x_y(float %x, float %y, float %z) {
+; CHECK-LABEL: @minimumnum_z_minimumnum_x_y(
+; CHECK-NEXT:    [[A:%.*]] = call float @llvm.minimumnum.f32(float [[X:%.*]], float [[Y:%.*]])
+; CHECK-NEXT:    [[B:%.*]] = call float @llvm.minimumnum.f32(float [[Z:%.*]], float [[A]])
+; CHECK-NEXT:    ret float [[B]]
+;
+  %a = call float @llvm.minimumnum.f32(float %x, float %y)
+  %b = call float @llvm.minimumnum.f32(float %z, float %a)
+  ret float %b
+}
+
+; negative test
+
+define float @minimumnum_x_y_minimumnum_z(float %x, float %y, float %z) {
+; CHECK-LABEL: @minimumnum_x_y_minimumnum_z(
+; CHECK-NEXT:    [[A:%.*]] = call float @llvm.minimumnum.f32(float [[X:%.*]], float [[Y:%.*]])
+; CHECK-NEXT:    [[B:%.*]] = call float @llvm.minimumnum.f32(float [[A]], float [[Z:%.*]])
+; CHECK-NEXT:    ret float [[B]]
+;
+  %a = call float @llvm.minimumnum.f32(float %x, float %y)
+  %b = call float @llvm.minimumnum.f32(float %a, float %z)
+  ret float %b
+}
+
+; minimumnum(X, -INF) --> -INF
+
+define float @minimumnum_neginf(float %x) {
+; CHECK-LABEL: @minimumnum_neginf(
+; CHECK-NEXT:    ret float 0xFFF0000000000000
+;
+  %val = call float @llvm.minimumnum.f32(float %x, float 0xFFF0000000000000)
+  ret float %val
+}
+
+define <2 x double> @minimumnum_neginf_commute_vec(<2 x double> %x) {
+; CHECK-LABEL: @minimumnum_neginf_commute_vec(
+; CHECK-NEXT:    ret <2 x double> splat (double 0xFFF0000000000000)
+;
+  %r = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> <double 0xFFF0000000000000, double 0xFFF0000000000000>, <2 x double> %x)
+  ret <2 x double> %r
+}
+
+; negative test
+
+define float @minimumnum_inf(float %x) {
+; CHECK-LABEL: @minimumnum_inf(
+; CHECK-NEXT:    [[VAL:%.*]] = call float @llvm.minimumnum.f32(float 0x7FF0000000000000, float [[X:%.*]])
+; CHECK-NEXT:    ret float [[VAL]]
+;
+  %val = call float @llvm.minimumnum.f32(float 0x7FF0000000000000, float %x)
+  ret float %val
+}
+
+define float @maximumnum_x_maximumnum_x_y(float %x, float %y) {
+; CHECK-LABEL: @maximumnum_x_maximumnum_x_y(
+; CHECK-NEXT:    [[A:%.*]] = call float @llvm.maximumnum.f32(float [[X:%.*]], float [[Y:%.*]])
+; CHECK-NEXT:    ret float [[A]]
+;
+  %a = call float @llvm.maximumnum.f32(float %x, float %y)
+  %b = call float @llvm.maximumnum.f32(float %x, float %a)
+  ret float %b
+}
+
+define float @maximumnum_y_maximumnum_x_y(float %x, float %y) {
+; CHECK-LABEL: @maximumnum_y_maximumnum_x_y(
+; CHECK-NEXT:    [[A:%.*]] = call float @llvm.maximumnum.f32(float [[X:%.*]], float [[Y:%.*]])
+; CHECK-NEXT:    ret float [[A]]
+;
+  %a = call float @llvm.maximumnum.f32(float %x, float %y)
+  %b = call float @llvm.maximumnum.f32(float %y, float %a)
+  ret float %b
+}
+
+define float @maximumnum_x_y_maximumnum_x(float %x, float %y) {
+; CHECK-LABEL: @maximumnum_x_y_maximumnum_x(
+; CHECK-NEXT:    [[A:%.*]] = call float @llvm.maximumnum.f32(float [[X:%.*]], float [[Y:%.*]])
+; CHECK-NEXT:    ret float [[A]]
+;
+  %a = call float @llvm.maximumnum.f32(float %x, float %y)
+  %b = call float @llvm.maximumnum.f32(float %a, float %x)
+  ret float %b
+}
+
+define float @maximumnum_x_y_maximumnum_y(float %x, float %y) {
+; CHECK-LABEL: @maximumnum_x_y_maximumnum_y(
+; CHECK-NEXT:    [[A:%.*]] = call float @llvm.maximumnum.f32(float [[X:%.*]], float [[Y:%.*]])
+; CHECK-NEXT:    ret float [[A]]
+;
+  %a = call float @llvm.maximumnum.f32(float %x, float %y)
+  %b = call float @llvm.maximumnum.f32(float %a, float %y)
+  ret float %b
+}
+
+; negative test
+
+define float @maximumnum_z_maximumnum_x_y(float %x, float %y, float %z) {
+; CHECK-LABEL: @maximumnum_z_maximumnum_x_y(
+; CHECK-NEXT:    [[A:%.*]] = call float @llvm.maximumnum.f32(float [[X:%.*]], float [[Y:%.*]])
+; CHECK-NEXT:    [[B:%.*]] = call float @llvm.maximumnum.f32(float [[Z:%.*]], float [[A]])
+; CHECK-NEXT:    ret float [[B]]
+;
+  %a = call float @llvm.maximumnum.f32(float %x, float %y)
+  %b = call float @llvm.maximumnum.f32(float %z, float %a)
+  ret float %b
+}
+
+; negative test
+
+define float @maximumnum_x_y_maximumnum_z(float %x, float %y, float %z) {
+; CHECK-LABEL: @maximumnum_x_y_maximumnum_z(
+; CHECK-NEXT:    [[A:%.*]] = call float @llvm.maximumnum.f32(float [[X:%.*]], float [[Y:%.*]])
+; CHECK-NEXT:    [[B:%.*]] = call float @llvm.maximumnum.f32(float [[A]], float [[Z:%.*]])
+; CHECK-NEXT:    ret float [[B]]
+;
+  %a = call float @llvm.maximumnum.f32(float %x, float %y)
+  %b = call float @llvm.maximumnum.f32(float %a, float %z)
+  ret float %b
+}
+
+; maximumnum(X, INF) --> INF
+
+define <2 x double> @maximumnum_inf(<2 x double> %x) {
+; CHECK-LABEL: @maximumnum_inf(
+; CHECK-NEXT:    ret <2 x double> splat (double 0x7FF0000000000000)
+;
+  %val = call <2 x double> @llvm.maximumnum.v2f64(<2 x double> %x, <2 x double><double 0x7FF0000000000000, double 0x7FF0000000000000>)
+  ret <2 x double> %val
+}
+
+define float @maximumnum_inf_commute(float %x) {
+; CHECK-LABEL: @maximumnum_inf_commute(
+; CHECK-NEXT:    ret float 0x7FF0000000000000
+;
+  %val = call float @llvm.maximumnum.f32(float 0x7FF0000000000000, float %x)
+  ret float %val
+}
+
+; negative test
+
+define float @maximumnum_neginf(float %x) {
+; CHECK-LABEL: @maximumnum_neginf(
+; CHECK-NEXT:    [[VAL:%.*]] = call float @llvm.maximumnum.f32(float 0xFFF0000000000000, float [[X:%.*]])
+; CHECK-NEXT:    ret float [[VAL]]
+;
+  %val = call float @llvm.maximumnum.f32(float 0xFFF0000000000000, float %x)
+  ret float %val
+}
+
+define double @maximumnum_maximumnum_minimumnum(double %x, double %y) {
+; CHECK-LABEL: @maximumnum_maximumnum_minimumnum(
+; CHECK-NEXT:    [[MAX:%.*]] = call double @llvm.maximumnum.f64(double [[X:%.*]], double [[Y:%.*]])
+; CHECK-NEXT:    ret double [[MAX]]
+;
+  %max = call double @llvm.maximumnum.f64(double %x, double %y)
+  %min = call double @llvm.minimumnum.f64(double %x, double %y)
+  %val = call double @llvm.maximumnum.f64(double %max, double %min)
+  ret double %val
+}
+
+define <2 x float> @maximumnum_minimumnum_maximumnum(<2 x float> %x, <2 x float> %y) {
+; CHECK-LABEL: @maximumnum_minimumnum_maximumnum(
+; CHECK-NEXT:    [[MAX:%.*]] = call <2 x float> @llvm.maximumnum.v2f32(<2 x float> [[X:%.*]], <2 x float> [[Y:%.*]])
+; CHECK-NEXT:    ret <2 x float> [[MAX]]
+;
+  %max = call <2 x float> @llvm.maximumnum.v2f32(<2 x float> %x, <2 x float> %y)
+  %min = call <2 x float> @llvm.minimumnum.v2f32(<2 x float> %x, <2 x float> %y)
+  %val = call <2 x float> @llvm.maximumnum.v2f32(<2 x float> %min, <2 x float> %max)
+  ret <2 x float> %val
+}
+
+define <2 x double> @maximumnum_minimumnum_minimumnum(<2 x double> %x, <2 x double> %y) {
+; CHECK-LABEL: @maximumnum_minimumnum_minimumnum(
+; CHECK-NEXT:    [[MIN1:%.*]] = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> [[X:%.*]], <2 x double> [[Y:%.*]])
+; CHECK-NEXT:    [[MIN2:%.*]] = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> [[X]], <2 x double> [[Y]])
+; CHECK-NEXT:    [[VAL:%.*]] = call <2 x double> @llvm.maximumnum.v2f64(<2 x double> [[MIN1]], <2 x double> [[MIN2]])
+; CHECK-NEXT:    ret <2 x double> [[VAL]]
+;
+  %min1 = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> %x, <2 x double> %y)
+  %min2 = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> %x, <2 x double> %y)
+  %val = call <2 x double> @llvm.maximumnum.v2f64(<2 x double> %min1, <2 x double> %min2)
+  ret <2 x double> %val
+}
+
+define float @maximumnum_maximumnum_maximumnum(float %x, float %y) {
+; CHECK-LABEL: @maximumnum_maximumnum_maximumnum(
+; CHECK-NEXT:    [[MAX1:%.*]] = call float @llvm.maximumnum.f32(float [[X:%.*]], float [[Y:%.*]])
+; CHECK-NEXT:    ret float [[MAX1]]
+;
+  %max1 = call float @llvm.maximumnum.f32(float %x, float %y)
+  %max2 = call float @llvm.maximumnum.f32(float %x, float %y)
+  %val = call float @llvm.maximumnum.f32(float %max1, float %max2)
+  ret float %val
+}
+
+define double @minimumnum_maximumnum_minimumnum(double %x, double %y) {
+; CHECK-LABEL: @minimumnum_maximumnum_minimumnum(
+; CHECK-NEXT:    [[MIN:%.*]] = call double @llvm.minimumnum.f64(double [[X:%.*]], double [[Y:%.*]])
+; CHECK-NEXT:    ret double [[MIN]]
+;
+  %max = call double @llvm.maximumnum.f64(double %x, double %y)
+  %min = call double @llvm.minimumnum.f64(double %x, double %y)
+  %val = call double @llvm.minimumnum.f64(double %max, double %min)
+  ret double %val
+}
+
+define float @minimumnum_minimumnum_maximumnum(float %x, float %y) {
+; CHECK-LABEL: @minimumnum_minimumnum_maximumnum(
+; CHECK-NEXT:    [[MIN:%.*]] = call float @llvm.minimumnum.f32(float [[X:%.*]], float [[Y:%.*]])
+; CHECK-NEXT:    ret float [[MIN]]
+;
+  %max = call float @llvm.maximumnum.f32(float %x, float %y)
+  %min = call float @llvm.minimumnum.f32(float %x, float %y)
+  %val = call float @llvm.minimumnum.f32(float %min, float %max)
+  ret float %val
+}
+
+define <2 x float> @minimumnum_maximumnum_maximumnum(<2 x float> %x, <2 x float> %y) {
+; CHECK-LABEL: @minimumnum_maximumnum_maximumnum(
+; CHECK-NEXT:    [[MAX1:%.*]] = call <2 x float> @llvm.maximumnum.v2f32(<2 x float> [[X:%.*]], <2 x float> [[Y:%.*]])
+; CHECK-NEXT:    [[MAX2:%.*]] = call <2 x float> @llvm.maximumnum.v2f32(<2 x float> [[X]], <2 x float> [[Y]])
+; CHECK-NEXT:    [[VAL:%.*]] = call <2 x float> @llvm.minimumnum.v2f32(<2 x float> [[MAX1]], <2 x float> [[MAX2]])
+; CHECK-NEXT:    ret <2 x float> [[VAL]]
+;
+  %max1 = call <2 x float> @llvm.maximumnum.v2f32(<2 x float> %x, <2 x float> %y)
+  %max2 = call <2 x float> @llvm.maximumnum.v2f32(<2 x float> %x, <2 x float> %y)
+  %val = call <2 x float> @llvm.minimumnum.v2f32(<2 x float> %max1, <2 x float> %max2)
+  ret <2 x float> %val
+}
+
+define <2 x double> @minimumnum_minimumnum_minimumnum(<2 x double> %x, <2 x double> %y) {
+; CHECK-LABEL: @minimumnum_minimumnum_minimumnum(
+; CHECK-NEXT:    [[MIN1:%.*]] = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> [[X:%.*]], <2 x double> [[Y:%.*]])
+; CHECK-NEXT:    ret <2 x double> [[MIN1]]
+;
+  %min1 = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> %x, <2 x double> %y)
+  %min2 = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> %x, <2 x double> %y)
+  %val = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> %min1, <2 x double> %min2)
+  ret <2 x double> %val
+}



More information about the llvm-commits mailing list