[llvm] SelectionDAG: Support nofpclass (PR #108350)

YunQiang Su via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 13 01:03:38 PDT 2024


https://github.com/wzssyqa updated https://github.com/llvm/llvm-project/pull/108350

>From 314ccabb7284a7bb0f48377783dd85b3c854d44f Mon Sep 17 00:00:00 2001
From: YunQiang Su <syq at debian.org>
Date: Thu, 12 Sep 2024 17:00:13 +0800
Subject: [PATCH] SelectionDAG: Support nofpclass

Currently SelectionDAG ignroes the nofpclass information from arguments.
Such as

   define dso_local float @f(float noundef nofpclass(nan zero) %a, float noundef nofpclass(nan zero) %b) #0 {
       entry:
       %cond = tail call float @llvm.maximumnum.f32(float %a, float %b)
       ret float %cond
   }

In SelectionDAG::isKnownNeverNaN, a false is returned.

TODO:
1) bool SelectionDAG::isKnownNeverNaN(SDValue Op, bool SNaN, unsigned Depth)
   needs to process hasNoSNaN;
2) bool SelectionDAG::isKnownNeverZeroFloat(SDValue Op)
   needs to process Zero and SignedZero.
These 2 problems will be fixed with other PRs.
---
 llvm/include/llvm/CodeGen/SelectionDAG.h      |    8 +
 llvm/include/llvm/CodeGen/SelectionDAGNodes.h |   33 +-
 .../lib/CodeGen/SelectionDAG/SelectionDAG.cpp |   35 +-
 .../SelectionDAG/SelectionDAGBuilder.cpp      |   16 +
 .../CodeGen/SelectionDAG/TargetLowering.cpp   |   36 +-
 .../LoongArch/fp-maximumnum-minimumnum.ll     |  403 ++++++
 .../CodeGen/Mips/fp-maximumnum-minimumnum.ll  |  678 +++++++++
 .../CodeGen/X86/fminimumnum-fmaximumnum.ll    | 1210 +++++++++++++++++
 8 files changed, 2410 insertions(+), 9 deletions(-)
 create mode 100644 llvm/test/CodeGen/X86/fminimumnum-fmaximumnum.ll

