[llvm] d012e03 - [GISel] Use GISelValueTracking in isKnownNeverNaN (#190542)

via llvm-commits llvm-commits at lists.llvm.org
Mon Apr 13 06:42:17 PDT 2026


Author: Tim Gymnich
Date: 2026-04-13T13:42:12Z
New Revision: d012e0380a8f1e16b2720d98b96197084f2e1207

URL: https://github.com/llvm/llvm-project/commit/d012e0380a8f1e16b2720d98b96197084f2e1207
DIFF: https://github.com/llvm/llvm-project/commit/d012e0380a8f1e16b2720d98b96197084f2e1207.diff

LOG: [GISel] Use GISelValueTracking in isKnownNeverNaN (#190542)

Pass GISelValueTracking* through isKnownNeverNaN and isKnownNeverSNaN so
that the implementation can call computeKnownFPClass to derive NaN
information from value tracking, rather than only looking at flags and
direct constant definitions. Update all callers.

Co-Authored-By: Claude Sonnet 4.6 <noreply at anthropic.com>

Added: 
    llvm/test/CodeGen/AMDGPU/GlobalISel/known-fpclass-phi.mir

Modified: 
    llvm/include/llvm/CodeGen/GlobalISel/GISelValueTracking.h
    llvm/include/llvm/CodeGen/GlobalISel/MIPatternMatch.h
    llvm/include/llvm/CodeGen/GlobalISel/Utils.h
    llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
    llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
    llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
    llvm/lib/CodeGen/GlobalISel/Utils.cpp
    llvm/lib/Target/AMDGPU/AMDGPUInstructions.td
    llvm/lib/Target/AMDGPU/AMDGPURegBankCombiner.cpp
    llvm/test/CodeGen/AArch64/known-never-nan.ll
    llvm/test/CodeGen/AMDGPU/GlobalISel/clamp-minmax-const-combine.ll
    llvm/test/CodeGen/AMDGPU/GlobalISel/fmed3-min-max-const-combine.ll
    llvm/test/CodeGen/AMDGPU/GlobalISel/legalize-fmaxnum.mir
    llvm/test/CodeGen/AMDGPU/GlobalISel/legalize-fminnum.mir
    llvm/test/CodeGen/AMDGPU/GlobalISel/regbankcombiner-clamp-minmax-const.mir
    llvm/test/CodeGen/AMDGPU/GlobalISel/regbankcombiner-fmed3-minmax-const.mir
    llvm/test/CodeGen/AMDGPU/fmed3.ll
    llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/CodeGen/GlobalISel/GISelValueTracking.h b/llvm/include/llvm/CodeGen/GlobalISel/GISelValueTracking.h
index 2ce085b8da7b6..5b6cb05553bc9 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/GISelValueTracking.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/GISelValueTracking.h
@@ -142,6 +142,14 @@ class LLVM_ABI GISelValueTracking : public GISelChangeObserver {
                                    FPClassTest InterestedClasses,
                                    unsigned Depth);
 
+  /// Returns true if \p Val can be assumed to never be a NaN. If \p SNaN is
+  /// true, this returns whether \p Val can be assumed to never be a signaling
+  /// NaN.
+  bool isKnownNeverNaN(Register Val, bool SNaN = false);
+
+  /// Returns true if \p Val can be assumed to never be a signaling NaN.
+  bool isKnownNeverSNaN(Register Val) { return isKnownNeverNaN(Val, true); }
+
   // Observer API. No-op for non-caching implementation.
   void erasingInstr(MachineInstr &MI) override {}
   void createdInstr(MachineInstr &MI) override {}

diff  --git a/llvm/include/llvm/CodeGen/GlobalISel/MIPatternMatch.h b/llvm/include/llvm/CodeGen/GlobalISel/MIPatternMatch.h
index 8db99ba4ed883..db1f4a89d3469 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/MIPatternMatch.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/MIPatternMatch.h
@@ -761,6 +761,12 @@ inline UnaryOp_match<SrcTy, TargetOpcode::G_FSQRT> m_GFSqrt(const SrcTy &Src) {
   return UnaryOp_match<SrcTy, TargetOpcode::G_FSQRT>(Src);
 }
 
+template <typename SrcTy>
+inline UnaryOp_match<SrcTy, TargetOpcode::G_FFLOOR>
+m_GFFloor(const SrcTy &Src) {
+  return UnaryOp_match<SrcTy, TargetOpcode::G_FFLOOR>(Src);
+}
+
 // General helper for generic MI compares, i.e. G_ICMP and G_FCMP
 // TODO: Allow checking a specific predicate.
 template <typename Pred_P, typename LHS_P, typename RHS_P, unsigned Opcode,

diff  --git a/llvm/include/llvm/CodeGen/GlobalISel/Utils.h b/llvm/include/llvm/CodeGen/GlobalISel/Utils.h
index de6606e7ed14a..84b4e84f0c64d 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/Utils.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/Utils.h
@@ -338,16 +338,6 @@ LLVM_ABI bool
 isKnownToBeAPowerOfTwo(Register Val, const MachineRegisterInfo &MRI,
                        GISelValueTracking *ValueTracking = nullptr);
 
-/// Returns true if \p Val can be assumed to never be a NaN. If \p SNaN is true,
-/// this returns if \p Val can be assumed to never be a signaling NaN.
-LLVM_ABI bool isKnownNeverNaN(Register Val, const MachineRegisterInfo &MRI,
-                              bool SNaN = false);
-
-/// Returns true if \p Val can be assumed to never be a signaling NaN.
-inline bool isKnownNeverSNaN(Register Val, const MachineRegisterInfo &MRI) {
-  return isKnownNeverNaN(Val, MRI, true);
-}
-
 LLVM_ABI Align inferAlignFromPtrInfo(MachineFunction &MF,
                                      const MachinePointerInfo &MPO);
 

diff  --git a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
index 177170575fe07..0a7d682c44049 100644
--- a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
@@ -7093,8 +7093,8 @@ unsigned CombinerHelper::getFPMinMaxOpcForSelect(
 CombinerHelper::SelectPatternNaNBehaviour
 CombinerHelper::computeRetValAgainstNaN(Register LHS, Register RHS,
                                         bool IsOrderedComparison) const {
-  bool LHSSafe = isKnownNeverNaN(LHS, MRI);
-  bool RHSSafe = isKnownNeverNaN(RHS, MRI);
+  bool LHSSafe = VT->isKnownNeverNaN(LHS);
+  bool RHSSafe = VT->isKnownNeverNaN(RHS);
   // Completely unsafe.
   if (!LHSSafe && !RHSSafe)
     return SelectPatternNaNBehaviour::NOT_APPLICABLE;

diff  --git a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
index a00e17cb3e441..0a58b611c0eca 100644
--- a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
@@ -892,13 +892,6 @@ void GISelValueTracking::computeKnownBitsImpl(Register R, KnownBits &Known,
   LLVM_DEBUG(dumpResult(MI, Known, Depth));
 }
 
-static bool outputDenormalIsIEEEOrPosZero(const MachineFunction &MF, LLT Ty) {
-  Ty = Ty.getScalarType();
-  DenormalMode Mode = MF.getDenormalMode(getFltSemanticForLLT(Ty));
-  return Mode.Output == DenormalMode::IEEE ||
-         Mode.Output == DenormalMode::PositiveZero;
-}
-
 void GISelValueTracking::computeKnownFPClass(Register R, KnownFPClass &Known,
                                              FPClassTest InterestedClasses,
                                              unsigned Depth) {
@@ -908,6 +901,15 @@ void GISelValueTracking::computeKnownFPClass(Register R, KnownFPClass &Known,
   computeKnownFPClass(R, DemandedElts, InterestedClasses, Known, Depth);
 }
 
+/// Return true if this value is known to be the fractional part x - floor(x),
+/// which lies in [0, 1). This implies the value cannot introduce overflow in a
+/// fmul when the other operand is known finite.
+static bool isAbsoluteValueULEOne(Register R, const MachineRegisterInfo &MRI) {
+  using namespace MIPatternMatch;
+  Register SubX;
+  return mi_match(R, MRI, m_GFSub(m_Reg(SubX), m_GFFloor(m_DeferredReg(SubX))));
+}
+
 void GISelValueTracking::computeKnownFPClassForFPTrunc(
     const MachineInstr &MI, const APInt &DemandedElts,
     FPClassTest InterestedClasses, KnownFPClass &Known, unsigned Depth) {
@@ -919,15 +921,7 @@ void GISelValueTracking::computeKnownFPClassForFPTrunc(
   KnownFPClass KnownSrc;
   computeKnownFPClass(Val, DemandedElts, InterestedClasses, KnownSrc,
                       Depth + 1);
-
-  // Sign should be preserved
-  // TODO: Handle cannot be ordered greater than zero
-  if (KnownSrc.cannotBeOrderedLessThanZero())
-    Known.knownNot(KnownFPClass::OrderedLessThanZeroMask);
-
-  Known.propagateNaN(KnownSrc, true);
-
-  // Infinity needs a range check.
+  Known = KnownFPClass::fptrunc(KnownSrc);
 }
 
 void GISelValueTracking::computeKnownFPClass(Register R,
@@ -1096,19 +1090,42 @@ void GISelValueTracking::computeKnownFPClass(Register R,
     Register B = MI.getOperand(2).getReg();
     Register C = MI.getOperand(3).getReg();
 
-    if (A != B)
-      break;
+    DenormalMode Mode =
+        MF->getDenormalMode(getFltSemanticForLLT(DstTy.getScalarType()));
 
-    // The multiply cannot be -0 and therefore the add can't be -0
-    Known.knownNot(fcNegZero);
-
-    // x * x + y is non-negative if y is non-negative.
-    KnownFPClass KnownAddend;
-    computeKnownFPClass(C, DemandedElts, InterestedClasses, KnownAddend,
-                        Depth + 1);
-
-    if (KnownAddend.cannotBeOrderedLessThanZero())
-      Known.knownNot(fcNegative);
+    if (A == B && isGuaranteedNotToBeUndef(A, MRI, Depth + 1)) {
+      // x * x + y
+      KnownFPClass KnownSrc, KnownAddend;
+      computeKnownFPClass(C, DemandedElts, InterestedClasses, KnownAddend,
+                          Depth + 1);
+      computeKnownFPClass(A, DemandedElts, InterestedClasses, KnownSrc,
+                          Depth + 1);
+      if (KnownNotFromFlags) {
+        KnownSrc.knownNot(KnownNotFromFlags);
+        KnownAddend.knownNot(KnownNotFromFlags);
+      }
+      Known = KnownFPClass::fma_square(KnownSrc, KnownAddend, Mode);
+    } else {
+      KnownFPClass KnownSrc[3];
+      computeKnownFPClass(A, DemandedElts, InterestedClasses, KnownSrc[0],
+                          Depth + 1);
+      if (KnownSrc[0].isUnknown())
+        break;
+      computeKnownFPClass(B, DemandedElts, InterestedClasses, KnownSrc[1],
+                          Depth + 1);
+      if (KnownSrc[1].isUnknown())
+        break;
+      computeKnownFPClass(C, DemandedElts, InterestedClasses, KnownSrc[2],
+                          Depth + 1);
+      if (KnownSrc[2].isUnknown())
+        break;
+      if (KnownNotFromFlags) {
+        KnownSrc[0].knownNot(KnownNotFromFlags);
+        KnownSrc[1].knownNot(KnownNotFromFlags);
+        KnownSrc[2].knownNot(KnownNotFromFlags);
+      }
+      Known = KnownFPClass::fma(KnownSrc[0], KnownSrc[1], KnownSrc[2], Mode);
+    }
     break;
   }
   case TargetOpcode::G_FSQRT:
@@ -1119,20 +1136,13 @@ void GISelValueTracking::computeKnownFPClass(Register R,
       InterestedSrcs |= KnownFPClass::OrderedLessThanZeroMask;
 
     Register Val = MI.getOperand(1).getReg();
-
     computeKnownFPClass(Val, DemandedElts, InterestedSrcs, KnownSrc, Depth + 1);
 
-    if (KnownSrc.isKnownNeverPosInfinity())
-      Known.knownNot(fcPosInf);
-    if (KnownSrc.isKnownNever(fcSNan))
-      Known.knownNot(fcSNan);
-
-    // Any negative value besides -0 returns a nan.
-    if (KnownSrc.isKnownNeverNaN() && KnownSrc.cannotBeOrderedLessThanZero())
-      Known.knownNot(fcNan);
-
-    // The only negative value that can be returned is -0 for -0 inputs.
-    Known.knownNot(fcNegInf | fcNegSubnormal | fcNegNormal);
+    DenormalMode Mode =
+        MF->getDenormalMode(getFltSemanticForLLT(DstTy.getScalarType()));
+    Known = KnownFPClass::sqrt(KnownSrc, Mode);
+    if (MI.getFlag(MachineInstr::MIFlag::FmNsz))
+      Known.knownNot(fcNegZero);
     break;
   }
   case TargetOpcode::G_FABS: {
@@ -1146,19 +1156,92 @@ void GISelValueTracking::computeKnownFPClass(Register R,
     Known.fabs();
     break;
   }
+  case TargetOpcode::G_FATAN2: {
+    Register Y = MI.getOperand(1).getReg();
+    Register X = MI.getOperand(2).getReg();
+    KnownFPClass KnownY, KnownX;
+    computeKnownFPClass(Y, DemandedElts, InterestedClasses, KnownY, Depth + 1);
+    computeKnownFPClass(X, DemandedElts, InterestedClasses, KnownX, Depth + 1);
+    Known = KnownFPClass::atan2(KnownY, KnownX);
+    break;
+  }
+  case TargetOpcode::G_FSINH: {
+    Register Val = MI.getOperand(1).getReg();
+    KnownFPClass KnownSrc;
+    computeKnownFPClass(Val, DemandedElts, InterestedClasses, KnownSrc,
+                        Depth + 1);
+    Known = KnownFPClass::sinh(KnownSrc);
+    break;
+  }
+  case TargetOpcode::G_FCOSH: {
+    Register Val = MI.getOperand(1).getReg();
+    KnownFPClass KnownSrc;
+    computeKnownFPClass(Val, DemandedElts, InterestedClasses, KnownSrc,
+                        Depth + 1);
+    Known = KnownFPClass::cosh(KnownSrc);
+    break;
+  }
+  case TargetOpcode::G_FTANH: {
+    Register Val = MI.getOperand(1).getReg();
+    KnownFPClass KnownSrc;
+    computeKnownFPClass(Val, DemandedElts, InterestedClasses, KnownSrc,
+                        Depth + 1);
+    Known = KnownFPClass::tanh(KnownSrc);
+    break;
+  }
+  case TargetOpcode::G_FASIN: {
+    Register Val = MI.getOperand(1).getReg();
+    KnownFPClass KnownSrc;
+    computeKnownFPClass(Val, DemandedElts, InterestedClasses, KnownSrc,
+                        Depth + 1);
+    Known = KnownFPClass::asin(KnownSrc);
+    break;
+  }
+  case TargetOpcode::G_FACOS: {
+    Register Val = MI.getOperand(1).getReg();
+    KnownFPClass KnownSrc;
+    computeKnownFPClass(Val, DemandedElts, InterestedClasses, KnownSrc,
+                        Depth + 1);
+    Known = KnownFPClass::acos(KnownSrc);
+    break;
+  }
+  case TargetOpcode::G_FATAN: {
+    Register Val = MI.getOperand(1).getReg();
+    KnownFPClass KnownSrc;
+    computeKnownFPClass(Val, DemandedElts, InterestedClasses, KnownSrc,
+                        Depth + 1);
+    Known = KnownFPClass::atan(KnownSrc);
+    break;
+  }
+  case TargetOpcode::G_FTAN: {
+    Register Val = MI.getOperand(1).getReg();
+    KnownFPClass KnownSrc;
+    computeKnownFPClass(Val, DemandedElts, InterestedClasses, KnownSrc,
+                        Depth + 1);
+    Known = KnownFPClass::tan(KnownSrc);
+    break;
+  }
   case TargetOpcode::G_FSIN:
-  case TargetOpcode::G_FCOS:
-  case TargetOpcode::G_FSINCOS: {
+  case TargetOpcode::G_FCOS: {
     // Return NaN on infinite inputs.
     Register Val = MI.getOperand(1).getReg();
     KnownFPClass KnownSrc;
-
     computeKnownFPClass(Val, DemandedElts, InterestedClasses, KnownSrc,
                         Depth + 1);
-    Known.knownNot(fcInf);
-
-    if (KnownSrc.isKnownNeverNaN() && KnownSrc.isKnownNeverInfinity())
-      Known.knownNot(fcNan);
+    Known = Opcode == TargetOpcode::G_FCOS ? KnownFPClass::cos(KnownSrc)
+                                           : KnownFPClass::sin(KnownSrc);
+    break;
+  }
+  case TargetOpcode::G_FSINCOS: {
+    // Operand layout: (sin_dst, cos_dst, src)
+    Register Src = MI.getOperand(2).getReg();
+    KnownFPClass KnownSrc;
+    computeKnownFPClass(Src, DemandedElts, InterestedClasses, KnownSrc,
+                        Depth + 1);
+    if (R == MI.getOperand(0).getReg())
+      Known = KnownFPClass::sin(KnownSrc);
+    else
+      Known = KnownFPClass::cos(KnownSrc);
     break;
   }
   case TargetOpcode::G_FMAXNUM:
@@ -1178,99 +1261,35 @@ void GISelValueTracking::computeKnownFPClass(Register R,
     computeKnownFPClass(RHS, DemandedElts, InterestedClasses, KnownRHS,
                         Depth + 1);
 
-    bool NeverNaN = KnownLHS.isKnownNeverNaN() || KnownRHS.isKnownNeverNaN();
-    Known = KnownLHS | KnownRHS;
-
-    // If either operand is not NaN, the result is not NaN.
-    if (NeverNaN && (Opcode == TargetOpcode::G_FMINNUM ||
-                     Opcode == TargetOpcode::G_FMAXNUM ||
-                     Opcode == TargetOpcode::G_FMINIMUMNUM ||
-                     Opcode == TargetOpcode::G_FMAXIMUMNUM))
-      Known.knownNot(fcNan);
-
-    if (Opcode == TargetOpcode::G_FMAXNUM ||
-        Opcode == TargetOpcode::G_FMAXIMUMNUM ||
-        Opcode == TargetOpcode::G_FMAXNUM_IEEE) {
-      // If at least one operand is known to be positive, the result must be
-      // positive.
-      if ((KnownLHS.cannotBeOrderedLessThanZero() &&
-           KnownLHS.isKnownNeverNaN()) ||
-          (KnownRHS.cannotBeOrderedLessThanZero() &&
-           KnownRHS.isKnownNeverNaN()))
-        Known.knownNot(KnownFPClass::OrderedLessThanZeroMask);
-    } else if (Opcode == TargetOpcode::G_FMAXIMUM) {
-      // If at least one operand is known to be positive, the result must be
-      // positive.
-      if (KnownLHS.cannotBeOrderedLessThanZero() ||
-          KnownRHS.cannotBeOrderedLessThanZero())
-        Known.knownNot(KnownFPClass::OrderedLessThanZeroMask);
-    } else if (Opcode == TargetOpcode::G_FMINNUM ||
-               Opcode == TargetOpcode::G_FMINIMUMNUM ||
-               Opcode == TargetOpcode::G_FMINNUM_IEEE) {
-      // If at least one operand is known to be negative, the result must be
-      // negative.
-      if ((KnownLHS.cannotBeOrderedGreaterThanZero() &&
-           KnownLHS.isKnownNeverNaN()) ||
-          (KnownRHS.cannotBeOrderedGreaterThanZero() &&
-           KnownRHS.isKnownNeverNaN()))
-        Known.knownNot(KnownFPClass::OrderedGreaterThanZeroMask);
-    } else if (Opcode == TargetOpcode::G_FMINIMUM) {
-      // If at least one operand is known to be negative, the result must be
-      // negative.
-      if (KnownLHS.cannotBeOrderedGreaterThanZero() ||
-          KnownRHS.cannotBeOrderedGreaterThanZero())
-        Known.knownNot(KnownFPClass::OrderedGreaterThanZeroMask);
-    } else {
-      llvm_unreachable("unhandled intrinsic");
-    }
-
-    // Fixup zero handling if denormals could be returned as a zero.
-    //
-    // As there's no spec for denormal flushing, be conservative with the
-    // treatment of denormals that could be flushed to zero. For older
-    // subtargets on AMDGPU the min/max instructions would not flush the
-    // output and return the original value.
-    //
-    if ((Known.KnownFPClasses & fcZero) != fcNone &&
-        !Known.isKnownNeverSubnormal()) {
-      DenormalMode Mode =
-          MF->getDenormalMode(getFltSemanticForLLT(DstTy.getScalarType()));
-      if (Mode != DenormalMode::getIEEE())
-        Known.KnownFPClasses |= fcZero;
+    KnownFPClass::MinMaxKind Kind;
+    switch (Opcode) {
+    case TargetOpcode::G_FMINIMUM:
+      Kind = KnownFPClass::MinMaxKind::minimum;
+      break;
+    case TargetOpcode::G_FMAXIMUM:
+      Kind = KnownFPClass::MinMaxKind::maximum;
+      break;
+    case TargetOpcode::G_FMINIMUMNUM:
+      Kind = KnownFPClass::MinMaxKind::minimumnum;
+      break;
+    case TargetOpcode::G_FMAXIMUMNUM:
+      Kind = KnownFPClass::MinMaxKind::maximumnum;
+      break;
+    case TargetOpcode::G_FMINNUM:
+    case TargetOpcode::G_FMINNUM_IEEE:
+      Kind = KnownFPClass::MinMaxKind::minnum;
+      break;
+    case TargetOpcode::G_FMAXNUM:
+    case TargetOpcode::G_FMAXNUM_IEEE:
+      Kind = KnownFPClass::MinMaxKind::maxnum;
+      break;
+    default:
+      llvm_unreachable("unhandled min/max opcode");
     }
 
-    if (Known.isKnownNeverNaN()) {
-      if (KnownLHS.SignBit && KnownRHS.SignBit &&
-          *KnownLHS.SignBit == *KnownRHS.SignBit) {
-        if (*KnownLHS.SignBit)
-          Known.signBitMustBeOne();
-        else
-          Known.signBitMustBeZero();
-      } else if ((Opcode == TargetOpcode::G_FMAXIMUM ||
-                  Opcode == TargetOpcode::G_FMINIMUM) ||
-                 Opcode == TargetOpcode::G_FMAXIMUMNUM ||
-                 Opcode == TargetOpcode::G_FMINIMUMNUM ||
-                 Opcode == TargetOpcode::G_FMAXNUM_IEEE ||
-                 Opcode == TargetOpcode::G_FMINNUM_IEEE ||
-                 // FIXME: Should be using logical zero versions
-                 ((KnownLHS.isKnownNeverNegZero() ||
-                   KnownRHS.isKnownNeverPosZero()) &&
-                  (KnownLHS.isKnownNeverPosZero() ||
-                   KnownRHS.isKnownNeverNegZero()))) {
-        if ((Opcode == TargetOpcode::G_FMAXIMUM ||
-             Opcode == TargetOpcode::G_FMAXNUM ||
-             Opcode == TargetOpcode::G_FMAXIMUMNUM ||
-             Opcode == TargetOpcode::G_FMAXNUM_IEEE) &&
-            (KnownLHS.SignBit == false || KnownRHS.SignBit == false))
-          Known.signBitMustBeZero();
-        else if ((Opcode == TargetOpcode::G_FMINIMUM ||
-                  Opcode == TargetOpcode::G_FMINNUM ||
-                  Opcode == TargetOpcode::G_FMINIMUMNUM ||
-                  Opcode == TargetOpcode::G_FMINNUM_IEEE) &&
-                 (KnownLHS.SignBit == true || KnownRHS.SignBit == true))
-          Known.signBitMustBeOne();
-      }
-    }
+    DenormalMode Mode =
+        MF->getDenormalMode(getFltSemanticForLLT(DstTy.getScalarType()));
+    Known = KnownFPClass::minMaxLike(KnownLHS, KnownRHS, Kind, Mode);
     break;
   }
   case TargetOpcode::G_FCANONICALIZE: {
@@ -1279,42 +1298,10 @@ void GISelValueTracking::computeKnownFPClass(Register R,
     computeKnownFPClass(Val, DemandedElts, InterestedClasses, KnownSrc,
                         Depth + 1);
 
-    // This is essentially a stronger form of
-    // propagateCanonicalizingSrc. Other "canonicalizing" operations don't
-    // actually have an IR canonicalization guarantee.
-
-    // Canonicalize may flush denormals to zero, so we have to consider the
-    // denormal mode to preserve known-not-0 knowledge.
-    Known.KnownFPClasses = KnownSrc.KnownFPClasses | fcZero | fcQNan;
-
-    // Stronger version of propagateNaN
-    // Canonicalize is guaranteed to quiet signaling nans.
-    if (KnownSrc.isKnownNeverNaN())
-      Known.knownNot(fcNan);
-    else
-      Known.knownNot(fcSNan);
-
-    // If the parent function flushes denormals, the canonical output cannot
-    // be a denormal.
     LLT Ty = MRI.getType(Val).getScalarType();
     const fltSemantics &FPType = getFltSemanticForLLT(Ty);
     DenormalMode DenormMode = MF->getDenormalMode(FPType);
-    if (DenormMode == DenormalMode::getIEEE()) {
-      if (KnownSrc.isKnownNever(fcPosZero))
-        Known.knownNot(fcPosZero);
-      if (KnownSrc.isKnownNever(fcNegZero))
-        Known.knownNot(fcNegZero);
-      break;
-    }
-
-    if (DenormMode.inputsAreZero() || DenormMode.outputsAreZero())
-      Known.knownNot(fcSubnormal);
-
-    if (DenormMode.Input == DenormalMode::PositiveZero ||
-        (DenormMode.Output == DenormalMode::PositiveZero &&
-         DenormMode.Input == DenormalMode::IEEE))
-      Known.knownNot(fcNegZero);
-
+    Known = KnownFPClass::canonicalize(KnownSrc, DenormMode);
     break;
   }
   case TargetOpcode::G_VECREDUCE_FMAX:
@@ -1332,13 +1319,14 @@ void GISelValueTracking::computeKnownFPClass(Register R,
       Known.SignBit.reset();
     break;
   }
-  case TargetOpcode::G_TRUNC:
   case TargetOpcode::G_FFLOOR:
   case TargetOpcode::G_FCEIL:
   case TargetOpcode::G_FRINT:
   case TargetOpcode::G_FNEARBYINT:
   case TargetOpcode::G_INTRINSIC_FPTRUNC_ROUND:
-  case TargetOpcode::G_INTRINSIC_ROUND: {
+  case TargetOpcode::G_INTRINSIC_ROUND:
+  case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
+  case TargetOpcode::G_INTRINSIC_TRUNC: {
     Register Val = MI.getOperand(1).getReg();
     KnownFPClass KnownSrc;
     FPClassTest InterestedSrcs = InterestedClasses;
@@ -1348,37 +1336,20 @@ void GISelValueTracking::computeKnownFPClass(Register R,
       InterestedSrcs |= fcNegFinite;
     computeKnownFPClass(Val, DemandedElts, InterestedSrcs, KnownSrc, Depth + 1);
 
-    // Integer results cannot be subnormal.
-    Known.knownNot(fcSubnormal);
-
-    Known.propagateNaN(KnownSrc, true);
-
     // TODO: handle multi unit FPTypes once LLT FPInfo lands
-
-    // Negative round ups to 0 produce -0
-    if (KnownSrc.isKnownNever(fcPosFinite))
-      Known.knownNot(fcPosFinite);
-    if (KnownSrc.isKnownNever(fcNegFinite))
-      Known.knownNot(fcNegFinite);
-
+    bool IsTrunc = Opcode == TargetOpcode::G_INTRINSIC_TRUNC;
+    Known = KnownFPClass::roundToIntegral(KnownSrc, IsTrunc,
+                                          /*IsMultiUnitFPType=*/false);
     break;
   }
   case TargetOpcode::G_FEXP:
   case TargetOpcode::G_FEXP2:
   case TargetOpcode::G_FEXP10: {
-    Known.knownNot(fcNegative);
-    if ((InterestedClasses & fcNan) == fcNone)
-      break;
-
     Register Val = MI.getOperand(1).getReg();
     KnownFPClass KnownSrc;
     computeKnownFPClass(Val, DemandedElts, InterestedClasses, KnownSrc,
                         Depth + 1);
-    if (KnownSrc.isKnownNeverNaN()) {
-      Known.knownNot(fcNan);
-      Known.signBitMustBeZero();
-    }
-
+    Known = KnownFPClass::exp(KnownSrc);
     break;
   }
   case TargetOpcode::G_FLOG:
@@ -1395,25 +1366,16 @@ void GISelValueTracking::computeKnownFPClass(Register R,
     if ((InterestedClasses & fcNegInf) != fcNone)
       InterestedSrcs |= fcZero | fcSubnormal;
     if ((InterestedClasses & fcNan) != fcNone)
-      InterestedSrcs |= fcNan | (fcNegative & ~fcNan);
+      InterestedSrcs |= fcNan | fcNegative;
 
     Register Val = MI.getOperand(1).getReg();
     KnownFPClass KnownSrc;
     computeKnownFPClass(Val, DemandedElts, InterestedSrcs, KnownSrc, Depth + 1);
 
-    if (KnownSrc.isKnownNeverPosInfinity())
-      Known.knownNot(fcPosInf);
-
-    if (KnownSrc.isKnownNeverNaN() && KnownSrc.cannotBeOrderedLessThanZero())
-      Known.knownNot(fcNan);
-
     LLT Ty = MRI.getType(Val).getScalarType();
     const fltSemantics &FltSem = getFltSemanticForLLT(Ty);
     DenormalMode Mode = MF->getDenormalMode(FltSem);
-
-    if (KnownSrc.isKnownNeverLogicalZero(Mode))
-      Known.knownNot(fcNegInf);
-
+    Known = KnownFPClass::log(KnownSrc, Mode);
     break;
   }
   case TargetOpcode::G_FPOWI: {
@@ -1425,24 +1387,12 @@ void GISelValueTracking::computeKnownFPClass(Register R,
     KnownBits ExponentKnownBits = getKnownBits(
         Exp, ExpTy.isVector() ? DemandedElts : APInt(1, 1), Depth + 1);
 
-    if (ExponentKnownBits.Zero[0]) { // Is even
-      Known.knownNot(fcNegative);
-      break;
-    }
-
-    // Given that exp is an integer, here are the
-    // ways that pow can return a negative value:
-    //
-    //   pow(-x, exp)   --> negative if exp is odd and x is negative.
-    //   pow(-0, exp)   --> -inf if exp is negative odd.
-    //   pow(-0, exp)   --> -0 if exp is positive odd.
-    //   pow(-inf, exp) --> -0 if exp is negative odd.
-    //   pow(-inf, exp) --> -inf if exp is positive odd.
     Register Val = MI.getOperand(1).getReg();
     KnownFPClass KnownSrc;
-    computeKnownFPClass(Val, DemandedElts, fcNegative, KnownSrc, Depth + 1);
-    if (KnownSrc.isKnownNever(fcNegative))
-      Known.knownNot(fcNegative);
+    if (ExponentKnownBits.isZero() || !ExponentKnownBits.isEven())
+      computeKnownFPClass(Val, DemandedElts, fcNegative, KnownSrc, Depth + 1);
+
+    Known = KnownFPClass::powi(KnownSrc, ExponentKnownBits);
     break;
   }
   case TargetOpcode::G_FLDEXP:
@@ -1451,33 +1401,21 @@ void GISelValueTracking::computeKnownFPClass(Register R,
     KnownFPClass KnownSrc;
     computeKnownFPClass(Val, DemandedElts, InterestedClasses, KnownSrc,
                         Depth + 1);
-    Known.propagateNaN(KnownSrc, /*PropagateSign=*/true);
-
-    // Sign is preserved, but underflows may produce zeroes.
-    if (KnownSrc.isKnownNever(fcNegative))
-      Known.knownNot(fcNegative);
-    else if (KnownSrc.cannotBeOrderedLessThanZero())
-      Known.knownNot(KnownFPClass::OrderedLessThanZeroMask);
-
-    if (KnownSrc.isKnownNever(fcPositive))
-      Known.knownNot(fcPositive);
-    else if (KnownSrc.cannotBeOrderedGreaterThanZero())
-      Known.knownNot(KnownFPClass::OrderedGreaterThanZeroMask);
 
     // Can refine inf/zero handling based on the exponent operand.
     const FPClassTest ExpInfoMask = fcZero | fcSubnormal | fcInf;
-    if ((InterestedClasses & ExpInfoMask) == fcNone)
-      break;
-    if ((KnownSrc.KnownFPClasses & ExpInfoMask) == fcNone)
-      break;
-
-    // TODO: Handle constant range of Exp
+    KnownBits ExpBits;
+    if ((KnownSrc.KnownFPClasses & ExpInfoMask) != fcNone) {
+      Register ExpReg = MI.getOperand(2).getReg();
+      LLT ExpTy = MRI.getType(ExpReg);
+      ExpBits = getKnownBits(
+          ExpReg, ExpTy.isVector() ? DemandedElts : APInt(1, 1), Depth + 1);
+    }
 
-    break;
-  }
-  case TargetOpcode::G_INTRINSIC_ROUNDEVEN: {
-    computeKnownFPClassForFPTrunc(MI, DemandedElts, InterestedClasses, Known,
-                                  Depth);
+    LLT ScalarTy = DstTy.getScalarType();
+    const fltSemantics &Flt = getFltSemanticForLLT(ScalarTy);
+    DenormalMode Mode = MF->getDenormalMode(Flt);
+    Known = KnownFPClass::ldexp(KnownSrc, ExpBits, Flt, Mode);
     break;
   }
   case TargetOpcode::G_FADD:
@@ -1486,112 +1424,88 @@ void GISelValueTracking::computeKnownFPClass(Register R,
   case TargetOpcode::G_STRICT_FSUB: {
     Register LHS = MI.getOperand(1).getReg();
     Register RHS = MI.getOperand(2).getReg();
-    KnownFPClass KnownLHS, KnownRHS;
+    bool IsAdd = (Opcode == TargetOpcode::G_FADD ||
+                  Opcode == TargetOpcode::G_STRICT_FADD);
     bool WantNegative =
-        (Opcode == TargetOpcode::G_FADD ||
-         Opcode == TargetOpcode::G_STRICT_FADD) &&
+        IsAdd &&
         (InterestedClasses & KnownFPClass::OrderedLessThanZeroMask) != fcNone;
     bool WantNaN = (InterestedClasses & fcNan) != fcNone;
     bool WantNegZero = (InterestedClasses & fcNegZero) != fcNone;
 
-    if (!WantNaN && !WantNegative && !WantNegZero)
+    if (!WantNaN && !WantNegative && !WantNegZero) {
       break;
+    }
+
+    DenormalMode Mode =
+        MF->getDenormalMode(getFltSemanticForLLT(DstTy.getScalarType()));
 
     FPClassTest InterestedSrcs = InterestedClasses;
     if (WantNegative)
       InterestedSrcs |= KnownFPClass::OrderedLessThanZeroMask;
     if (InterestedClasses & fcNan)
       InterestedSrcs |= fcInf;
+
+    // Special case fadd x, x (canonical form of fmul x, 2).
+    if (IsAdd && LHS == RHS && isGuaranteedNotToBeUndef(LHS, MRI, Depth + 1)) {
+      KnownFPClass KnownSelf;
+      computeKnownFPClass(LHS, DemandedElts, InterestedSrcs, KnownSelf,
+                          Depth + 1);
+      Known = KnownFPClass::fadd_self(KnownSelf, Mode);
+      break;
+    }
+
+    KnownFPClass KnownLHS, KnownRHS;
     computeKnownFPClass(RHS, DemandedElts, InterestedSrcs, KnownRHS, Depth + 1);
 
     if ((WantNaN && KnownRHS.isKnownNeverNaN()) ||
         (WantNegative && KnownRHS.cannotBeOrderedLessThanZero()) ||
-        WantNegZero ||
-        (Opcode == TargetOpcode::G_FSUB ||
-         Opcode == TargetOpcode::G_STRICT_FSUB)) {
-
+        WantNegZero || !IsAdd) {
       // RHS is canonically cheaper to compute. Skip inspecting the LHS if
       // there's no point.
       computeKnownFPClass(LHS, DemandedElts, InterestedSrcs, KnownLHS,
                           Depth + 1);
-      // Adding positive and negative infinity produces NaN.
-      // TODO: Check sign of infinities.
-      if (KnownLHS.isKnownNeverNaN() && KnownRHS.isKnownNeverNaN() &&
-          (KnownLHS.isKnownNeverInfinity() || KnownRHS.isKnownNeverInfinity()))
-        Known.knownNot(fcNan);
-
-      if (Opcode == TargetOpcode::G_FADD ||
-          Opcode == TargetOpcode::G_STRICT_FADD) {
-        if (KnownLHS.cannotBeOrderedLessThanZero() &&
-            KnownRHS.cannotBeOrderedLessThanZero())
-          Known.knownNot(KnownFPClass::OrderedLessThanZeroMask);
-
-        // (fadd x, 0.0) is guaranteed to return +0.0, not -0.0.
-        if ((KnownLHS.isKnownNeverLogicalNegZero(MF->getDenormalMode(
-                 getFltSemanticForLLT(DstTy.getScalarType()))) ||
-             KnownRHS.isKnownNeverLogicalNegZero(MF->getDenormalMode(
-                 getFltSemanticForLLT(DstTy.getScalarType())))) &&
-            // Make sure output negative denormal can't flush to -0
-            outputDenormalIsIEEEOrPosZero(*MF, DstTy))
-          Known.knownNot(fcNegZero);
-      } else {
-        // Only fsub -0, +0 can return -0
-        if ((KnownLHS.isKnownNeverLogicalNegZero(MF->getDenormalMode(
-                 getFltSemanticForLLT(DstTy.getScalarType()))) ||
-             KnownRHS.isKnownNeverLogicalPosZero(MF->getDenormalMode(
-                 getFltSemanticForLLT(DstTy.getScalarType())))) &&
-            // Make sure output negative denormal can't flush to -0
-            outputDenormalIsIEEEOrPosZero(*MF, DstTy))
-          Known.knownNot(fcNegZero);
-      }
     }
 
+    if (IsAdd)
+      Known = KnownFPClass::fadd(KnownLHS, KnownRHS, Mode);
+    else
+      Known = KnownFPClass::fsub(KnownLHS, KnownRHS, Mode);
     break;
   }
   case TargetOpcode::G_FMUL:
   case TargetOpcode::G_STRICT_FMUL: {
     Register LHS = MI.getOperand(1).getReg();
     Register RHS = MI.getOperand(2).getReg();
-    // X * X is always non-negative or a NaN.
-    if (LHS == RHS)
-      Known.knownNot(fcNegative);
-
-    if ((InterestedClasses & fcNan) != fcNan)
-      break;
-
-    // fcSubnormal is only needed in case of DAZ.
-    const FPClassTest NeedForNan = fcNan | fcInf | fcZero | fcSubnormal;
-
-    KnownFPClass KnownLHS, KnownRHS;
-    computeKnownFPClass(RHS, DemandedElts, NeedForNan, KnownRHS, Depth + 1);
-    if (!KnownRHS.isKnownNeverNaN())
-      break;
-
-    computeKnownFPClass(LHS, DemandedElts, NeedForNan, KnownLHS, Depth + 1);
-    if (!KnownLHS.isKnownNeverNaN())
-      break;
-
-    if (KnownLHS.SignBit && KnownRHS.SignBit) {
-      if (*KnownLHS.SignBit == *KnownRHS.SignBit)
-        Known.signBitMustBeZero();
-      else
-        Known.signBitMustBeOne();
-    }
-
-    // If 0 * +/-inf produces NaN.
-    if (KnownLHS.isKnownNeverInfinity() && KnownRHS.isKnownNeverInfinity()) {
-      Known.knownNot(fcNan);
-      break;
+    DenormalMode Mode =
+        MF->getDenormalMode(getFltSemanticForLLT(DstTy.getScalarType()));
+
+    // X * X is always non-negative or a NaN (use square() for precision).
+    if (LHS == RHS && isGuaranteedNotToBeUndef(LHS, MRI, Depth + 1)) {
+      KnownFPClass KnownSrc;
+      computeKnownFPClass(LHS, DemandedElts, fcAllFlags, KnownSrc, Depth + 1);
+      Known = KnownFPClass::square(KnownSrc, Mode);
+    } else {
+      // If RHS is a scalar constant, use the more precise APFloat overload.
+      auto RHSCst = GFConstant::getConstant(RHS, MRI);
+      if (RHSCst && RHSCst->getKind() == GFConstant::GFConstantKind::Scalar) {
+        KnownFPClass KnownLHS;
+        computeKnownFPClass(LHS, DemandedElts, fcAllFlags, KnownLHS, Depth + 1);
+        Known = KnownFPClass::fmul(KnownLHS, RHSCst->getScalarValue(), Mode);
+      } else {
+        KnownFPClass KnownLHS, KnownRHS;
+        computeKnownFPClass(RHS, DemandedElts, fcAllFlags, KnownRHS, Depth + 1);
+        computeKnownFPClass(LHS, DemandedElts, fcAllFlags, KnownLHS, Depth + 1);
+        Known = KnownFPClass::fmul(KnownLHS, KnownRHS, Mode);
+
+        // If one operand is known |x| <= 1 and the other is finite, the
+        // product cannot overflow to infinity.
+        if (KnownLHS.isKnownNever(fcInf) && isAbsoluteValueULEOne(RHS, MRI))
+          Known.knownNot(fcInf);
+        else if (KnownRHS.isKnownNever(fcInf) &&
+                 isAbsoluteValueULEOne(LHS, MRI))
+          Known.knownNot(fcInf);
+      }
     }
-
-    if ((KnownRHS.isKnownNeverInfinity() ||
-         KnownLHS.isKnownNeverLogicalZero(MF->getDenormalMode(
-             getFltSemanticForLLT(DstTy.getScalarType())))) &&
-        (KnownLHS.isKnownNeverInfinity() ||
-         KnownRHS.isKnownNeverLogicalZero(
-             MF->getDenormalMode(getFltSemanticForLLT(DstTy.getScalarType())))))
-      Known.knownNot(fcNan);
-
     break;
   }
   case TargetOpcode::G_FDIV:
@@ -1599,16 +1513,38 @@ void GISelValueTracking::computeKnownFPClass(Register R,
     Register LHS = MI.getOperand(1).getReg();
     Register RHS = MI.getOperand(2).getReg();
 
-    if (LHS == RHS) {
-      // TODO: Could filter out snan if we inspect the operand
+    if (Opcode == TargetOpcode::G_FREM)
+      Known.knownNot(fcInf);
+
+    DenormalMode Mode =
+        MF->getDenormalMode(getFltSemanticForLLT(DstTy.getScalarType()));
+
+    if (LHS == RHS && isGuaranteedNotToBeUndef(LHS, MRI, Depth + 1)) {
       if (Opcode == TargetOpcode::G_FDIV) {
-        // X / X is always exactly 1.0 or a NaN.
-        Known.KnownFPClasses = fcNan | fcPosNormal;
+        const bool WantNan = (InterestedClasses & fcNan) != fcNone;
+        if (!WantNan) {
+          // X / X is always exactly 1.0 or a NaN.
+          Known.KnownFPClasses = fcPosNormal | fcNan;
+          break;
+        }
+        KnownFPClass KnownSrc;
+        computeKnownFPClass(LHS, DemandedElts,
+                            fcNan | fcInf | fcZero | fcSubnormal, KnownSrc,
+                            Depth + 1);
+        Known = KnownFPClass::fdiv_self(KnownSrc, Mode);
       } else {
-        // X % X is always exactly [+-]0.0 or a NaN.
-        Known.KnownFPClasses = fcNan | fcZero;
+        const bool WantNan = (InterestedClasses & fcNan) != fcNone;
+        if (!WantNan) {
+          // X % X is always exactly [+-]0.0 or a NaN.
+          Known.KnownFPClasses = fcZero | fcNan;
+          break;
+        }
+        KnownFPClass KnownSrc;
+        computeKnownFPClass(LHS, DemandedElts,
+                            fcNan | fcInf | fcZero | fcSubnormal, KnownSrc,
+                            Depth + 1);
+        Known = KnownFPClass::frem_self(KnownSrc, Mode);
       }
-
       break;
     }
 
@@ -1616,49 +1552,30 @@ void GISelValueTracking::computeKnownFPClass(Register R,
     const bool WantNegative = (InterestedClasses & fcNegative) != fcNone;
     const bool WantPositive = Opcode == TargetOpcode::G_FREM &&
                               (InterestedClasses & fcPositive) != fcNone;
-    if (!WantNan && !WantNegative && !WantPositive)
+    if (!WantNan && !WantNegative && !WantPositive) {
       break;
+    }
 
     KnownFPClass KnownLHS, KnownRHS;
 
     computeKnownFPClass(RHS, DemandedElts, fcNan | fcInf | fcZero | fcNegative,
                         KnownRHS, Depth + 1);
 
-    bool KnowSomethingUseful =
-        KnownRHS.isKnownNeverNaN() || KnownRHS.isKnownNever(fcNegative);
+    bool KnowSomethingUseful = KnownRHS.isKnownNeverNaN() ||
+                               KnownRHS.isKnownNever(fcNegative) ||
+                               KnownRHS.isKnownNever(fcPositive);
 
     if (KnowSomethingUseful || WantPositive) {
-      const FPClassTest InterestedLHS =
-          WantPositive ? fcAllFlags
-                       : fcNan | fcInf | fcZero | fcSubnormal | fcNegative;
-
-      computeKnownFPClass(LHS, DemandedElts, InterestedClasses & InterestedLHS,
-                          KnownLHS, Depth + 1);
+      computeKnownFPClass(LHS, DemandedElts, fcAllFlags, KnownLHS, Depth + 1);
     }
 
     if (Opcode == TargetOpcode::G_FDIV) {
-      // Only 0/0, Inf/Inf produce NaN.
-      if (KnownLHS.isKnownNeverNaN() && KnownRHS.isKnownNeverNaN() &&
-          (KnownLHS.isKnownNeverInfinity() ||
-           KnownRHS.isKnownNeverInfinity()) &&
-          ((KnownLHS.isKnownNeverLogicalZero(MF->getDenormalMode(
-               getFltSemanticForLLT(DstTy.getScalarType())))) ||
-           (KnownRHS.isKnownNeverLogicalZero(MF->getDenormalMode(
-               getFltSemanticForLLT(DstTy.getScalarType())))))) {
-        Known.knownNot(fcNan);
-      }
-
-      // X / -0.0 is -Inf (or NaN).
-      // +X / +X is +X
-      if (KnownLHS.isKnownNever(fcNegative) &&
-          KnownRHS.isKnownNever(fcNegative))
-        Known.knownNot(fcNegative);
+      Known = KnownFPClass::fdiv(KnownLHS, KnownRHS, Mode);
     } else {
       // Inf REM x and x REM 0 produce NaN.
       if (KnownLHS.isKnownNeverNaN() && KnownRHS.isKnownNeverNaN() &&
           KnownLHS.isKnownNeverInfinity() &&
-          KnownRHS.isKnownNeverLogicalZero(MF->getDenormalMode(
-              getFltSemanticForLLT(DstTy.getScalarType())))) {
+          KnownRHS.isKnownNeverLogicalZero(Mode)) {
         Known.knownNot(fcNan);
       }
 
@@ -1674,32 +1591,33 @@ void GISelValueTracking::computeKnownFPClass(Register R,
       if (KnownLHS.isKnownNever(fcPositive))
         Known.knownNot(fcPositive);
     }
-
+    break;
+  }
+  case TargetOpcode::G_FFREXP: {
+    // Only handle the mantissa output (operand 0); the exponent is an integer.
+    if (R != MI.getOperand(0).getReg())
+      break;
+    Register Src = MI.getOperand(2).getReg();
+    KnownFPClass KnownSrc;
+    computeKnownFPClass(Src, DemandedElts, InterestedClasses, KnownSrc,
+                        Depth + 1);
+    DenormalMode Mode =
+        MF->getDenormalMode(getFltSemanticForLLT(DstTy.getScalarType()));
+    Known = KnownFPClass::frexp_mant(KnownSrc, Mode);
     break;
   }
   case TargetOpcode::G_FPEXT: {
-    Register Dst = MI.getOperand(0).getReg();
     Register Src = MI.getOperand(1).getReg();
-    // Infinity, nan and zero propagate from source.
-    computeKnownFPClass(R, DemandedElts, InterestedClasses, Known, Depth + 1);
+    KnownFPClass KnownSrc;
+    computeKnownFPClass(Src, DemandedElts, InterestedClasses, KnownSrc,
+                        Depth + 1);
 
-    LLT DstTy = MRI.getType(Dst).getScalarType();
-    const fltSemantics &DstSem = getFltSemanticForLLT(DstTy);
+    LLT DstScalarTy = DstTy.getScalarType();
+    const fltSemantics &DstSem = getFltSemanticForLLT(DstScalarTy);
     LLT SrcTy = MRI.getType(Src).getScalarType();
     const fltSemantics &SrcSem = getFltSemanticForLLT(SrcTy);
 
-    // All subnormal inputs should be in the normal range in the result type.
-    if (APFloat::isRepresentableAsNormalIn(SrcSem, DstSem)) {
-      if (Known.KnownFPClasses & fcPosSubnormal)
-        Known.KnownFPClasses |= fcPosNormal;
-      if (Known.KnownFPClasses & fcNegSubnormal)
-        Known.KnownFPClasses |= fcNegNormal;
-      Known.knownNot(fcSubnormal);
-    }
-
-    // Sign bit of a nan isn't guaranteed.
-    if (!Known.isKnownNeverNaN())
-      Known.SignBit = std::nullopt;
+    Known = KnownFPClass::fpext(KnownSrc, DstSem, SrcSem);
     break;
   }
   case TargetOpcode::G_FPTRUNC: {
@@ -1717,24 +1635,48 @@ void GISelValueTracking::computeKnownFPClass(Register R,
 
     // sitofp and uitofp turn into +0.0 for zero.
     Known.knownNot(fcNegZero);
+
+    // UIToFP is always non-negative regardless of known bits.
     if (Opcode == TargetOpcode::G_UITOFP)
       Known.signBitMustBeZero();
 
+    // Only compute known bits if we can learn something useful from them.
+    if (!(InterestedClasses & (fcPosZero | fcNormal | fcInf)))
+      break;
+
     Register Val = MI.getOperand(1).getReg();
     LLT Ty = MRI.getType(Val);
+    KnownBits IntKnown = getKnownBits(
+        Val, Ty.isVector() ? DemandedElts : APInt(1, 1), Depth + 1);
+
+    // If the integer is non-zero, the result cannot be +0.0.
+    if (IntKnown.isNonZero())
+      Known.knownNot(fcPosZero);
+
+    if (Opcode == TargetOpcode::G_SITOFP) {
+      // If the signed integer is known non-negative, the result is
+      // non-negative. If the signed integer is known negative, the result is
+      // negative.
+      if (IntKnown.isNonNegative())
+        Known.signBitMustBeZero();
+      else if (IntKnown.isNegative())
+        Known.signBitMustBeOne();
+    }
 
     if (InterestedClasses & fcInf) {
-      // Get width of largest magnitude integer (remove a bit if signed).
-      // This still works for a signed minimum value because the largest FP
-      // value is scaled by some fraction close to 2.0 (1.0 + 0.xxxx).;
-      int IntSize = Ty.getScalarSizeInBits();
-      if (Opcode == TargetOpcode::G_SITOFP)
-        --IntSize;
+      LLT FPTy = DstTy.getScalarType();
+      const fltSemantics &FltSem = getFltSemanticForLLT(FPTy);
+
+      // Compute the effective integer width after removing known-zero leading
+      // bits, to check if the result can overflow to infinity.
+      int IntSize = IntKnown.getBitWidth();
+      if (Opcode == TargetOpcode::G_UITOFP)
+        IntSize -= IntKnown.countMinLeadingZeros();
+      else
+        IntSize -= IntKnown.countMinSignBits();
 
       // If the exponent of the largest finite FP value can hold the largest
       // integer, the result of the cast must be finite.
-      LLT FPTy = DstTy.getScalarType();
-      const fltSemantics &FltSem = getFltSemanticForLLT(FPTy);
       if (ilogb(APFloat::getLargest(FltSem)) >= IntSize)
         Known.knownNot(fcInf);
     }
@@ -1877,6 +1819,33 @@ void GISelValueTracking::computeKnownFPClass(Register R,
     }
     break;
   }
+  case TargetOpcode::G_PHI: {
+    // Cap PHI recursion below the global limit to avoid spending the entire
+    // budget chasing loop back-edges (matches ValueTracking's
+    // PhiRecursionLimit).
+    if (Depth + 2 > MaxAnalysisRecursionDepth)
+      break;
+    // PHI's operands are a mix of registers and basic blocks interleaved.
+    // We only care about the register ones.
+    bool First = true;
+    for (unsigned Idx = 1; Idx < MI.getNumOperands(); Idx += 2) {
+      const MachineOperand &Src = MI.getOperand(Idx);
+      Register SrcReg = Src.getReg();
+      if (First) {
+        computeKnownFPClass(SrcReg, DemandedElts, InterestedClasses, Known,
+                            Depth + 1);
+        First = false;
+      } else {
+        KnownFPClass Known2;
+        computeKnownFPClass(SrcReg, DemandedElts, InterestedClasses, Known2,
+                            Depth + 1);
+        Known = Known.intersectWith(Known2);
+      }
+      if (Known.isUnknown())
+        break;
+    }
+    break;
+  }
   case TargetOpcode::COPY: {
     Register Src = MI.getOperand(1).getReg();
 
@@ -1931,6 +1900,88 @@ KnownFPClass GISelValueTracking::computeKnownFPClass(
   return computeKnownFPClass(R, DemandedElts, Flags, InterestedClasses, Depth);
 }
 
+bool GISelValueTracking::isKnownNeverNaN(Register Val, bool SNaN) {
+  const MachineInstr *DefMI = MRI.getVRegDef(Val);
+  if (!DefMI)
+    return false;
+
+  if (DefMI->getFlag(MachineInstr::FmNoNans))
+    return true;
+
+  // IEEE 754 arithmetic operations always quiet signaling NaNs. Short-circuit
+  // the value-tracking analysis for the SNaN-only case: if the defining op is
+  // known to quiet sNaN, the output can never be an sNaN.
+  if (SNaN) {
+    switch (DefMI->getOpcode()) {
+    default:
+      break;
+    case TargetOpcode::G_FADD:
+    case TargetOpcode::G_STRICT_FADD:
+    case TargetOpcode::G_FSUB:
+    case TargetOpcode::G_STRICT_FSUB:
+    case TargetOpcode::G_FMUL:
+    case TargetOpcode::G_STRICT_FMUL:
+    case TargetOpcode::G_FDIV:
+    case TargetOpcode::G_FREM:
+    case TargetOpcode::G_FMA:
+    case TargetOpcode::G_STRICT_FMA:
+    case TargetOpcode::G_FMAD:
+    case TargetOpcode::G_FSQRT:
+    case TargetOpcode::G_STRICT_FSQRT:
+    // Note: G_FABS and G_FNEG are bit-manipulation ops that preserve sNaN
+    // exactly (LLVM LangRef: "never change anything except possibly the sign
+    // bit"). They must NOT be listed here.
+    case TargetOpcode::G_FSIN:
+    case TargetOpcode::G_FCOS:
+    case TargetOpcode::G_FSINCOS:
+    case TargetOpcode::G_FTAN:
+    case TargetOpcode::G_FASIN:
+    case TargetOpcode::G_FACOS:
+    case TargetOpcode::G_FATAN:
+    case TargetOpcode::G_FATAN2:
+    case TargetOpcode::G_FSINH:
+    case TargetOpcode::G_FCOSH:
+    case TargetOpcode::G_FTANH:
+    case TargetOpcode::G_FEXP:
+    case TargetOpcode::G_FEXP2:
+    case TargetOpcode::G_FEXP10:
+    case TargetOpcode::G_FLOG:
+    case TargetOpcode::G_FLOG2:
+    case TargetOpcode::G_FLOG10:
+    case TargetOpcode::G_FPOWI:
+    case TargetOpcode::G_FLDEXP:
+    case TargetOpcode::G_STRICT_FLDEXP:
+    case TargetOpcode::G_FFREXP:
+    case TargetOpcode::G_INTRINSIC_TRUNC:
+    case TargetOpcode::G_INTRINSIC_ROUND:
+    case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
+    case TargetOpcode::G_FFLOOR:
+    case TargetOpcode::G_FCEIL:
+    case TargetOpcode::G_FRINT:
+    case TargetOpcode::G_FNEARBYINT:
+    case TargetOpcode::G_FPEXT:
+    case TargetOpcode::G_FPTRUNC:
+    case TargetOpcode::G_FCANONICALIZE:
+    case TargetOpcode::G_FMINNUM:
+    case TargetOpcode::G_FMAXNUM:
+    case TargetOpcode::G_FMINNUM_IEEE:
+    case TargetOpcode::G_FMAXNUM_IEEE:
+    case TargetOpcode::G_FMINIMUM:
+    case TargetOpcode::G_FMAXIMUM:
+    case TargetOpcode::G_FMINIMUMNUM:
+    case TargetOpcode::G_FMAXIMUMNUM:
+      return true;
+    }
+  }
+
+  KnownFPClass FPClass = computeKnownFPClass(Val, SNaN ? fcSNan : fcNan);
+
+  if (SNaN)
+    return FPClass.isKnownNever(fcSNan);
+
+  return FPClass.isKnownNeverNaN();
+}
+
 /// Compute number of sign bits for the intersection of \p Src0 and \p Src1
 unsigned GISelValueTracking::computeNumSignBitsMin(Register Src0, Register Src1,
                                                    const APInt &DemandedElts,

diff  --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index b3a51f9fd5761..e78dfb0565439 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -8968,10 +8968,10 @@ LegalizerHelper::lowerFMinNumMaxNum(MachineInstr &MI) {
     // Note this must be done here, and not as an optimization combine in the
     // absence of a dedicate quiet-snan instruction as we're using an
     // omni-purpose G_FCANONICALIZE.
-    if (!isKnownNeverSNaN(Src0, MRI))
+    if (!VT->isKnownNeverSNaN(Src0))
       Src0 = MIRBuilder.buildFCanonicalize(Ty, Src0, MI.getFlags()).getReg(0);
 
-    if (!isKnownNeverSNaN(Src1, MRI))
+    if (!VT->isKnownNeverSNaN(Src1))
       Src1 = MIRBuilder.buildFCanonicalize(Ty, Src1, MI.getFlags()).getReg(0);
   }
 
@@ -9011,7 +9011,7 @@ LegalizerHelper::lowerFMinimumMaximum(MachineInstr &MI) {
 
   // Propagate any NaN of both operands
   if (!MI.getFlag(MachineInstr::FmNoNans) &&
-      (!isKnownNeverNaN(Src0, MRI) || !isKnownNeverNaN(Src1, MRI))) {
+      (!VT->isKnownNeverNaN(Src0) || !VT->isKnownNeverNaN(Src1))) {
     auto IsOrdered = MIRBuilder.buildFCmp(CmpInst::FCMP_ORD, CmpTy, Src0, Src1);
 
     LLT ElementTy = Ty.isScalar() ? Ty : Ty.getElementType();

diff  --git a/llvm/lib/CodeGen/GlobalISel/Utils.cpp b/llvm/lib/CodeGen/GlobalISel/Utils.cpp
index dacea8e2bbf57..ee0aaf9a49994 100644
--- a/llvm/lib/CodeGen/GlobalISel/Utils.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/Utils.cpp
@@ -837,89 +837,6 @@ llvm::ConstantFoldVectorBinop(unsigned Opcode, const Register Op1,
   return FoldedElements;
 }
 
-bool llvm::isKnownNeverNaN(Register Val, const MachineRegisterInfo &MRI,
-                           bool SNaN) {
-  const MachineInstr *DefMI = MRI.getVRegDef(Val);
-  if (!DefMI)
-    return false;
-
-  if (DefMI->getFlag(MachineInstr::FmNoNans))
-    return true;
-
-  // If the value is a constant, we can obviously see if it is a NaN or not.
-  if (const ConstantFP *FPVal = getConstantFPVRegVal(Val, MRI)) {
-    return !FPVal->getValueAPF().isNaN() ||
-           (SNaN && !FPVal->getValueAPF().isSignaling());
-  }
-
-  if (DefMI->getOpcode() == TargetOpcode::G_BUILD_VECTOR) {
-    for (const auto &Op : DefMI->uses())
-      if (!isKnownNeverNaN(Op.getReg(), MRI, SNaN))
-        return false;
-    return true;
-  }
-
-  switch (DefMI->getOpcode()) {
-  default:
-    break;
-  case TargetOpcode::G_FADD:
-  case TargetOpcode::G_FSUB:
-  case TargetOpcode::G_FMUL:
-  case TargetOpcode::G_FDIV:
-  case TargetOpcode::G_FREM:
-  case TargetOpcode::G_FSIN:
-  case TargetOpcode::G_FCOS:
-  case TargetOpcode::G_FTAN:
-  case TargetOpcode::G_FACOS:
-  case TargetOpcode::G_FASIN:
-  case TargetOpcode::G_FATAN:
-  case TargetOpcode::G_FATAN2:
-  case TargetOpcode::G_FCOSH:
-  case TargetOpcode::G_FSINH:
-  case TargetOpcode::G_FTANH:
-  case TargetOpcode::G_FMA:
-  case TargetOpcode::G_FMAD:
-    if (SNaN)
-      return true;
-
-    // TODO: Need isKnownNeverInfinity
-    return false;
-  case TargetOpcode::G_FMINNUM_IEEE:
-  case TargetOpcode::G_FMAXNUM_IEEE: {
-    if (SNaN)
-      return true;
-    // This can return a NaN if either operand is an sNaN, or if both operands
-    // are NaN.
-    return (isKnownNeverNaN(DefMI->getOperand(1).getReg(), MRI) &&
-            isKnownNeverSNaN(DefMI->getOperand(2).getReg(), MRI)) ||
-           (isKnownNeverSNaN(DefMI->getOperand(1).getReg(), MRI) &&
-            isKnownNeverNaN(DefMI->getOperand(2).getReg(), MRI));
-  }
-  case TargetOpcode::G_FMINNUM:
-  case TargetOpcode::G_FMAXNUM: {
-    // Only one needs to be known not-nan, since it will be returned if the
-    // other ends up being one.
-    return isKnownNeverNaN(DefMI->getOperand(1).getReg(), MRI, SNaN) ||
-           isKnownNeverNaN(DefMI->getOperand(2).getReg(), MRI, SNaN);
-  }
-  }
-
-  if (SNaN) {
-    // FP operations quiet. For now, just handle the ones inserted during
-    // legalization.
-    switch (DefMI->getOpcode()) {
-    case TargetOpcode::G_FPEXT:
-    case TargetOpcode::G_FPTRUNC:
-    case TargetOpcode::G_FCANONICALIZE:
-      return true;
-    default:
-      return false;
-    }
-  }
-
-  return false;
-}
-
 Align llvm::inferAlignFromPtrInfo(MachineFunction &MF,
                                   const MachinePointerInfo &MPO) {
   auto PSV = dyn_cast_if_present<const PseudoSourceValue *>(MPO.V);

diff  --git a/llvm/lib/Target/AMDGPU/AMDGPUInstructions.td b/llvm/lib/Target/AMDGPU/AMDGPUInstructions.td
index 9b6443a99ac55..2814482f5a73a 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUInstructions.td
+++ b/llvm/lib/Target/AMDGPU/AMDGPUInstructions.td
@@ -844,7 +844,7 @@ class NeverNaNPats<dag ops, list<dag> frags> : PatFrags<ops, frags> {
     return CurDAG->isKnownNeverNaN(SDValue(N,0));
   }];
   let GISelPredicateCode = [{
-    return isKnownNeverNaN(MI.getOperand(0).getReg(), MRI);
+    return VT->isKnownNeverNaN(MI.getOperand(0).getReg());
   }];
 }
 

diff  --git a/llvm/lib/Target/AMDGPU/AMDGPURegBankCombiner.cpp b/llvm/lib/Target/AMDGPU/AMDGPURegBankCombiner.cpp
index 0e1d4075ed92e..990d879c2bf09 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPURegBankCombiner.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPURegBankCombiner.cpp
@@ -265,7 +265,7 @@ bool AMDGPURegBankCombinerImpl::matchFPMinMaxToMed3(
   // nodes(max/min) have same behavior when one input is NaN and other isn't.
   // Don't consider max(min(SNaN, K1), K0) since there is no isKnownNeverQNaN,
   // also post-legalizer inputs to min/max are fcanonicalized (never SNaN).
-  if ((getIEEE() && isFminnumIeee(MI)) || isKnownNeverNaN(Dst, MRI)) {
+  if ((getIEEE() && isFminnumIeee(MI)) || VT->isKnownNeverNaN(Dst)) {
     // Don't fold single use constant that can't be inlined.
     if ((!MRI.hasOneNonDBGUse(K0->VReg) || TII.isInlineConstant(K0->Value)) &&
         (!MRI.hasOneNonDBGUse(K1->VReg) || TII.isInlineConstant(K1->Value))) {
@@ -295,8 +295,8 @@ bool AMDGPURegBankCombinerImpl::matchFPMinMaxToClamp(MachineInstr &MI,
   // For IEEE=true consider NaN inputs. Only min(max(QNaN, 0.0), 1.0) evaluates
   // to 0.0 requires dx10_clamp = true.
   if ((getIEEE() && getDX10Clamp() && isFminnumIeee(MI) &&
-       isKnownNeverSNaN(Val, MRI)) ||
-      isKnownNeverNaN(MI.getOperand(0).getReg(), MRI)) {
+       VT->isKnownNeverSNaN(Val)) ||
+      VT->isKnownNeverNaN(MI.getOperand(0).getReg())) {
     Reg = Val;
     return true;
   }
@@ -342,9 +342,9 @@ bool AMDGPURegBankCombinerImpl::matchFPMed3ToClamp(MachineInstr &MI,
   // no NaN inputs. Most often MI is marked with nnan fast math flag.
   // For IEEE=true consider NaN inputs. Requires dx10_clamp = true. Safe to fold
   // when Val could be QNaN. If Val can also be SNaN third input should be 0.0.
-  if (isKnownNeverNaN(MI.getOperand(0).getReg(), MRI) ||
+  if (VT->isKnownNeverNaN(MI.getOperand(0).getReg()) ||
       (getIEEE() && getDX10Clamp() &&
-       (isKnownNeverSNaN(Val, MRI) || isOp3Zero()))) {
+       (VT->isKnownNeverSNaN(Val) || isOp3Zero()))) {
     Reg = Val;
     return true;
   }

diff  --git a/llvm/test/CodeGen/AArch64/known-never-nan.ll b/llvm/test/CodeGen/AArch64/known-never-nan.ll
index bd080e29890e2..13f14dda19e84 100644
--- a/llvm/test/CodeGen/AArch64/known-never-nan.ll
+++ b/llvm/test/CodeGen/AArch64/known-never-nan.ll
@@ -27,18 +27,30 @@ define float @fmaxnm(i32 %i1, i32 %i2) #0 {
 ; If f1 is 0, fmul is NaN because 0.0 * -INF = NaN
 ; Therefore, this is not fmaxnm.
 define float @not_fmaxnm_maybe_nan(i32 %i1, i32 %i2) #0 {
-; CHECK-LABEL: not_fmaxnm_maybe_nan:
-; CHECK:       // %bb.0:
-; CHECK-NEXT:    ucvtf s0, w0
-; CHECK-NEXT:    ucvtf s1, w1
-; CHECK-NEXT:    mov w8, #-8388608 // =0xff800000
-; CHECK-NEXT:    fmov s2, #17.00000000
-; CHECK-NEXT:    fmov s3, w8
-; CHECK-NEXT:    fmul s0, s0, s3
-; CHECK-NEXT:    fadd s1, s1, s2
-; CHECK-NEXT:    fcmp s0, s1
-; CHECK-NEXT:    fcsel s0, s0, s1, pl
-; CHECK-NEXT:    ret
+; CHECK-SD-LABEL: not_fmaxnm_maybe_nan:
+; CHECK-SD:       // %bb.0:
+; CHECK-SD-NEXT:    ucvtf s0, w0
+; CHECK-SD-NEXT:    ucvtf s1, w1
+; CHECK-SD-NEXT:    mov w8, #-8388608 // =0xff800000
+; CHECK-SD-NEXT:    fmov s2, #17.00000000
+; CHECK-SD-NEXT:    fmov s3, w8
+; CHECK-SD-NEXT:    fmul s0, s0, s3
+; CHECK-SD-NEXT:    fadd s1, s1, s2
+; CHECK-SD-NEXT:    fcmp s0, s1
+; CHECK-SD-NEXT:    fcsel s0, s0, s1, pl
+; CHECK-SD-NEXT:    ret
+;
+; CHECK-GI-LABEL: not_fmaxnm_maybe_nan:
+; CHECK-GI:       // %bb.0:
+; CHECK-GI-NEXT:    ucvtf s0, w0
+; CHECK-GI-NEXT:    ucvtf s1, w1
+; CHECK-GI-NEXT:    mov w8, #-8388608 // =0xff800000
+; CHECK-GI-NEXT:    fmov s2, #17.00000000
+; CHECK-GI-NEXT:    fmov s3, w8
+; CHECK-GI-NEXT:    fmul s0, s0, s3
+; CHECK-GI-NEXT:    fadd s1, s1, s2
+; CHECK-GI-NEXT:    fmax s0, s0, s1
+; CHECK-GI-NEXT:    ret
   %f1 = uitofp i32 %i1 to float
   %fmul = fmul float %f1, 0xfff0000000000000 ; -INFINITY as 64-bit hex
   %f2 = uitofp i32 %i2 to float
@@ -50,6 +62,3 @@ define float @not_fmaxnm_maybe_nan(i32 %i1, i32 %i2) #0 {
 
 attributes #0 = { "no-signed-zeros-fp-math"="true" }
 
-;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
-; CHECK-GI: {{.*}}
-; CHECK-SD: {{.*}}

diff  --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/clamp-minmax-const-combine.ll b/llvm/test/CodeGen/AMDGPU/GlobalISel/clamp-minmax-const-combine.ll
index 8fd41241b7ae4..9e708c4b0a7a3 100644
--- a/llvm/test/CodeGen/AMDGPU/GlobalISel/clamp-minmax-const-combine.ll
+++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/clamp-minmax-const-combine.ll
@@ -384,9 +384,7 @@ define float @test_min_max_maybe_NaN_input_ieee_false(float %a) #1 {
 ; GFX10-LABEL: test_min_max_maybe_NaN_input_ieee_false:
 ; GFX10:       ; %bb.0:
 ; GFX10-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX10-NEXT:    v_mul_f32_e32 v0, 2.0, v0
-; GFX10-NEXT:    v_max_f32_e32 v0, 0, v0
-; GFX10-NEXT:    v_min_f32_e32 v0, 1.0, v0
+; GFX10-NEXT:    v_mul_f32_e64 v0, v0, 2.0 clamp
 ; GFX10-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX1170-LABEL: test_min_max_maybe_NaN_input_ieee_false:
@@ -415,8 +413,7 @@ define float @test_min_max_maybe_NaN_input_ieee_true_dx10clamp_false(float %a) #
 ; GFX10-LABEL: test_min_max_maybe_NaN_input_ieee_true_dx10clamp_false:
 ; GFX10:       ; %bb.0:
 ; GFX10-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX10-NEXT:    v_mul_f32_e32 v0, 2.0, v0
-; GFX10-NEXT:    v_med3_f32 v0, v0, 0, 1.0
+; GFX10-NEXT:    v_mul_f32_e64 v0, v0, 2.0 clamp
 ; GFX10-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX1170-LABEL: test_min_max_maybe_NaN_input_ieee_true_dx10clamp_false:
@@ -446,17 +443,13 @@ define float @test_max_min_maybe_NaN_input_ieee_true(float %a) #0 {
 ; GFX10-LABEL: test_max_min_maybe_NaN_input_ieee_true:
 ; GFX10:       ; %bb.0:
 ; GFX10-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX10-NEXT:    v_mul_f32_e32 v0, 2.0, v0
-; GFX10-NEXT:    v_min_f32_e32 v0, 1.0, v0
-; GFX10-NEXT:    v_max_f32_e32 v0, 0, v0
+; GFX10-NEXT:    v_mul_f32_e64 v0, v0, 2.0 clamp
 ; GFX10-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX1170-LABEL: test_max_min_maybe_NaN_input_ieee_true:
 ; GFX1170:       ; %bb.0:
 ; GFX1170-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX1170-NEXT:    v_mul_f32_e32 v0, 2.0, v0
-; GFX1170-NEXT:    s_delay_alu instid0(VALU_DEP_1)
-; GFX1170-NEXT:    v_minmax_num_f32 v0, v0, 1.0, 0
+; GFX1170-NEXT:    v_mul_f32_e64 v0, v0, 2.0 clamp
 ; GFX1170-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX12-LABEL: test_max_min_maybe_NaN_input_ieee_true:
@@ -466,9 +459,7 @@ define float @test_max_min_maybe_NaN_input_ieee_true(float %a) #0 {
 ; GFX12-NEXT:    s_wait_samplecnt 0x0
 ; GFX12-NEXT:    s_wait_bvhcnt 0x0
 ; GFX12-NEXT:    s_wait_kmcnt 0x0
-; GFX12-NEXT:    v_mul_f32_e32 v0, 2.0, v0
-; GFX12-NEXT:    s_delay_alu instid0(VALU_DEP_1)
-; GFX12-NEXT:    v_minmax_num_f32 v0, v0, 1.0, 0
+; GFX12-NEXT:    v_mul_f32_e64 v0, v0, 2.0 clamp
 ; GFX12-NEXT:    s_setpc_b64 s[30:31]
   %fmul = fmul float %a, 2.0
   %minnum = call float @llvm.minnum.f32(float %fmul, float 1.0)
@@ -480,17 +471,13 @@ define float @test_max_min_maybe_NaN_input_ieee_false(float %a) #1 {
 ; GFX10-LABEL: test_max_min_maybe_NaN_input_ieee_false:
 ; GFX10:       ; %bb.0:
 ; GFX10-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX10-NEXT:    v_mul_f32_e32 v0, 2.0, v0
-; GFX10-NEXT:    v_min_f32_e32 v0, 1.0, v0
-; GFX10-NEXT:    v_max_f32_e32 v0, 0, v0
+; GFX10-NEXT:    v_mul_f32_e64 v0, v0, 2.0 clamp
 ; GFX10-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX1170-LABEL: test_max_min_maybe_NaN_input_ieee_false:
 ; GFX1170:       ; %bb.0:
 ; GFX1170-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX1170-NEXT:    v_mul_f32_e32 v0, 2.0, v0
-; GFX1170-NEXT:    s_delay_alu instid0(VALU_DEP_1)
-; GFX1170-NEXT:    v_minmax_num_f32 v0, v0, 1.0, 0
+; GFX1170-NEXT:    v_mul_f32_e64 v0, v0, 2.0 clamp
 ; GFX1170-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX12-LABEL: test_max_min_maybe_NaN_input_ieee_false:
@@ -500,9 +487,7 @@ define float @test_max_min_maybe_NaN_input_ieee_false(float %a) #1 {
 ; GFX12-NEXT:    s_wait_samplecnt 0x0
 ; GFX12-NEXT:    s_wait_bvhcnt 0x0
 ; GFX12-NEXT:    s_wait_kmcnt 0x0
-; GFX12-NEXT:    v_mul_f32_e32 v0, 2.0, v0
-; GFX12-NEXT:    s_delay_alu instid0(VALU_DEP_1)
-; GFX12-NEXT:    v_minmax_num_f32 v0, v0, 1.0, 0
+; GFX12-NEXT:    v_mul_f32_e64 v0, v0, 2.0 clamp
 ; GFX12-NEXT:    s_setpc_b64 s[30:31]
   %fmul = fmul float %a, 2.0
   %minnum = call float @llvm.minnum.f32(float %fmul, float 1.0)

diff  --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/fmed3-min-max-const-combine.ll b/llvm/test/CodeGen/AMDGPU/GlobalISel/fmed3-min-max-const-combine.ll
index dbcd4eaa2d71d..2677e2e8005d7 100644
--- a/llvm/test/CodeGen/AMDGPU/GlobalISel/fmed3-min-max-const-combine.ll
+++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/fmed3-min-max-const-combine.ll
@@ -553,15 +553,13 @@ define float @test_min_max_maybe_NaN_input_ieee_false(float %a) #1 {
 ; GFX8-LABEL: test_min_max_maybe_NaN_input_ieee_false:
 ; GFX8:       ; %bb.0:
 ; GFX8-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX8-NEXT:    v_max_f32_e32 v0, 2.0, v0
-; GFX8-NEXT:    v_min_f32_e32 v0, 4.0, v0
+; GFX8-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
 ; GFX8-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX10-LABEL: test_min_max_maybe_NaN_input_ieee_false:
 ; GFX10:       ; %bb.0:
 ; GFX10-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX10-NEXT:    v_max_f32_e32 v0, 2.0, v0
-; GFX10-NEXT:    v_min_f32_e32 v0, 4.0, v0
+; GFX10-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
 ; GFX10-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX1170-LABEL: test_min_max_maybe_NaN_input_ieee_false:
@@ -594,15 +592,13 @@ define float @test_max_min_maybe_NaN_input_ieee_false(float %a) #1 {
 ; GFX8-LABEL: test_max_min_maybe_NaN_input_ieee_false:
 ; GFX8:       ; %bb.0:
 ; GFX8-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX8-NEXT:    v_min_f32_e32 v0, 4.0, v0
-; GFX8-NEXT:    v_max_f32_e32 v0, 2.0, v0
+; GFX8-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
 ; GFX8-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX10-LABEL: test_max_min_maybe_NaN_input_ieee_false:
 ; GFX10:       ; %bb.0:
 ; GFX10-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX10-NEXT:    v_min_f32_e32 v0, 4.0, v0
-; GFX10-NEXT:    v_max_f32_e32 v0, 2.0, v0
+; GFX10-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
 ; GFX10-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX1170-LABEL: test_max_min_maybe_NaN_input_ieee_false:
@@ -610,7 +606,7 @@ define float @test_max_min_maybe_NaN_input_ieee_false(float %a) #1 {
 ; GFX1170-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
 ; GFX1170-NEXT:    v_max_num_f32_e32 v0, v0, v0
 ; GFX1170-NEXT:    s_delay_alu instid0(VALU_DEP_1)
-; GFX1170-NEXT:    v_minmax_num_f32 v0, v0, 4.0, 2.0
+; GFX1170-NEXT:    v_med3_num_f32 v0, v0, 2.0, 4.0
 ; GFX1170-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX12-LABEL: test_max_min_maybe_NaN_input_ieee_false:
@@ -622,7 +618,7 @@ define float @test_max_min_maybe_NaN_input_ieee_false(float %a) #1 {
 ; GFX12-NEXT:    s_wait_kmcnt 0x0
 ; GFX12-NEXT:    v_max_num_f32_e32 v0, v0, v0
 ; GFX12-NEXT:    s_delay_alu instid0(VALU_DEP_1)
-; GFX12-NEXT:    v_minmax_num_f32 v0, v0, 4.0, 2.0
+; GFX12-NEXT:    v_med3_num_f32 v0, v0, 2.0, 4.0
 ; GFX12-NEXT:    s_setpc_b64 s[30:31]
   %minnum = call float @llvm.minnum.f32(float %a, float 4.0)
   %fmed = call float @llvm.maxnum.f32(float %minnum, float 2.0)
@@ -635,16 +631,14 @@ define float @test_max_min_maybe_NaN_input_ieee_true(float %a) #0 {
 ; GFX8:       ; %bb.0:
 ; GFX8-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
 ; GFX8-NEXT:    v_mul_f32_e32 v0, 1.0, v0
-; GFX8-NEXT:    v_min_f32_e32 v0, 4.0, v0
-; GFX8-NEXT:    v_max_f32_e32 v0, 2.0, v0
+; GFX8-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
 ; GFX8-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX10-LABEL: test_max_min_maybe_NaN_input_ieee_true:
 ; GFX10:       ; %bb.0:
 ; GFX10-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
 ; GFX10-NEXT:    v_max_f32_e32 v0, v0, v0
-; GFX10-NEXT:    v_min_f32_e32 v0, 4.0, v0
-; GFX10-NEXT:    v_max_f32_e32 v0, 2.0, v0
+; GFX10-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
 ; GFX10-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX1170-LABEL: test_max_min_maybe_NaN_input_ieee_true:
@@ -652,7 +646,7 @@ define float @test_max_min_maybe_NaN_input_ieee_true(float %a) #0 {
 ; GFX1170-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
 ; GFX1170-NEXT:    v_max_num_f32_e32 v0, v0, v0
 ; GFX1170-NEXT:    s_delay_alu instid0(VALU_DEP_1)
-; GFX1170-NEXT:    v_minmax_num_f32 v0, v0, 4.0, 2.0
+; GFX1170-NEXT:    v_med3_num_f32 v0, v0, 2.0, 4.0
 ; GFX1170-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX12-LABEL: test_max_min_maybe_NaN_input_ieee_true:
@@ -664,7 +658,7 @@ define float @test_max_min_maybe_NaN_input_ieee_true(float %a) #0 {
 ; GFX12-NEXT:    s_wait_kmcnt 0x0
 ; GFX12-NEXT:    v_max_num_f32_e32 v0, v0, v0
 ; GFX12-NEXT:    s_delay_alu instid0(VALU_DEP_1)
-; GFX12-NEXT:    v_minmax_num_f32 v0, v0, 4.0, 2.0
+; GFX12-NEXT:    v_med3_num_f32 v0, v0, 2.0, 4.0
 ; GFX12-NEXT:    s_setpc_b64 s[30:31]
   %minnum = call float @llvm.minnum.f32(float %a, float 4.0)
   %fmed = call float @llvm.maxnum.f32(float %minnum, float 2.0)

diff  --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/known-fpclass-phi.mir b/llvm/test/CodeGen/AMDGPU/GlobalISel/known-fpclass-phi.mir
new file mode 100644
index 0000000000000..091d5fee1545d
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/known-fpclass-phi.mir
@@ -0,0 +1,148 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 -run-pass=legalizer %s -o - | FileCheck %s
+
+# Tests for G_PHI handling in GISelValueTracking::computeKnownFPClass.
+#
+# When all incoming values of a G_PHI are known to have certain FP classes,
+# the intersection of their known classes is propagated through the PHI.
+# This allows the legalizer to skip NaN fixup code in G_FMINIMUM/G_FMAXIMUM.
+#
+# Structure:
+#   bb.0 (entry):  defines entry constants, jumps to bb.1
+#   bb.1 (header): G_PHI of non-NaN constants, conditional branch to bb.2 or bb.3
+#   bb.2 (body):   defines back-edge constants, jumps back to bb.1
+#   bb.3 (exit):   uses PHI value in G_FMINIMUM
+
+---
+# Both operands of G_FMINIMUM are PHIs whose all incoming values are non-NaN
+# constants (1.0/2.0 and 3.0/4.0).  The legalizer should fully skip the NaN
+# fixup: no G_FCMP ord + G_SELECT, just G_FMINNUM_IEEE.
+name: test_fminimum_phi_both_nnan
+tracksRegLiveness: true
+body: |
+  ; CHECK-LABEL: name: test_fminimum_phi_both_nnan
+  ; CHECK: bb.0:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT:   liveins: $sgpr0
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:_(s32) = COPY $sgpr0
+  ; CHECK-NEXT:   [[C:%[0-9]+]]:_(s32) = G_FCONSTANT float 1.000000e+00
+  ; CHECK-NEXT:   [[C1:%[0-9]+]]:_(s32) = G_FCONSTANT float 3.000000e+00
+  ; CHECK-NEXT:   G_BR %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1:
+  ; CHECK-NEXT:   successors: %bb.3(0x40000000), %bb.2(0x40000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI:%[0-9]+]]:_(s32) = G_PHI [[C]](s32), %bb.0, %4(s32), %bb.2
+  ; CHECK-NEXT:   [[PHI1:%[0-9]+]]:_(s32) = G_PHI [[C1]](s32), %bb.0, %6(s32), %bb.2
+  ; CHECK-NEXT:   [[TRUNC:%[0-9]+]]:_(s1) = G_TRUNC [[COPY]](s32)
+  ; CHECK-NEXT:   G_BRCOND [[TRUNC]](s1), %bb.3
+  ; CHECK-NEXT:   G_BR %bb.2
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[C2:%[0-9]+]]:_(s32) = G_FCONSTANT float 2.000000e+00
+  ; CHECK-NEXT:   [[C3:%[0-9]+]]:_(s32) = G_FCONSTANT float 4.000000e+00
+  ; CHECK-NEXT:   G_BR %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.3:
+  ; CHECK-NEXT:   [[FMINNUM_IEEE:%[0-9]+]]:_(s32) = G_FMINNUM_IEEE [[PHI]], [[PHI1]]
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:_(s32) = COPY [[FMINNUM_IEEE]](s32)
+  ; CHECK-NEXT:   $vgpr0 = COPY [[COPY1]](s32)
+  ; CHECK-NEXT:   SI_RETURN implicit $vgpr0
+
+  bb.0:
+    liveins: $sgpr0
+
+    %0:_(s32) = COPY $sgpr0
+    %1:_(s32) = G_FCONSTANT float 1.000000e+00
+    %2:_(s32) = G_FCONSTANT float 3.000000e+00
+    G_BR %bb.1
+
+  bb.1:
+    ; PHI merges two non-NaN constants: 1.0/2.0 and 3.0/4.0
+    %5:_(s32) = G_PHI %1(s32), %bb.0, %3(s32), %bb.2
+    %6:_(s32) = G_PHI %2(s32), %bb.0, %4(s32), %bb.2
+    %7:_(s1) = G_TRUNC %0(s32)
+    G_BRCOND %7(s1), %bb.3
+    G_BR %bb.2
+
+  bb.2:
+    %3:_(s32) = G_FCONSTANT float 2.000000e+00
+    %4:_(s32) = G_FCONSTANT float 4.000000e+00
+    G_BR %bb.1
+
+  bb.3:
+    ; G_FMINIMUM of two PHIs both known non-NaN.
+    ; NaN fixup entirely skipped: no G_FCMP ord + G_SELECT, just G_FMINNUM_IEEE.
+    %8:_(s32) = G_FMINIMUM %5, %6
+    $vgpr0 = COPY %8(s32)
+    SI_RETURN implicit $vgpr0
+...
+
+---
+# One operand of G_FMINIMUM is a PHI whose incoming values are all non-NaN
+# constants; the other is an unknown COPY (potentially NaN).
+# The NaN fixup IS emitted because the COPY may be NaN.
+name: test_fminimum_phi_one_nnan
+tracksRegLiveness: true
+body: |
+  ; CHECK-LABEL: name: test_fminimum_phi_one_nnan
+  ; CHECK: bb.0:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT:   liveins: $sgpr0, $vgpr0
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:_(s32) = COPY $sgpr0
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:_(s32) = COPY $vgpr0
+  ; CHECK-NEXT:   [[C:%[0-9]+]]:_(s32) = G_FCONSTANT float 1.000000e+00
+  ; CHECK-NEXT:   G_BR %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1:
+  ; CHECK-NEXT:   successors: %bb.3(0x40000000), %bb.2(0x40000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI:%[0-9]+]]:_(s32) = G_PHI [[C]](s32), %bb.0, %4(s32), %bb.2
+  ; CHECK-NEXT:   [[TRUNC:%[0-9]+]]:_(s1) = G_TRUNC [[COPY]](s32)
+  ; CHECK-NEXT:   G_BRCOND [[TRUNC]](s1), %bb.3
+  ; CHECK-NEXT:   G_BR %bb.2
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[C1:%[0-9]+]]:_(s32) = G_FCONSTANT float 2.000000e+00
+  ; CHECK-NEXT:   G_BR %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.3:
+  ; CHECK-NEXT:   [[FMINNUM_IEEE:%[0-9]+]]:_(s32) = G_FMINNUM_IEEE [[PHI]], [[COPY1]]
+  ; CHECK-NEXT:   [[FCMP:%[0-9]+]]:_(s1) = G_FCMP floatpred(ord), [[PHI]](s32), [[COPY1]]
+  ; CHECK-NEXT:   [[C2:%[0-9]+]]:_(s32) = G_FCONSTANT float 0x7FF8000000000000
+  ; CHECK-NEXT:   [[SELECT:%[0-9]+]]:_(s32) = G_SELECT [[FCMP]](s1), [[FMINNUM_IEEE]], [[C2]]
+  ; CHECK-NEXT:   [[COPY2:%[0-9]+]]:_(s32) = COPY [[SELECT]](s32)
+  ; CHECK-NEXT:   $vgpr0 = COPY [[COPY2]](s32)
+  ; CHECK-NEXT:   SI_RETURN implicit $vgpr0
+
+  bb.0:
+    liveins: $sgpr0, $vgpr0
+
+    %0:_(s32) = COPY $sgpr0
+    %9:_(s32) = COPY $vgpr0
+    %1:_(s32) = G_FCONSTANT float 1.000000e+00
+    G_BR %bb.1
+
+  bb.1:
+    %3:_(s32) = G_PHI %1(s32), %bb.0, %2(s32), %bb.2
+    %4:_(s1) = G_TRUNC %0(s32)
+    G_BRCOND %4(s1), %bb.3
+    G_BR %bb.2
+
+  bb.2:
+    %2:_(s32) = G_FCONSTANT float 2.000000e+00
+    G_BR %bb.1
+
+  bb.3:
+    ; PHI is known non-NaN (1.0 or 2.0), %9 (from $vgpr0) is potentially NaN.
+    ; NaN fixup IS emitted because the other input may be NaN.
+    %6:_(s32) = G_FMINIMUM %3, %9
+    $vgpr0 = COPY %6(s32)
+    SI_RETURN implicit $vgpr0
+...

diff  --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/legalize-fmaxnum.mir b/llvm/test/CodeGen/AMDGPU/GlobalISel/legalize-fmaxnum.mir
index 3fc2b1cd66c1c..ed6e554948611 100644
--- a/llvm/test/CodeGen/AMDGPU/GlobalISel/legalize-fmaxnum.mir
+++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/legalize-fmaxnum.mir
@@ -746,9 +746,8 @@ body: |
     ; SI-NEXT: [[FCANONICALIZE1:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[COPY1]]
     ; SI-NEXT: [[FMAXNUM_IEEE:%[0-9]+]]:_(s32) = G_FMAXNUM_IEEE [[FCANONICALIZE]], [[FCANONICALIZE1]]
     ; SI-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
-    ; SI-NEXT: [[FCANONICALIZE2:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[FMAXNUM_IEEE]]
-    ; SI-NEXT: [[FCANONICALIZE3:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[COPY2]]
-    ; SI-NEXT: [[FMAXNUM_IEEE1:%[0-9]+]]:_(s32) = G_FMAXNUM_IEEE [[FCANONICALIZE2]], [[FCANONICALIZE3]]
+    ; SI-NEXT: [[FCANONICALIZE2:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[COPY2]]
+    ; SI-NEXT: [[FMAXNUM_IEEE1:%[0-9]+]]:_(s32) = G_FMAXNUM_IEEE [[FMAXNUM_IEEE]], [[FCANONICALIZE2]]
     ; SI-NEXT: $vgpr0 = COPY [[FMAXNUM_IEEE1]](s32)
     ;
     ; VI-LABEL: name: test_fmaxnum_with_fmaxnum_argument_s32_ieee_mode_on
@@ -760,9 +759,8 @@ body: |
     ; VI-NEXT: [[FCANONICALIZE1:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[COPY1]]
     ; VI-NEXT: [[FMAXNUM_IEEE:%[0-9]+]]:_(s32) = G_FMAXNUM_IEEE [[FCANONICALIZE]], [[FCANONICALIZE1]]
     ; VI-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
-    ; VI-NEXT: [[FCANONICALIZE2:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[FMAXNUM_IEEE]]
-    ; VI-NEXT: [[FCANONICALIZE3:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[COPY2]]
-    ; VI-NEXT: [[FMAXNUM_IEEE1:%[0-9]+]]:_(s32) = G_FMAXNUM_IEEE [[FCANONICALIZE2]], [[FCANONICALIZE3]]
+    ; VI-NEXT: [[FCANONICALIZE2:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[COPY2]]
+    ; VI-NEXT: [[FMAXNUM_IEEE1:%[0-9]+]]:_(s32) = G_FMAXNUM_IEEE [[FMAXNUM_IEEE]], [[FCANONICALIZE2]]
     ; VI-NEXT: $vgpr0 = COPY [[FMAXNUM_IEEE1]](s32)
     ;
     ; GFX9-LABEL: name: test_fmaxnum_with_fmaxnum_argument_s32_ieee_mode_on
@@ -774,9 +772,8 @@ body: |
     ; GFX9-NEXT: [[FCANONICALIZE1:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[COPY1]]
     ; GFX9-NEXT: [[FMAXNUM_IEEE:%[0-9]+]]:_(s32) = G_FMAXNUM_IEEE [[FCANONICALIZE]], [[FCANONICALIZE1]]
     ; GFX9-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
-    ; GFX9-NEXT: [[FCANONICALIZE2:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[FMAXNUM_IEEE]]
-    ; GFX9-NEXT: [[FCANONICALIZE3:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[COPY2]]
-    ; GFX9-NEXT: [[FMAXNUM_IEEE1:%[0-9]+]]:_(s32) = G_FMAXNUM_IEEE [[FCANONICALIZE2]], [[FCANONICALIZE3]]
+    ; GFX9-NEXT: [[FCANONICALIZE2:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[COPY2]]
+    ; GFX9-NEXT: [[FMAXNUM_IEEE1:%[0-9]+]]:_(s32) = G_FMAXNUM_IEEE [[FMAXNUM_IEEE]], [[FCANONICALIZE2]]
     ; GFX9-NEXT: $vgpr0 = COPY [[FMAXNUM_IEEE1]](s32)
     %0:_(s32) = COPY $vgpr0
     %1:_(s32) = COPY $vgpr1
@@ -856,9 +853,8 @@ body: |
     ; SI-NEXT: [[FCANONICALIZE1:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[COPY1]]
     ; SI-NEXT: [[FMINNUM_IEEE:%[0-9]+]]:_(s32) = G_FMINNUM_IEEE [[FCANONICALIZE]], [[FCANONICALIZE1]]
     ; SI-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
-    ; SI-NEXT: [[FCANONICALIZE2:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[FMINNUM_IEEE]]
-    ; SI-NEXT: [[FCANONICALIZE3:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[COPY2]]
-    ; SI-NEXT: [[FMAXNUM_IEEE:%[0-9]+]]:_(s32) = G_FMAXNUM_IEEE [[FCANONICALIZE2]], [[FCANONICALIZE3]]
+    ; SI-NEXT: [[FCANONICALIZE2:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[COPY2]]
+    ; SI-NEXT: [[FMAXNUM_IEEE:%[0-9]+]]:_(s32) = G_FMAXNUM_IEEE [[FMINNUM_IEEE]], [[FCANONICALIZE2]]
     ; SI-NEXT: $vgpr0 = COPY [[FMAXNUM_IEEE]](s32)
     ;
     ; VI-LABEL: name: test_fmaxnum_with_fminnum_argument_s32_ieee_mode_on
@@ -870,9 +866,8 @@ body: |
     ; VI-NEXT: [[FCANONICALIZE1:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[COPY1]]
     ; VI-NEXT: [[FMINNUM_IEEE:%[0-9]+]]:_(s32) = G_FMINNUM_IEEE [[FCANONICALIZE]], [[FCANONICALIZE1]]
     ; VI-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
-    ; VI-NEXT: [[FCANONICALIZE2:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[FMINNUM_IEEE]]
-    ; VI-NEXT: [[FCANONICALIZE3:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[COPY2]]
-    ; VI-NEXT: [[FMAXNUM_IEEE:%[0-9]+]]:_(s32) = G_FMAXNUM_IEEE [[FCANONICALIZE2]], [[FCANONICALIZE3]]
+    ; VI-NEXT: [[FCANONICALIZE2:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[COPY2]]
+    ; VI-NEXT: [[FMAXNUM_IEEE:%[0-9]+]]:_(s32) = G_FMAXNUM_IEEE [[FMINNUM_IEEE]], [[FCANONICALIZE2]]
     ; VI-NEXT: $vgpr0 = COPY [[FMAXNUM_IEEE]](s32)
     ;
     ; GFX9-LABEL: name: test_fmaxnum_with_fminnum_argument_s32_ieee_mode_on
@@ -884,9 +879,8 @@ body: |
     ; GFX9-NEXT: [[FCANONICALIZE1:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[COPY1]]
     ; GFX9-NEXT: [[FMINNUM_IEEE:%[0-9]+]]:_(s32) = G_FMINNUM_IEEE [[FCANONICALIZE]], [[FCANONICALIZE1]]
     ; GFX9-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
-    ; GFX9-NEXT: [[FCANONICALIZE2:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[FMINNUM_IEEE]]
-    ; GFX9-NEXT: [[FCANONICALIZE3:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[COPY2]]
-    ; GFX9-NEXT: [[FMAXNUM_IEEE:%[0-9]+]]:_(s32) = G_FMAXNUM_IEEE [[FCANONICALIZE2]], [[FCANONICALIZE3]]
+    ; GFX9-NEXT: [[FCANONICALIZE2:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[COPY2]]
+    ; GFX9-NEXT: [[FMAXNUM_IEEE:%[0-9]+]]:_(s32) = G_FMAXNUM_IEEE [[FMINNUM_IEEE]], [[FCANONICALIZE2]]
     ; GFX9-NEXT: $vgpr0 = COPY [[FMAXNUM_IEEE]](s32)
     %0:_(s32) = COPY $vgpr0
     %1:_(s32) = COPY $vgpr1

diff  --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/legalize-fminnum.mir b/llvm/test/CodeGen/AMDGPU/GlobalISel/legalize-fminnum.mir
index e2b3f3560acfc..f511df1976d0e 100644
--- a/llvm/test/CodeGen/AMDGPU/GlobalISel/legalize-fminnum.mir
+++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/legalize-fminnum.mir
@@ -746,9 +746,8 @@ body: |
     ; SI-NEXT: [[FCANONICALIZE1:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[COPY1]]
     ; SI-NEXT: [[FMINNUM_IEEE:%[0-9]+]]:_(s32) = G_FMINNUM_IEEE [[FCANONICALIZE]], [[FCANONICALIZE1]]
     ; SI-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
-    ; SI-NEXT: [[FCANONICALIZE2:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[FMINNUM_IEEE]]
-    ; SI-NEXT: [[FCANONICALIZE3:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[COPY2]]
-    ; SI-NEXT: [[FMINNUM_IEEE1:%[0-9]+]]:_(s32) = G_FMINNUM_IEEE [[FCANONICALIZE2]], [[FCANONICALIZE3]]
+    ; SI-NEXT: [[FCANONICALIZE2:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[COPY2]]
+    ; SI-NEXT: [[FMINNUM_IEEE1:%[0-9]+]]:_(s32) = G_FMINNUM_IEEE [[FMINNUM_IEEE]], [[FCANONICALIZE2]]
     ; SI-NEXT: $vgpr0 = COPY [[FMINNUM_IEEE1]](s32)
     ;
     ; VI-LABEL: name: test_fminnum_with_fminnum_argument_s32_ieee_mode_on
@@ -760,9 +759,8 @@ body: |
     ; VI-NEXT: [[FCANONICALIZE1:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[COPY1]]
     ; VI-NEXT: [[FMINNUM_IEEE:%[0-9]+]]:_(s32) = G_FMINNUM_IEEE [[FCANONICALIZE]], [[FCANONICALIZE1]]
     ; VI-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
-    ; VI-NEXT: [[FCANONICALIZE2:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[FMINNUM_IEEE]]
-    ; VI-NEXT: [[FCANONICALIZE3:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[COPY2]]
-    ; VI-NEXT: [[FMINNUM_IEEE1:%[0-9]+]]:_(s32) = G_FMINNUM_IEEE [[FCANONICALIZE2]], [[FCANONICALIZE3]]
+    ; VI-NEXT: [[FCANONICALIZE2:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[COPY2]]
+    ; VI-NEXT: [[FMINNUM_IEEE1:%[0-9]+]]:_(s32) = G_FMINNUM_IEEE [[FMINNUM_IEEE]], [[FCANONICALIZE2]]
     ; VI-NEXT: $vgpr0 = COPY [[FMINNUM_IEEE1]](s32)
     ;
     ; GFX9-LABEL: name: test_fminnum_with_fminnum_argument_s32_ieee_mode_on
@@ -774,9 +772,8 @@ body: |
     ; GFX9-NEXT: [[FCANONICALIZE1:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[COPY1]]
     ; GFX9-NEXT: [[FMINNUM_IEEE:%[0-9]+]]:_(s32) = G_FMINNUM_IEEE [[FCANONICALIZE]], [[FCANONICALIZE1]]
     ; GFX9-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
-    ; GFX9-NEXT: [[FCANONICALIZE2:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[FMINNUM_IEEE]]
-    ; GFX9-NEXT: [[FCANONICALIZE3:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[COPY2]]
-    ; GFX9-NEXT: [[FMINNUM_IEEE1:%[0-9]+]]:_(s32) = G_FMINNUM_IEEE [[FCANONICALIZE2]], [[FCANONICALIZE3]]
+    ; GFX9-NEXT: [[FCANONICALIZE2:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[COPY2]]
+    ; GFX9-NEXT: [[FMINNUM_IEEE1:%[0-9]+]]:_(s32) = G_FMINNUM_IEEE [[FMINNUM_IEEE]], [[FCANONICALIZE2]]
     ; GFX9-NEXT: $vgpr0 = COPY [[FMINNUM_IEEE1]](s32)
     %0:_(s32) = COPY $vgpr0
     %1:_(s32) = COPY $vgpr1
@@ -856,9 +853,8 @@ body: |
     ; SI-NEXT: [[FCANONICALIZE1:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[COPY1]]
     ; SI-NEXT: [[FMAXNUM_IEEE:%[0-9]+]]:_(s32) = G_FMAXNUM_IEEE [[FCANONICALIZE]], [[FCANONICALIZE1]]
     ; SI-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
-    ; SI-NEXT: [[FCANONICALIZE2:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[FMAXNUM_IEEE]]
-    ; SI-NEXT: [[FCANONICALIZE3:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[COPY2]]
-    ; SI-NEXT: [[FMINNUM_IEEE:%[0-9]+]]:_(s32) = G_FMINNUM_IEEE [[FCANONICALIZE2]], [[FCANONICALIZE3]]
+    ; SI-NEXT: [[FCANONICALIZE2:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[COPY2]]
+    ; SI-NEXT: [[FMINNUM_IEEE:%[0-9]+]]:_(s32) = G_FMINNUM_IEEE [[FMAXNUM_IEEE]], [[FCANONICALIZE2]]
     ; SI-NEXT: $vgpr0 = COPY [[FMINNUM_IEEE]](s32)
     ;
     ; VI-LABEL: name: test_fminnum_with_fmaxnum_argument_s32_ieee_mode_on
@@ -870,9 +866,8 @@ body: |
     ; VI-NEXT: [[FCANONICALIZE1:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[COPY1]]
     ; VI-NEXT: [[FMAXNUM_IEEE:%[0-9]+]]:_(s32) = G_FMAXNUM_IEEE [[FCANONICALIZE]], [[FCANONICALIZE1]]
     ; VI-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
-    ; VI-NEXT: [[FCANONICALIZE2:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[FMAXNUM_IEEE]]
-    ; VI-NEXT: [[FCANONICALIZE3:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[COPY2]]
-    ; VI-NEXT: [[FMINNUM_IEEE:%[0-9]+]]:_(s32) = G_FMINNUM_IEEE [[FCANONICALIZE2]], [[FCANONICALIZE3]]
+    ; VI-NEXT: [[FCANONICALIZE2:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[COPY2]]
+    ; VI-NEXT: [[FMINNUM_IEEE:%[0-9]+]]:_(s32) = G_FMINNUM_IEEE [[FMAXNUM_IEEE]], [[FCANONICALIZE2]]
     ; VI-NEXT: $vgpr0 = COPY [[FMINNUM_IEEE]](s32)
     ;
     ; GFX9-LABEL: name: test_fminnum_with_fmaxnum_argument_s32_ieee_mode_on
@@ -884,9 +879,8 @@ body: |
     ; GFX9-NEXT: [[FCANONICALIZE1:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[COPY1]]
     ; GFX9-NEXT: [[FMAXNUM_IEEE:%[0-9]+]]:_(s32) = G_FMAXNUM_IEEE [[FCANONICALIZE]], [[FCANONICALIZE1]]
     ; GFX9-NEXT: [[COPY2:%[0-9]+]]:_(s32) = COPY $vgpr2
-    ; GFX9-NEXT: [[FCANONICALIZE2:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[FMAXNUM_IEEE]]
-    ; GFX9-NEXT: [[FCANONICALIZE3:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[COPY2]]
-    ; GFX9-NEXT: [[FMINNUM_IEEE:%[0-9]+]]:_(s32) = G_FMINNUM_IEEE [[FCANONICALIZE2]], [[FCANONICALIZE3]]
+    ; GFX9-NEXT: [[FCANONICALIZE2:%[0-9]+]]:_(s32) = G_FCANONICALIZE [[COPY2]]
+    ; GFX9-NEXT: [[FMINNUM_IEEE:%[0-9]+]]:_(s32) = G_FMINNUM_IEEE [[FMAXNUM_IEEE]], [[FCANONICALIZE2]]
     ; GFX9-NEXT: $vgpr0 = COPY [[FMINNUM_IEEE]](s32)
     %0:_(s32) = COPY $vgpr0
     %1:_(s32) = COPY $vgpr1

diff  --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/regbankcombiner-clamp-minmax-const.mir b/llvm/test/CodeGen/AMDGPU/GlobalISel/regbankcombiner-clamp-minmax-const.mir
index 70fd67363648d..c3eed50092056 100644
--- a/llvm/test/CodeGen/AMDGPU/GlobalISel/regbankcombiner-clamp-minmax-const.mir
+++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/regbankcombiner-clamp-minmax-const.mir
@@ -441,13 +441,8 @@ body: |
     ; CHECK-NEXT: [[C:%[0-9]+]]:sgpr(s32) = G_FCONSTANT float 2.000000e+00
     ; CHECK-NEXT: [[COPY1:%[0-9]+]]:vgpr(s32) = COPY [[C]](s32)
     ; CHECK-NEXT: [[FMUL:%[0-9]+]]:vgpr(s32) = G_FMUL [[COPY]], [[COPY1]]
-    ; CHECK-NEXT: [[C1:%[0-9]+]]:sgpr(s32) = G_FCONSTANT float 0.000000e+00
-    ; CHECK-NEXT: [[COPY2:%[0-9]+]]:vgpr(s32) = COPY [[C1]](s32)
-    ; CHECK-NEXT: [[FMAXNUM:%[0-9]+]]:vgpr(s32) = G_FMAXNUM [[FMUL]], [[COPY2]]
-    ; CHECK-NEXT: [[C2:%[0-9]+]]:sgpr(s32) = G_FCONSTANT float 1.000000e+00
-    ; CHECK-NEXT: [[COPY3:%[0-9]+]]:vgpr(s32) = COPY [[C2]](s32)
-    ; CHECK-NEXT: [[FMINNUM:%[0-9]+]]:vgpr(s32) = G_FMINNUM [[FMAXNUM]], [[COPY3]]
-    ; CHECK-NEXT: $vgpr0 = COPY [[FMINNUM]](s32)
+    ; CHECK-NEXT: [[AMDGPU_CLAMP:%[0-9]+]]:vgpr(s32) = G_AMDGPU_CLAMP [[FMUL]]
+    ; CHECK-NEXT: $vgpr0 = COPY [[AMDGPU_CLAMP]](s32)
     %0:vgpr(s32) = COPY $vgpr0
     %2:sgpr(s32) = G_FCONSTANT float 2.000000e+00
     %9:vgpr(s32) = COPY %2(s32)
@@ -481,13 +476,9 @@ body: |
     ; CHECK-NEXT: [[C:%[0-9]+]]:sgpr(s32) = G_FCONSTANT float 2.000000e+00
     ; CHECK-NEXT: [[COPY1:%[0-9]+]]:vgpr(s32) = COPY [[C]](s32)
     ; CHECK-NEXT: [[FMUL:%[0-9]+]]:vgpr(s32) = G_FMUL [[COPY]], [[COPY1]]
-    ; CHECK-NEXT: [[C1:%[0-9]+]]:sgpr(s32) = G_FCONSTANT float 0.000000e+00
     ; CHECK-NEXT: [[FCANONICALIZE:%[0-9]+]]:vgpr(s32) = G_FCANONICALIZE [[FMUL]]
-    ; CHECK-NEXT: [[COPY2:%[0-9]+]]:vgpr(s32) = COPY [[C1]](s32)
-    ; CHECK-NEXT: [[C2:%[0-9]+]]:sgpr(s32) = G_FCONSTANT float 1.000000e+00
-    ; CHECK-NEXT: [[COPY3:%[0-9]+]]:vgpr(s32) = COPY [[C2]](s32)
-    ; CHECK-NEXT: [[AMDGPU_FMED3_:%[0-9]+]]:vgpr(s32) = G_AMDGPU_FMED3 [[FCANONICALIZE]], [[COPY2]], [[COPY3]]
-    ; CHECK-NEXT: $vgpr0 = COPY [[AMDGPU_FMED3_]](s32)
+    ; CHECK-NEXT: [[AMDGPU_CLAMP:%[0-9]+]]:vgpr(s32) = G_AMDGPU_CLAMP [[FCANONICALIZE]]
+    ; CHECK-NEXT: $vgpr0 = COPY [[AMDGPU_CLAMP]](s32)
     %0:vgpr(s32) = COPY $vgpr0
     %2:sgpr(s32) = G_FCONSTANT float 2.000000e+00
     %10:vgpr(s32) = COPY %2(s32)
@@ -522,14 +513,9 @@ body: |
     ; CHECK-NEXT: [[C:%[0-9]+]]:sgpr(s32) = G_FCONSTANT float 2.000000e+00
     ; CHECK-NEXT: [[COPY1:%[0-9]+]]:vgpr(s32) = COPY [[C]](s32)
     ; CHECK-NEXT: [[FMUL:%[0-9]+]]:vgpr(s32) = G_FMUL [[COPY]], [[COPY1]]
-    ; CHECK-NEXT: [[C1:%[0-9]+]]:sgpr(s32) = G_FCONSTANT float 1.000000e+00
     ; CHECK-NEXT: [[FCANONICALIZE:%[0-9]+]]:vgpr(s32) = G_FCANONICALIZE [[FMUL]]
-    ; CHECK-NEXT: [[COPY2:%[0-9]+]]:vgpr(s32) = COPY [[C1]](s32)
-    ; CHECK-NEXT: [[FMINNUM_IEEE:%[0-9]+]]:vgpr(s32) = G_FMINNUM_IEEE [[FCANONICALIZE]], [[COPY2]]
-    ; CHECK-NEXT: [[C2:%[0-9]+]]:sgpr(s32) = G_FCONSTANT float 0.000000e+00
-    ; CHECK-NEXT: [[COPY3:%[0-9]+]]:vgpr(s32) = COPY [[C2]](s32)
-    ; CHECK-NEXT: [[FMAXNUM_IEEE:%[0-9]+]]:vgpr(s32) = G_FMAXNUM_IEEE [[FMINNUM_IEEE]], [[COPY3]]
-    ; CHECK-NEXT: $vgpr0 = COPY [[FMAXNUM_IEEE]](s32)
+    ; CHECK-NEXT: [[AMDGPU_CLAMP:%[0-9]+]]:vgpr(s32) = G_AMDGPU_CLAMP [[FCANONICALIZE]]
+    ; CHECK-NEXT: $vgpr0 = COPY [[AMDGPU_CLAMP]](s32)
     %0:vgpr(s32) = COPY $vgpr0
     %2:sgpr(s32) = G_FCONSTANT float 2.000000e+00
     %10:vgpr(s32) = COPY %2(s32)
@@ -564,13 +550,8 @@ body: |
     ; CHECK-NEXT: [[C:%[0-9]+]]:sgpr(s32) = G_FCONSTANT float 2.000000e+00
     ; CHECK-NEXT: [[COPY1:%[0-9]+]]:vgpr(s32) = COPY [[C]](s32)
     ; CHECK-NEXT: [[FMUL:%[0-9]+]]:vgpr(s32) = G_FMUL [[COPY]], [[COPY1]]
-    ; CHECK-NEXT: [[C1:%[0-9]+]]:sgpr(s32) = G_FCONSTANT float 1.000000e+00
-    ; CHECK-NEXT: [[COPY2:%[0-9]+]]:vgpr(s32) = COPY [[C1]](s32)
-    ; CHECK-NEXT: [[FMINNUM:%[0-9]+]]:vgpr(s32) = G_FMINNUM [[FMUL]], [[COPY2]]
-    ; CHECK-NEXT: [[C2:%[0-9]+]]:sgpr(s32) = G_FCONSTANT float 0.000000e+00
-    ; CHECK-NEXT: [[COPY3:%[0-9]+]]:vgpr(s32) = COPY [[C2]](s32)
-    ; CHECK-NEXT: [[FMAXNUM:%[0-9]+]]:vgpr(s32) = G_FMAXNUM [[FMINNUM]], [[COPY3]]
-    ; CHECK-NEXT: $vgpr0 = COPY [[FMAXNUM]](s32)
+    ; CHECK-NEXT: [[AMDGPU_CLAMP:%[0-9]+]]:vgpr(s32) = G_AMDGPU_CLAMP [[FMUL]]
+    ; CHECK-NEXT: $vgpr0 = COPY [[AMDGPU_CLAMP]](s32)
     %0:vgpr(s32) = COPY $vgpr0
     %2:sgpr(s32) = G_FCONSTANT float 2.000000e+00
     %9:vgpr(s32) = COPY %2(s32)

diff  --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/regbankcombiner-fmed3-minmax-const.mir b/llvm/test/CodeGen/AMDGPU/GlobalISel/regbankcombiner-fmed3-minmax-const.mir
index 2f41d86100040..a53e97af0d028 100644
--- a/llvm/test/CodeGen/AMDGPU/GlobalISel/regbankcombiner-fmed3-minmax-const.mir
+++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/regbankcombiner-fmed3-minmax-const.mir
@@ -469,11 +469,10 @@ body: |
     ; CHECK-NEXT: [[COPY:%[0-9]+]]:vgpr(s32) = COPY $vgpr0
     ; CHECK-NEXT: [[C:%[0-9]+]]:sgpr(s32) = G_FCONSTANT float 2.000000e+00
     ; CHECK-NEXT: [[COPY1:%[0-9]+]]:vgpr(s32) = COPY [[C]](s32)
-    ; CHECK-NEXT: [[FMAXNUM:%[0-9]+]]:vgpr(s32) = G_FMAXNUM [[COPY]], [[COPY1]]
     ; CHECK-NEXT: [[C1:%[0-9]+]]:sgpr(s32) = G_FCONSTANT float 4.000000e+00
     ; CHECK-NEXT: [[COPY2:%[0-9]+]]:vgpr(s32) = COPY [[C1]](s32)
-    ; CHECK-NEXT: [[FMINNUM:%[0-9]+]]:vgpr(s32) = G_FMINNUM [[FMAXNUM]], [[COPY2]]
-    ; CHECK-NEXT: $vgpr0 = COPY [[FMINNUM]](s32)
+    ; CHECK-NEXT: [[AMDGPU_FMED3_:%[0-9]+]]:vgpr(s32) = G_AMDGPU_FMED3 [[COPY]], [[COPY1]], [[COPY2]]
+    ; CHECK-NEXT: $vgpr0 = COPY [[AMDGPU_FMED3_]](s32)
     %0:vgpr(s32) = COPY $vgpr0
     %2:sgpr(s32) = G_FCONSTANT float 2.000000e+00
     %7:vgpr(s32) = COPY %2(s32)
@@ -502,11 +501,10 @@ body: |
     ; CHECK-NEXT: [[COPY:%[0-9]+]]:vgpr(s32) = COPY $vgpr0
     ; CHECK-NEXT: [[C:%[0-9]+]]:sgpr(s32) = G_FCONSTANT float 4.000000e+00
     ; CHECK-NEXT: [[COPY1:%[0-9]+]]:vgpr(s32) = COPY [[C]](s32)
-    ; CHECK-NEXT: [[FMINNUM:%[0-9]+]]:vgpr(s32) = G_FMINNUM [[COPY]], [[COPY1]]
     ; CHECK-NEXT: [[C1:%[0-9]+]]:sgpr(s32) = G_FCONSTANT float 2.000000e+00
     ; CHECK-NEXT: [[COPY2:%[0-9]+]]:vgpr(s32) = COPY [[C1]](s32)
-    ; CHECK-NEXT: [[FMAXNUM:%[0-9]+]]:vgpr(s32) = G_FMAXNUM [[FMINNUM]], [[COPY2]]
-    ; CHECK-NEXT: $vgpr0 = COPY [[FMAXNUM]](s32)
+    ; CHECK-NEXT: [[AMDGPU_FMED3_:%[0-9]+]]:vgpr(s32) = G_AMDGPU_FMED3 [[COPY]], [[COPY2]], [[COPY1]]
+    ; CHECK-NEXT: $vgpr0 = COPY [[AMDGPU_FMED3_]](s32)
     %0:vgpr(s32) = COPY $vgpr0
     %2:sgpr(s32) = G_FCONSTANT float 4.000000e+00
     %7:vgpr(s32) = COPY %2(s32)
@@ -536,11 +534,10 @@ body: |
     ; CHECK-NEXT: [[C:%[0-9]+]]:sgpr(s32) = G_FCONSTANT float 4.000000e+00
     ; CHECK-NEXT: [[FCANONICALIZE:%[0-9]+]]:vgpr(s32) = G_FCANONICALIZE [[COPY]]
     ; CHECK-NEXT: [[COPY1:%[0-9]+]]:vgpr(s32) = COPY [[C]](s32)
-    ; CHECK-NEXT: [[FMINNUM_IEEE:%[0-9]+]]:vgpr(s32) = G_FMINNUM_IEEE [[FCANONICALIZE]], [[COPY1]]
     ; CHECK-NEXT: [[C1:%[0-9]+]]:sgpr(s32) = G_FCONSTANT float 2.000000e+00
     ; CHECK-NEXT: [[COPY2:%[0-9]+]]:vgpr(s32) = COPY [[C1]](s32)
-    ; CHECK-NEXT: [[FMAXNUM_IEEE:%[0-9]+]]:vgpr(s32) = G_FMAXNUM_IEEE [[FMINNUM_IEEE]], [[COPY2]]
-    ; CHECK-NEXT: $vgpr0 = COPY [[FMAXNUM_IEEE]](s32)
+    ; CHECK-NEXT: [[AMDGPU_FMED3_:%[0-9]+]]:vgpr(s32) = G_AMDGPU_FMED3 [[FCANONICALIZE]], [[COPY2]], [[COPY1]]
+    ; CHECK-NEXT: $vgpr0 = COPY [[AMDGPU_FMED3_]](s32)
     %0:vgpr(s32) = COPY $vgpr0
     %2:sgpr(s32) = G_FCONSTANT float 4.000000e+00
     %7:vgpr(s32) = G_FCANONICALIZE %0

diff  --git a/llvm/test/CodeGen/AMDGPU/fmed3.ll b/llvm/test/CodeGen/AMDGPU/fmed3.ll
index 406eb9503242c..4923dcc93888d 100644
--- a/llvm/test/CodeGen/AMDGPU/fmed3.ll
+++ b/llvm/test/CodeGen/AMDGPU/fmed3.ll
@@ -8919,23 +8919,12 @@ define double @v_test_fmed3_r_i_i_f64_minimumnum_maximumnum(double %a) {
 }
 
 define float @v_test_nnan_input_fmed3_r_i_i_f32_maximum_minimum(float %a) {
-; SI-SDAG-LABEL: v_test_nnan_input_fmed3_r_i_i_f32_maximum_minimum:
-; SI-SDAG:       ; %bb.0:
-; SI-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; SI-SDAG-NEXT:    v_add_f32_e32 v0, 1.0, v0
-; SI-SDAG-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
-; SI-SDAG-NEXT:    s_setpc_b64 s[30:31]
-;
-; SI-GISEL-LABEL: v_test_nnan_input_fmed3_r_i_i_f32_maximum_minimum:
-; SI-GISEL:       ; %bb.0:
-; SI-GISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; SI-GISEL-NEXT:    v_add_f32_e32 v0, 1.0, v0
-; SI-GISEL-NEXT:    v_mov_b32_e32 v1, 0x7fc00000
-; SI-GISEL-NEXT:    v_max_f32_e32 v2, 2.0, v0
-; SI-GISEL-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
-; SI-GISEL-NEXT:    v_cmp_o_f32_e32 vcc, 4.0, v2
-; SI-GISEL-NEXT:    v_cndmask_b32_e32 v0, v1, v0, vcc
-; SI-GISEL-NEXT:    s_setpc_b64 s[30:31]
+; SI-LABEL: v_test_nnan_input_fmed3_r_i_i_f32_maximum_minimum:
+; SI:       ; %bb.0:
+; SI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; SI-NEXT:    v_add_f32_e32 v0, 1.0, v0
+; SI-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; SI-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; VI-SDAG-LABEL: v_test_nnan_input_fmed3_r_i_i_f32_maximum_minimum:
 ; VI-SDAG:       ; %bb.0:
@@ -8948,50 +8937,23 @@ define float @v_test_nnan_input_fmed3_r_i_i_f32_maximum_minimum(float %a) {
 ; VI-GISEL:       ; %bb.0:
 ; VI-GISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
 ; VI-GISEL-NEXT:    v_add_f32_e32 v0, 1.0, v0
-; VI-GISEL-NEXT:    v_max_f32_e32 v1, 2.0, v0
 ; VI-GISEL-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
-; VI-GISEL-NEXT:    v_mov_b32_e32 v2, 0x7fc00000
-; VI-GISEL-NEXT:    v_cmp_o_f32_e32 vcc, 4.0, v1
-; VI-GISEL-NEXT:    v_cndmask_b32_e32 v0, v2, v0, vcc
 ; VI-GISEL-NEXT:    s_setpc_b64 s[30:31]
 ;
-; GFX9-SDAG-LABEL: v_test_nnan_input_fmed3_r_i_i_f32_maximum_minimum:
-; GFX9-SDAG:       ; %bb.0:
-; GFX9-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-SDAG-NEXT:    v_add_f32_e32 v0, 1.0, v0
-; GFX9-SDAG-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
-; GFX9-SDAG-NEXT:    s_setpc_b64 s[30:31]
-;
-; GFX9-GISEL-LABEL: v_test_nnan_input_fmed3_r_i_i_f32_maximum_minimum:
-; GFX9-GISEL:       ; %bb.0:
-; GFX9-GISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-GISEL-NEXT:    v_add_f32_e32 v0, 1.0, v0
-; GFX9-GISEL-NEXT:    v_max_f32_e32 v1, 2.0, v0
-; GFX9-GISEL-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
-; GFX9-GISEL-NEXT:    v_mov_b32_e32 v2, 0x7fc00000
-; GFX9-GISEL-NEXT:    v_cmp_o_f32_e32 vcc, 4.0, v1
-; GFX9-GISEL-NEXT:    v_cndmask_b32_e32 v0, v2, v0, vcc
-; GFX9-GISEL-NEXT:    s_setpc_b64 s[30:31]
-;
-; GFX11-SDAG-LABEL: v_test_nnan_input_fmed3_r_i_i_f32_maximum_minimum:
-; GFX11-SDAG:       ; %bb.0:
-; GFX11-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-SDAG-NEXT:    v_add_f32_e32 v0, 1.0, v0
-; GFX11-SDAG-NEXT:    s_delay_alu instid0(VALU_DEP_1)
-; GFX11-SDAG-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
-; GFX11-SDAG-NEXT:    s_setpc_b64 s[30:31]
+; GFX9-LABEL: v_test_nnan_input_fmed3_r_i_i_f32_maximum_minimum:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_add_f32_e32 v0, 1.0, v0
+; GFX9-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
 ;
-; GFX11-GISEL-LABEL: v_test_nnan_input_fmed3_r_i_i_f32_maximum_minimum:
-; GFX11-GISEL:       ; %bb.0:
-; GFX11-GISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-GISEL-NEXT:    v_add_f32_e32 v0, 1.0, v0
-; GFX11-GISEL-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(SKIP_1) | instid1(VALU_DEP_2)
-; GFX11-GISEL-NEXT:    v_max_f32_e32 v1, 2.0, v0
-; GFX11-GISEL-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
-; GFX11-GISEL-NEXT:    v_cmp_o_f32_e32 vcc_lo, 4.0, v1
-; GFX11-GISEL-NEXT:    s_delay_alu instid0(VALU_DEP_2)
-; GFX11-GISEL-NEXT:    v_cndmask_b32_e32 v0, 0x7fc00000, v0, vcc_lo
-; GFX11-GISEL-NEXT:    s_setpc_b64 s[30:31]
+; GFX11-LABEL: v_test_nnan_input_fmed3_r_i_i_f32_maximum_minimum:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT:    v_add_f32_e32 v0, 1.0, v0
+; GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; GFX11-NEXT:    s_setpc_b64 s[30:31]
   %a.add = fadd nnan float %a, 1.0
   %max = call float @llvm.maximum.f32(float %a.add, float 2.0)
   %med = call float @llvm.minimum.f32(float %max, float 4.0)
@@ -9113,72 +9075,22 @@ define <2 x half> @v_test_nnan_input_fmed3_r_i_i_v2f16_maximum_minimum(<2 x half
 ; VI-GISEL-NEXT:    v_or_b32_e32 v0, v1, v0
 ; VI-GISEL-NEXT:    s_setpc_b64 s[30:31]
 ;
-; GFX9-SDAG-LABEL: v_test_nnan_input_fmed3_r_i_i_v2f16_maximum_minimum:
-; GFX9-SDAG:       ; %bb.0:
-; GFX9-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-SDAG-NEXT:    v_pk_add_f16 v0, v0, 1.0 op_sel_hi:[1,0]
-; GFX9-SDAG-NEXT:    v_pk_max_f16 v0, v0, 2.0 op_sel_hi:[1,0]
-; GFX9-SDAG-NEXT:    v_pk_min_f16 v0, v0, 4.0 op_sel_hi:[1,0]
-; GFX9-SDAG-NEXT:    s_setpc_b64 s[30:31]
-;
-; GFX9-GISEL-LABEL: v_test_nnan_input_fmed3_r_i_i_v2f16_maximum_minimum:
-; GFX9-GISEL:       ; %bb.0:
-; GFX9-GISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-GISEL-NEXT:    v_pk_add_f16 v0, v0, 1.0 op_sel_hi:[1,0]
-; GFX9-GISEL-NEXT:    v_pk_max_f16 v0, v0, 2.0 op_sel_hi:[1,0]
-; GFX9-GISEL-NEXT:    v_mov_b32_e32 v2, 0x4400
-; GFX9-GISEL-NEXT:    v_pk_min_f16 v1, v0, 4.0 op_sel_hi:[1,0]
-; GFX9-GISEL-NEXT:    v_cmp_o_f16_sdwa vcc, v0, v2 src0_sel:WORD_1 src1_sel:DWORD
-; GFX9-GISEL-NEXT:    v_mov_b32_e32 v2, 0x7e00
-; GFX9-GISEL-NEXT:    v_cmp_o_f16_e64 s[4:5], 4.0, v0
-; GFX9-GISEL-NEXT:    v_cndmask_b32_e64 v0, v2, v1, s[4:5]
-; GFX9-GISEL-NEXT:    v_cndmask_b32_sdwa v1, v2, v1, vcc dst_sel:DWORD dst_unused:UNUSED_PAD src0_sel:DWORD src1_sel:WORD_1
-; GFX9-GISEL-NEXT:    v_and_b32_e32 v0, 0xffff, v0
-; GFX9-GISEL-NEXT:    v_lshl_or_b32 v0, v1, 16, v0
-; GFX9-GISEL-NEXT:    s_setpc_b64 s[30:31]
-;
-; GFX11-SDAG-LABEL: v_test_nnan_input_fmed3_r_i_i_v2f16_maximum_minimum:
-; GFX11-SDAG:       ; %bb.0:
-; GFX11-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-SDAG-NEXT:    v_pk_add_f16 v0, v0, 1.0 op_sel_hi:[1,0]
-; GFX11-SDAG-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
-; GFX11-SDAG-NEXT:    v_pk_max_f16 v0, v0, 2.0 op_sel_hi:[1,0]
-; GFX11-SDAG-NEXT:    v_pk_min_f16 v0, v0, 4.0 op_sel_hi:[1,0]
-; GFX11-SDAG-NEXT:    s_setpc_b64 s[30:31]
-;
-; GFX11-GISEL-FAKE16-LABEL: v_test_nnan_input_fmed3_r_i_i_v2f16_maximum_minimum:
-; GFX11-GISEL-FAKE16:       ; %bb.0:
-; GFX11-GISEL-FAKE16-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-GISEL-FAKE16-NEXT:    v_pk_add_f16 v0, v0, 1.0 op_sel_hi:[1,0]
-; GFX11-GISEL-FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
-; GFX11-GISEL-FAKE16-NEXT:    v_pk_max_f16 v0, v0, 2.0 op_sel_hi:[1,0]
-; GFX11-GISEL-FAKE16-NEXT:    v_pk_min_f16 v1, v0, 4.0 op_sel_hi:[1,0]
-; GFX11-GISEL-FAKE16-NEXT:    v_lshrrev_b32_e32 v2, 16, v0
-; GFX11-GISEL-FAKE16-NEXT:    v_cmp_o_f16_e32 vcc_lo, 4.0, v0
-; GFX11-GISEL-FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_3) | instskip(SKIP_1) | instid1(VALU_DEP_4)
-; GFX11-GISEL-FAKE16-NEXT:    v_lshrrev_b32_e32 v3, 16, v1
-; GFX11-GISEL-FAKE16-NEXT:    v_cndmask_b32_e32 v0, 0x7e00, v1, vcc_lo
-; GFX11-GISEL-FAKE16-NEXT:    v_cmp_o_f16_e32 vcc_lo, 4.0, v2
-; GFX11-GISEL-FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_3) | instskip(NEXT) | instid1(VALU_DEP_3)
-; GFX11-GISEL-FAKE16-NEXT:    v_cndmask_b32_e32 v1, 0x7e00, v3, vcc_lo
-; GFX11-GISEL-FAKE16-NEXT:    v_and_b32_e32 v0, 0xffff, v0
-; GFX11-GISEL-FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_1)
-; GFX11-GISEL-FAKE16-NEXT:    v_lshl_or_b32 v0, v1, 16, v0
-; GFX11-GISEL-FAKE16-NEXT:    s_setpc_b64 s[30:31]
+; GFX9-LABEL: v_test_nnan_input_fmed3_r_i_i_v2f16_maximum_minimum:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_pk_add_f16 v0, v0, 1.0 op_sel_hi:[1,0]
+; GFX9-NEXT:    v_pk_max_f16 v0, v0, 2.0 op_sel_hi:[1,0]
+; GFX9-NEXT:    v_pk_min_f16 v0, v0, 4.0 op_sel_hi:[1,0]
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
 ;
-; GFX11-GISEL-TRUE16-LABEL: v_test_nnan_input_fmed3_r_i_i_v2f16_maximum_minimum:
-; GFX11-GISEL-TRUE16:       ; %bb.0:
-; GFX11-GISEL-TRUE16-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-GISEL-TRUE16-NEXT:    v_pk_add_f16 v0, v0, 1.0 op_sel_hi:[1,0]
-; GFX11-GISEL-TRUE16-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
-; GFX11-GISEL-TRUE16-NEXT:    v_pk_max_f16 v0, v0, 2.0 op_sel_hi:[1,0]
-; GFX11-GISEL-TRUE16-NEXT:    v_pk_min_f16 v1, v0, 4.0 op_sel_hi:[1,0]
-; GFX11-GISEL-TRUE16-NEXT:    v_cmp_o_f16_e32 vcc_lo, 4.0, v0.l
-; GFX11-GISEL-TRUE16-NEXT:    v_cmp_o_f16_e64 s0, 4.0, v0.h
-; GFX11-GISEL-TRUE16-NEXT:    s_delay_alu instid0(VALU_DEP_3) | instskip(NEXT) | instid1(VALU_DEP_2)
-; GFX11-GISEL-TRUE16-NEXT:    v_cndmask_b16 v0.l, 0x7e00, v1.l, vcc_lo
-; GFX11-GISEL-TRUE16-NEXT:    v_cndmask_b16 v0.h, 0x7e00, v1.h, s0
-; GFX11-GISEL-TRUE16-NEXT:    s_setpc_b64 s[30:31]
+; GFX11-LABEL: v_test_nnan_input_fmed3_r_i_i_v2f16_maximum_minimum:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT:    v_pk_add_f16 v0, v0, 1.0 op_sel_hi:[1,0]
+; GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX11-NEXT:    v_pk_max_f16 v0, v0, 2.0 op_sel_hi:[1,0]
+; GFX11-NEXT:    v_pk_min_f16 v0, v0, 4.0 op_sel_hi:[1,0]
+; GFX11-NEXT:    s_setpc_b64 s[30:31]
   %a.add = fadd nnan <2 x half> %a, splat (half 1.0)
   %max = call <2 x half> @llvm.maximum.v2f16(<2 x half> %a.add, <2 x half> splat (half 2.0))
   %med = call <2 x half> @llvm.minimum.v2f16(<2 x half> %max, <2 x half> splat (half 4.0))
@@ -9209,18 +9121,13 @@ define half @v_test_nnan_input_fmed3_r_i_i_f16_maximum_minimum(half %a) {
 ; SI-GISEL:       ; %bb.0:
 ; SI-GISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
 ; SI-GISEL-NEXT:    v_cvt_f32_f16_e32 v0, v0
-; SI-GISEL-NEXT:    v_mov_b32_e32 v1, 0x7fc00000
 ; SI-GISEL-NEXT:    v_add_f32_e32 v0, 1.0, v0
 ; SI-GISEL-NEXT:    v_cvt_f16_f32_e32 v0, v0
 ; SI-GISEL-NEXT:    v_cvt_f32_f16_e32 v0, v0
-; SI-GISEL-NEXT:    v_max_f32_e32 v2, 2.0, v0
-; SI-GISEL-NEXT:    v_cmp_o_f32_e32 vcc, 2.0, v0
-; SI-GISEL-NEXT:    v_cndmask_b32_e32 v0, v1, v2, vcc
+; SI-GISEL-NEXT:    v_max_f32_e32 v0, 2.0, v0
 ; SI-GISEL-NEXT:    v_cvt_f16_f32_e32 v0, v0
 ; SI-GISEL-NEXT:    v_cvt_f32_f16_e32 v0, v0
-; SI-GISEL-NEXT:    v_min_f32_e32 v2, 4.0, v0
-; SI-GISEL-NEXT:    v_cmp_o_f32_e32 vcc, 4.0, v0
-; SI-GISEL-NEXT:    v_cndmask_b32_e32 v0, v1, v2, vcc
+; SI-GISEL-NEXT:    v_min_f32_e32 v0, 4.0, v0
 ; SI-GISEL-NEXT:    v_cvt_f16_f32_e32 v0, v0
 ; SI-GISEL-NEXT:    s_setpc_b64 s[30:31]
 ;
@@ -9237,35 +9144,19 @@ define half @v_test_nnan_input_fmed3_r_i_i_f16_maximum_minimum(half %a) {
 ; VI-GISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
 ; VI-GISEL-NEXT:    v_add_f16_e32 v0, 1.0, v0
 ; VI-GISEL-NEXT:    v_cvt_f32_f16_e32 v0, v0
-; VI-GISEL-NEXT:    v_mov_b32_e32 v1, 0x7fc00000
-; VI-GISEL-NEXT:    v_max_f32_e32 v2, 2.0, v0
-; VI-GISEL-NEXT:    v_cmp_o_f32_e32 vcc, 2.0, v0
-; VI-GISEL-NEXT:    v_cndmask_b32_e32 v0, v1, v2, vcc
+; VI-GISEL-NEXT:    v_max_f32_e32 v0, 2.0, v0
 ; VI-GISEL-NEXT:    v_cvt_f16_f32_e32 v0, v0
 ; VI-GISEL-NEXT:    v_cvt_f32_f16_e32 v0, v0
-; VI-GISEL-NEXT:    v_min_f32_e32 v2, 4.0, v0
-; VI-GISEL-NEXT:    v_cmp_o_f32_e32 vcc, 4.0, v0
-; VI-GISEL-NEXT:    v_cndmask_b32_e32 v0, v1, v2, vcc
+; VI-GISEL-NEXT:    v_min_f32_e32 v0, 4.0, v0
 ; VI-GISEL-NEXT:    v_cvt_f16_f32_e32 v0, v0
 ; VI-GISEL-NEXT:    s_setpc_b64 s[30:31]
 ;
-; GFX9-SDAG-LABEL: v_test_nnan_input_fmed3_r_i_i_f16_maximum_minimum:
-; GFX9-SDAG:       ; %bb.0:
-; GFX9-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-SDAG-NEXT:    v_add_f16_e32 v0, 1.0, v0
-; GFX9-SDAG-NEXT:    v_med3_f16 v0, v0, 2.0, 4.0
-; GFX9-SDAG-NEXT:    s_setpc_b64 s[30:31]
-;
-; GFX9-GISEL-LABEL: v_test_nnan_input_fmed3_r_i_i_f16_maximum_minimum:
-; GFX9-GISEL:       ; %bb.0:
-; GFX9-GISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-GISEL-NEXT:    v_add_f16_e32 v0, 1.0, v0
-; GFX9-GISEL-NEXT:    v_max_f16_e32 v1, 2.0, v0
-; GFX9-GISEL-NEXT:    v_med3_f16 v0, v0, 2.0, 4.0
-; GFX9-GISEL-NEXT:    v_mov_b32_e32 v2, 0x7e00
-; GFX9-GISEL-NEXT:    v_cmp_o_f16_e32 vcc, 4.0, v1
-; GFX9-GISEL-NEXT:    v_cndmask_b32_e32 v0, v2, v0, vcc
-; GFX9-GISEL-NEXT:    s_setpc_b64 s[30:31]
+; GFX9-LABEL: v_test_nnan_input_fmed3_r_i_i_f16_maximum_minimum:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_add_f16_e32 v0, 1.0, v0
+; GFX9-NEXT:    v_med3_f16 v0, v0, 2.0, 4.0
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX11-SDAG-FAKE16-LABEL: v_test_nnan_input_fmed3_r_i_i_f16_maximum_minimum:
 ; GFX11-SDAG-FAKE16:       ; %bb.0:
@@ -9279,12 +9170,8 @@ define half @v_test_nnan_input_fmed3_r_i_i_f16_maximum_minimum(half %a) {
 ; GFX11-GISEL-FAKE16:       ; %bb.0:
 ; GFX11-GISEL-FAKE16-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
 ; GFX11-GISEL-FAKE16-NEXT:    v_add_f16_e32 v0, 1.0, v0
-; GFX11-GISEL-FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(SKIP_1) | instid1(VALU_DEP_2)
-; GFX11-GISEL-FAKE16-NEXT:    v_max_f16_e32 v1, 2.0, v0
+; GFX11-GISEL-FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_1)
 ; GFX11-GISEL-FAKE16-NEXT:    v_med3_f16 v0, v0, 2.0, 4.0
-; GFX11-GISEL-FAKE16-NEXT:    v_cmp_o_f16_e32 vcc_lo, 4.0, v1
-; GFX11-GISEL-FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_2)
-; GFX11-GISEL-FAKE16-NEXT:    v_cndmask_b32_e32 v0, 0x7e00, v0, vcc_lo
 ; GFX11-GISEL-FAKE16-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX11-SDAG-TRUE16-LABEL: v_test_nnan_input_fmed3_r_i_i_f16_maximum_minimum:
@@ -9299,12 +9186,8 @@ define half @v_test_nnan_input_fmed3_r_i_i_f16_maximum_minimum(half %a) {
 ; GFX11-GISEL-TRUE16:       ; %bb.0:
 ; GFX11-GISEL-TRUE16-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
 ; GFX11-GISEL-TRUE16-NEXT:    v_add_f16_e32 v0.l, 1.0, v0.l
-; GFX11-GISEL-TRUE16-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(SKIP_1) | instid1(VALU_DEP_2)
-; GFX11-GISEL-TRUE16-NEXT:    v_max_f16_e32 v0.h, 2.0, v0.l
+; GFX11-GISEL-TRUE16-NEXT:    s_delay_alu instid0(VALU_DEP_1)
 ; GFX11-GISEL-TRUE16-NEXT:    v_med3_f16 v0.l, v0.l, 2.0, 4.0
-; GFX11-GISEL-TRUE16-NEXT:    v_cmp_o_f16_e32 vcc_lo, 4.0, v0.h
-; GFX11-GISEL-TRUE16-NEXT:    s_delay_alu instid0(VALU_DEP_2)
-; GFX11-GISEL-TRUE16-NEXT:    v_cndmask_b32_e32 v0, 0x7e00, v0, vcc_lo
 ; GFX11-GISEL-TRUE16-NEXT:    s_setpc_b64 s[30:31]
   %a.add = fadd nnan half %a, 1.0
   %max = call half @llvm.maximum.f16(half %a.add, half 2.0)
@@ -9313,25 +9196,13 @@ define half @v_test_nnan_input_fmed3_r_i_i_f16_maximum_minimum(half %a) {
 }
 
 define double @v_test_nnan_input_fmed3_r_i_i_f64_maximum_minimum(double %a) {
-; SI-SDAG-LABEL: v_test_nnan_input_fmed3_r_i_i_f64_maximum_minimum:
-; SI-SDAG:       ; %bb.0:
-; SI-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; SI-SDAG-NEXT:    v_add_f64 v[0:1], v[0:1], 1.0
-; SI-SDAG-NEXT:    v_max_f64 v[0:1], v[0:1], 2.0
-; SI-SDAG-NEXT:    v_min_f64 v[0:1], v[0:1], 4.0
-; SI-SDAG-NEXT:    s_setpc_b64 s[30:31]
-;
-; SI-GISEL-LABEL: v_test_nnan_input_fmed3_r_i_i_f64_maximum_minimum:
-; SI-GISEL:       ; %bb.0:
-; SI-GISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; SI-GISEL-NEXT:    v_add_f64 v[0:1], v[0:1], 1.0
-; SI-GISEL-NEXT:    v_mov_b32_e32 v4, 0x7ff80000
-; SI-GISEL-NEXT:    v_max_f64 v[0:1], v[0:1], 2.0
-; SI-GISEL-NEXT:    v_min_f64 v[2:3], v[0:1], 4.0
-; SI-GISEL-NEXT:    v_cmp_o_f64_e32 vcc, 4.0, v[0:1]
-; SI-GISEL-NEXT:    v_cndmask_b32_e32 v0, 0, v2, vcc
-; SI-GISEL-NEXT:    v_cndmask_b32_e32 v1, v4, v3, vcc
-; SI-GISEL-NEXT:    s_setpc_b64 s[30:31]
+; SI-LABEL: v_test_nnan_input_fmed3_r_i_i_f64_maximum_minimum:
+; SI:       ; %bb.0:
+; SI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; SI-NEXT:    v_add_f64 v[0:1], v[0:1], 1.0
+; SI-NEXT:    v_max_f64 v[0:1], v[0:1], 2.0
+; SI-NEXT:    v_min_f64 v[0:1], v[0:1], 4.0
+; SI-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; VI-SDAG-LABEL: v_test_nnan_input_fmed3_r_i_i_f64_maximum_minimum:
 ; VI-SDAG:       ; %bb.0:
@@ -9346,53 +9217,25 @@ define double @v_test_nnan_input_fmed3_r_i_i_f64_maximum_minimum(double %a) {
 ; VI-GISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
 ; VI-GISEL-NEXT:    v_add_f64 v[0:1], v[0:1], 1.0
 ; VI-GISEL-NEXT:    v_max_f64 v[0:1], v[0:1], 2.0
-; VI-GISEL-NEXT:    v_min_f64 v[2:3], v[0:1], 4.0
-; VI-GISEL-NEXT:    v_cmp_o_f64_e32 vcc, 4.0, v[0:1]
-; VI-GISEL-NEXT:    v_mov_b32_e32 v1, 0x7ff80000
-; VI-GISEL-NEXT:    v_cndmask_b32_e32 v0, 0, v2, vcc
-; VI-GISEL-NEXT:    v_cndmask_b32_e32 v1, v1, v3, vcc
+; VI-GISEL-NEXT:    v_min_f64 v[0:1], v[0:1], 4.0
 ; VI-GISEL-NEXT:    s_setpc_b64 s[30:31]
 ;
-; GFX9-SDAG-LABEL: v_test_nnan_input_fmed3_r_i_i_f64_maximum_minimum:
-; GFX9-SDAG:       ; %bb.0:
-; GFX9-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-SDAG-NEXT:    v_add_f64 v[0:1], v[0:1], 1.0
-; GFX9-SDAG-NEXT:    v_max_f64 v[0:1], v[0:1], 2.0
-; GFX9-SDAG-NEXT:    v_min_f64 v[0:1], v[0:1], 4.0
-; GFX9-SDAG-NEXT:    s_setpc_b64 s[30:31]
-;
-; GFX9-GISEL-LABEL: v_test_nnan_input_fmed3_r_i_i_f64_maximum_minimum:
-; GFX9-GISEL:       ; %bb.0:
-; GFX9-GISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-GISEL-NEXT:    v_add_f64 v[0:1], v[0:1], 1.0
-; GFX9-GISEL-NEXT:    v_max_f64 v[0:1], v[0:1], 2.0
-; GFX9-GISEL-NEXT:    v_min_f64 v[2:3], v[0:1], 4.0
-; GFX9-GISEL-NEXT:    v_cmp_o_f64_e32 vcc, 4.0, v[0:1]
-; GFX9-GISEL-NEXT:    v_mov_b32_e32 v1, 0x7ff80000
-; GFX9-GISEL-NEXT:    v_cndmask_b32_e32 v0, 0, v2, vcc
-; GFX9-GISEL-NEXT:    v_cndmask_b32_e32 v1, v1, v3, vcc
-; GFX9-GISEL-NEXT:    s_setpc_b64 s[30:31]
-;
-; GFX11-SDAG-LABEL: v_test_nnan_input_fmed3_r_i_i_f64_maximum_minimum:
-; GFX11-SDAG:       ; %bb.0:
-; GFX11-SDAG-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-SDAG-NEXT:    v_add_f64 v[0:1], v[0:1], 1.0
-; GFX11-SDAG-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
-; GFX11-SDAG-NEXT:    v_max_f64 v[0:1], v[0:1], 2.0
-; GFX11-SDAG-NEXT:    v_min_f64 v[0:1], v[0:1], 4.0
-; GFX11-SDAG-NEXT:    s_setpc_b64 s[30:31]
+; GFX9-LABEL: v_test_nnan_input_fmed3_r_i_i_f64_maximum_minimum:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_add_f64 v[0:1], v[0:1], 1.0
+; GFX9-NEXT:    v_max_f64 v[0:1], v[0:1], 2.0
+; GFX9-NEXT:    v_min_f64 v[0:1], v[0:1], 4.0
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
 ;
-; GFX11-GISEL-LABEL: v_test_nnan_input_fmed3_r_i_i_f64_maximum_minimum:
-; GFX11-GISEL:       ; %bb.0:
-; GFX11-GISEL-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-GISEL-NEXT:    v_add_f64 v[0:1], v[0:1], 1.0
-; GFX11-GISEL-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
-; GFX11-GISEL-NEXT:    v_max_f64 v[0:1], v[0:1], 2.0
-; GFX11-GISEL-NEXT:    v_min_f64 v[2:3], v[0:1], 4.0
-; GFX11-GISEL-NEXT:    v_cmp_o_f64_e32 vcc_lo, 4.0, v[0:1]
-; GFX11-GISEL-NEXT:    s_delay_alu instid0(VALU_DEP_2)
-; GFX11-GISEL-NEXT:    v_dual_cndmask_b32 v0, 0, v2 :: v_dual_cndmask_b32 v1, 0x7ff80000, v3
-; GFX11-GISEL-NEXT:    s_setpc_b64 s[30:31]
+; GFX11-LABEL: v_test_nnan_input_fmed3_r_i_i_f64_maximum_minimum:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT:    v_add_f64 v[0:1], v[0:1], 1.0
+; GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX11-NEXT:    v_max_f64 v[0:1], v[0:1], 2.0
+; GFX11-NEXT:    v_min_f64 v[0:1], v[0:1], 4.0
+; GFX11-NEXT:    s_setpc_b64 s[30:31]
   %a.add = fadd nnan double %a, 1.0
   %max = call double @llvm.maximum.f64(double %a.add, double 2.0)
   %med = call double @llvm.minimum.f64(double %max, double 4.0)

diff  --git a/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp b/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp
index e47e53968b090..b10fd4621b0fd 100644
--- a/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp
+++ b/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp
@@ -115,8 +115,8 @@ TEST_F(AArch64GISelMITest, TestFPClassCstZeroFPExt) {
 
   KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
 
-  EXPECT_EQ(fcZero | fcNormal, Known.KnownFPClasses);
-  EXPECT_EQ(std::nullopt, Known.SignBit);
+  EXPECT_EQ(fcPosZero, Known.KnownFPClasses);
+  EXPECT_EQ(false, Known.SignBit);
 }
 
 TEST_F(AArch64GISelMITest, TestFPClassCstVecZeroFPExt) {
@@ -141,8 +141,8 @@ TEST_F(AArch64GISelMITest, TestFPClassCstVecZeroFPExt) {
 
   KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
 
-  EXPECT_EQ(fcZero | fcNormal, Known.KnownFPClasses);
-  EXPECT_EQ(std::nullopt, Known.SignBit);
+  EXPECT_EQ(fcPosZero, Known.KnownFPClasses);
+  EXPECT_EQ(false, Known.SignBit);
 }
 
 TEST_F(AArch64GISelMITest, TestFPClassCstZeroFPTrunc) {
@@ -164,7 +164,7 @@ TEST_F(AArch64GISelMITest, TestFPClassCstZeroFPTrunc) {
 
   KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
 
-  EXPECT_EQ(fcZero | fcPosSubnormal | fcPosNormal, Known.KnownFPClasses);
+  EXPECT_EQ(fcPosFinite | fcNegZero, Known.KnownFPClasses);
   EXPECT_EQ(false, Known.SignBit);
 }
 
@@ -190,7 +190,7 @@ TEST_F(AArch64GISelMITest, TestFPClassCstVecZeroFPTrunc) {
 
   KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
 
-  EXPECT_EQ(fcZero | fcPosSubnormal | fcPosNormal, Known.KnownFPClasses);
+  EXPECT_EQ(fcPosFinite | fcNegZero, Known.KnownFPClasses);
   EXPECT_EQ(false, Known.SignBit);
 }
 
@@ -546,7 +546,7 @@ TEST_F(AArch64GISelMITest, TestFPClassFnegFabsNInf) {
 
   KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
 
-  EXPECT_EQ((fcNegative & ~fcNegInf) | fcNan, Known.KnownFPClasses);
+  EXPECT_EQ(fcNegFinite | fcNan, Known.KnownFPClasses);
   EXPECT_EQ(true, Known.SignBit);
 }
 
@@ -623,7 +623,7 @@ TEST_F(AArch64GISelMITest, TestFPClassCopySignNInfSrc0_NegSign) {
 
   KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
 
-  EXPECT_EQ(fcNegFinite | fcNan, Known.KnownFPClasses);
+  EXPECT_EQ(fcNan | fcNegZero | fcNegNormal, Known.KnownFPClasses);
   EXPECT_EQ(true, Known.SignBit);
 }
 
@@ -649,7 +649,7 @@ TEST_F(AArch64GISelMITest, TestFPClassCopySignNInfSrc0_PosSign) {
 
   KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
 
-  EXPECT_EQ(fcPosFinite | fcNan, Known.KnownFPClasses);
+  EXPECT_EQ(fcNan | fcPosZero | fcPosNormal, Known.KnownFPClasses);
   EXPECT_EQ(false, Known.SignBit);
 }
 
@@ -673,7 +673,7 @@ TEST_F(AArch64GISelMITest, TestFPClassUIToFP) {
 
   KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
 
-  EXPECT_EQ(fcPosFinite & ~fcSubnormal, Known.KnownFPClasses);
+  EXPECT_EQ(fcPosZero | fcPosNormal, Known.KnownFPClasses);
   EXPECT_EQ(false, Known.SignBit);
 }
 
@@ -697,7 +697,7 @@ TEST_F(AArch64GISelMITest, TestFPClassSIToFP) {
 
   KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
 
-  EXPECT_EQ(fcFinite & ~fcNegZero & ~fcSubnormal, Known.KnownFPClasses);
+  EXPECT_EQ(fcPosNormal | fcNegNormal | fcPosZero, Known.KnownFPClasses);
   EXPECT_EQ(std::nullopt, Known.SignBit);
 }
 
@@ -804,7 +804,8 @@ TEST_F(AArch64GISelMITest, TestFPClassFstrictAdd_Zero) {
 TEST_F(AArch64GISelMITest, TestFPClassFMul) {
   StringRef MIRString = R"(
     %ptr:_(p0) = G_IMPLICIT_DEF
-    %val:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+    %load:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+    %val:_(s32) = G_FREEZE %load
     %fmul:_(s32) = G_FMUL %val, %val
     %copy_fadd:_(s32) = COPY %fmul
 )";
@@ -847,7 +848,7 @@ TEST_F(AArch64GISelMITest, TestFPClassFMulZero) {
 
   KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
 
-  EXPECT_EQ(fcPositive, Known.KnownFPClasses);
+  EXPECT_EQ(fcPosZero, Known.KnownFPClasses);
   EXPECT_EQ(false, Known.SignBit);
 }
 
@@ -873,7 +874,7 @@ TEST_F(AArch64GISelMITest, TestFPClassFLogNeg) {
 
   KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
 
-  EXPECT_EQ(fcFinite | fcNan | fcNegInf, Known.KnownFPClasses);
+  EXPECT_EQ(fcNan | fcNegInf | fcPosZero | fcNormal, Known.KnownFPClasses);
   EXPECT_EQ(std::nullopt, Known.SignBit);
 }
 
@@ -896,7 +897,7 @@ TEST_F(AArch64GISelMITest, TestFPClassFLogPosZero) {
 
   KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
 
-  EXPECT_EQ(fcFinite | fcNegInf, Known.KnownFPClasses);
+  EXPECT_EQ(fcNegInf | fcPosZero | fcNormal, Known.KnownFPClasses);
   EXPECT_EQ(std::nullopt, Known.SignBit);
 }
 
@@ -919,7 +920,7 @@ TEST_F(AArch64GISelMITest, TestFPClassFLogNegZero) {
 
   KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
 
-  EXPECT_EQ(fcFinite | fcNegInf, Known.KnownFPClasses);
+  EXPECT_EQ(fcNegInf | fcPosZero | fcNormal, Known.KnownFPClasses);
   EXPECT_EQ(std::nullopt, Known.SignBit);
 }
 
@@ -944,7 +945,7 @@ TEST_F(AArch64GISelMITest, TestFPClassCopy) {
 
   KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
 
-  EXPECT_EQ(fcPositive | fcNan, Known.KnownFPClasses);
+  EXPECT_EQ(~fcNegative, Known.KnownFPClasses);
   EXPECT_EQ(false, Known.SignBit);
 }
 
@@ -1047,14 +1048,15 @@ TEST_F(AArch64GISelMITest, TestFPClassFPowIPos) {
 
   KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
 
-  EXPECT_EQ(fcPositive | fcNan, Known.KnownFPClasses);
-  EXPECT_EQ(std::nullopt, Known.SignBit);
+  EXPECT_EQ(fcPositive, Known.KnownFPClasses);
+  EXPECT_EQ(false, Known.SignBit);
 }
 
 TEST_F(AArch64GISelMITest, TestFPClassFDiv) {
   StringRef MIRString = R"(
     %ptr:_(p0) = G_IMPLICIT_DEF
-    %val:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+    %load:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+    %val:_(s32) = G_FREEZE %load
     %fdiv:_(s32) = G_FDIV %val, %val
     %copy_fdiv:_(s32) = COPY %fdiv
 )";
@@ -1095,14 +1097,15 @@ TEST_F(AArch64GISelMITest, TestFPClassFDiv_Inf) {
 
   KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
 
-  EXPECT_EQ(fcPositive, Known.KnownFPClasses);
+  EXPECT_EQ(fcPosInf, Known.KnownFPClasses);
   EXPECT_EQ(false, Known.SignBit);
 }
 
 TEST_F(AArch64GISelMITest, TestFPClassFRem) {
   StringRef MIRString = R"(
     %ptr:_(p0) = G_IMPLICIT_DEF
-    %val:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+    %load:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+    %val:_(s32) = G_FREEZE %load
     %frem:_(s32) = G_FREM %val, %val
     %copy_frem:_(s32) = COPY %frem
 )";
@@ -1123,6 +1126,32 @@ TEST_F(AArch64GISelMITest, TestFPClassFRem) {
   EXPECT_EQ(std::nullopt, Known.SignBit);
 }
 
+TEST_F(AArch64GISelMITest, TestFPClassFRemSelf_KnownFiniteNonZero) {
+  // X % X where X is a known-finite, known-nonzero value should produce
+  // exactly [+-]0.0 (no NaN possible).
+  StringRef MIRString = R"(
+    %val:_(s32) = G_FCONSTANT float 2.0
+    %frem:_(s32) = G_FREM %val, %val
+    %copy_frem:_(s32) = COPY %frem
+)";
+
+  setUp(MIRString);
+  if (!TM)
+    GTEST_SKIP();
+
+  Register CopyReg = Copies[Copies.size() - 1];
+  MachineInstr *FinalCopy = MRI->getVRegDef(CopyReg);
+  Register SrcReg = FinalCopy->getOperand(1).getReg();
+
+  GISelValueTracking Info(*MF);
+
+  KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
+
+  // 2.0 % 2.0 = 0.0 exactly — NaN is impossible since 2.0 is finite and
+  // nonzero.
+  EXPECT_EQ(fcZero, Known.KnownFPClasses);
+}
+
 TEST_F(AArch64GISelMITest, TestFPClassShuffleVec) {
   StringRef MIRString = R"(
     %ptr:_(p0) = G_IMPLICIT_DEF
@@ -1257,3 +1286,360 @@ TEST_F(AArch64GISelMITest, TestFPClassVecInsertElem) {
   EXPECT_EQ(fcPosFinite, Known.KnownFPClasses);
   EXPECT_EQ(false, Known.SignBit);
 }
+
+TEST_F(AArch64GISelMITest, TestFPClassFSinh) {
+  StringRef MIRString = R"(
+    %ptr:_(p0) = G_IMPLICIT_DEF
+    %val:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+    %fsinh:_(s32) = G_FSINH %val
+    %copy:_(s32) = COPY %fsinh
+)";
+  setUp(MIRString);
+  if (!TM)
+    GTEST_SKIP();
+  Register CopyReg = Copies[Copies.size() - 1];
+  MachineInstr *FinalCopy = MRI->getVRegDef(CopyReg);
+  Register SrcReg = FinalCopy->getOperand(1).getReg();
+  GISelValueTracking Info(*MF);
+  KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
+  EXPECT_EQ(fcAllFlags, Known.KnownFPClasses);
+  EXPECT_EQ(std::nullopt, Known.SignBit);
+}
+
+TEST_F(AArch64GISelMITest, TestFPClassFSinhPos) {
+  // sinh is sign-preserving: non-negative input → non-negative output.
+  StringRef MIRString = R"(
+    %ptr:_(p0) = G_IMPLICIT_DEF
+    %val:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+    %fabs:_(s32) = nnan ninf G_FABS %val
+    %fsinh:_(s32) = G_FSINH %fabs
+    %copy:_(s32) = COPY %fsinh
+)";
+  setUp(MIRString);
+  if (!TM)
+    GTEST_SKIP();
+  Register CopyReg = Copies[Copies.size() - 1];
+  MachineInstr *FinalCopy = MRI->getVRegDef(CopyReg);
+  Register SrcReg = FinalCopy->getOperand(1).getReg();
+  GISelValueTracking Info(*MF);
+  KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
+  EXPECT_EQ(fcPositive, Known.KnownFPClasses);
+  EXPECT_EQ(false, Known.SignBit);
+}
+
+TEST_F(AArch64GISelMITest, TestFPClassFCosh) {
+  // cosh(x) >= 1 for all real x; never negative.
+  StringRef MIRString = R"(
+    %ptr:_(p0) = G_IMPLICIT_DEF
+    %val:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+    %fcosh:_(s32) = G_FCOSH %val
+    %copy:_(s32) = COPY %fcosh
+)";
+  setUp(MIRString);
+  if (!TM)
+    GTEST_SKIP();
+  Register CopyReg = Copies[Copies.size() - 1];
+  MachineInstr *FinalCopy = MRI->getVRegDef(CopyReg);
+  Register SrcReg = FinalCopy->getOperand(1).getReg();
+  GISelValueTracking Info(*MF);
+  KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
+  EXPECT_EQ(fcPositive | fcNan, Known.KnownFPClasses);
+  EXPECT_EQ(std::nullopt, Known.SignBit);
+}
+
+TEST_F(AArch64GISelMITest, TestFPClassFCoshNNaN) {
+  // cosh of a non-NaN source is non-NaN (and non-negative).
+  StringRef MIRString = R"(
+    %ptr:_(p0) = G_IMPLICIT_DEF
+    %val:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+    %fabs:_(s32) = nnan G_FABS %val
+    %fcosh:_(s32) = G_FCOSH %fabs
+    %copy:_(s32) = COPY %fcosh
+)";
+  setUp(MIRString);
+  if (!TM)
+    GTEST_SKIP();
+  Register CopyReg = Copies[Copies.size() - 1];
+  MachineInstr *FinalCopy = MRI->getVRegDef(CopyReg);
+  Register SrcReg = FinalCopy->getOperand(1).getReg();
+  GISelValueTracking Info(*MF);
+  KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
+  EXPECT_EQ(fcPositive, Known.KnownFPClasses);
+  EXPECT_EQ(false, Known.SignBit);
+}
+
+TEST_F(AArch64GISelMITest, TestFPClassFTanh) {
+  // tanh is bounded to (-1, 1): never Inf.
+  StringRef MIRString = R"(
+    %ptr:_(p0) = G_IMPLICIT_DEF
+    %val:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+    %ftanh:_(s32) = G_FTANH %val
+    %copy:_(s32) = COPY %ftanh
+)";
+  setUp(MIRString);
+  if (!TM)
+    GTEST_SKIP();
+  Register CopyReg = Copies[Copies.size() - 1];
+  MachineInstr *FinalCopy = MRI->getVRegDef(CopyReg);
+  Register SrcReg = FinalCopy->getOperand(1).getReg();
+  GISelValueTracking Info(*MF);
+  KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
+  EXPECT_EQ(fcAllFlags & ~fcInf, Known.KnownFPClasses);
+  EXPECT_EQ(std::nullopt, Known.SignBit);
+}
+
+TEST_F(AArch64GISelMITest, TestFPClassFTanhPos) {
+  // tanh is sign-preserving and bounded to (-1,1): non-negative finite output.
+  StringRef MIRString = R"(
+    %ptr:_(p0) = G_IMPLICIT_DEF
+    %val:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+    %fabs:_(s32) = nnan ninf G_FABS %val
+    %ftanh:_(s32) = G_FTANH %fabs
+    %copy:_(s32) = COPY %ftanh
+)";
+  setUp(MIRString);
+  if (!TM)
+    GTEST_SKIP();
+  Register CopyReg = Copies[Copies.size() - 1];
+  MachineInstr *FinalCopy = MRI->getVRegDef(CopyReg);
+  Register SrcReg = FinalCopy->getOperand(1).getReg();
+  GISelValueTracking Info(*MF);
+  KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
+  EXPECT_EQ(fcPosFinite, Known.KnownFPClasses);
+  EXPECT_EQ(false, Known.SignBit);
+}
+
+TEST_F(AArch64GISelMITest, TestFPClassFAsin) {
+  // asin is bounded to [-π/2, π/2]: never Inf.
+  StringRef MIRString = R"(
+    %ptr:_(p0) = G_IMPLICIT_DEF
+    %val:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+    %fasin:_(s32) = G_FASIN %val
+    %copy:_(s32) = COPY %fasin
+)";
+  setUp(MIRString);
+  if (!TM)
+    GTEST_SKIP();
+  Register CopyReg = Copies[Copies.size() - 1];
+  MachineInstr *FinalCopy = MRI->getVRegDef(CopyReg);
+  Register SrcReg = FinalCopy->getOperand(1).getReg();
+  GISelValueTracking Info(*MF);
+  KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
+  EXPECT_EQ(fcAllFlags & ~fcInf, Known.KnownFPClasses);
+  EXPECT_EQ(std::nullopt, Known.SignBit);
+}
+
+TEST_F(AArch64GISelMITest, TestFPClassFAsinPos) {
+  // asin is sign-preserving and bounded: non-negative finite output.
+  StringRef MIRString = R"(
+    %ptr:_(p0) = G_IMPLICIT_DEF
+    %val:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+    %fabs:_(s32) = nnan ninf G_FABS %val
+    %fasin:_(s32) = G_FASIN %fabs
+    %copy:_(s32) = COPY %fasin
+)";
+  setUp(MIRString);
+  if (!TM)
+    GTEST_SKIP();
+  Register CopyReg = Copies[Copies.size() - 1];
+  MachineInstr *FinalCopy = MRI->getVRegDef(CopyReg);
+  Register SrcReg = FinalCopy->getOperand(1).getReg();
+  GISelValueTracking Info(*MF);
+  KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
+  EXPECT_EQ(fcPosFinite, Known.KnownFPClasses);
+  EXPECT_EQ(false, Known.SignBit);
+}
+
+TEST_F(AArch64GISelMITest, TestFPClassFAcos) {
+  // acos is bounded to [0, π]: never Inf, never negative.
+  StringRef MIRString = R"(
+    %ptr:_(p0) = G_IMPLICIT_DEF
+    %val:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+    %facos:_(s32) = G_FACOS %val
+    %copy:_(s32) = COPY %facos
+)";
+  setUp(MIRString);
+  if (!TM)
+    GTEST_SKIP();
+  Register CopyReg = Copies[Copies.size() - 1];
+  MachineInstr *FinalCopy = MRI->getVRegDef(CopyReg);
+  Register SrcReg = FinalCopy->getOperand(1).getReg();
+  GISelValueTracking Info(*MF);
+  KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
+  EXPECT_EQ(fcPosFinite | fcNan, Known.KnownFPClasses);
+  EXPECT_EQ(std::nullopt, Known.SignBit);
+}
+
+TEST_F(AArch64GISelMITest, TestFPClassFAtan) {
+  // atan is bounded to (-π/2, π/2): never Inf (atan(±Inf) = ±π/2, finite).
+  StringRef MIRString = R"(
+    %ptr:_(p0) = G_IMPLICIT_DEF
+    %val:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+    %fatan:_(s32) = G_FATAN %val
+    %copy:_(s32) = COPY %fatan
+)";
+  setUp(MIRString);
+  if (!TM)
+    GTEST_SKIP();
+  Register CopyReg = Copies[Copies.size() - 1];
+  MachineInstr *FinalCopy = MRI->getVRegDef(CopyReg);
+  Register SrcReg = FinalCopy->getOperand(1).getReg();
+  GISelValueTracking Info(*MF);
+  KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
+  EXPECT_EQ(fcAllFlags & ~fcInf, Known.KnownFPClasses);
+  EXPECT_EQ(std::nullopt, Known.SignBit);
+}
+
+TEST_F(AArch64GISelMITest, TestFPClassFAtanPos) {
+  // atan is sign-preserving and bounded: non-negative finite output.
+  StringRef MIRString = R"(
+    %ptr:_(p0) = G_IMPLICIT_DEF
+    %val:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+    %fabs:_(s32) = nnan ninf G_FABS %val
+    %fatan:_(s32) = G_FATAN %fabs
+    %copy:_(s32) = COPY %fatan
+)";
+  setUp(MIRString);
+  if (!TM)
+    GTEST_SKIP();
+  Register CopyReg = Copies[Copies.size() - 1];
+  MachineInstr *FinalCopy = MRI->getVRegDef(CopyReg);
+  Register SrcReg = FinalCopy->getOperand(1).getReg();
+  GISelValueTracking Info(*MF);
+  KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
+  EXPECT_EQ(fcPosFinite, Known.KnownFPClasses);
+  EXPECT_EQ(false, Known.SignBit);
+}
+
+TEST_F(AArch64GISelMITest, TestFPClassFTan) {
+  // tan(±Inf) = NaN, tan(finite) = finite: never Inf.
+  StringRef MIRString = R"(
+    %ptr:_(p0) = G_IMPLICIT_DEF
+    %val:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+    %ftan:_(s32) = G_FTAN %val
+    %copy:_(s32) = COPY %ftan
+)";
+  setUp(MIRString);
+  if (!TM)
+    GTEST_SKIP();
+  Register CopyReg = Copies[Copies.size() - 1];
+  MachineInstr *FinalCopy = MRI->getVRegDef(CopyReg);
+  Register SrcReg = FinalCopy->getOperand(1).getReg();
+  GISelValueTracking Info(*MF);
+  KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
+  EXPECT_EQ(fcAllFlags & ~fcInf, Known.KnownFPClasses);
+  EXPECT_EQ(std::nullopt, Known.SignBit);
+}
+
+TEST_F(AArch64GISelMITest, TestFPClassFTanNNaN) {
+  // tan of a non-NaN, non-Inf source is non-NaN and non-Inf.
+  StringRef MIRString = R"(
+    %ptr:_(p0) = G_IMPLICIT_DEF
+    %val:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+    %fabs:_(s32) = nnan ninf G_FABS %val
+    %ftan:_(s32) = G_FTAN %fabs
+    %copy:_(s32) = COPY %ftan
+)";
+  setUp(MIRString);
+  if (!TM)
+    GTEST_SKIP();
+  Register CopyReg = Copies[Copies.size() - 1];
+  MachineInstr *FinalCopy = MRI->getVRegDef(CopyReg);
+  Register SrcReg = FinalCopy->getOperand(1).getReg();
+  GISelValueTracking Info(*MF);
+  KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
+  EXPECT_EQ(fcFinite, Known.KnownFPClasses);
+  EXPECT_EQ(std::nullopt, Known.SignBit);
+}
+
+TEST_F(AArch64GISelMITest, TestFPClassFAtan2) {
+  // atan2 result is in (-π, π]: never Inf.
+  StringRef MIRString = R"(
+    %ptr:_(p0) = G_IMPLICIT_DEF
+    %y:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+    %x:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+    %fatan2:_(s32) = G_FATAN2 %y, %x
+    %copy:_(s32) = COPY %fatan2
+)";
+  setUp(MIRString);
+  if (!TM)
+    GTEST_SKIP();
+  Register CopyReg = Copies[Copies.size() - 1];
+  MachineInstr *FinalCopy = MRI->getVRegDef(CopyReg);
+  Register SrcReg = FinalCopy->getOperand(1).getReg();
+  GISelValueTracking Info(*MF);
+  KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
+  EXPECT_EQ(fcAllFlags & ~fcInf, Known.KnownFPClasses);
+  EXPECT_EQ(std::nullopt, Known.SignBit);
+}
+
+TEST_F(AArch64GISelMITest, TestFPClassFAtan2NNaN) {
+  // atan2 with two non-NaN inputs is non-NaN and non-Inf.
+  StringRef MIRString = R"(
+    %ptr:_(p0) = G_IMPLICIT_DEF
+    %y:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+    %x:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+    %fabs_y:_(s32) = nnan ninf G_FABS %y
+    %fabs_x:_(s32) = nnan ninf G_FABS %x
+    %fatan2:_(s32) = G_FATAN2 %fabs_y, %fabs_x
+    %copy:_(s32) = COPY %fatan2
+)";
+  setUp(MIRString);
+  if (!TM)
+    GTEST_SKIP();
+  Register CopyReg = Copies[Copies.size() - 1];
+  MachineInstr *FinalCopy = MRI->getVRegDef(CopyReg);
+  Register SrcReg = FinalCopy->getOperand(1).getReg();
+  GISelValueTracking Info(*MF);
+  KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
+  EXPECT_EQ(fcFinite, Known.KnownFPClasses);
+  EXPECT_EQ(std::nullopt, Known.SignBit);
+}
+
+// isAbsoluteValueULEOne: x - floor(x) is in [0, 1), so multiplying a known-
+// finite value by it cannot overflow to infinity.
+TEST_F(AArch64GISelMITest, TestFPClassFMulAbsULEOne) {
+  StringRef MIRString = R"(
+    %ptr:_(p0) = G_IMPLICIT_DEF
+    %x:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+    %val:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+    %floor:_(s32) = G_FFLOOR %x
+    %fract:_(s32) = G_FSUB %x, %floor
+    %finite:_(s32) = nnan ninf G_FABS %val
+    %fmul:_(s32) = G_FMUL %finite, %fract
+    %copy:_(s32) = COPY %fmul
+)";
+  setUp(MIRString);
+  if (!TM)
+    GTEST_SKIP();
+  Register CopyReg = Copies[Copies.size() - 1];
+  MachineInstr *FinalCopy = MRI->getVRegDef(CopyReg);
+  Register SrcReg = FinalCopy->getOperand(1).getReg();
+  GISelValueTracking Info(*MF);
+  KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
+  EXPECT_EQ(~fcInf, Known.KnownFPClasses);
+  EXPECT_EQ(std::nullopt, Known.SignBit);
+}
+
+// G_FMA with A == B (and A guaranteed not-undef): the multiply part is a
+// square, so the result is known non-negative (never fcNegative).
+TEST_F(AArch64GISelMITest, TestFPClassFMASelfSquare) {
+  StringRef MIRString = R"(
+    %ptr:_(p0) = G_IMPLICIT_DEF
+    %load:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+    %val:_(s32) = G_FREEZE %load
+    %c:_(s32) = G_FCONSTANT float 1.0
+    %fma:_(s32) = G_FMA %val, %val, %c
+    %copy:_(s32) = COPY %fma
+)";
+  setUp(MIRString);
+  if (!TM)
+    GTEST_SKIP();
+  Register CopyReg = Copies[Copies.size() - 1];
+  MachineInstr *FinalCopy = MRI->getVRegDef(CopyReg);
+  Register SrcReg = FinalCopy->getOperand(1).getReg();
+  GISelValueTracking Info(*MF);
+  KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
+  EXPECT_EQ(fcNan | fcPosInf | fcPosNormal, Known.KnownFPClasses);
+  EXPECT_EQ(std::nullopt, Known.SignBit);
+}


        


More information about the llvm-commits mailing list