diff --git a/llvm/include/llvm/CodeGen/SelectionDAG.h b/llvm/include/llvm/CodeGen/SelectionDAG.h
index 7ee8ca18c2c1de..0c49b4d4ee1229 100644
--- a/llvm/include/llvm/CodeGen/SelectionDAG.h
+++ b/llvm/include/llvm/CodeGen/SelectionDAG.h
@@ -2136,6 +2136,14 @@ class SelectionDAG {
   /// positive or negative zero.
   bool isKnownNeverZeroFloat(SDValue Op) const;
 
+  /// Test whether the given floating point SDValue is known to never be
+  /// positive zero.
+  bool isKnownNeverPosZeroFloat(SDValue Op) const;
+
+  /// Test whether the given floating point SDValue is known to never be
+  /// negative zero.
+  bool isKnownNeverNegZeroFloat(SDValue Op) const;
+
   /// Test whether the given SDValue is known to contain non-zero value(s).
   bool isKnownNeverZero(SDValue Op, unsigned Depth = 0) const;
 
diff --git a/llvm/include/llvm/CodeGen/SelectionDAGNodes.h b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h
index 6067b3b29ea181..737927aba67edf 100644
--- a/llvm/include/llvm/CodeGen/SelectionDAGNodes.h
+++ b/llvm/include/llvm/CodeGen/SelectionDAGNodes.h
@@ -383,6 +383,7 @@ struct SDNodeFlags {
   bool Exact : 1;
   bool Disjoint : 1;
   bool NonNeg : 1;
+  // deprecated: Use NoQNanS && NoSNaNs
   bool NoNaNs : 1;
   bool NoInfs : 1;
   bool NoSignedZeros : 1;
@@ -400,6 +401,11 @@ struct SDNodeFlags {
   // Instructions with attached 'unpredictable' metadata on IR level.
   bool Unpredictable : 1;
 
+  bool NoQNaNs : 1;
+  bool NoSNaNs : 1;
+  bool NoPosZeros : 1;
+  bool NoNegZeros : 1;
+
 public:
   /// Default constructor turns off all optimization flags.
   SDNodeFlags()
@@ -407,12 +413,15 @@ struct SDNodeFlags {
         Disjoint(false), NonNeg(false), NoNaNs(false), NoInfs(false),
         NoSignedZeros(false), AllowReciprocal(false), AllowContract(false),
         ApproximateFuncs(false), AllowReassociation(false), NoFPExcept(false),
-        Unpredictable(false) {}
+        Unpredictable(false), NoQNaNs(false), NoSNaNs(false), NoPosZeros(false),
+        NoNegZeros(false) {}
 
   /// Propagate the fast-math-flags from an IR FPMathOperator.
   void copyFMF(const FPMathOperator &FPMO) {
-    setNoNaNs(FPMO.hasNoNaNs());
+    setNoSNaNs(FPMO.hasNoNaNs());
+    setNoQNaNs(FPMO.hasNoNaNs());
     setNoInfs(FPMO.hasNoInfs());
+    setNoNegZeros(FPMO.hasNoSignedZeros());
     setNoSignedZeros(FPMO.hasNoSignedZeros());
     setAllowReciprocal(FPMO.hasAllowReciprocal());
     setAllowContract(FPMO.hasAllowContract());
@@ -426,8 +435,20 @@ struct SDNodeFlags {
   void setExact(bool b) { Exact = b; }
   void setDisjoint(bool b) { Disjoint = b; }
   void setNonNeg(bool b) { NonNeg = b; }
-  void setNoNaNs(bool b) { NoNaNs = b; }
+  [[deprecated("Use SetSNaNs() and SetQNaNs()")]] void setNoNaNs(bool b) {
+    NoNaNs = NoQNaNs = NoSNaNs = b;
+  }
+  void setNoQNaNs(bool b) {
+    NoQNaNs = b;
+    NoNaNs = (NoQNaNs && NoSNaNs);
+  }
+  void setNoSNaNs(bool b) {
+    NoSNaNs = b;
+    NoNaNs = (NoQNaNs && NoSNaNs);
+  }
   void setNoInfs(bool b) { NoInfs = b; }
+  void setNoPosZeros(bool b) { NoPosZeros = b; }
+  void setNoNegZeros(bool b) { NoNegZeros = b; }
   void setNoSignedZeros(bool b) { NoSignedZeros = b; }
   void setAllowReciprocal(bool b) { AllowReciprocal = b; }
   void setAllowContract(bool b) { AllowContract = b; }
@@ -442,8 +463,12 @@ struct SDNodeFlags {
   bool hasExact() const { return Exact; }
   bool hasDisjoint() const { return Disjoint; }
   bool hasNonNeg() const { return NonNeg; }
-  bool hasNoNaNs() const { return NoNaNs; }
+  bool hasNoNaNs() const { return (NoSNaNs && NoQNaNs); }
+  bool hasNoSNaNs() const { return NoSNaNs; }
+  bool hasNoQNaNs() const { return NoQNaNs; }
   bool hasNoInfs() const { return NoInfs; }
+  bool hasNoPosZeros() const { return NoPosZeros; }
+  bool hasNoNegZeros() const { return NoNegZeros; }
   bool hasNoSignedZeros() const { return NoSignedZeros; }
   bool hasAllowReciprocal() const { return AllowReciprocal; }
   bool hasAllowContract() const { return AllowContract; }
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 29505f444b7650..34f719f6678b62 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -5435,7 +5435,12 @@ bool SelectionDAG::isBaseWithConstantOffset(SDValue Op) const {
 
 bool SelectionDAG::isKnownNeverNaN(SDValue Op, bool SNaN, unsigned Depth) const {
   // If we're told that NaNs won't happen, assume they won't.
-  if (getTarget().Options.NoNaNsFPMath || Op->getFlags().hasNoNaNs())
+  if (getTarget().Options.NoNaNsFPMath)
+    return true;
+  SDNodeFlags OpFlags = Op->getFlags();
+  if (SNaN && OpFlags.hasNoSNaNs())
+    return true;
+  if (OpFlags.hasNoSNaNs() && OpFlags.hasNoQNaNs())
     return true;
 
   if (Depth >= MaxRecursionDepth)
@@ -5569,11 +5574,39 @@ bool SelectionDAG::isKnownNeverZeroFloat(SDValue Op) const {
   assert(Op.getValueType().isFloatingPoint() &&
          "Floating point type expected");
 
+  SDNodeFlags OpFlags = Op->getFlags();
+  if (OpFlags.hasNoPosZeros() && OpFlags.hasNoNegZeros())
+    return true;
+
   // If the value is a constant, we can obviously see if it is a zero or not.
   return ISD::matchUnaryFpPredicate(
       Op, [](ConstantFPSDNode *C) { return !C->isZero(); });
 }
 
+bool SelectionDAG::isKnownNeverPosZeroFloat(SDValue Op) const {
+  assert(Op.getValueType().isFloatingPoint() && "Floating point type expected");
+
+  SDNodeFlags OpFlags = Op->getFlags();
+  if (OpFlags.hasNoPosZeros())
+    return true;
+
+  // If the value is a constant, we can obviously see if it is a zero or not.
+  return ISD::matchUnaryFpPredicate(
+      Op, [](ConstantFPSDNode *C) { return !C->isZero() || C->isNegative(); });
+}
+
+bool SelectionDAG::isKnownNeverNegZeroFloat(SDValue Op) const {
+  assert(Op.getValueType().isFloatingPoint() && "Floating point type expected");
+
+  SDNodeFlags OpFlags = Op->getFlags();
+  if (OpFlags.hasNoNegZeros())
+    return true;
+
+  // If the value is a constant, we can obviously see if it is a zero or not.
+  return ISD::matchUnaryFpPredicate(
+      Op, [](ConstantFPSDNode *C) { return !C->isZero() || !C->isNegative(); });
+}
+
 bool SelectionDAG::isKnownNeverZero(SDValue Op, unsigned Depth) const {
   if (Depth >= MaxRecursionDepth)
     return false; // Limit search depth.
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 1dbcf8fd765101..dfefb29a931b99 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -11773,6 +11773,22 @@ void SelectionDAGISel::LowerArguments(const Function &F) {
           AssertOp = ISD::AssertSext;
         else if (Arg.hasAttribute(Attribute::ZExt))
           AssertOp = ISD::AssertZext;
+        if (Arg.hasAttribute(Attribute::NoFPClass)) {
+          SDNodeFlags InValFlags = InVals[i]->getFlags();
+          bool NoSNaN = ((Arg.getNoFPClass() & llvm::fcSNan) == llvm::fcSNan);
+          bool NoQNaN = ((Arg.getNoFPClass() & llvm::fcQNan) == llvm::fcQNan);
+          InValFlags.setNoSNaNs(NoSNaN);
+          InValFlags.setNoQNaNs(NoQNaN);
+          bool NoPosZeros =
+              ((Arg.getNoFPClass() & llvm::fcPosZero) == llvm::fcPosZero);
+          bool NoNegZeros =
+              ((Arg.getNoFPClass() & llvm::fcNegZero) == llvm::fcNegZero);
+          InValFlags.setNoPosZeros(NoPosZeros);
+          InValFlags.setNoNegZeros(NoNegZeros);
+          InValFlags.setNoInfs((Arg.getNoFPClass() & llvm::fcInf) ==
+                               llvm::fcInf);
+          InVals[i]->setFlags(InValFlags);
+        }
 
         ArgValues.push_back(getCopyFromParts(DAG, dl, &InVals[i], NumParts,
                                              PartVT, VT, nullptr, NewRoot,
diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
index 03010c1df00145..747696bd5243d3 100644
--- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
@@ -8563,6 +8563,8 @@ SDValue TargetLowering::expandFMINIMUMNUM_FMAXIMUMNUM(SDNode *Node,
   bool IsMax = Opc == ISD::FMAXIMUMNUM;
   const TargetOptions &Options = DAG.getTarget().Options;
   SDNodeFlags Flags = Node->getFlags();
+  SDNodeFlags LHSFlagsOrig = LHS->getFlags();
+  SDNodeFlags RHSFlagsOrig = RHS->getFlags();
 
   unsigned NewOp =
       Opc == ISD::FMINIMUMNUM ? ISD::FMINNUM_IEEE : ISD::FMAXNUM_IEEE;
@@ -8597,7 +8599,11 @@ SDValue TargetLowering::expandFMINIMUMNUM_FMAXIMUMNUM(SDNode *Node,
   if ((Flags.hasNoNaNs() ||
        (DAG.isKnownNeverSNaN(LHS) && DAG.isKnownNeverSNaN(RHS))) &&
       (Flags.hasNoSignedZeros() || DAG.isKnownNeverZeroFloat(LHS) ||
-       DAG.isKnownNeverZeroFloat(RHS))) {
+       DAG.isKnownNeverZeroFloat(RHS) ||
+       (DAG.isKnownNeverPosZeroFloat(LHS) &&
+        DAG.isKnownNeverPosZeroFloat(RHS)) ||
+       (DAG.isKnownNeverNegZeroFloat(LHS) &&
+        DAG.isKnownNeverNegZeroFloat(RHS)))) {
     unsigned IEEE2008Op = Opc == ISD::FMINIMUMNUM ? ISD::FMINNUM : ISD::FMAXNUM;
     if (isOperationLegalOrCustom(IEEE2008Op, VT))
       return DAG.getNode(IEEE2008Op, DL, VT, LHS, RHS, Flags);
@@ -8606,22 +8612,44 @@ SDValue TargetLowering::expandFMINIMUMNUM_FMAXIMUMNUM(SDNode *Node,
   // If only one operand is NaN, override it with another operand.
   if (!Flags.hasNoNaNs() && !DAG.isKnownNeverNaN(LHS)) {
     LHS = DAG.getSelectCC(DL, LHS, LHS, RHS, LHS, ISD::SETUO);
+    SDNodeFlags LHSFlags = LHS->getFlags();
+    SDNodeFlags RHSFlags = RHS->getFlags();
+    if (RHSFlags.hasNoSNaNs())
+      LHSFlags.setNoSNaNs(true);
+    if (RHSFlags.hasNoQNaNs())
+      LHSFlags.setNoQNaNs(true);
+    LHSFlags.setNoPosZeros(LHSFlagsOrig.hasNoPosZeros());
+    LHSFlags.setNoNegZeros(LHSFlagsOrig.hasNoNegZeros());
+    LHS->setFlags(LHSFlags);
   }
   if (!Flags.hasNoNaNs() && !DAG.isKnownNeverNaN(RHS)) {
     RHS = DAG.getSelectCC(DL, RHS, RHS, LHS, RHS, ISD::SETUO);
+    SDNodeFlags LHSFlags = LHS->getFlags();
+    SDNodeFlags RHSFlags = RHS->getFlags();
+    if (LHSFlags.hasNoSNaNs())
+      RHSFlags.setNoSNaNs(true);
+    if (LHSFlags.hasNoQNaNs())
+      RHSFlags.setNoQNaNs(true);
+    RHSFlags.setNoPosZeros(RHSFlagsOrig.hasNoPosZeros());
+    RHSFlags.setNoNegZeros(RHSFlagsOrig.hasNoNegZeros());
+    RHS->setFlags(RHSFlags);
   }
 
   SDValue MinMax =
       DAG.getSelectCC(DL, LHS, RHS, LHS, RHS, IsMax ? ISD::SETGT : ISD::SETLT);
   // If MinMax is NaN, let's quiet it.
-  if (!Flags.hasNoNaNs() && !DAG.isKnownNeverNaN(LHS) &&
-      !DAG.isKnownNeverNaN(RHS)) {
+  if (!Flags.hasNoNaNs() && !DAG.isKnownNeverSNaN(LHS) &&
+      !DAG.isKnownNeverSNaN(RHS)) {
     MinMax = DAG.getNode(ISD::FCANONICALIZE, DL, VT, MinMax, Flags);
   }
 
   // Fixup signed zero behavior.
   if (Options.NoSignedZerosFPMath || Flags.hasNoSignedZeros() ||
-      DAG.isKnownNeverZeroFloat(LHS) || DAG.isKnownNeverZeroFloat(RHS)) {
+      DAG.isKnownNeverZeroFloat(LHS) || DAG.isKnownNeverZeroFloat(RHS) ||
+      (DAG.isKnownNeverPosZeroFloat(LHS) &&
+       DAG.isKnownNeverPosZeroFloat(RHS)) ||
+      (DAG.isKnownNeverNegZeroFloat(LHS) &&
+       DAG.isKnownNeverNegZeroFloat(RHS))) {
     return MinMax;
   }
   SDValue TestZero =
diff --git a/llvm/test/CodeGen/LoongArch/fp-maximumnum-minimumnum.ll b/llvm/test/CodeGen/LoongArch/fp-maximumnum-minimumnum.ll
index b4fdd954b856c8..05b55bda6fafc4 100644
--- a/llvm/test/CodeGen/LoongArch/fp-maximumnum-minimumnum.ll
+++ b/llvm/test/CodeGen/LoongArch/fp-maximumnum-minimumnum.ll
@@ -100,6 +100,109 @@ define float @maximumnum_float_nnan(float %x, float %y) {
   ret float %z
 }
 
+define float @maximumnum_float_nnan_arg(float nofpclass(nan) %x, float nofpclass(nan) %y) {
+;
+; LA32F-LABEL: maximumnum_float_nnan_arg:
+; LA32F:       # %bb.0:
+; LA32F-NEXT:    fmax.s $fa0, $fa0, $fa1
+; LA32F-NEXT:    ret
+;
+; LA32D-LABEL: maximumnum_float_nnan_arg:
+; LA32D:       # %bb.0:
+; LA32D-NEXT:    fmax.s $fa0, $fa0, $fa1
+; LA32D-NEXT:    ret
+;
+; LA64F-LABEL: maximumnum_float_nnan_arg:
+; LA64F:       # %bb.0:
+; LA64F-NEXT:    fmax.s $fa0, $fa0, $fa1
+; LA64F-NEXT:    ret
+;
+; LA64D-LABEL: maximumnum_float_nnan_arg:
+; LA64D:       # %bb.0:
+; LA64D-NEXT:    fmax.s $fa0, $fa0, $fa1
+; LA64D-NEXT:    ret
+  %z = call float @llvm.maximumnum.f32(float %x, float %y)
+  ret float %z
+}
+
+define float @maximumnum_float_n2nan_arg(float nofpclass(qnan snan) %x, float nofpclass(qnan snan) %y) {
+;
+; LA32F-LABEL: maximumnum_float_n2nan_arg:
+; LA32F:       # %bb.0:
+; LA32F-NEXT:    fmax.s $fa0, $fa0, $fa1
+; LA32F-NEXT:    ret
+;
+; LA32D-LABEL: maximumnum_float_n2nan_arg:
+; LA32D:       # %bb.0:
+; LA32D-NEXT:    fmax.s $fa0, $fa0, $fa1
+; LA32D-NEXT:    ret
+;
+; LA64F-LABEL: maximumnum_float_n2nan_arg:
+; LA64F:       # %bb.0:
+; LA64F-NEXT:    fmax.s $fa0, $fa0, $fa1
+; LA64F-NEXT:    ret
+;
+; LA64D-LABEL: maximumnum_float_n2nan_arg:
+; LA64D:       # %bb.0:
+; LA64D-NEXT:    fmax.s $fa0, $fa0, $fa1
+; LA64D-NEXT:    ret
+  %z = call float @llvm.maximumnum.f32(float %x, float %y)
+  ret float %z
+}
+
+define float @maximumnum_float_nsnan_arg(float nofpclass(snan) %x, float nofpclass(snan) %y) {
+;
+; LA32F-LABEL: maximumnum_float_nsnan_arg:
+; LA32F:       # %bb.0:
+; LA32F-NEXT:    fmax.s $fa0, $fa0, $fa1
+; LA32F-NEXT:    ret
+;
+; LA32D-LABEL: maximumnum_float_nsnan_arg:
+; LA32D:       # %bb.0:
+; LA32D-NEXT:    fmax.s $fa0, $fa0, $fa1
+; LA32D-NEXT:    ret
+;
+; LA64F-LABEL: maximumnum_float_nsnan_arg:
+; LA64F:       # %bb.0:
+; LA64F-NEXT:    fmax.s $fa0, $fa0, $fa1
+; LA64F-NEXT:    ret
+;
+; LA64D-LABEL: maximumnum_float_nsnan_arg:
+; LA64D:       # %bb.0:
+; LA64D-NEXT:    fmax.s $fa0, $fa0, $fa1
+; LA64D-NEXT:    ret
+  %z = call float @llvm.maximumnum.f32(float %x, float %y)
+  ret float %z
+}
+
+define float @maximumnum_float_n1snan_arg(float nofpclass(snan) %x, float %y) {
+;
+; LA32F-LABEL: maximumnum_float_n1snan_arg:
+; LA32F:       # %bb.0:
+; LA32F-NEXT:    fmax.s $fa1, $fa1, $fa1
+; LA32F-NEXT:    fmax.s $fa0, $fa0, $fa1
+; LA32F-NEXT:    ret
+;
+; LA32D-LABEL: maximumnum_float_n1snan_arg:
+; LA32D:       # %bb.0:
+; LA32D-NEXT:    fmax.s $fa1, $fa1, $fa1
+; LA32D-NEXT:    fmax.s $fa0, $fa0, $fa1
+; LA32D-NEXT:    ret
+;
+; LA64F-LABEL: maximumnum_float_n1snan_arg:
+; LA64F:       # %bb.0:
+; LA64F-NEXT:    fmax.s $fa1, $fa1, $fa1
+; LA64F-NEXT:    fmax.s $fa0, $fa0, $fa1
+; LA64F-NEXT:    ret
+;
+; LA64D-LABEL: maximumnum_float_n1snan_arg:
+; LA64D:       # %bb.0:
+; LA64D-NEXT:    fmax.s $fa1, $fa1, $fa1
+; LA64D-NEXT:    fmax.s $fa0, $fa0, $fa1
+; LA64D-NEXT:    ret
+  %z = call float @llvm.maximumnum.f32(float %x, float %y)
+  ret float %z
+}
 
 define double @maximumnum_double(double %x, double %y) {
 ;
@@ -220,6 +323,156 @@ define double @maximumnum_double_nnan(double %x, double %y) {
   ret double %z
 }
 
+define double @maximumnum_double_nnan_arg(double nofpclass(nan) %x, double nofpclass(nan) %y) {
+;
+; LA32F-LABEL: maximumnum_double_nnan_arg:
+; LA32F:       # %bb.0:
+; LA32F-NEXT:    addi.w $sp, $sp, -16
+; LA32F-NEXT:    .cfi_def_cfa_offset 16
+; LA32F-NEXT:    st.w $ra, $sp, 12 # 4-byte Folded Spill
+; LA32F-NEXT:    .cfi_offset 1, -4
+; LA32F-NEXT:    bl %plt(fmaximum_num)
+; LA32F-NEXT:    ld.w $ra, $sp, 12 # 4-byte Folded Reload
+; LA32F-NEXT:    addi.w $sp, $sp, 16
+; LA32F-NEXT:    ret
+;
+; LA32D-LABEL: maximumnum_double_nnan_arg:
+; LA32D:       # %bb.0:
+; LA32D-NEXT:    fmax.d $fa0, $fa0, $fa1
+; LA32D-NEXT:    ret
+;
+; LA64F-LABEL: maximumnum_double_nnan_arg:
+; LA64F:       # %bb.0:
+; LA64F-NEXT:    addi.d $sp, $sp, -16
+; LA64F-NEXT:    .cfi_def_cfa_offset 16
+; LA64F-NEXT:    st.d $ra, $sp, 8 # 8-byte Folded Spill
+; LA64F-NEXT:    .cfi_offset 1, -8
+; LA64F-NEXT:    bl %plt(fmaximum_num)
+; LA64F-NEXT:    ld.d $ra, $sp, 8 # 8-byte Folded Reload
+; LA64F-NEXT:    addi.d $sp, $sp, 16
+; LA64F-NEXT:    ret
+;
+; LA64D-LABEL: maximumnum_double_nnan_arg:
+; LA64D:       # %bb.0:
+; LA64D-NEXT:    fmax.d $fa0, $fa0, $fa1
+; LA64D-NEXT:    ret
+  %z = call double @llvm.maximumnum.f64(double %x, double %y)
+  ret double %z
+}
+
+define double @maximumnum_double_n2nan_arg(double nofpclass(qnan snan) %x, double nofpclass(qnan snan) %y) {
+;
+; LA32F-LABEL: maximumnum_double_n2nan_arg:
+; LA32F:       # %bb.0:
+; LA32F-NEXT:    addi.w $sp, $sp, -16
+; LA32F-NEXT:    .cfi_def_cfa_offset 16
+; LA32F-NEXT:    st.w $ra, $sp, 12 # 4-byte Folded Spill
+; LA32F-NEXT:    .cfi_offset 1, -4
+; LA32F-NEXT:    bl %plt(fmaximum_num)
+; LA32F-NEXT:    ld.w $ra, $sp, 12 # 4-byte Folded Reload
+; LA32F-NEXT:    addi.w $sp, $sp, 16
+; LA32F-NEXT:    ret
+;
+; LA32D-LABEL: maximumnum_double_n2nan_arg:
+; LA32D:       # %bb.0:
+; LA32D-NEXT:    fmax.d $fa0, $fa0, $fa1
+; LA32D-NEXT:    ret
+;
+; LA64F-LABEL: maximumnum_double_n2nan_arg:
+; LA64F:       # %bb.0:
+; LA64F-NEXT:    addi.d $sp, $sp, -16
+; LA64F-NEXT:    .cfi_def_cfa_offset 16
+; LA64F-NEXT:    st.d $ra, $sp, 8 # 8-byte Folded Spill
+; LA64F-NEXT:    .cfi_offset 1, -8
+; LA64F-NEXT:    bl %plt(fmaximum_num)
+; LA64F-NEXT:    ld.d $ra, $sp, 8 # 8-byte Folded Reload
+; LA64F-NEXT:    addi.d $sp, $sp, 16
+; LA64F-NEXT:    ret
+;
+; LA64D-LABEL: maximumnum_double_n2nan_arg:
+; LA64D:       # %bb.0:
+; LA64D-NEXT:    fmax.d $fa0, $fa0, $fa1
+; LA64D-NEXT:    ret
+  %z = call double @llvm.maximumnum.f64(double %x, double %y)
+  ret double %z
+}
+
+define double @maximumnum_double_nsnan_arg(double nofpclass(snan) %x, double nofpclass(snan) %y) {
+;
+; LA32F-LABEL: maximumnum_double_nsnan_arg:
+; LA32F:       # %bb.0:
+; LA32F-NEXT:    addi.w $sp, $sp, -16
+; LA32F-NEXT:    .cfi_def_cfa_offset 16
+; LA32F-NEXT:    st.w $ra, $sp, 12 # 4-byte Folded Spill
+; LA32F-NEXT:    .cfi_offset 1, -4
+; LA32F-NEXT:    bl %plt(fmaximum_num)
+; LA32F-NEXT:    ld.w $ra, $sp, 12 # 4-byte Folded Reload
+; LA32F-NEXT:    addi.w $sp, $sp, 16
+; LA32F-NEXT:    ret
+;
+; LA32D-LABEL: maximumnum_double_nsnan_arg:
+; LA32D:       # %bb.0:
+; LA32D-NEXT:    fmax.d $fa0, $fa0, $fa1
+; LA32D-NEXT:    ret
+;
+; LA64F-LABEL: maximumnum_double_nsnan_arg:
+; LA64F:       # %bb.0:
+; LA64F-NEXT:    addi.d $sp, $sp, -16
+; LA64F-NEXT:    .cfi_def_cfa_offset 16
+; LA64F-NEXT:    st.d $ra, $sp, 8 # 8-byte Folded Spill
+; LA64F-NEXT:    .cfi_offset 1, -8
+; LA64F-NEXT:    bl %plt(fmaximum_num)
+; LA64F-NEXT:    ld.d $ra, $sp, 8 # 8-byte Folded Reload
+; LA64F-NEXT:    addi.d $sp, $sp, 16
+; LA64F-NEXT:    ret
+;
+; LA64D-LABEL: maximumnum_double_nsnan_arg:
+; LA64D:       # %bb.0:
+; LA64D-NEXT:    fmax.d $fa0, $fa0, $fa1
+; LA64D-NEXT:    ret
+  %z = call double @llvm.maximumnum.f64(double %x, double %y)
+  ret double %z
+}
+
+define double @maximumnum_double_n1snan_arg(double nofpclass(snan) %x, double %y) {
+;
+; LA32F-LABEL: maximumnum_double_n1snan_arg:
+; LA32F:       # %bb.0:
+; LA32F-NEXT:    addi.w $sp, $sp, -16
+; LA32F-NEXT:    .cfi_def_cfa_offset 16
+; LA32F-NEXT:    st.w $ra, $sp, 12 # 4-byte Folded Spill
+; LA32F-NEXT:    .cfi_offset 1, -4
+; LA32F-NEXT:    bl %plt(fmaximum_num)
+; LA32F-NEXT:    ld.w $ra, $sp, 12 # 4-byte Folded Reload
+; LA32F-NEXT:    addi.w $sp, $sp, 16
+; LA32F-NEXT:    ret
+;
+; LA32D-LABEL: maximumnum_double_n1snan_arg:
+; LA32D:       # %bb.0:
+; LA32D-NEXT:    fmax.d $fa1, $fa1, $fa1
+; LA32D-NEXT:    fmax.d $fa0, $fa0, $fa1
+; LA32D-NEXT:    ret
+;
+; LA64F-LABEL: maximumnum_double_n1snan_arg:
+; LA64F:       # %bb.0:
+; LA64F-NEXT:    addi.d $sp, $sp, -16
+; LA64F-NEXT:    .cfi_def_cfa_offset 16
+; LA64F-NEXT:    st.d $ra, $sp, 8 # 8-byte Folded Spill
+; LA64F-NEXT:    .cfi_offset 1, -8
+; LA64F-NEXT:    bl %plt(fmaximum_num)
+; LA64F-NEXT:    ld.d $ra, $sp, 8 # 8-byte Folded Reload
+; LA64F-NEXT:    addi.d $sp, $sp, 16
+; LA64F-NEXT:    ret
+;
+; LA64D-LABEL: maximumnum_double_n1snan_arg:
+; LA64D:       # %bb.0:
+; LA64D-NEXT:    fmax.d $fa1, $fa1, $fa1
+; LA64D-NEXT:    fmax.d $fa0, $fa0, $fa1
+; LA64D-NEXT:    ret
+  %z = call double @llvm.maximumnum.f64(double %x, double %y)
+  ret double %z
+}
+
 define float @minimumnum_float(float %x, float %y) {
 ;
 ; LA32F-LABEL: minimumnum_float:
@@ -429,3 +682,153 @@ define double @minimumnum_double_nnan(double %x, double %y) {
   %z = call nnan double @llvm.minimumnum.f64(double %x, double %y)
   ret double %z
 }
+
+define double @minimumnum_double_nnan_arg(double nofpclass(nan) %x, double nofpclass(nan) %y) {
+;
+; LA32F-LABEL: minimumnum_double_nnan_arg:
+; LA32F:       # %bb.0:
+; LA32F-NEXT:    addi.w $sp, $sp, -16
+; LA32F-NEXT:    .cfi_def_cfa_offset 16
+; LA32F-NEXT:    st.w $ra, $sp, 12 # 4-byte Folded Spill
+; LA32F-NEXT:    .cfi_offset 1, -4
+; LA32F-NEXT:    bl %plt(fminimum_num)
+; LA32F-NEXT:    ld.w $ra, $sp, 12 # 4-byte Folded Reload
+; LA32F-NEXT:    addi.w $sp, $sp, 16
+; LA32F-NEXT:    ret
+;
+; LA32D-LABEL: minimumnum_double_nnan_arg:
+; LA32D:       # %bb.0:
+; LA32D-NEXT:    fmin.d $fa0, $fa0, $fa1
+; LA32D-NEXT:    ret
+;
+; LA64F-LABEL: minimumnum_double_nnan_arg:
+; LA64F:       # %bb.0:
+; LA64F-NEXT:    addi.d $sp, $sp, -16
+; LA64F-NEXT:    .cfi_def_cfa_offset 16
+; LA64F-NEXT:    st.d $ra, $sp, 8 # 8-byte Folded Spill
+; LA64F-NEXT:    .cfi_offset 1, -8
+; LA64F-NEXT:    bl %plt(fminimum_num)
+; LA64F-NEXT:    ld.d $ra, $sp, 8 # 8-byte Folded Reload
+; LA64F-NEXT:    addi.d $sp, $sp, 16
+; LA64F-NEXT:    ret
+;
+; LA64D-LABEL: minimumnum_double_nnan_arg:
+; LA64D:       # %bb.0:
+; LA64D-NEXT:    fmin.d $fa0, $fa0, $fa1
+; LA64D-NEXT:    ret
+  %z = call double @llvm.minimumnum.f64(double %x, double %y)
+  ret double %z
+}
+
+define double @minimumnum_double_n2nan_arg(double nofpclass(qnan snan) %x, double nofpclass(qnan snan) %y) {
+;
+; LA32F-LABEL: minimumnum_double_n2nan_arg:
+; LA32F:       # %bb.0:
+; LA32F-NEXT:    addi.w $sp, $sp, -16
+; LA32F-NEXT:    .cfi_def_cfa_offset 16
+; LA32F-NEXT:    st.w $ra, $sp, 12 # 4-byte Folded Spill
+; LA32F-NEXT:    .cfi_offset 1, -4
+; LA32F-NEXT:    bl %plt(fminimum_num)
+; LA32F-NEXT:    ld.w $ra, $sp, 12 # 4-byte Folded Reload
+; LA32F-NEXT:    addi.w $sp, $sp, 16
+; LA32F-NEXT:    ret
+;
+; LA32D-LABEL: minimumnum_double_n2nan_arg:
+; LA32D:       # %bb.0:
+; LA32D-NEXT:    fmin.d $fa0, $fa0, $fa1
+; LA32D-NEXT:    ret
+;
+; LA64F-LABEL: minimumnum_double_n2nan_arg:
+; LA64F:       # %bb.0:
+; LA64F-NEXT:    addi.d $sp, $sp, -16
+; LA64F-NEXT:    .cfi_def_cfa_offset 16
+; LA64F-NEXT:    st.d $ra, $sp, 8 # 8-byte Folded Spill
+; LA64F-NEXT:    .cfi_offset 1, -8
+; LA64F-NEXT:    bl %plt(fminimum_num)
+; LA64F-NEXT:    ld.d $ra, $sp, 8 # 8-byte Folded Reload
+; LA64F-NEXT:    addi.d $sp, $sp, 16
+; LA64F-NEXT:    ret
+;
+; LA64D-LABEL: minimumnum_double_n2nan_arg:
+; LA64D:       # %bb.0:
+; LA64D-NEXT:    fmin.d $fa0, $fa0, $fa1
+; LA64D-NEXT:    ret
+  %z = call double @llvm.minimumnum.f64(double %x, double %y)
+  ret double %z
+}
+
+define double @minimumnum_double_nsnan_arg(double nofpclass(snan) %x, double nofpclass(snan) %y) {
+;
+; LA32F-LABEL: minimumnum_double_nsnan_arg:
+; LA32F:       # %bb.0:
+; LA32F-NEXT:    addi.w $sp, $sp, -16
+; LA32F-NEXT:    .cfi_def_cfa_offset 16
+; LA32F-NEXT:    st.w $ra, $sp, 12 # 4-byte Folded Spill
+; LA32F-NEXT:    .cfi_offset 1, -4
+; LA32F-NEXT:    bl %plt(fminimum_num)
+; LA32F-NEXT:    ld.w $ra, $sp, 12 # 4-byte Folded Reload
+; LA32F-NEXT:    addi.w $sp, $sp, 16
+; LA32F-NEXT:    ret
+;
+; LA32D-LABEL: minimumnum_double_nsnan_arg:
+; LA32D:       # %bb.0:
+; LA32D-NEXT:    fmin.d $fa0, $fa0, $fa1
+; LA32D-NEXT:    ret
+;
+; LA64F-LABEL: minimumnum_double_nsnan_arg:
+; LA64F:       # %bb.0:
+; LA64F-NEXT:    addi.d $sp, $sp, -16
+; LA64F-NEXT:    .cfi_def_cfa_offset 16
+; LA64F-NEXT:    st.d $ra, $sp, 8 # 8-byte Folded Spill
+; LA64F-NEXT:    .cfi_offset 1, -8
+; LA64F-NEXT:    bl %plt(fminimum_num)
+; LA64F-NEXT:    ld.d $ra, $sp, 8 # 8-byte Folded Reload
+; LA64F-NEXT:    addi.d $sp, $sp, 16
+; LA64F-NEXT:    ret
+;
+; LA64D-LABEL: minimumnum_double_nsnan_arg:
+; LA64D:       # %bb.0:
+; LA64D-NEXT:    fmin.d $fa0, $fa0, $fa1
+; LA64D-NEXT:    ret
+  %z = call double @llvm.minimumnum.f64(double %x, double %y)
+  ret double %z
+}
+
+define double @minimumnum_double_n1snan_arg(double nofpclass(snan) %x, double %y) {
+;
+; LA32F-LABEL: minimumnum_double_n1snan_arg:
+; LA32F:       # %bb.0:
+; LA32F-NEXT:    addi.w $sp, $sp, -16
+; LA32F-NEXT:    .cfi_def_cfa_offset 16
+; LA32F-NEXT:    st.w $ra, $sp, 12 # 4-byte Folded Spill
+; LA32F-NEXT:    .cfi_offset 1, -4
+; LA32F-NEXT:    bl %plt(fminimum_num)
+; LA32F-NEXT:    ld.w $ra, $sp, 12 # 4-byte Folded Reload
+; LA32F-NEXT:    addi.w $sp, $sp, 16
+; LA32F-NEXT:    ret
+;
+; LA32D-LABEL: minimumnum_double_n1snan_arg:
+; LA32D:       # %bb.0:
+; LA32D-NEXT:    fmax.d $fa1, $fa1, $fa1
+; LA32D-NEXT:    fmin.d $fa0, $fa0, $fa1
+; LA32D-NEXT:    ret
+;
+; LA64F-LABEL: minimumnum_double_n1snan_arg:
+; LA64F:       # %bb.0:
+; LA64F-NEXT:    addi.d $sp, $sp, -16
+; LA64F-NEXT:    .cfi_def_cfa_offset 16
+; LA64F-NEXT:    st.d $ra, $sp, 8 # 8-byte Folded Spill
+; LA64F-NEXT:    .cfi_offset 1, -8
+; LA64F-NEXT:    bl %plt(fminimum_num)
+; LA64F-NEXT:    ld.d $ra, $sp, 8 # 8-byte Folded Reload
+; LA64F-NEXT:    addi.d $sp, $sp, 16
+; LA64F-NEXT:    ret
+;
+; LA64D-LABEL: minimumnum_double_n1snan_arg:
+; LA64D:       # %bb.0:
+; LA64D-NEXT:    fmax.d $fa1, $fa1, $fa1
+; LA64D-NEXT:    fmin.d $fa0, $fa0, $fa1
+; LA64D-NEXT:    ret
+  %z = call double @llvm.minimumnum.f64(double %x, double %y)
+  ret double %z
+}
diff --git a/llvm/test/CodeGen/Mips/fp-maximumnum-minimumnum.ll b/llvm/test/CodeGen/Mips/fp-maximumnum-minimumnum.ll
index bc81966ca0f5c9..999fffbef88585 100644
--- a/llvm/test/CodeGen/Mips/fp-maximumnum-minimumnum.ll
+++ b/llvm/test/CodeGen/Mips/fp-maximumnum-minimumnum.ll
@@ -1,5 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
 ; RUN: llc --mtriple=mipsisa32r6 < %s | FileCheck %s --check-prefix=MIPS32R6
+; RUN: llc --mtriple=mips64 < %s | FileCheck %s --check-prefix=MIPS64
 
 declare float @llvm.maximumnum.f32(float, float)
 declare double @llvm.maximumnum.f64(double, double)
@@ -13,6 +14,28 @@ define float @maximumnum_float(float %x, float %y) {
 ; MIPS32R6-NEXT:    min.s $f1, $f12, $f12
 ; MIPS32R6-NEXT:    jr $ra
 ; MIPS32R6-NEXT:    max.s $f0, $f1, $f0
+;
+; MIPS64-LABEL: maximumnum_float:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    c.un.s $f12, $f12
+; MIPS64-NEXT:    movt.s $f12, $f13, $fcc0
+; MIPS64-NEXT:    c.un.s $f13, $f13
+; MIPS64-NEXT:    movt.s $f13, $f12, $fcc0
+; MIPS64-NEXT:    c.ule.s $f12, $f13
+; MIPS64-NEXT:    mov.s $f0, $f13
+; MIPS64-NEXT:    movf.s $f0, $f12, $fcc0
+; MIPS64-NEXT:    add.s $f1, $f0, $f0
+; MIPS64-NEXT:    c.un.s $f0, $f0
+; MIPS64-NEXT:    movt.s $f0, $f1, $fcc0
+; MIPS64-NEXT:    mfc1 $1, $f12
+; MIPS64-NEXT:    mov.s $f1, $f0
+; MIPS64-NEXT:    movz.s $f1, $f12, $1
+; MIPS64-NEXT:    mfc1 $1, $f13
+; MIPS64-NEXT:    mtc1 $zero, $f2
+; MIPS64-NEXT:    movz.s $f1, $f13, $1
+; MIPS64-NEXT:    c.eq.s $f0, $f2
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.s $f0, $f1, $fcc0
   %z = call float @llvm.maximumnum.f32(float %x, float %y)
   ret float %z
 }
@@ -24,6 +47,20 @@ define float @maximumnum_float_nsz(float %x, float %y) {
 ; MIPS32R6-NEXT:    min.s $f1, $f12, $f12
 ; MIPS32R6-NEXT:    jr $ra
 ; MIPS32R6-NEXT:    max.s $f0, $f1, $f0
+;
+; MIPS64-LABEL: maximumnum_float_nsz:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    mov.s $f0, $f13
+; MIPS64-NEXT:    c.un.s $f12, $f12
+; MIPS64-NEXT:    movt.s $f12, $f13, $fcc0
+; MIPS64-NEXT:    c.un.s $f13, $f13
+; MIPS64-NEXT:    movt.s $f0, $f12, $fcc0
+; MIPS64-NEXT:    c.ule.s $f12, $f0
+; MIPS64-NEXT:    movf.s $f0, $f12, $fcc0
+; MIPS64-NEXT:    add.s $f1, $f0, $f0
+; MIPS64-NEXT:    c.un.s $f0, $f0
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.s $f0, $f1, $fcc0
   %z = call nsz float @llvm.maximumnum.f32(float %x, float %y)
   ret float %z
 }
@@ -33,10 +70,132 @@ define float @maximumnum_float_nnan(float %x, float %y) {
 ; MIPS32R6:       # %bb.0:
 ; MIPS32R6-NEXT:    jr $ra
 ; MIPS32R6-NEXT:    max.s $f0, $f12, $f14
+;
+; MIPS64-LABEL: maximumnum_float_nnan:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    c.ule.s $f12, $f13
+; MIPS64-NEXT:    mov.s $f0, $f13
+; MIPS64-NEXT:    movf.s $f0, $f12, $fcc0
+; MIPS64-NEXT:    mfc1 $1, $f12
+; MIPS64-NEXT:    mov.s $f1, $f0
+; MIPS64-NEXT:    movz.s $f1, $f12, $1
+; MIPS64-NEXT:    mfc1 $1, $f13
+; MIPS64-NEXT:    movz.s $f1, $f13, $1
+; MIPS64-NEXT:    mtc1 $zero, $f2
+; MIPS64-NEXT:    c.eq.s $f0, $f2
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.s $f0, $f1, $fcc0
   %z = call nnan float @llvm.maximumnum.f32(float %x, float %y)
   ret float %z
 }
 
+define float @maximumnum_float_nnan_arg(float nofpclass(nan) %x, float nofpclass(nan) %y) {
+; MIPS32R6-LABEL: maximumnum_float_nnan_arg:
+; MIPS32R6:       # %bb.0:
+; MIPS32R6-NEXT:    jr $ra
+; MIPS32R6-NEXT:    max.s $f0, $f12, $f14
+;
+; MIPS64-LABEL: maximumnum_float_nnan_arg:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    c.ule.s $f12, $f13
+; MIPS64-NEXT:    mov.s $f0, $f13
+; MIPS64-NEXT:    movf.s $f0, $f12, $fcc0
+; MIPS64-NEXT:    mfc1 $1, $f12
+; MIPS64-NEXT:    mov.s $f1, $f0
+; MIPS64-NEXT:    movz.s $f1, $f12, $1
+; MIPS64-NEXT:    mfc1 $1, $f13
+; MIPS64-NEXT:    movz.s $f1, $f13, $1
+; MIPS64-NEXT:    mtc1 $zero, $f2
+; MIPS64-NEXT:    c.eq.s $f0, $f2
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.s $f0, $f1, $fcc0
+  %z = call float @llvm.maximumnum.f32(float %x, float %y)
+  ret float %z
+}
+
+define float @maximumnum_float_n2nan_arg(float nofpclass(qnan snan) %x, float nofpclass(qnan snan) %y) {
+; MIPS32R6-LABEL: maximumnum_float_n2nan_arg:
+; MIPS32R6:       # %bb.0:
+; MIPS32R6-NEXT:    jr $ra
+; MIPS32R6-NEXT:    max.s $f0, $f12, $f14
+;
+; MIPS64-LABEL: maximumnum_float_n2nan_arg:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    c.ule.s $f12, $f13
+; MIPS64-NEXT:    mov.s $f0, $f13
+; MIPS64-NEXT:    movf.s $f0, $f12, $fcc0
+; MIPS64-NEXT:    mfc1 $1, $f12
+; MIPS64-NEXT:    mov.s $f1, $f0
+; MIPS64-NEXT:    movz.s $f1, $f12, $1
+; MIPS64-NEXT:    mfc1 $1, $f13
+; MIPS64-NEXT:    movz.s $f1, $f13, $1
+; MIPS64-NEXT:    mtc1 $zero, $f2
+; MIPS64-NEXT:    c.eq.s $f0, $f2
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.s $f0, $f1, $fcc0
+  %z = call float @llvm.maximumnum.f32(float %x, float %y)
+  ret float %z
+}
+
+define float @maximumnum_float_nsnan_arg(float nofpclass(snan) %x, float nofpclass(snan) %y) {
+; MIPS32R6-LABEL: maximumnum_float_nsnan_arg:
+; MIPS32R6:       # %bb.0:
+; MIPS32R6-NEXT:    jr $ra
+; MIPS32R6-NEXT:    max.s $f0, $f12, $f14
+;
+; MIPS64-LABEL: maximumnum_float_nsnan_arg:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    c.un.s $f12, $f12
+; MIPS64-NEXT:    movt.s $f12, $f13, $fcc0
+; MIPS64-NEXT:    c.un.s $f13, $f13
+; MIPS64-NEXT:    movt.s $f13, $f12, $fcc0
+; MIPS64-NEXT:    c.ule.s $f12, $f13
+; MIPS64-NEXT:    mov.s $f0, $f13
+; MIPS64-NEXT:    movf.s $f0, $f12, $fcc0
+; MIPS64-NEXT:    mfc1 $1, $f12
+; MIPS64-NEXT:    mov.s $f1, $f0
+; MIPS64-NEXT:    movz.s $f1, $f12, $1
+; MIPS64-NEXT:    mfc1 $1, $f13
+; MIPS64-NEXT:    movz.s $f1, $f13, $1
+; MIPS64-NEXT:    mtc1 $zero, $f2
+; MIPS64-NEXT:    c.eq.s $f0, $f2
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.s $f0, $f1, $fcc0
+  %z = call float @llvm.maximumnum.f32(float %x, float %y)
+  ret float %z
+}
+
+define float @maximumnum_float_n1snan_arg(float nofpclass(snan) %x, float %y) {
+; MIPS32R6-LABEL: maximumnum_float_n1snan_arg:
+; MIPS32R6:       # %bb.0:
+; MIPS32R6-NEXT:    min.s $f0, $f14, $f14
+; MIPS32R6-NEXT:    jr $ra
+; MIPS32R6-NEXT:    max.s $f0, $f12, $f0
+;
+; MIPS64-LABEL: maximumnum_float_n1snan_arg:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    c.un.s $f12, $f12
+; MIPS64-NEXT:    movt.s $f12, $f13, $fcc0
+; MIPS64-NEXT:    c.un.s $f13, $f13
+; MIPS64-NEXT:    movt.s $f13, $f12, $fcc0
+; MIPS64-NEXT:    c.ule.s $f12, $f13
+; MIPS64-NEXT:    mov.s $f0, $f13
+; MIPS64-NEXT:    movf.s $f0, $f12, $fcc0
+; MIPS64-NEXT:    add.s $f1, $f0, $f0
+; MIPS64-NEXT:    c.un.s $f0, $f0
+; MIPS64-NEXT:    movt.s $f0, $f1, $fcc0
+; MIPS64-NEXT:    mfc1 $1, $f12
+; MIPS64-NEXT:    mov.s $f1, $f0
+; MIPS64-NEXT:    movz.s $f1, $f12, $1
+; MIPS64-NEXT:    mfc1 $1, $f13
+; MIPS64-NEXT:    mtc1 $zero, $f2
+; MIPS64-NEXT:    movz.s $f1, $f13, $1
+; MIPS64-NEXT:    c.eq.s $f0, $f2
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.s $f0, $f1, $fcc0
+  %z = call float @llvm.maximumnum.f32(float %x, float %y)
+  ret float %z
+}
 
 define double @maximumnum_double(double %x, double %y) {
 ; MIPS32R6-LABEL: maximumnum_double:
@@ -45,6 +204,28 @@ define double @maximumnum_double(double %x, double %y) {
 ; MIPS32R6-NEXT:    min.d $f1, $f12, $f12
 ; MIPS32R6-NEXT:    jr $ra
 ; MIPS32R6-NEXT:    max.d $f0, $f1, $f0
+;
+; MIPS64-LABEL: maximumnum_double:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    c.un.d $f12, $f12
+; MIPS64-NEXT:    movt.d $f12, $f13, $fcc0
+; MIPS64-NEXT:    c.un.d $f13, $f13
+; MIPS64-NEXT:    movt.d $f13, $f12, $fcc0
+; MIPS64-NEXT:    c.ule.d $f12, $f13
+; MIPS64-NEXT:    mov.d $f0, $f13
+; MIPS64-NEXT:    movf.d $f0, $f12, $fcc0
+; MIPS64-NEXT:    add.d $f1, $f0, $f0
+; MIPS64-NEXT:    c.un.d $f0, $f0
+; MIPS64-NEXT:    movt.d $f0, $f1, $fcc0
+; MIPS64-NEXT:    dmfc1 $1, $f12
+; MIPS64-NEXT:    mov.d $f1, $f0
+; MIPS64-NEXT:    movz.d $f1, $f12, $1
+; MIPS64-NEXT:    dmfc1 $1, $f13
+; MIPS64-NEXT:    movz.d $f1, $f13, $1
+; MIPS64-NEXT:    dmtc1 $zero, $f2
+; MIPS64-NEXT:    c.eq.d $f0, $f2
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.d $f0, $f1, $fcc0
   %z = call double @llvm.maximumnum.f64(double %x, double %y)
   ret double %z
 }
@@ -56,6 +237,20 @@ define double @maximumnum_double_nsz(double %x, double %y) {
 ; MIPS32R6-NEXT:    min.d $f1, $f12, $f12
 ; MIPS32R6-NEXT:    jr $ra
 ; MIPS32R6-NEXT:    max.d $f0, $f1, $f0
+;
+; MIPS64-LABEL: maximumnum_double_nsz:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    mov.d $f0, $f13
+; MIPS64-NEXT:    c.un.d $f12, $f12
+; MIPS64-NEXT:    movt.d $f12, $f13, $fcc0
+; MIPS64-NEXT:    c.un.d $f13, $f13
+; MIPS64-NEXT:    movt.d $f0, $f12, $fcc0
+; MIPS64-NEXT:    c.ule.d $f12, $f0
+; MIPS64-NEXT:    movf.d $f0, $f12, $fcc0
+; MIPS64-NEXT:    add.d $f1, $f0, $f0
+; MIPS64-NEXT:    c.un.d $f0, $f0
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.d $f0, $f1, $fcc0
   %z = call nsz double @llvm.maximumnum.f64(double %x, double %y)
   ret double %z
 }
@@ -65,10 +260,133 @@ define double @maximumnum_double_nnan(double %x, double %y) {
 ; MIPS32R6:       # %bb.0:
 ; MIPS32R6-NEXT:    jr $ra
 ; MIPS32R6-NEXT:    max.d $f0, $f12, $f14
+;
+; MIPS64-LABEL: maximumnum_double_nnan:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    c.ule.d $f12, $f13
+; MIPS64-NEXT:    mov.d $f0, $f13
+; MIPS64-NEXT:    movf.d $f0, $f12, $fcc0
+; MIPS64-NEXT:    dmfc1 $1, $f12
+; MIPS64-NEXT:    mov.d $f1, $f0
+; MIPS64-NEXT:    movz.d $f1, $f12, $1
+; MIPS64-NEXT:    dmfc1 $1, $f13
+; MIPS64-NEXT:    movz.d $f1, $f13, $1
+; MIPS64-NEXT:    dmtc1 $zero, $f2
+; MIPS64-NEXT:    c.eq.d $f0, $f2
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.d $f0, $f1, $fcc0
   %z = call nnan double @llvm.maximumnum.f64(double %x, double %y)
   ret double %z
 }
 
+define double @maximumnum_double_nnan_arg(double nofpclass(nan) %x, double nofpclass(nan) %y) {
+; MIPS32R6-LABEL: maximumnum_double_nnan_arg:
+; MIPS32R6:       # %bb.0:
+; MIPS32R6-NEXT:    jr $ra
+; MIPS32R6-NEXT:    max.d $f0, $f12, $f14
+;
+; MIPS64-LABEL: maximumnum_double_nnan_arg:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    c.ule.d $f12, $f13
+; MIPS64-NEXT:    mov.d $f0, $f13
+; MIPS64-NEXT:    movf.d $f0, $f12, $fcc0
+; MIPS64-NEXT:    dmfc1 $1, $f12
+; MIPS64-NEXT:    mov.d $f1, $f0
+; MIPS64-NEXT:    movz.d $f1, $f12, $1
+; MIPS64-NEXT:    dmfc1 $1, $f13
+; MIPS64-NEXT:    movz.d $f1, $f13, $1
+; MIPS64-NEXT:    dmtc1 $zero, $f2
+; MIPS64-NEXT:    c.eq.d $f0, $f2
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.d $f0, $f1, $fcc0
+  %z = call double @llvm.maximumnum.f64(double %x, double %y)
+  ret double %z
+}
+
+define double @maximumnum_double_n2nan_arg(double nofpclass(qnan snan) %x, double nofpclass(qnan snan) %y) {
+; MIPS32R6-LABEL: maximumnum_double_n2nan_arg:
+; MIPS32R6:       # %bb.0:
+; MIPS32R6-NEXT:    jr $ra
+; MIPS32R6-NEXT:    max.d $f0, $f12, $f14
+;
+; MIPS64-LABEL: maximumnum_double_n2nan_arg:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    c.ule.d $f12, $f13
+; MIPS64-NEXT:    mov.d $f0, $f13
+; MIPS64-NEXT:    movf.d $f0, $f12, $fcc0
+; MIPS64-NEXT:    dmfc1 $1, $f12
+; MIPS64-NEXT:    mov.d $f1, $f0
+; MIPS64-NEXT:    movz.d $f1, $f12, $1
+; MIPS64-NEXT:    dmfc1 $1, $f13
+; MIPS64-NEXT:    movz.d $f1, $f13, $1
+; MIPS64-NEXT:    dmtc1 $zero, $f2
+; MIPS64-NEXT:    c.eq.d $f0, $f2
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.d $f0, $f1, $fcc0
+  %z = call double @llvm.maximumnum.f64(double %x, double %y)
+  ret double %z
+}
+
+define double @maximumnum_double_nsnan_arg(double nofpclass(snan) %x, double nofpclass(snan) %y) {
+; MIPS32R6-LABEL: maximumnum_double_nsnan_arg:
+; MIPS32R6:       # %bb.0:
+; MIPS32R6-NEXT:    jr $ra
+; MIPS32R6-NEXT:    max.d $f0, $f12, $f14
+;
+; MIPS64-LABEL: maximumnum_double_nsnan_arg:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    c.un.d $f12, $f12
+; MIPS64-NEXT:    movt.d $f12, $f13, $fcc0
+; MIPS64-NEXT:    c.un.d $f13, $f13
+; MIPS64-NEXT:    movt.d $f13, $f12, $fcc0
+; MIPS64-NEXT:    c.ule.d $f12, $f13
+; MIPS64-NEXT:    mov.d $f0, $f13
+; MIPS64-NEXT:    movf.d $f0, $f12, $fcc0
+; MIPS64-NEXT:    dmfc1 $1, $f12
+; MIPS64-NEXT:    mov.d $f1, $f0
+; MIPS64-NEXT:    movz.d $f1, $f12, $1
+; MIPS64-NEXT:    dmfc1 $1, $f13
+; MIPS64-NEXT:    movz.d $f1, $f13, $1
+; MIPS64-NEXT:    dmtc1 $zero, $f2
+; MIPS64-NEXT:    c.eq.d $f0, $f2
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.d $f0, $f1, $fcc0
+  %z = call double @llvm.maximumnum.f64(double %x, double %y)
+  ret double %z
+}
+
+define double @maximumnum_double_n1snan_arg(double nofpclass(snan) %x, double %y) {
+; MIPS32R6-LABEL: maximumnum_double_n1snan_arg:
+; MIPS32R6:       # %bb.0:
+; MIPS32R6-NEXT:    min.d $f0, $f14, $f14
+; MIPS32R6-NEXT:    jr $ra
+; MIPS32R6-NEXT:    max.d $f0, $f12, $f0
+;
+; MIPS64-LABEL: maximumnum_double_n1snan_arg:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    c.un.d $f12, $f12
+; MIPS64-NEXT:    movt.d $f12, $f13, $fcc0
+; MIPS64-NEXT:    c.un.d $f13, $f13
+; MIPS64-NEXT:    movt.d $f13, $f12, $fcc0
+; MIPS64-NEXT:    c.ule.d $f12, $f13
+; MIPS64-NEXT:    mov.d $f0, $f13
+; MIPS64-NEXT:    movf.d $f0, $f12, $fcc0
+; MIPS64-NEXT:    add.d $f1, $f0, $f0
+; MIPS64-NEXT:    c.un.d $f0, $f0
+; MIPS64-NEXT:    movt.d $f0, $f1, $fcc0
+; MIPS64-NEXT:    dmfc1 $1, $f12
+; MIPS64-NEXT:    mov.d $f1, $f0
+; MIPS64-NEXT:    movz.d $f1, $f12, $1
+; MIPS64-NEXT:    dmfc1 $1, $f13
+; MIPS64-NEXT:    movz.d $f1, $f13, $1
+; MIPS64-NEXT:    dmtc1 $zero, $f2
+; MIPS64-NEXT:    c.eq.d $f0, $f2
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.d $f0, $f1, $fcc0
+  %z = call double @llvm.maximumnum.f64(double %x, double %y)
+  ret double %z
+}
+
 define float @minimumnum_float(float %x, float %y) {
 ; MIPS32R6-LABEL: minimumnum_float:
 ; MIPS32R6:       # %bb.0:
@@ -76,6 +394,31 @@ define float @minimumnum_float(float %x, float %y) {
 ; MIPS32R6-NEXT:    min.s $f1, $f12, $f12
 ; MIPS32R6-NEXT:    jr $ra
 ; MIPS32R6-NEXT:    min.s $f0, $f1, $f0
+;
+; MIPS64-LABEL: minimumnum_float:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    c.un.s $f12, $f12
+; MIPS64-NEXT:    movt.s $f12, $f13, $fcc0
+; MIPS64-NEXT:    c.un.s $f13, $f13
+; MIPS64-NEXT:    movt.s $f13, $f12, $fcc0
+; MIPS64-NEXT:    c.olt.s $f12, $f13
+; MIPS64-NEXT:    mov.s $f0, $f13
+; MIPS64-NEXT:    movt.s $f0, $f12, $fcc0
+; MIPS64-NEXT:    add.s $f1, $f0, $f0
+; MIPS64-NEXT:    c.un.s $f0, $f0
+; MIPS64-NEXT:    movt.s $f0, $f1, $fcc0
+; MIPS64-NEXT:    mfc1 $1, $f12
+; MIPS64-NEXT:    lui $2, 32768
+; MIPS64-NEXT:    xor $1, $1, $2
+; MIPS64-NEXT:    mov.s $f1, $f0
+; MIPS64-NEXT:    movz.s $f1, $f12, $1
+; MIPS64-NEXT:    mfc1 $1, $f13
+; MIPS64-NEXT:    xor $1, $1, $2
+; MIPS64-NEXT:    mtc1 $zero, $f2
+; MIPS64-NEXT:    movz.s $f1, $f13, $1
+; MIPS64-NEXT:    c.eq.s $f0, $f2
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.s $f0, $f1, $fcc0
   %z = call float @llvm.minimumnum.f32(float %x, float %y)
   ret float %z
 }
@@ -87,6 +430,20 @@ define float @minimumnum_float_nsz(float %x, float %y) {
 ; MIPS32R6-NEXT:    min.s $f1, $f12, $f12
 ; MIPS32R6-NEXT:    jr $ra
 ; MIPS32R6-NEXT:    min.s $f0, $f1, $f0
+;
+; MIPS64-LABEL: minimumnum_float_nsz:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    mov.s $f0, $f13
+; MIPS64-NEXT:    c.un.s $f12, $f12
+; MIPS64-NEXT:    movt.s $f12, $f13, $fcc0
+; MIPS64-NEXT:    c.un.s $f13, $f13
+; MIPS64-NEXT:    movt.s $f0, $f12, $fcc0
+; MIPS64-NEXT:    c.olt.s $f12, $f0
+; MIPS64-NEXT:    movt.s $f0, $f12, $fcc0
+; MIPS64-NEXT:    add.s $f1, $f0, $f0
+; MIPS64-NEXT:    c.un.s $f0, $f0
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.s $f0, $f1, $fcc0
   %z = call nsz float @llvm.minimumnum.f32(float %x, float %y)
   ret float %z
 }
@@ -96,10 +453,148 @@ define float @minimumnum_float_nnan(float %x, float %y) {
 ; MIPS32R6:       # %bb.0:
 ; MIPS32R6-NEXT:    jr $ra
 ; MIPS32R6-NEXT:    min.s $f0, $f12, $f14
+;
+; MIPS64-LABEL: minimumnum_float_nnan:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    c.olt.s $f12, $f13
+; MIPS64-NEXT:    mov.s $f0, $f13
+; MIPS64-NEXT:    movt.s $f0, $f12, $fcc0
+; MIPS64-NEXT:    mfc1 $1, $f12
+; MIPS64-NEXT:    lui $2, 32768
+; MIPS64-NEXT:    xor $1, $1, $2
+; MIPS64-NEXT:    mov.s $f1, $f0
+; MIPS64-NEXT:    movz.s $f1, $f12, $1
+; MIPS64-NEXT:    mfc1 $1, $f13
+; MIPS64-NEXT:    xor $1, $1, $2
+; MIPS64-NEXT:    movz.s $f1, $f13, $1
+; MIPS64-NEXT:    mtc1 $zero, $f2
+; MIPS64-NEXT:    c.eq.s $f0, $f2
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.s $f0, $f1, $fcc0
   %z = call nnan float @llvm.minimumnum.f32(float %x, float %y)
   ret float %z
 }
 
+define float @minimumnum_float_nnan_arg(float nofpclass(nan) %x, float nofpclass(nan) %y) {
+; MIPS32R6-LABEL: minimumnum_float_nnan_arg:
+; MIPS32R6:       # %bb.0:
+; MIPS32R6-NEXT:    jr $ra
+; MIPS32R6-NEXT:    min.s $f0, $f12, $f14
+;
+; MIPS64-LABEL: minimumnum_float_nnan_arg:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    c.olt.s $f12, $f13
+; MIPS64-NEXT:    mov.s $f0, $f13
+; MIPS64-NEXT:    movt.s $f0, $f12, $fcc0
+; MIPS64-NEXT:    mfc1 $1, $f12
+; MIPS64-NEXT:    lui $2, 32768
+; MIPS64-NEXT:    xor $1, $1, $2
+; MIPS64-NEXT:    mov.s $f1, $f0
+; MIPS64-NEXT:    movz.s $f1, $f12, $1
+; MIPS64-NEXT:    mfc1 $1, $f13
+; MIPS64-NEXT:    xor $1, $1, $2
+; MIPS64-NEXT:    movz.s $f1, $f13, $1
+; MIPS64-NEXT:    mtc1 $zero, $f2
+; MIPS64-NEXT:    c.eq.s $f0, $f2
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.s $f0, $f1, $fcc0
+  %z = call float @llvm.minimumnum.f32(float %x, float %y)
+  ret float %z
+}
+
+define float @minimumnum_float_n2nan_arg(float nofpclass(qnan snan) %x, float nofpclass(qnan snan) %y) {
+; MIPS32R6-LABEL: minimumnum_float_n2nan_arg:
+; MIPS32R6:       # %bb.0:
+; MIPS32R6-NEXT:    jr $ra
+; MIPS32R6-NEXT:    min.s $f0, $f12, $f14
+;
+; MIPS64-LABEL: minimumnum_float_n2nan_arg:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    c.olt.s $f12, $f13
+; MIPS64-NEXT:    mov.s $f0, $f13
+; MIPS64-NEXT:    movt.s $f0, $f12, $fcc0
+; MIPS64-NEXT:    mfc1 $1, $f12
+; MIPS64-NEXT:    lui $2, 32768
+; MIPS64-NEXT:    xor $1, $1, $2
+; MIPS64-NEXT:    mov.s $f1, $f0
+; MIPS64-NEXT:    movz.s $f1, $f12, $1
+; MIPS64-NEXT:    mfc1 $1, $f13
+; MIPS64-NEXT:    xor $1, $1, $2
+; MIPS64-NEXT:    movz.s $f1, $f13, $1
+; MIPS64-NEXT:    mtc1 $zero, $f2
+; MIPS64-NEXT:    c.eq.s $f0, $f2
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.s $f0, $f1, $fcc0
+  %z = call float @llvm.minimumnum.f32(float %x, float %y)
+  ret float %z
+}
+
+define float @minimumnum_float_nsnan_arg(float nofpclass(snan) %x, float nofpclass(snan) %y) {
+; MIPS32R6-LABEL: minimumnum_float_nsnan_arg:
+; MIPS32R6:       # %bb.0:
+; MIPS32R6-NEXT:    jr $ra
+; MIPS32R6-NEXT:    min.s $f0, $f12, $f14
+;
+; MIPS64-LABEL: minimumnum_float_nsnan_arg:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    c.un.s $f12, $f12
+; MIPS64-NEXT:    movt.s $f12, $f13, $fcc0
+; MIPS64-NEXT:    c.un.s $f13, $f13
+; MIPS64-NEXT:    movt.s $f13, $f12, $fcc0
+; MIPS64-NEXT:    c.olt.s $f12, $f13
+; MIPS64-NEXT:    mov.s $f0, $f13
+; MIPS64-NEXT:    movt.s $f0, $f12, $fcc0
+; MIPS64-NEXT:    mfc1 $1, $f12
+; MIPS64-NEXT:    lui $2, 32768
+; MIPS64-NEXT:    xor $1, $1, $2
+; MIPS64-NEXT:    mov.s $f1, $f0
+; MIPS64-NEXT:    movz.s $f1, $f12, $1
+; MIPS64-NEXT:    mfc1 $1, $f13
+; MIPS64-NEXT:    xor $1, $1, $2
+; MIPS64-NEXT:    movz.s $f1, $f13, $1
+; MIPS64-NEXT:    mtc1 $zero, $f2
+; MIPS64-NEXT:    c.eq.s $f0, $f2
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.s $f0, $f1, $fcc0
+  %z = call float @llvm.minimumnum.f32(float %x, float %y)
+  ret float %z
+}
+
+define float @minimumnum_float_n1snan_arg(float nofpclass(snan) %x, float %y) {
+; MIPS32R6-LABEL: minimumnum_float_n1snan_arg:
+; MIPS32R6:       # %bb.0:
+; MIPS32R6-NEXT:    min.s $f0, $f14, $f14
+; MIPS32R6-NEXT:    jr $ra
+; MIPS32R6-NEXT:    min.s $f0, $f12, $f0
+;
+; MIPS64-LABEL: minimumnum_float_n1snan_arg:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    c.un.s $f12, $f12
+; MIPS64-NEXT:    movt.s $f12, $f13, $fcc0
+; MIPS64-NEXT:    c.un.s $f13, $f13
+; MIPS64-NEXT:    movt.s $f13, $f12, $fcc0
+; MIPS64-NEXT:    c.olt.s $f12, $f13
+; MIPS64-NEXT:    mov.s $f0, $f13
+; MIPS64-NEXT:    movt.s $f0, $f12, $fcc0
+; MIPS64-NEXT:    add.s $f1, $f0, $f0
+; MIPS64-NEXT:    c.un.s $f0, $f0
+; MIPS64-NEXT:    movt.s $f0, $f1, $fcc0
+; MIPS64-NEXT:    mfc1 $1, $f12
+; MIPS64-NEXT:    lui $2, 32768
+; MIPS64-NEXT:    xor $1, $1, $2
+; MIPS64-NEXT:    mov.s $f1, $f0
+; MIPS64-NEXT:    movz.s $f1, $f12, $1
+; MIPS64-NEXT:    mfc1 $1, $f13
+; MIPS64-NEXT:    xor $1, $1, $2
+; MIPS64-NEXT:    mtc1 $zero, $f2
+; MIPS64-NEXT:    movz.s $f1, $f13, $1
+; MIPS64-NEXT:    c.eq.s $f0, $f2
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.s $f0, $f1, $fcc0
+  %z = call float @llvm.minimumnum.f32(float %x, float %y)
+  ret float %z
+}
+
 define double @minimumnum_double(double %x, double %y) {
 ; MIPS32R6-LABEL: minimumnum_double:
 ; MIPS32R6:       # %bb.0:
@@ -107,6 +602,32 @@ define double @minimumnum_double(double %x, double %y) {
 ; MIPS32R6-NEXT:    min.d $f1, $f12, $f12
 ; MIPS32R6-NEXT:    jr $ra
 ; MIPS32R6-NEXT:    min.d $f0, $f1, $f0
+;
+; MIPS64-LABEL: minimumnum_double:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    c.un.d $f12, $f12
+; MIPS64-NEXT:    movt.d $f12, $f13, $fcc0
+; MIPS64-NEXT:    c.un.d $f13, $f13
+; MIPS64-NEXT:    movt.d $f13, $f12, $fcc0
+; MIPS64-NEXT:    c.olt.d $f12, $f13
+; MIPS64-NEXT:    mov.d $f0, $f13
+; MIPS64-NEXT:    movt.d $f0, $f12, $fcc0
+; MIPS64-NEXT:    add.d $f1, $f0, $f0
+; MIPS64-NEXT:    c.un.d $f0, $f0
+; MIPS64-NEXT:    movt.d $f0, $f1, $fcc0
+; MIPS64-NEXT:    dmfc1 $1, $f12
+; MIPS64-NEXT:    daddiu $2, $zero, 1
+; MIPS64-NEXT:    dsll $2, $2, 63
+; MIPS64-NEXT:    xor $1, $1, $2
+; MIPS64-NEXT:    mov.d $f1, $f0
+; MIPS64-NEXT:    movz.d $f1, $f12, $1
+; MIPS64-NEXT:    dmfc1 $1, $f13
+; MIPS64-NEXT:    xor $1, $1, $2
+; MIPS64-NEXT:    movz.d $f1, $f13, $1
+; MIPS64-NEXT:    dmtc1 $zero, $f2
+; MIPS64-NEXT:    c.eq.d $f0, $f2
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.d $f0, $f1, $fcc0
   %z = call double @llvm.minimumnum.f64(double %x, double %y)
   ret double %z
 }
@@ -118,6 +639,20 @@ define double @minimumnum_double_nsz(double %x, double %y) {
 ; MIPS32R6-NEXT:    min.d $f1, $f12, $f12
 ; MIPS32R6-NEXT:    jr $ra
 ; MIPS32R6-NEXT:    min.d $f0, $f1, $f0
+;
+; MIPS64-LABEL: minimumnum_double_nsz:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    mov.d $f0, $f13
+; MIPS64-NEXT:    c.un.d $f12, $f12
+; MIPS64-NEXT:    movt.d $f12, $f13, $fcc0
+; MIPS64-NEXT:    c.un.d $f13, $f13
+; MIPS64-NEXT:    movt.d $f0, $f12, $fcc0
+; MIPS64-NEXT:    c.olt.d $f12, $f0
+; MIPS64-NEXT:    movt.d $f0, $f12, $fcc0
+; MIPS64-NEXT:    add.d $f1, $f0, $f0
+; MIPS64-NEXT:    c.un.d $f0, $f0
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.d $f0, $f1, $fcc0
   %z = call nsz double @llvm.minimumnum.f64(double %x, double %y)
   ret double %z
 }
@@ -127,6 +662,149 @@ define double @minimumnum_double_nnan(double %x, double %y) {
 ; MIPS32R6:       # %bb.0:
 ; MIPS32R6-NEXT:    jr $ra
 ; MIPS32R6-NEXT:    min.d $f0, $f12, $f14
+;
+; MIPS64-LABEL: minimumnum_double_nnan:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    c.olt.d $f12, $f13
+; MIPS64-NEXT:    mov.d $f0, $f13
+; MIPS64-NEXT:    movt.d $f0, $f12, $fcc0
+; MIPS64-NEXT:    daddiu $1, $zero, 1
+; MIPS64-NEXT:    dsll $1, $1, 63
+; MIPS64-NEXT:    dmfc1 $2, $f12
+; MIPS64-NEXT:    xor $2, $2, $1
+; MIPS64-NEXT:    mov.d $f1, $f0
+; MIPS64-NEXT:    movz.d $f1, $f12, $2
+; MIPS64-NEXT:    dmfc1 $2, $f13
+; MIPS64-NEXT:    xor $1, $2, $1
+; MIPS64-NEXT:    movz.d $f1, $f13, $1
+; MIPS64-NEXT:    dmtc1 $zero, $f2
+; MIPS64-NEXT:    c.eq.d $f0, $f2
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.d $f0, $f1, $fcc0
   %z = call nnan double @llvm.minimumnum.f64(double %x, double %y)
   ret double %z
 }
+
+define double @minimumnum_double_nnan_arg(double nofpclass(nan) %x, double nofpclass(nan) %y) {
+; MIPS32R6-LABEL: minimumnum_double_nnan_arg:
+; MIPS32R6:       # %bb.0:
+; MIPS32R6-NEXT:    jr $ra
+; MIPS32R6-NEXT:    min.d $f0, $f12, $f14
+;
+; MIPS64-LABEL: minimumnum_double_nnan_arg:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    c.olt.d $f12, $f13
+; MIPS64-NEXT:    mov.d $f0, $f13
+; MIPS64-NEXT:    movt.d $f0, $f12, $fcc0
+; MIPS64-NEXT:    daddiu $1, $zero, 1
+; MIPS64-NEXT:    dsll $1, $1, 63
+; MIPS64-NEXT:    dmfc1 $2, $f12
+; MIPS64-NEXT:    xor $2, $2, $1
+; MIPS64-NEXT:    mov.d $f1, $f0
+; MIPS64-NEXT:    movz.d $f1, $f12, $2
+; MIPS64-NEXT:    dmfc1 $2, $f13
+; MIPS64-NEXT:    xor $1, $2, $1
+; MIPS64-NEXT:    movz.d $f1, $f13, $1
+; MIPS64-NEXT:    dmtc1 $zero, $f2
+; MIPS64-NEXT:    c.eq.d $f0, $f2
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.d $f0, $f1, $fcc0
+  %z = call double @llvm.minimumnum.f64(double %x, double %y)
+  ret double %z
+}
+
+define double @minimumnum_double_n2nan_arg(double nofpclass(qnan snan) %x, double nofpclass(qnan snan) %y) {
+; MIPS32R6-LABEL: minimumnum_double_n2nan_arg:
+; MIPS32R6:       # %bb.0:
+; MIPS32R6-NEXT:    jr $ra
+; MIPS32R6-NEXT:    min.d $f0, $f12, $f14
+;
+; MIPS64-LABEL: minimumnum_double_n2nan_arg:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    c.olt.d $f12, $f13
+; MIPS64-NEXT:    mov.d $f0, $f13
+; MIPS64-NEXT:    movt.d $f0, $f12, $fcc0
+; MIPS64-NEXT:    daddiu $1, $zero, 1
+; MIPS64-NEXT:    dsll $1, $1, 63
+; MIPS64-NEXT:    dmfc1 $2, $f12
+; MIPS64-NEXT:    xor $2, $2, $1
+; MIPS64-NEXT:    mov.d $f1, $f0
+; MIPS64-NEXT:    movz.d $f1, $f12, $2
+; MIPS64-NEXT:    dmfc1 $2, $f13
+; MIPS64-NEXT:    xor $1, $2, $1
+; MIPS64-NEXT:    movz.d $f1, $f13, $1
+; MIPS64-NEXT:    dmtc1 $zero, $f2
+; MIPS64-NEXT:    c.eq.d $f0, $f2
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.d $f0, $f1, $fcc0
+  %z = call double @llvm.minimumnum.f64(double %x, double %y)
+  ret double %z
+}
+
+define double @minimumnum_double_nsnan_arg(double nofpclass(snan) %x, double nofpclass(snan) %y) {
+; MIPS32R6-LABEL: minimumnum_double_nsnan_arg:
+; MIPS32R6:       # %bb.0:
+; MIPS32R6-NEXT:    jr $ra
+; MIPS32R6-NEXT:    min.d $f0, $f12, $f14
+;
+; MIPS64-LABEL: minimumnum_double_nsnan_arg:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    c.un.d $f12, $f12
+; MIPS64-NEXT:    movt.d $f12, $f13, $fcc0
+; MIPS64-NEXT:    c.un.d $f13, $f13
+; MIPS64-NEXT:    movt.d $f13, $f12, $fcc0
+; MIPS64-NEXT:    c.olt.d $f12, $f13
+; MIPS64-NEXT:    mov.d $f0, $f13
+; MIPS64-NEXT:    movt.d $f0, $f12, $fcc0
+; MIPS64-NEXT:    dmfc1 $1, $f12
+; MIPS64-NEXT:    daddiu $2, $zero, 1
+; MIPS64-NEXT:    dsll $2, $2, 63
+; MIPS64-NEXT:    xor $1, $1, $2
+; MIPS64-NEXT:    mov.d $f1, $f0
+; MIPS64-NEXT:    movz.d $f1, $f12, $1
+; MIPS64-NEXT:    dmfc1 $1, $f13
+; MIPS64-NEXT:    xor $1, $1, $2
+; MIPS64-NEXT:    movz.d $f1, $f13, $1
+; MIPS64-NEXT:    dmtc1 $zero, $f2
+; MIPS64-NEXT:    c.eq.d $f0, $f2
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.d $f0, $f1, $fcc0
+  %z = call double @llvm.minimumnum.f64(double %x, double %y)
+  ret double %z
+}
+
+define double @minimumnum_double_n1snan_arg(double nofpclass(snan) %x, double %y) {
+; MIPS32R6-LABEL: minimumnum_double_n1snan_arg:
+; MIPS32R6:       # %bb.0:
+; MIPS32R6-NEXT:    min.d $f0, $f14, $f14
+; MIPS32R6-NEXT:    jr $ra
+; MIPS32R6-NEXT:    min.d $f0, $f12, $f0
+;
+; MIPS64-LABEL: minimumnum_double_n1snan_arg:
+; MIPS64:       # %bb.0:
+; MIPS64-NEXT:    c.un.d $f12, $f12
+; MIPS64-NEXT:    movt.d $f12, $f13, $fcc0
+; MIPS64-NEXT:    c.un.d $f13, $f13
+; MIPS64-NEXT:    movt.d $f13, $f12, $fcc0
+; MIPS64-NEXT:    c.olt.d $f12, $f13
+; MIPS64-NEXT:    mov.d $f0, $f13
+; MIPS64-NEXT:    movt.d $f0, $f12, $fcc0
+; MIPS64-NEXT:    add.d $f1, $f0, $f0
+; MIPS64-NEXT:    c.un.d $f0, $f0
+; MIPS64-NEXT:    movt.d $f0, $f1, $fcc0
+; MIPS64-NEXT:    dmfc1 $1, $f12
+; MIPS64-NEXT:    daddiu $2, $zero, 1
+; MIPS64-NEXT:    dsll $2, $2, 63
+; MIPS64-NEXT:    xor $1, $1, $2
+; MIPS64-NEXT:    mov.d $f1, $f0
+; MIPS64-NEXT:    movz.d $f1, $f12, $1
+; MIPS64-NEXT:    dmfc1 $1, $f13
+; MIPS64-NEXT:    xor $1, $1, $2
+; MIPS64-NEXT:    movz.d $f1, $f13, $1
+; MIPS64-NEXT:    dmtc1 $zero, $f2
+; MIPS64-NEXT:    c.eq.d $f0, $f2
+; MIPS64-NEXT:    jr $ra
+; MIPS64-NEXT:    movt.d $f0, $f1, $fcc0
+  %z = call double @llvm.minimumnum.f64(double %x, double %y)
+  ret double %z
+}
diff --git a/llvm/test/CodeGen/X86/fminimumnum-fmaximumnum.ll b/llvm/test/CodeGen/X86/fminimumnum-fmaximumnum.ll
new file mode 100644
index 00000000000000..38d996c432f20f
--- /dev/null
+++ b/llvm/test/CodeGen/X86/fminimumnum-fmaximumnum.ll
@@ -0,0 +1,1210 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+sse2     | FileCheck %s --check-prefixes=SSE2
+; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+avx      | FileCheck %s --check-prefixes=AVX
+; RUN: llc < %s -mtriple=i686-unknown-unknown                    | FileCheck %s --check-prefixes=X86
+; RUN: llc < %s -mtriple=i686-unknown-unknown -mattr=+avx        | FileCheck %s --check-prefixes=X86AVX
+
+declare float @llvm.maximumnum.f32(float, float)
+declare double @llvm.maximumnum.f64(double, double)
+declare float @llvm.minimumnum.f32(float, float)
+declare double @llvm.minimumnum.f64(double, double)
+
+define dso_local float @maxf_nzero(float nofpclass(nzero snan) noundef %a, float nofpclass(nzero snan) noundef %b) local_unnamed_addr #0 {
+; SSE2-LABEL: maxf_nzero:
+; SSE2:       # %bb.0: # %entry
+; SSE2-NEXT:    movaps %xmm0, %xmm2
+; SSE2-NEXT:    cmpunordss %xmm0, %xmm2
+; SSE2-NEXT:    movaps %xmm2, %xmm3
+; SSE2-NEXT:    andps %xmm1, %xmm3
+; SSE2-NEXT:    andnps %xmm0, %xmm2
+; SSE2-NEXT:    orps %xmm3, %xmm2
+; SSE2-NEXT:    movaps %xmm1, %xmm3
+; SSE2-NEXT:    cmpunordss %xmm1, %xmm3
+; SSE2-NEXT:    movaps %xmm3, %xmm0
+; SSE2-NEXT:    andps %xmm2, %xmm0
+; SSE2-NEXT:    andnps %xmm1, %xmm3
+; SSE2-NEXT:    orps %xmm0, %xmm3
+; SSE2-NEXT:    movaps %xmm3, %xmm0
+; SSE2-NEXT:    cmpltss %xmm2, %xmm0
+; SSE2-NEXT:    andps %xmm0, %xmm2
+; SSE2-NEXT:    andnps %xmm3, %xmm0
+; SSE2-NEXT:    orps %xmm2, %xmm0
+; SSE2-NEXT:    retq
+;
+; AVX-LABEL: maxf_nzero:
+; AVX:       # %bb.0: # %entry
+; AVX-NEXT:    vcmpunordss %xmm0, %xmm0, %xmm2
+; AVX-NEXT:    vblendvps %xmm2, %xmm1, %xmm0, %xmm0
+; AVX-NEXT:    vcmpunordss %xmm1, %xmm1, %xmm2
+; AVX-NEXT:    vblendvps %xmm2, %xmm0, %xmm1, %xmm1
+; AVX-NEXT:    vcmpltss %xmm0, %xmm1, %xmm2
+; AVX-NEXT:    vblendvps %xmm2, %xmm0, %xmm1, %xmm0
+; AVX-NEXT:    retq
+;
+; X86-LABEL: maxf_nzero:
+; X86:       # %bb.0: # %entry
+; X86-NEXT:    flds {{[0-9]+}}(%esp)
+; X86-NEXT:    flds {{[0-9]+}}(%esp)
+; X86-NEXT:    fucom %st(0)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    fld %st(1)
+; X86-NEXT:    jp .LBB0_2
+; X86-NEXT:  # %bb.1: # %entry
+; X86-NEXT:    fstp %st(0)
+; X86-NEXT:    fldz
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:  .LBB0_2: # %entry
+; X86-NEXT:    fstp %st(1)
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:    fucom %st(0)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    fld %st(1)
+; X86-NEXT:    jp .LBB0_4
+; X86-NEXT:  # %bb.3: # %entry
+; X86-NEXT:    fstp %st(0)
+; X86-NEXT:    fldz
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:  .LBB0_4: # %entry
+; X86-NEXT:    fstp %st(1)
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:    fucom %st(1)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    ja .LBB0_6
+; X86-NEXT:  # %bb.5: # %entry
+; X86-NEXT:    fstp %st(0)
+; X86-NEXT:    fldz
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:  .LBB0_6: # %entry
+; X86-NEXT:    fstp %st(1)
+; X86-NEXT:    retl
+;
+; X86AVX-LABEL: maxf_nzero:
+; X86AVX:       # %bb.0: # %entry
+; X86AVX-NEXT:    pushl %eax
+; X86AVX-NEXT:    .cfi_def_cfa_offset 8
+; X86AVX-NEXT:    vmovss {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; X86AVX-NEXT:    vmovss {{.*#+}} xmm1 = mem[0],zero,zero,zero
+; X86AVX-NEXT:    vcmpunordss %xmm0, %xmm0, %xmm2
+; X86AVX-NEXT:    vblendvps %xmm2, %xmm1, %xmm0, %xmm0
+; X86AVX-NEXT:    vcmpunordss %xmm1, %xmm1, %xmm2
+; X86AVX-NEXT:    vblendvps %xmm2, %xmm0, %xmm1, %xmm1
+; X86AVX-NEXT:    vcmpltss %xmm0, %xmm1, %xmm2
+; X86AVX-NEXT:    vblendvps %xmm2, %xmm0, %xmm1, %xmm0
+; X86AVX-NEXT:    vmovss %xmm0, (%esp)
+; X86AVX-NEXT:    flds (%esp)
+; X86AVX-NEXT:    popl %eax
+; X86AVX-NEXT:    .cfi_def_cfa_offset 4
+; X86AVX-NEXT:    retl
+entry:
+  %cond = tail call float @llvm.maximumnum.f32(float %a, float %b)
+  ret float %cond
+}
+
+define dso_local float @maxf_pzero(float nofpclass(pzero snan) noundef %a, float nofpclass(pzero snan) noundef %b) local_unnamed_addr #0 {
+; SSE2-LABEL: maxf_pzero:
+; SSE2:       # %bb.0: # %entry
+; SSE2-NEXT:    movaps %xmm0, %xmm2
+; SSE2-NEXT:    cmpunordss %xmm0, %xmm2
+; SSE2-NEXT:    movaps %xmm2, %xmm3
+; SSE2-NEXT:    andps %xmm1, %xmm3
+; SSE2-NEXT:    andnps %xmm0, %xmm2
+; SSE2-NEXT:    orps %xmm3, %xmm2
+; SSE2-NEXT:    movaps %xmm1, %xmm3
+; SSE2-NEXT:    cmpunordss %xmm1, %xmm3
+; SSE2-NEXT:    movaps %xmm3, %xmm0
+; SSE2-NEXT:    andps %xmm2, %xmm0
+; SSE2-NEXT:    andnps %xmm1, %xmm3
+; SSE2-NEXT:    orps %xmm0, %xmm3
+; SSE2-NEXT:    movaps %xmm3, %xmm0
+; SSE2-NEXT:    cmpltss %xmm2, %xmm0
+; SSE2-NEXT:    andps %xmm0, %xmm2
+; SSE2-NEXT:    andnps %xmm3, %xmm0
+; SSE2-NEXT:    orps %xmm2, %xmm0
+; SSE2-NEXT:    retq
+;
+; AVX-LABEL: maxf_pzero:
+; AVX:       # %bb.0: # %entry
+; AVX-NEXT:    vcmpunordss %xmm0, %xmm0, %xmm2
+; AVX-NEXT:    vblendvps %xmm2, %xmm1, %xmm0, %xmm0
+; AVX-NEXT:    vcmpunordss %xmm1, %xmm1, %xmm2
+; AVX-NEXT:    vblendvps %xmm2, %xmm0, %xmm1, %xmm1
+; AVX-NEXT:    vcmpltss %xmm0, %xmm1, %xmm2
+; AVX-NEXT:    vblendvps %xmm2, %xmm0, %xmm1, %xmm0
+; AVX-NEXT:    retq
+;
+; X86-LABEL: maxf_pzero:
+; X86:       # %bb.0: # %entry
+; X86-NEXT:    flds {{[0-9]+}}(%esp)
+; X86-NEXT:    flds {{[0-9]+}}(%esp)
+; X86-NEXT:    fucom %st(0)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    fld %st(1)
+; X86-NEXT:    jp .LBB1_2
+; X86-NEXT:  # %bb.1: # %entry
+; X86-NEXT:    fstp %st(0)
+; X86-NEXT:    fldz
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:  .LBB1_2: # %entry
+; X86-NEXT:    fstp %st(1)
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:    fucom %st(0)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    fld %st(1)
+; X86-NEXT:    jp .LBB1_4
+; X86-NEXT:  # %bb.3: # %entry
+; X86-NEXT:    fstp %st(0)
+; X86-NEXT:    fldz
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:  .LBB1_4: # %entry
+; X86-NEXT:    fstp %st(1)
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:    fucom %st(1)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    ja .LBB1_6
+; X86-NEXT:  # %bb.5: # %entry
+; X86-NEXT:    fstp %st(0)
+; X86-NEXT:    fldz
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:  .LBB1_6: # %entry
+; X86-NEXT:    fstp %st(1)
+; X86-NEXT:    retl
+;
+; X86AVX-LABEL: maxf_pzero:
+; X86AVX:       # %bb.0: # %entry
+; X86AVX-NEXT:    pushl %eax
+; X86AVX-NEXT:    .cfi_def_cfa_offset 8
+; X86AVX-NEXT:    vmovss {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; X86AVX-NEXT:    vmovss {{.*#+}} xmm1 = mem[0],zero,zero,zero
+; X86AVX-NEXT:    vcmpunordss %xmm0, %xmm0, %xmm2
+; X86AVX-NEXT:    vblendvps %xmm2, %xmm1, %xmm0, %xmm0
+; X86AVX-NEXT:    vcmpunordss %xmm1, %xmm1, %xmm2
+; X86AVX-NEXT:    vblendvps %xmm2, %xmm0, %xmm1, %xmm1
+; X86AVX-NEXT:    vcmpltss %xmm0, %xmm1, %xmm2
+; X86AVX-NEXT:    vblendvps %xmm2, %xmm0, %xmm1, %xmm0
+; X86AVX-NEXT:    vmovss %xmm0, (%esp)
+; X86AVX-NEXT:    flds (%esp)
+; X86AVX-NEXT:    popl %eax
+; X86AVX-NEXT:    .cfi_def_cfa_offset 4
+; X86AVX-NEXT:    retl
+entry:
+  %cond = tail call float @llvm.maximumnum.f32(float %a, float %b)
+  ret float %cond
+}
+
+define dso_local float @maxf_zero(float nofpclass(zero snan) noundef %a, float nofpclass(zero snan) noundef %b) local_unnamed_addr #0 {
+; SSE2-LABEL: maxf_zero:
+; SSE2:       # %bb.0: # %entry
+; SSE2-NEXT:    movaps %xmm0, %xmm2
+; SSE2-NEXT:    cmpunordss %xmm0, %xmm2
+; SSE2-NEXT:    movaps %xmm2, %xmm3
+; SSE2-NEXT:    andps %xmm1, %xmm3
+; SSE2-NEXT:    andnps %xmm0, %xmm2
+; SSE2-NEXT:    orps %xmm3, %xmm2
+; SSE2-NEXT:    movaps %xmm1, %xmm3
+; SSE2-NEXT:    cmpunordss %xmm1, %xmm3
+; SSE2-NEXT:    movaps %xmm3, %xmm0
+; SSE2-NEXT:    andps %xmm2, %xmm0
+; SSE2-NEXT:    andnps %xmm1, %xmm3
+; SSE2-NEXT:    orps %xmm0, %xmm3
+; SSE2-NEXT:    movaps %xmm3, %xmm0
+; SSE2-NEXT:    cmpltss %xmm2, %xmm0
+; SSE2-NEXT:    andps %xmm0, %xmm2
+; SSE2-NEXT:    andnps %xmm3, %xmm0
+; SSE2-NEXT:    orps %xmm2, %xmm0
+; SSE2-NEXT:    retq
+;
+; AVX-LABEL: maxf_zero:
+; AVX:       # %bb.0: # %entry
+; AVX-NEXT:    vcmpunordss %xmm0, %xmm0, %xmm2
+; AVX-NEXT:    vblendvps %xmm2, %xmm1, %xmm0, %xmm0
+; AVX-NEXT:    vcmpunordss %xmm1, %xmm1, %xmm2
+; AVX-NEXT:    vblendvps %xmm2, %xmm0, %xmm1, %xmm1
+; AVX-NEXT:    vcmpltss %xmm0, %xmm1, %xmm2
+; AVX-NEXT:    vblendvps %xmm2, %xmm0, %xmm1, %xmm0
+; AVX-NEXT:    retq
+;
+; X86-LABEL: maxf_zero:
+; X86:       # %bb.0: # %entry
+; X86-NEXT:    flds {{[0-9]+}}(%esp)
+; X86-NEXT:    flds {{[0-9]+}}(%esp)
+; X86-NEXT:    fucom %st(0)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    fld %st(1)
+; X86-NEXT:    jp .LBB2_2
+; X86-NEXT:  # %bb.1: # %entry
+; X86-NEXT:    fstp %st(0)
+; X86-NEXT:    fldz
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:  .LBB2_2: # %entry
+; X86-NEXT:    fstp %st(1)
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:    fucom %st(0)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    fld %st(1)
+; X86-NEXT:    jp .LBB2_4
+; X86-NEXT:  # %bb.3: # %entry
+; X86-NEXT:    fstp %st(0)
+; X86-NEXT:    fldz
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:  .LBB2_4: # %entry
+; X86-NEXT:    fstp %st(1)
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:    fucom %st(1)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    ja .LBB2_6
+; X86-NEXT:  # %bb.5: # %entry
+; X86-NEXT:    fstp %st(0)
+; X86-NEXT:    fldz
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:  .LBB2_6: # %entry
+; X86-NEXT:    fstp %st(1)
+; X86-NEXT:    retl
+;
+; X86AVX-LABEL: maxf_zero:
+; X86AVX:       # %bb.0: # %entry
+; X86AVX-NEXT:    pushl %eax
+; X86AVX-NEXT:    .cfi_def_cfa_offset 8
+; X86AVX-NEXT:    vmovss {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; X86AVX-NEXT:    vmovss {{.*#+}} xmm1 = mem[0],zero,zero,zero
+; X86AVX-NEXT:    vcmpunordss %xmm0, %xmm0, %xmm2
+; X86AVX-NEXT:    vblendvps %xmm2, %xmm1, %xmm0, %xmm0
+; X86AVX-NEXT:    vcmpunordss %xmm1, %xmm1, %xmm2
+; X86AVX-NEXT:    vblendvps %xmm2, %xmm0, %xmm1, %xmm1
+; X86AVX-NEXT:    vcmpltss %xmm0, %xmm1, %xmm2
+; X86AVX-NEXT:    vblendvps %xmm2, %xmm0, %xmm1, %xmm0
+; X86AVX-NEXT:    vmovss %xmm0, (%esp)
+; X86AVX-NEXT:    flds (%esp)
+; X86AVX-NEXT:    popl %eax
+; X86AVX-NEXT:    .cfi_def_cfa_offset 4
+; X86AVX-NEXT:    retl
+entry:
+  %cond = tail call float @llvm.maximumnum.f32(float %a, float %b)
+  ret float %cond
+}
+
+define dso_local double @maxd_nzero(double nofpclass(nzero snan) noundef %a, double nofpclass(nzero snan) noundef %b) local_unnamed_addr #0 {
+; SSE2-LABEL: maxd_nzero:
+; SSE2:       # %bb.0: # %entry
+; SSE2-NEXT:    movapd %xmm0, %xmm2
+; SSE2-NEXT:    cmpunordsd %xmm0, %xmm2
+; SSE2-NEXT:    movapd %xmm2, %xmm3
+; SSE2-NEXT:    andpd %xmm1, %xmm3
+; SSE2-NEXT:    andnpd %xmm0, %xmm2
+; SSE2-NEXT:    orpd %xmm3, %xmm2
+; SSE2-NEXT:    movapd %xmm1, %xmm3
+; SSE2-NEXT:    cmpunordsd %xmm1, %xmm3
+; SSE2-NEXT:    movapd %xmm3, %xmm0
+; SSE2-NEXT:    andpd %xmm2, %xmm0
+; SSE2-NEXT:    andnpd %xmm1, %xmm3
+; SSE2-NEXT:    orpd %xmm0, %xmm3
+; SSE2-NEXT:    movapd %xmm3, %xmm0
+; SSE2-NEXT:    cmpltsd %xmm2, %xmm0
+; SSE2-NEXT:    andpd %xmm0, %xmm2
+; SSE2-NEXT:    andnpd %xmm3, %xmm0
+; SSE2-NEXT:    orpd %xmm2, %xmm0
+; SSE2-NEXT:    retq
+;
+; AVX-LABEL: maxd_nzero:
+; AVX:       # %bb.0: # %entry
+; AVX-NEXT:    vcmpunordsd %xmm0, %xmm0, %xmm2
+; AVX-NEXT:    vblendvpd %xmm2, %xmm1, %xmm0, %xmm0
+; AVX-NEXT:    vcmpunordsd %xmm1, %xmm1, %xmm2
+; AVX-NEXT:    vblendvpd %xmm2, %xmm0, %xmm1, %xmm1
+; AVX-NEXT:    vcmpltsd %xmm0, %xmm1, %xmm2
+; AVX-NEXT:    vblendvpd %xmm2, %xmm0, %xmm1, %xmm0
+; AVX-NEXT:    retq
+;
+; X86-LABEL: maxd_nzero:
+; X86:       # %bb.0: # %entry
+; X86-NEXT:    fldl {{[0-9]+}}(%esp)
+; X86-NEXT:    fldl {{[0-9]+}}(%esp)
+; X86-NEXT:    fucom %st(0)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    fld %st(1)
+; X86-NEXT:    jp .LBB3_2
+; X86-NEXT:  # %bb.1: # %entry
+; X86-NEXT:    fstp %st(0)
+; X86-NEXT:    fldz
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:  .LBB3_2: # %entry
+; X86-NEXT:    fstp %st(1)
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:    fucom %st(0)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    fld %st(1)
+; X86-NEXT:    jp .LBB3_4
+; X86-NEXT:  # %bb.3: # %entry
+; X86-NEXT:    fstp %st(0)
+; X86-NEXT:    fldz
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:  .LBB3_4: # %entry
+; X86-NEXT:    fstp %st(1)
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:    fucom %st(1)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    ja .LBB3_6
+; X86-NEXT:  # %bb.5: # %entry
+; X86-NEXT:    fstp %st(0)
+; X86-NEXT:    fldz
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:  .LBB3_6: # %entry
+; X86-NEXT:    fstp %st(1)
+; X86-NEXT:    retl
+;
+; X86AVX-LABEL: maxd_nzero:
+; X86AVX:       # %bb.0: # %entry
+; X86AVX-NEXT:    pushl %ebp
+; X86AVX-NEXT:    .cfi_def_cfa_offset 8
+; X86AVX-NEXT:    .cfi_offset %ebp, -8
+; X86AVX-NEXT:    movl %esp, %ebp
+; X86AVX-NEXT:    .cfi_def_cfa_register %ebp
+; X86AVX-NEXT:    andl $-8, %esp
+; X86AVX-NEXT:    subl $8, %esp
+; X86AVX-NEXT:    vmovsd {{.*#+}} xmm0 = mem[0],zero
+; X86AVX-NEXT:    vmovsd {{.*#+}} xmm1 = mem[0],zero
+; X86AVX-NEXT:    vcmpunordsd %xmm0, %xmm0, %xmm2
+; X86AVX-NEXT:    vblendvpd %xmm2, %xmm1, %xmm0, %xmm0
+; X86AVX-NEXT:    vcmpunordsd %xmm1, %xmm1, %xmm2
+; X86AVX-NEXT:    vblendvpd %xmm2, %xmm0, %xmm1, %xmm1
+; X86AVX-NEXT:    vcmpltsd %xmm0, %xmm1, %xmm2
+; X86AVX-NEXT:    vblendvpd %xmm2, %xmm0, %xmm1, %xmm0
+; X86AVX-NEXT:    vmovlpd %xmm0, (%esp)
+; X86AVX-NEXT:    fldl (%esp)
+; X86AVX-NEXT:    movl %ebp, %esp
+; X86AVX-NEXT:    popl %ebp
+; X86AVX-NEXT:    .cfi_def_cfa %esp, 4
+; X86AVX-NEXT:    retl
+entry:
+  %cond = tail call double @llvm.maximumnum.f64(double %a, double %b)
+  ret double %cond
+}
+
+define dso_local double @maxd_pzero(double nofpclass(pzero snan) noundef %a, double nofpclass(pzero snan) noundef %b) local_unnamed_addr #0 {
+; SSE2-LABEL: maxd_pzero:
+; SSE2:       # %bb.0: # %entry
+; SSE2-NEXT:    movapd %xmm0, %xmm2
+; SSE2-NEXT:    cmpunordsd %xmm0, %xmm2
+; SSE2-NEXT:    movapd %xmm2, %xmm3
+; SSE2-NEXT:    andpd %xmm1, %xmm3
+; SSE2-NEXT:    andnpd %xmm0, %xmm2
+; SSE2-NEXT:    orpd %xmm3, %xmm2
+; SSE2-NEXT:    movapd %xmm1, %xmm3
+; SSE2-NEXT:    cmpunordsd %xmm1, %xmm3
+; SSE2-NEXT:    movapd %xmm3, %xmm0
+; SSE2-NEXT:    andpd %xmm2, %xmm0
+; SSE2-NEXT:    andnpd %xmm1, %xmm3
+; SSE2-NEXT:    orpd %xmm0, %xmm3
+; SSE2-NEXT:    movapd %xmm3, %xmm0
+; SSE2-NEXT:    cmpltsd %xmm2, %xmm0
+; SSE2-NEXT:    andpd %xmm0, %xmm2
+; SSE2-NEXT:    andnpd %xmm3, %xmm0
+; SSE2-NEXT:    orpd %xmm2, %xmm0
+; SSE2-NEXT:    retq
+;
+; AVX-LABEL: maxd_pzero:
+; AVX:       # %bb.0: # %entry
+; AVX-NEXT:    vcmpunordsd %xmm0, %xmm0, %xmm2
+; AVX-NEXT:    vblendvpd %xmm2, %xmm1, %xmm0, %xmm0
+; AVX-NEXT:    vcmpunordsd %xmm1, %xmm1, %xmm2
+; AVX-NEXT:    vblendvpd %xmm2, %xmm0, %xmm1, %xmm1
+; AVX-NEXT:    vcmpltsd %xmm0, %xmm1, %xmm2
+; AVX-NEXT:    vblendvpd %xmm2, %xmm0, %xmm1, %xmm0
+; AVX-NEXT:    retq
+;
+; X86-LABEL: maxd_pzero:
+; X86:       # %bb.0: # %entry
+; X86-NEXT:    fldl {{[0-9]+}}(%esp)
+; X86-NEXT:    fldl {{[0-9]+}}(%esp)
+; X86-NEXT:    fucom %st(0)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    fld %st(1)
+; X86-NEXT:    jp .LBB4_2
+; X86-NEXT:  # %bb.1: # %entry
+; X86-NEXT:    fstp %st(0)
+; X86-NEXT:    fldz
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:  .LBB4_2: # %entry
+; X86-NEXT:    fstp %st(1)
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:    fucom %st(0)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    fld %st(1)
+; X86-NEXT:    jp .LBB4_4
+; X86-NEXT:  # %bb.3: # %entry
+; X86-NEXT:    fstp %st(0)
+; X86-NEXT:    fldz
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:  .LBB4_4: # %entry
+; X86-NEXT:    fstp %st(1)
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:    fucom %st(1)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    ja .LBB4_6
+; X86-NEXT:  # %bb.5: # %entry
+; X86-NEXT:    fstp %st(0)
+; X86-NEXT:    fldz
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:  .LBB4_6: # %entry
+; X86-NEXT:    fstp %st(1)
+; X86-NEXT:    retl
+;
+; X86AVX-LABEL: maxd_pzero:
+; X86AVX:       # %bb.0: # %entry
+; X86AVX-NEXT:    pushl %ebp
+; X86AVX-NEXT:    .cfi_def_cfa_offset 8
+; X86AVX-NEXT:    .cfi_offset %ebp, -8
+; X86AVX-NEXT:    movl %esp, %ebp
+; X86AVX-NEXT:    .cfi_def_cfa_register %ebp
+; X86AVX-NEXT:    andl $-8, %esp
+; X86AVX-NEXT:    subl $8, %esp
+; X86AVX-NEXT:    vmovsd {{.*#+}} xmm0 = mem[0],zero
+; X86AVX-NEXT:    vmovsd {{.*#+}} xmm1 = mem[0],zero
+; X86AVX-NEXT:    vcmpunordsd %xmm0, %xmm0, %xmm2
+; X86AVX-NEXT:    vblendvpd %xmm2, %xmm1, %xmm0, %xmm0
+; X86AVX-NEXT:    vcmpunordsd %xmm1, %xmm1, %xmm2
+; X86AVX-NEXT:    vblendvpd %xmm2, %xmm0, %xmm1, %xmm1
+; X86AVX-NEXT:    vcmpltsd %xmm0, %xmm1, %xmm2
+; X86AVX-NEXT:    vblendvpd %xmm2, %xmm0, %xmm1, %xmm0
+; X86AVX-NEXT:    vmovlpd %xmm0, (%esp)
+; X86AVX-NEXT:    fldl (%esp)
+; X86AVX-NEXT:    movl %ebp, %esp
+; X86AVX-NEXT:    popl %ebp
+; X86AVX-NEXT:    .cfi_def_cfa %esp, 4
+; X86AVX-NEXT:    retl
+entry:
+  %cond = tail call double @llvm.maximumnum.f64(double %a, double %b)
+  ret double %cond
+}
+
+define dso_local double @maxd_zero(double nofpclass(zero snan) noundef %a, double nofpclass(zero snan) noundef %b) local_unnamed_addr #0 {
+; SSE2-LABEL: maxd_zero:
+; SSE2:       # %bb.0: # %entry
+; SSE2-NEXT:    movapd %xmm0, %xmm2
+; SSE2-NEXT:    cmpunordsd %xmm0, %xmm2
+; SSE2-NEXT:    movapd %xmm2, %xmm3
+; SSE2-NEXT:    andpd %xmm1, %xmm3
+; SSE2-NEXT:    andnpd %xmm0, %xmm2
+; SSE2-NEXT:    orpd %xmm3, %xmm2
+; SSE2-NEXT:    movapd %xmm1, %xmm3
+; SSE2-NEXT:    cmpunordsd %xmm1, %xmm3
+; SSE2-NEXT:    movapd %xmm3, %xmm0
+; SSE2-NEXT:    andpd %xmm2, %xmm0
+; SSE2-NEXT:    andnpd %xmm1, %xmm3
+; SSE2-NEXT:    orpd %xmm0, %xmm3
+; SSE2-NEXT:    movapd %xmm3, %xmm0
+; SSE2-NEXT:    cmpltsd %xmm2, %xmm0
+; SSE2-NEXT:    andpd %xmm0, %xmm2
+; SSE2-NEXT:    andnpd %xmm3, %xmm0
+; SSE2-NEXT:    orpd %xmm2, %xmm0
+; SSE2-NEXT:    retq
+;
+; AVX-LABEL: maxd_zero:
+; AVX:       # %bb.0: # %entry
+; AVX-NEXT:    vcmpunordsd %xmm0, %xmm0, %xmm2
+; AVX-NEXT:    vblendvpd %xmm2, %xmm1, %xmm0, %xmm0
+; AVX-NEXT:    vcmpunordsd %xmm1, %xmm1, %xmm2
+; AVX-NEXT:    vblendvpd %xmm2, %xmm0, %xmm1, %xmm1
+; AVX-NEXT:    vcmpltsd %xmm0, %xmm1, %xmm2
+; AVX-NEXT:    vblendvpd %xmm2, %xmm0, %xmm1, %xmm0
+; AVX-NEXT:    retq
+;
+; X86-LABEL: maxd_zero:
+; X86:       # %bb.0: # %entry
+; X86-NEXT:    fldl {{[0-9]+}}(%esp)
+; X86-NEXT:    fldl {{[0-9]+}}(%esp)
+; X86-NEXT:    fucom %st(0)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    fld %st(1)
+; X86-NEXT:    jp .LBB5_2
+; X86-NEXT:  # %bb.1: # %entry
+; X86-NEXT:    fstp %st(0)
+; X86-NEXT:    fldz
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:  .LBB5_2: # %entry
+; X86-NEXT:    fstp %st(1)
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:    fucom %st(0)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    fld %st(1)
+; X86-NEXT:    jp .LBB5_4
+; X86-NEXT:  # %bb.3: # %entry
+; X86-NEXT:    fstp %st(0)
+; X86-NEXT:    fldz
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:  .LBB5_4: # %entry
+; X86-NEXT:    fstp %st(1)
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:    fucom %st(1)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    ja .LBB5_6
+; X86-NEXT:  # %bb.5: # %entry
+; X86-NEXT:    fstp %st(0)
+; X86-NEXT:    fldz
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:  .LBB5_6: # %entry
+; X86-NEXT:    fstp %st(1)
+; X86-NEXT:    retl
+;
+; X86AVX-LABEL: maxd_zero:
+; X86AVX:       # %bb.0: # %entry
+; X86AVX-NEXT:    pushl %ebp
+; X86AVX-NEXT:    .cfi_def_cfa_offset 8
+; X86AVX-NEXT:    .cfi_offset %ebp, -8
+; X86AVX-NEXT:    movl %esp, %ebp
+; X86AVX-NEXT:    .cfi_def_cfa_register %ebp
+; X86AVX-NEXT:    andl $-8, %esp
+; X86AVX-NEXT:    subl $8, %esp
+; X86AVX-NEXT:    vmovsd {{.*#+}} xmm0 = mem[0],zero
+; X86AVX-NEXT:    vmovsd {{.*#+}} xmm1 = mem[0],zero
+; X86AVX-NEXT:    vcmpunordsd %xmm0, %xmm0, %xmm2
+; X86AVX-NEXT:    vblendvpd %xmm2, %xmm1, %xmm0, %xmm0
+; X86AVX-NEXT:    vcmpunordsd %xmm1, %xmm1, %xmm2
+; X86AVX-NEXT:    vblendvpd %xmm2, %xmm0, %xmm1, %xmm1
+; X86AVX-NEXT:    vcmpltsd %xmm0, %xmm1, %xmm2
+; X86AVX-NEXT:    vblendvpd %xmm2, %xmm0, %xmm1, %xmm0
+; X86AVX-NEXT:    vmovlpd %xmm0, (%esp)
+; X86AVX-NEXT:    fldl (%esp)
+; X86AVX-NEXT:    movl %ebp, %esp
+; X86AVX-NEXT:    popl %ebp
+; X86AVX-NEXT:    .cfi_def_cfa %esp, 4
+; X86AVX-NEXT:    retl
+entry:
+  %cond = tail call double @llvm.maximumnum.f64(double %a, double %b)
+  ret double %cond
+}
+
+define dso_local float @minf_nzero(float nofpclass(nzero snan) noundef %a, float nofpclass(nzero snan) noundef %b) local_unnamed_addr #0 {
+; SSE2-LABEL: minf_nzero:
+; SSE2:       # %bb.0: # %entry
+; SSE2-NEXT:    movaps %xmm0, %xmm2
+; SSE2-NEXT:    cmpunordss %xmm0, %xmm2
+; SSE2-NEXT:    movaps %xmm2, %xmm3
+; SSE2-NEXT:    andps %xmm1, %xmm3
+; SSE2-NEXT:    andnps %xmm0, %xmm2
+; SSE2-NEXT:    orps %xmm3, %xmm2
+; SSE2-NEXT:    movaps %xmm1, %xmm3
+; SSE2-NEXT:    cmpunordss %xmm1, %xmm3
+; SSE2-NEXT:    movaps %xmm3, %xmm0
+; SSE2-NEXT:    andps %xmm2, %xmm0
+; SSE2-NEXT:    andnps %xmm1, %xmm3
+; SSE2-NEXT:    orps %xmm0, %xmm3
+; SSE2-NEXT:    movaps %xmm2, %xmm0
+; SSE2-NEXT:    cmpltss %xmm3, %xmm0
+; SSE2-NEXT:    andps %xmm0, %xmm2
+; SSE2-NEXT:    andnps %xmm3, %xmm0
+; SSE2-NEXT:    orps %xmm2, %xmm0
+; SSE2-NEXT:    retq
+;
+; AVX-LABEL: minf_nzero:
+; AVX:       # %bb.0: # %entry
+; AVX-NEXT:    vcmpunordss %xmm0, %xmm0, %xmm2
+; AVX-NEXT:    vblendvps %xmm2, %xmm1, %xmm0, %xmm0
+; AVX-NEXT:    vcmpunordss %xmm1, %xmm1, %xmm2
+; AVX-NEXT:    vblendvps %xmm2, %xmm0, %xmm1, %xmm1
+; AVX-NEXT:    vcmpltss %xmm1, %xmm0, %xmm2
+; AVX-NEXT:    vblendvps %xmm2, %xmm0, %xmm1, %xmm0
+; AVX-NEXT:    retq
+;
+; X86-LABEL: minf_nzero:
+; X86:       # %bb.0: # %entry
+; X86-NEXT:    flds {{[0-9]+}}(%esp)
+; X86-NEXT:    flds {{[0-9]+}}(%esp)
+; X86-NEXT:    fucom %st(0)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    fld %st(1)
+; X86-NEXT:    jp .LBB6_2
+; X86-NEXT:  # %bb.1: # %entry
+; X86-NEXT:    fstp %st(0)
+; X86-NEXT:    fldz
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:  .LBB6_2: # %entry
+; X86-NEXT:    fstp %st(1)
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:    fucom %st(0)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    fld %st(1)
+; X86-NEXT:    jp .LBB6_4
+; X86-NEXT:  # %bb.3: # %entry
+; X86-NEXT:    fstp %st(0)
+; X86-NEXT:    fldz
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:  .LBB6_4: # %entry
+; X86-NEXT:    fstp %st(1)
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:    fucom %st(1)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    jb .LBB6_6
+; X86-NEXT:  # %bb.5: # %entry
+; X86-NEXT:    fstp %st(0)
+; X86-NEXT:    fldz
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:  .LBB6_6: # %entry
+; X86-NEXT:    fstp %st(1)
+; X86-NEXT:    retl
+;
+; X86AVX-LABEL: minf_nzero:
+; X86AVX:       # %bb.0: # %entry
+; X86AVX-NEXT:    pushl %eax
+; X86AVX-NEXT:    .cfi_def_cfa_offset 8
+; X86AVX-NEXT:    vmovss {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; X86AVX-NEXT:    vmovss {{.*#+}} xmm1 = mem[0],zero,zero,zero
+; X86AVX-NEXT:    vcmpunordss %xmm0, %xmm0, %xmm2
+; X86AVX-NEXT:    vblendvps %xmm2, %xmm1, %xmm0, %xmm0
+; X86AVX-NEXT:    vcmpunordss %xmm1, %xmm1, %xmm2
+; X86AVX-NEXT:    vblendvps %xmm2, %xmm0, %xmm1, %xmm1
+; X86AVX-NEXT:    vcmpltss %xmm1, %xmm0, %xmm2
+; X86AVX-NEXT:    vblendvps %xmm2, %xmm0, %xmm1, %xmm0
+; X86AVX-NEXT:    vmovss %xmm0, (%esp)
+; X86AVX-NEXT:    flds (%esp)
+; X86AVX-NEXT:    popl %eax
+; X86AVX-NEXT:    .cfi_def_cfa_offset 4
+; X86AVX-NEXT:    retl
+entry:
+  %cond = tail call float @llvm.minimumnum.f32(float %a, float %b)
+  ret float %cond
+}
+
+define dso_local float @minf_pzero(float nofpclass(pzero snan) noundef %a, float nofpclass(pzero snan) noundef %b) local_unnamed_addr #0 {
+; SSE2-LABEL: minf_pzero:
+; SSE2:       # %bb.0: # %entry
+; SSE2-NEXT:    movaps %xmm0, %xmm2
+; SSE2-NEXT:    cmpunordss %xmm0, %xmm2
+; SSE2-NEXT:    movaps %xmm2, %xmm3
+; SSE2-NEXT:    andps %xmm1, %xmm3
+; SSE2-NEXT:    andnps %xmm0, %xmm2
+; SSE2-NEXT:    orps %xmm3, %xmm2
+; SSE2-NEXT:    movaps %xmm1, %xmm3
+; SSE2-NEXT:    cmpunordss %xmm1, %xmm3
+; SSE2-NEXT:    movaps %xmm3, %xmm0
+; SSE2-NEXT:    andps %xmm2, %xmm0
+; SSE2-NEXT:    andnps %xmm1, %xmm3
+; SSE2-NEXT:    orps %xmm0, %xmm3
+; SSE2-NEXT:    movaps %xmm2, %xmm0
+; SSE2-NEXT:    cmpltss %xmm3, %xmm0
+; SSE2-NEXT:    andps %xmm0, %xmm2
+; SSE2-NEXT:    andnps %xmm3, %xmm0
+; SSE2-NEXT:    orps %xmm2, %xmm0
+; SSE2-NEXT:    retq
+;
+; AVX-LABEL: minf_pzero:
+; AVX:       # %bb.0: # %entry
+; AVX-NEXT:    vcmpunordss %xmm0, %xmm0, %xmm2
+; AVX-NEXT:    vblendvps %xmm2, %xmm1, %xmm0, %xmm0
+; AVX-NEXT:    vcmpunordss %xmm1, %xmm1, %xmm2
+; AVX-NEXT:    vblendvps %xmm2, %xmm0, %xmm1, %xmm1
+; AVX-NEXT:    vcmpltss %xmm1, %xmm0, %xmm2
+; AVX-NEXT:    vblendvps %xmm2, %xmm0, %xmm1, %xmm0
+; AVX-NEXT:    retq
+;
+; X86-LABEL: minf_pzero:
+; X86:       # %bb.0: # %entry
+; X86-NEXT:    flds {{[0-9]+}}(%esp)
+; X86-NEXT:    flds {{[0-9]+}}(%esp)
+; X86-NEXT:    fucom %st(0)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    fld %st(1)
+; X86-NEXT:    jp .LBB7_2
+; X86-NEXT:  # %bb.1: # %entry
+; X86-NEXT:    fstp %st(0)
+; X86-NEXT:    fldz
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:  .LBB7_2: # %entry
+; X86-NEXT:    fstp %st(1)
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:    fucom %st(0)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    fld %st(1)
+; X86-NEXT:    jp .LBB7_4
+; X86-NEXT:  # %bb.3: # %entry
+; X86-NEXT:    fstp %st(0)
+; X86-NEXT:    fldz
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:  .LBB7_4: # %entry
+; X86-NEXT:    fstp %st(1)
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:    fucom %st(1)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    jb .LBB7_6
+; X86-NEXT:  # %bb.5: # %entry
+; X86-NEXT:    fstp %st(0)
+; X86-NEXT:    fldz
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:  .LBB7_6: # %entry
+; X86-NEXT:    fstp %st(1)
+; X86-NEXT:    retl
+;
+; X86AVX-LABEL: minf_pzero:
+; X86AVX:       # %bb.0: # %entry
+; X86AVX-NEXT:    pushl %eax
+; X86AVX-NEXT:    .cfi_def_cfa_offset 8
+; X86AVX-NEXT:    vmovss {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; X86AVX-NEXT:    vmovss {{.*#+}} xmm1 = mem[0],zero,zero,zero
+; X86AVX-NEXT:    vcmpunordss %xmm0, %xmm0, %xmm2
+; X86AVX-NEXT:    vblendvps %xmm2, %xmm1, %xmm0, %xmm0
+; X86AVX-NEXT:    vcmpunordss %xmm1, %xmm1, %xmm2
+; X86AVX-NEXT:    vblendvps %xmm2, %xmm0, %xmm1, %xmm1
+; X86AVX-NEXT:    vcmpltss %xmm1, %xmm0, %xmm2
+; X86AVX-NEXT:    vblendvps %xmm2, %xmm0, %xmm1, %xmm0
+; X86AVX-NEXT:    vmovss %xmm0, (%esp)
+; X86AVX-NEXT:    flds (%esp)
+; X86AVX-NEXT:    popl %eax
+; X86AVX-NEXT:    .cfi_def_cfa_offset 4
+; X86AVX-NEXT:    retl
+entry:
+  %cond = tail call float @llvm.minimumnum.f32(float %a, float %b)
+  ret float %cond
+}
+
+define dso_local float @minf_zero(float nofpclass(zero snan) noundef %a, float nofpclass(zero snan) noundef %b) local_unnamed_addr #0 {
+; SSE2-LABEL: minf_zero:
+; SSE2:       # %bb.0: # %entry
+; SSE2-NEXT:    movaps %xmm0, %xmm2
+; SSE2-NEXT:    cmpunordss %xmm0, %xmm2
+; SSE2-NEXT:    movaps %xmm2, %xmm3
+; SSE2-NEXT:    andps %xmm1, %xmm3
+; SSE2-NEXT:    andnps %xmm0, %xmm2
+; SSE2-NEXT:    orps %xmm3, %xmm2
+; SSE2-NEXT:    movaps %xmm1, %xmm3
+; SSE2-NEXT:    cmpunordss %xmm1, %xmm3
+; SSE2-NEXT:    movaps %xmm3, %xmm0
+; SSE2-NEXT:    andps %xmm2, %xmm0
+; SSE2-NEXT:    andnps %xmm1, %xmm3
+; SSE2-NEXT:    orps %xmm0, %xmm3
+; SSE2-NEXT:    movaps %xmm2, %xmm0
+; SSE2-NEXT:    cmpltss %xmm3, %xmm0
+; SSE2-NEXT:    andps %xmm0, %xmm2
+; SSE2-NEXT:    andnps %xmm3, %xmm0
+; SSE2-NEXT:    orps %xmm2, %xmm0
+; SSE2-NEXT:    retq
+;
+; AVX-LABEL: minf_zero:
+; AVX:       # %bb.0: # %entry
+; AVX-NEXT:    vcmpunordss %xmm0, %xmm0, %xmm2
+; AVX-NEXT:    vblendvps %xmm2, %xmm1, %xmm0, %xmm0
+; AVX-NEXT:    vcmpunordss %xmm1, %xmm1, %xmm2
+; AVX-NEXT:    vblendvps %xmm2, %xmm0, %xmm1, %xmm1
+; AVX-NEXT:    vcmpltss %xmm1, %xmm0, %xmm2
+; AVX-NEXT:    vblendvps %xmm2, %xmm0, %xmm1, %xmm0
+; AVX-NEXT:    retq
+;
+; X86-LABEL: minf_zero:
+; X86:       # %bb.0: # %entry
+; X86-NEXT:    flds {{[0-9]+}}(%esp)
+; X86-NEXT:    flds {{[0-9]+}}(%esp)
+; X86-NEXT:    fucom %st(0)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    fld %st(1)
+; X86-NEXT:    jp .LBB8_2
+; X86-NEXT:  # %bb.1: # %entry
+; X86-NEXT:    fstp %st(0)
+; X86-NEXT:    fldz
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:  .LBB8_2: # %entry
+; X86-NEXT:    fstp %st(1)
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:    fucom %st(0)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    fld %st(1)
+; X86-NEXT:    jp .LBB8_4
+; X86-NEXT:  # %bb.3: # %entry
+; X86-NEXT:    fstp %st(0)
+; X86-NEXT:    fldz
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:  .LBB8_4: # %entry
+; X86-NEXT:    fstp %st(1)
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:    fucom %st(1)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    jb .LBB8_6
+; X86-NEXT:  # %bb.5: # %entry
+; X86-NEXT:    fstp %st(0)
+; X86-NEXT:    fldz
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:  .LBB8_6: # %entry
+; X86-NEXT:    fstp %st(1)
+; X86-NEXT:    retl
+;
+; X86AVX-LABEL: minf_zero:
+; X86AVX:       # %bb.0: # %entry
+; X86AVX-NEXT:    pushl %eax
+; X86AVX-NEXT:    .cfi_def_cfa_offset 8
+; X86AVX-NEXT:    vmovss {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; X86AVX-NEXT:    vmovss {{.*#+}} xmm1 = mem[0],zero,zero,zero
+; X86AVX-NEXT:    vcmpunordss %xmm0, %xmm0, %xmm2
+; X86AVX-NEXT:    vblendvps %xmm2, %xmm1, %xmm0, %xmm0
+; X86AVX-NEXT:    vcmpunordss %xmm1, %xmm1, %xmm2
+; X86AVX-NEXT:    vblendvps %xmm2, %xmm0, %xmm1, %xmm1
+; X86AVX-NEXT:    vcmpltss %xmm1, %xmm0, %xmm2
+; X86AVX-NEXT:    vblendvps %xmm2, %xmm0, %xmm1, %xmm0
+; X86AVX-NEXT:    vmovss %xmm0, (%esp)
+; X86AVX-NEXT:    flds (%esp)
+; X86AVX-NEXT:    popl %eax
+; X86AVX-NEXT:    .cfi_def_cfa_offset 4
+; X86AVX-NEXT:    retl
+entry:
+  %cond = tail call float @llvm.minimumnum.f32(float %a, float %b)
+  ret float %cond
+}
+
+define dso_local double @mind_nzero(double nofpclass(nzero snan) noundef %a, double nofpclass(nzero snan) noundef %b) local_unnamed_addr #0 {
+; SSE2-LABEL: mind_nzero:
+; SSE2:       # %bb.0: # %entry
+; SSE2-NEXT:    movapd %xmm0, %xmm2
+; SSE2-NEXT:    cmpunordsd %xmm0, %xmm2
+; SSE2-NEXT:    movapd %xmm2, %xmm3
+; SSE2-NEXT:    andpd %xmm1, %xmm3
+; SSE2-NEXT:    andnpd %xmm0, %xmm2
+; SSE2-NEXT:    orpd %xmm3, %xmm2
+; SSE2-NEXT:    movapd %xmm1, %xmm3
+; SSE2-NEXT:    cmpunordsd %xmm1, %xmm3
+; SSE2-NEXT:    movapd %xmm3, %xmm0
+; SSE2-NEXT:    andpd %xmm2, %xmm0
+; SSE2-NEXT:    andnpd %xmm1, %xmm3
+; SSE2-NEXT:    orpd %xmm0, %xmm3
+; SSE2-NEXT:    movapd %xmm2, %xmm0
+; SSE2-NEXT:    cmpltsd %xmm3, %xmm0
+; SSE2-NEXT:    andpd %xmm0, %xmm2
+; SSE2-NEXT:    andnpd %xmm3, %xmm0
+; SSE2-NEXT:    orpd %xmm2, %xmm0
+; SSE2-NEXT:    retq
+;
+; AVX-LABEL: mind_nzero:
+; AVX:       # %bb.0: # %entry
+; AVX-NEXT:    vcmpunordsd %xmm0, %xmm0, %xmm2
+; AVX-NEXT:    vblendvpd %xmm2, %xmm1, %xmm0, %xmm0
+; AVX-NEXT:    vcmpunordsd %xmm1, %xmm1, %xmm2
+; AVX-NEXT:    vblendvpd %xmm2, %xmm0, %xmm1, %xmm1
+; AVX-NEXT:    vcmpltsd %xmm1, %xmm0, %xmm2
+; AVX-NEXT:    vblendvpd %xmm2, %xmm0, %xmm1, %xmm0
+; AVX-NEXT:    retq
+;
+; X86-LABEL: mind_nzero:
+; X86:       # %bb.0: # %entry
+; X86-NEXT:    fldl {{[0-9]+}}(%esp)
+; X86-NEXT:    fldl {{[0-9]+}}(%esp)
+; X86-NEXT:    fucom %st(0)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    fld %st(1)
+; X86-NEXT:    jp .LBB9_2
+; X86-NEXT:  # %bb.1: # %entry
+; X86-NEXT:    fstp %st(0)
+; X86-NEXT:    fldz
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:  .LBB9_2: # %entry
+; X86-NEXT:    fstp %st(1)
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:    fucom %st(0)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    fld %st(1)
+; X86-NEXT:    jp .LBB9_4
+; X86-NEXT:  # %bb.3: # %entry
+; X86-NEXT:    fstp %st(0)
+; X86-NEXT:    fldz
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:  .LBB9_4: # %entry
+; X86-NEXT:    fstp %st(1)
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:    fucom %st(1)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    jb .LBB9_6
+; X86-NEXT:  # %bb.5: # %entry
+; X86-NEXT:    fstp %st(0)
+; X86-NEXT:    fldz
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:  .LBB9_6: # %entry
+; X86-NEXT:    fstp %st(1)
+; X86-NEXT:    retl
+;
+; X86AVX-LABEL: mind_nzero:
+; X86AVX:       # %bb.0: # %entry
+; X86AVX-NEXT:    pushl %ebp
+; X86AVX-NEXT:    .cfi_def_cfa_offset 8
+; X86AVX-NEXT:    .cfi_offset %ebp, -8
+; X86AVX-NEXT:    movl %esp, %ebp
+; X86AVX-NEXT:    .cfi_def_cfa_register %ebp
+; X86AVX-NEXT:    andl $-8, %esp
+; X86AVX-NEXT:    subl $8, %esp
+; X86AVX-NEXT:    vmovsd {{.*#+}} xmm0 = mem[0],zero
+; X86AVX-NEXT:    vmovsd {{.*#+}} xmm1 = mem[0],zero
+; X86AVX-NEXT:    vcmpunordsd %xmm0, %xmm0, %xmm2
+; X86AVX-NEXT:    vblendvpd %xmm2, %xmm1, %xmm0, %xmm0
+; X86AVX-NEXT:    vcmpunordsd %xmm1, %xmm1, %xmm2
+; X86AVX-NEXT:    vblendvpd %xmm2, %xmm0, %xmm1, %xmm1
+; X86AVX-NEXT:    vcmpltsd %xmm1, %xmm0, %xmm2
+; X86AVX-NEXT:    vblendvpd %xmm2, %xmm0, %xmm1, %xmm0
+; X86AVX-NEXT:    vmovlpd %xmm0, (%esp)
+; X86AVX-NEXT:    fldl (%esp)
+; X86AVX-NEXT:    movl %ebp, %esp
+; X86AVX-NEXT:    popl %ebp
+; X86AVX-NEXT:    .cfi_def_cfa %esp, 4
+; X86AVX-NEXT:    retl
+entry:
+  %cond = tail call double @llvm.minimumnum.f64(double %a, double %b)
+  ret double %cond
+}
+
+define dso_local double @mind_pzero(double nofpclass(pzero snan) noundef %a, double nofpclass(pzero snan) noundef %b) local_unnamed_addr #0 {
+; SSE2-LABEL: mind_pzero:
+; SSE2:       # %bb.0: # %entry
+; SSE2-NEXT:    movapd %xmm0, %xmm2
+; SSE2-NEXT:    cmpunordsd %xmm0, %xmm2
+; SSE2-NEXT:    movapd %xmm2, %xmm3
+; SSE2-NEXT:    andpd %xmm1, %xmm3
+; SSE2-NEXT:    andnpd %xmm0, %xmm2
+; SSE2-NEXT:    orpd %xmm3, %xmm2
+; SSE2-NEXT:    movapd %xmm1, %xmm3
+; SSE2-NEXT:    cmpunordsd %xmm1, %xmm3
+; SSE2-NEXT:    movapd %xmm3, %xmm0
+; SSE2-NEXT:    andpd %xmm2, %xmm0
+; SSE2-NEXT:    andnpd %xmm1, %xmm3
+; SSE2-NEXT:    orpd %xmm0, %xmm3
+; SSE2-NEXT:    movapd %xmm2, %xmm0
+; SSE2-NEXT:    cmpltsd %xmm3, %xmm0
+; SSE2-NEXT:    andpd %xmm0, %xmm2
+; SSE2-NEXT:    andnpd %xmm3, %xmm0
+; SSE2-NEXT:    orpd %xmm2, %xmm0
+; SSE2-NEXT:    retq
+;
+; AVX-LABEL: mind_pzero:
+; AVX:       # %bb.0: # %entry
+; AVX-NEXT:    vcmpunordsd %xmm0, %xmm0, %xmm2
+; AVX-NEXT:    vblendvpd %xmm2, %xmm1, %xmm0, %xmm0
+; AVX-NEXT:    vcmpunordsd %xmm1, %xmm1, %xmm2
+; AVX-NEXT:    vblendvpd %xmm2, %xmm0, %xmm1, %xmm1
+; AVX-NEXT:    vcmpltsd %xmm1, %xmm0, %xmm2
+; AVX-NEXT:    vblendvpd %xmm2, %xmm0, %xmm1, %xmm0
+; AVX-NEXT:    retq
+;
+; X86-LABEL: mind_pzero:
+; X86:       # %bb.0: # %entry
+; X86-NEXT:    fldl {{[0-9]+}}(%esp)
+; X86-NEXT:    fldl {{[0-9]+}}(%esp)
+; X86-NEXT:    fucom %st(0)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    fld %st(1)
+; X86-NEXT:    jp .LBB10_2
+; X86-NEXT:  # %bb.1: # %entry
+; X86-NEXT:    fstp %st(0)
+; X86-NEXT:    fldz
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:  .LBB10_2: # %entry
+; X86-NEXT:    fstp %st(1)
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:    fucom %st(0)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    fld %st(1)
+; X86-NEXT:    jp .LBB10_4
+; X86-NEXT:  # %bb.3: # %entry
+; X86-NEXT:    fstp %st(0)
+; X86-NEXT:    fldz
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:  .LBB10_4: # %entry
+; X86-NEXT:    fstp %st(1)
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:    fucom %st(1)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    jb .LBB10_6
+; X86-NEXT:  # %bb.5: # %entry
+; X86-NEXT:    fstp %st(0)
+; X86-NEXT:    fldz
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:  .LBB10_6: # %entry
+; X86-NEXT:    fstp %st(1)
+; X86-NEXT:    retl
+;
+; X86AVX-LABEL: mind_pzero:
+; X86AVX:       # %bb.0: # %entry
+; X86AVX-NEXT:    pushl %ebp
+; X86AVX-NEXT:    .cfi_def_cfa_offset 8
+; X86AVX-NEXT:    .cfi_offset %ebp, -8
+; X86AVX-NEXT:    movl %esp, %ebp
+; X86AVX-NEXT:    .cfi_def_cfa_register %ebp
+; X86AVX-NEXT:    andl $-8, %esp
+; X86AVX-NEXT:    subl $8, %esp
+; X86AVX-NEXT:    vmovsd {{.*#+}} xmm0 = mem[0],zero
+; X86AVX-NEXT:    vmovsd {{.*#+}} xmm1 = mem[0],zero
+; X86AVX-NEXT:    vcmpunordsd %xmm0, %xmm0, %xmm2
+; X86AVX-NEXT:    vblendvpd %xmm2, %xmm1, %xmm0, %xmm0
+; X86AVX-NEXT:    vcmpunordsd %xmm1, %xmm1, %xmm2
+; X86AVX-NEXT:    vblendvpd %xmm2, %xmm0, %xmm1, %xmm1
+; X86AVX-NEXT:    vcmpltsd %xmm1, %xmm0, %xmm2
+; X86AVX-NEXT:    vblendvpd %xmm2, %xmm0, %xmm1, %xmm0
+; X86AVX-NEXT:    vmovlpd %xmm0, (%esp)
+; X86AVX-NEXT:    fldl (%esp)
+; X86AVX-NEXT:    movl %ebp, %esp
+; X86AVX-NEXT:    popl %ebp
+; X86AVX-NEXT:    .cfi_def_cfa %esp, 4
+; X86AVX-NEXT:    retl
+entry:
+  %cond = tail call double @llvm.minimumnum.f64(double %a, double %b)
+  ret double %cond
+}
+
+define dso_local double @mind_zero(double nofpclass(zero snan) noundef %a, double nofpclass(zero snan) noundef %b) local_unnamed_addr #0 {
+; SSE2-LABEL: mind_zero:
+; SSE2:       # %bb.0: # %entry
+; SSE2-NEXT:    movapd %xmm0, %xmm2
+; SSE2-NEXT:    cmpunordsd %xmm0, %xmm2
+; SSE2-NEXT:    movapd %xmm2, %xmm3
+; SSE2-NEXT:    andpd %xmm1, %xmm3
+; SSE2-NEXT:    andnpd %xmm0, %xmm2
+; SSE2-NEXT:    orpd %xmm3, %xmm2
+; SSE2-NEXT:    movapd %xmm1, %xmm3
+; SSE2-NEXT:    cmpunordsd %xmm1, %xmm3
+; SSE2-NEXT:    movapd %xmm3, %xmm0
+; SSE2-NEXT:    andpd %xmm2, %xmm0
+; SSE2-NEXT:    andnpd %xmm1, %xmm3
+; SSE2-NEXT:    orpd %xmm0, %xmm3
+; SSE2-NEXT:    movapd %xmm2, %xmm0
+; SSE2-NEXT:    cmpltsd %xmm3, %xmm0
+; SSE2-NEXT:    andpd %xmm0, %xmm2
+; SSE2-NEXT:    andnpd %xmm3, %xmm0
+; SSE2-NEXT:    orpd %xmm2, %xmm0
+; SSE2-NEXT:    retq
+;
+; AVX-LABEL: mind_zero:
+; AVX:       # %bb.0: # %entry
+; AVX-NEXT:    vcmpunordsd %xmm0, %xmm0, %xmm2
+; AVX-NEXT:    vblendvpd %xmm2, %xmm1, %xmm0, %xmm0
+; AVX-NEXT:    vcmpunordsd %xmm1, %xmm1, %xmm2
+; AVX-NEXT:    vblendvpd %xmm2, %xmm0, %xmm1, %xmm1
+; AVX-NEXT:    vcmpltsd %xmm1, %xmm0, %xmm2
+; AVX-NEXT:    vblendvpd %xmm2, %xmm0, %xmm1, %xmm0
+; AVX-NEXT:    retq
+;
+; X86-LABEL: mind_zero:
+; X86:       # %bb.0: # %entry
+; X86-NEXT:    fldl {{[0-9]+}}(%esp)
+; X86-NEXT:    fldl {{[0-9]+}}(%esp)
+; X86-NEXT:    fucom %st(0)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    fld %st(1)
+; X86-NEXT:    jp .LBB11_2
+; X86-NEXT:  # %bb.1: # %entry
+; X86-NEXT:    fstp %st(0)
+; X86-NEXT:    fldz
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:  .LBB11_2: # %entry
+; X86-NEXT:    fstp %st(1)
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:    fucom %st(0)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    fld %st(1)
+; X86-NEXT:    jp .LBB11_4
+; X86-NEXT:  # %bb.3: # %entry
+; X86-NEXT:    fstp %st(0)
+; X86-NEXT:    fldz
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:  .LBB11_4: # %entry
+; X86-NEXT:    fstp %st(1)
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:    fucom %st(1)
+; X86-NEXT:    fnstsw %ax
+; X86-NEXT:    # kill: def $ah killed $ah killed $ax
+; X86-NEXT:    sahf
+; X86-NEXT:    jb .LBB11_6
+; X86-NEXT:  # %bb.5: # %entry
+; X86-NEXT:    fstp %st(0)
+; X86-NEXT:    fldz
+; X86-NEXT:    fxch %st(1)
+; X86-NEXT:  .LBB11_6: # %entry
+; X86-NEXT:    fstp %st(1)
+; X86-NEXT:    retl
+;
+; X86AVX-LABEL: mind_zero:
+; X86AVX:       # %bb.0: # %entry
+; X86AVX-NEXT:    pushl %ebp
+; X86AVX-NEXT:    .cfi_def_cfa_offset 8
+; X86AVX-NEXT:    .cfi_offset %ebp, -8
+; X86AVX-NEXT:    movl %esp, %ebp
+; X86AVX-NEXT:    .cfi_def_cfa_register %ebp
+; X86AVX-NEXT:    andl $-8, %esp
+; X86AVX-NEXT:    subl $8, %esp
+; X86AVX-NEXT:    vmovsd {{.*#+}} xmm0 = mem[0],zero
+; X86AVX-NEXT:    vmovsd {{.*#+}} xmm1 = mem[0],zero
+; X86AVX-NEXT:    vcmpunordsd %xmm0, %xmm0, %xmm2
+; X86AVX-NEXT:    vblendvpd %xmm2, %xmm1, %xmm0, %xmm0
+; X86AVX-NEXT:    vcmpunordsd %xmm1, %xmm1, %xmm2
+; X86AVX-NEXT:    vblendvpd %xmm2, %xmm0, %xmm1, %xmm1
+; X86AVX-NEXT:    vcmpltsd %xmm1, %xmm0, %xmm2
+; X86AVX-NEXT:    vblendvpd %xmm2, %xmm0, %xmm1, %xmm0
+; X86AVX-NEXT:    vmovlpd %xmm0, (%esp)
+; X86AVX-NEXT:    fldl (%esp)
+; X86AVX-NEXT:    movl %ebp, %esp
+; X86AVX-NEXT:    popl %ebp
+; X86AVX-NEXT:    .cfi_def_cfa %esp, 4
+; X86AVX-NEXT:    retl
+entry:
+  %cond = tail call double @llvm.minimumnum.f64(double %a, double %b)
+  ret double %cond
+}



More information about the llvm-commits mailing list