Skip to content

[llvm][GISel] Use computeKnownFPClass #141484

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

tgymnich
Copy link
Member

@tgymnich tgymnich commented May 26, 2025

  • use newly introduced computeKnownFPClass in GISelValueTracking

cc @arsenm

Copy link

github-actions bot commented May 26, 2025

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff HEAD~1 HEAD --extensions h,cpp -- 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/AMDGPURegBankCombiner.cpp
View the diff from clang-format here.
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/Utils.h b/llvm/include/llvm/CodeGen/GlobalISel/Utils.h
index 5f79bc3d8..fc0f4f8f8 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/Utils.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/Utils.h
@@ -346,7 +346,8 @@ isKnownToBeAPowerOfTwo(Register Val, const MachineRegisterInfo &MRI,
 /// 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,
-                              GISelValueTracking *ValueTracking, bool SNaN = false);
+                              GISelValueTracking *ValueTracking,
+                              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,

@tgymnich tgymnich force-pushed the tim/use-gisel-compute-known-fpclass branch 4 times, most recently from 3749625 to b075896 Compare May 28, 2025 14:01
@tgymnich
Copy link
Member Author

tgymnich commented Jun 3, 2025

@arsenm how do you think we should go about handling SNaNs here? The previous code basically assumed that SNaNs can never occur.

@arsenm arsenm added llvm:globalisel floating-point Floating-point math labels Jun 5, 2025
@llvmbot
Copy link
Member

llvmbot commented Jun 5, 2025

@llvm/pr-subscribers-llvm-globalisel

Author: Tim Gymnich (tgymnich)

Changes
  • use newly introduced computeKnownFPClass in GISelValueTracking

cc @arsenm


Patch is 47.09 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/141484.diff

13 Files Affected:

  • (modified) llvm/include/llvm/CodeGen/GlobalISel/Utils.h (+4-3)
  • (modified) llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp (+2-2)
  • (modified) llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp (+174-30)
  • (modified) llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp (+2-2)
  • (modified) llvm/lib/CodeGen/GlobalISel/Utils.cpp (+6-72)
  • (modified) llvm/lib/Target/AMDGPU/AMDGPUInstructions.td (+1-1)
  • (modified) llvm/lib/Target/AMDGPU/AMDGPURegBankCombiner.cpp (+7-5)
  • (modified) llvm/test/CodeGen/AMDGPU/GlobalISel/clamp-fmed3-const-combine.ll (+13-5)
  • (modified) llvm/test/CodeGen/AMDGPU/GlobalISel/clamp-minmax-const-combine.ll (+13-19)
  • (modified) llvm/test/CodeGen/AMDGPU/GlobalISel/fmed3-min-max-const-combine.ll (+8-14)
  • (modified) llvm/test/CodeGen/AMDGPU/GlobalISel/regbankcombiner-clamp-fmed3-const.mir (+30-10)
  • (modified) llvm/test/CodeGen/AMDGPU/GlobalISel/regbankcombiner-clamp-minmax-const.mir (+8-27)
  • (modified) llvm/test/CodeGen/AMDGPU/GlobalISel/regbankcombiner-fmed3-minmax-const.mir (+6-9)
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/Utils.h b/llvm/include/llvm/CodeGen/GlobalISel/Utils.h
index 684a9bf554fb1..cd27a3d5cdbac 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/Utils.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/Utils.h
@@ -337,11 +337,12 @@ bool isKnownToBeAPowerOfTwo(Register Val, const MachineRegisterInfo &MRI,
 /// 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.
 bool isKnownNeverNaN(Register Val, const MachineRegisterInfo &MRI,
-                     bool SNaN = false);
+                     GISelValueTracking *ValueTracking, 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);
+inline bool isKnownNeverSNaN(Register Val, const MachineRegisterInfo &MRI,
+                             GISelValueTracking *ValueTracking) {
+  return isKnownNeverNaN(Val, MRI, ValueTracking, true);
 }
 
 Align inferAlignFromPtrInfo(MachineFunction &MF, const MachinePointerInfo &MPO);
diff --git a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
index b1e851183de0d..8952226ae7f1e 100644
--- a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
@@ -6519,8 +6519,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 = isKnownNeverNaN(LHS, MRI, VT);
+  bool RHSSafe = isKnownNeverNaN(RHS, MRI, VT);
   // 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 67b1a449f8483..e98c49bbcc9dd 100644
--- a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
@@ -693,6 +693,9 @@ static bool outputDenormalIsIEEEOrPosZero(const MachineFunction &MF, LLT Ty) {
 void GISelValueTracking::computeKnownFPClass(Register R, KnownFPClass &Known,
                                              FPClassTest InterestedClasses,
                                              unsigned Depth) {
+  if (!R.isVirtual())
+    return;
+
   LLT Ty = MRI.getType(R);
   APInt DemandedElts =
       Ty.isFixedVector() ? APInt::getAllOnes(Ty.getNumElements()) : APInt(1, 1);
@@ -736,6 +739,9 @@ void GISelValueTracking::computeKnownFPClass(Register R,
 
   assert(Depth <= MaxAnalysisRecursionDepth && "Limit Search Depth");
 
+  if (!R.isVirtual())
+    return;
+
   MachineInstr &MI = *MRI.getVRegDef(R);
   unsigned Opcode = MI.getOpcode();
   LLT DstTy = MRI.getType(R);
@@ -915,8 +921,6 @@ void GISelValueTracking::computeKnownFPClass(Register R,
 
     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())
@@ -939,6 +943,7 @@ void GISelValueTracking::computeKnownFPClass(Register R,
   }
   case TargetOpcode::G_FSIN:
   case TargetOpcode::G_FCOS:
+  case TargetOpcode::G_FTAN:
   case TargetOpcode::G_FSINCOS: {
     // Return NaN on infinite inputs.
     Register Val = MI.getOperand(1).getReg();
@@ -946,18 +951,19 @@ void GISelValueTracking::computeKnownFPClass(Register R,
 
     computeKnownFPClass(Val, DemandedElts, InterestedClasses, KnownSrc,
                         Depth + 1);
+
     Known.knownNot(fcInf);
 
     if (KnownSrc.isKnownNeverNaN() && KnownSrc.isKnownNeverInfinity())
       Known.knownNot(fcNan);
     break;
   }
+  case TargetOpcode::G_FMAXNUM_IEEE:
+  case TargetOpcode::G_FMINNUM_IEEE:
   case TargetOpcode::G_FMAXNUM:
   case TargetOpcode::G_FMINNUM:
-  case TargetOpcode::G_FMINNUM_IEEE:
   case TargetOpcode::G_FMAXIMUM:
   case TargetOpcode::G_FMINIMUM:
-  case TargetOpcode::G_FMAXNUM_IEEE:
   case TargetOpcode::G_FMAXIMUMNUM:
   case TargetOpcode::G_FMINIMUMNUM: {
     Register LHS = MI.getOperand(1).getReg();
@@ -972,6 +978,10 @@ void GISelValueTracking::computeKnownFPClass(Register R,
     bool NeverNaN = KnownLHS.isKnownNeverNaN() || KnownRHS.isKnownNeverNaN();
     Known = KnownLHS | KnownRHS;
 
+    if (Opcode == TargetOpcode::G_FMAXNUM_IEEE ||
+        Opcode == TargetOpcode::G_FMINNUM_IEEE)
+      Known.knownNot(fcSNan);
+
     // If either operand is not NaN, the result is not NaN.
     if (NeverNaN && (Opcode == TargetOpcode::G_FMINNUM ||
                      Opcode == TargetOpcode::G_FMAXNUM ||
@@ -979,6 +989,12 @@ void GISelValueTracking::computeKnownFPClass(Register R,
                      Opcode == TargetOpcode::G_FMAXIMUMNUM))
       Known.knownNot(fcNan);
 
+    if ((Opcode == TargetOpcode::G_FMAXNUM_IEEE ||
+         Opcode == TargetOpcode::G_FMINNUM_IEEE) &&
+        ((KnownLHS.isKnownNeverNaN() && KnownRHS.isKnownNever(fcSNan)) ||
+         (KnownLHS.isKnownNever(fcSNan) && KnownRHS.isKnownNeverNaN())))
+      Known.knownNot(fcNan);
+
     if (Opcode == TargetOpcode::G_FMAXNUM ||
         Opcode == TargetOpcode::G_FMAXIMUMNUM ||
         Opcode == TargetOpcode::G_FMAXNUM_IEEE) {
@@ -1024,7 +1040,8 @@ void GISelValueTracking::computeKnownFPClass(Register R,
     //
     if ((Known.KnownFPClasses & fcZero) != fcNone &&
         !Known.isKnownNeverSubnormal()) {
-      DenormalMode Mode = MF->getDenormalMode(getFltSemanticForLLT(DstTy));
+      DenormalMode Mode =
+          MF->getDenormalMode(getFltSemanticForLLT(DstTy.getScalarType()));
       if (Mode != DenormalMode::getIEEE())
         Known.KnownFPClasses |= fcZero;
     }
@@ -1066,6 +1083,7 @@ void GISelValueTracking::computeKnownFPClass(Register R,
   case TargetOpcode::G_FCANONICALIZE: {
     Register Val = MI.getOperand(1).getReg();
     KnownFPClass KnownSrc;
+
     computeKnownFPClass(Val, DemandedElts, InterestedClasses, KnownSrc,
                         Depth + 1);
 
@@ -1086,8 +1104,8 @@ void GISelValueTracking::computeKnownFPClass(Register R,
 
     // If the parent function flushes denormals, the canonical output cannot
     // be a denormal.
-    LLT Ty = MRI.getType(Val);
-    const fltSemantics &FPType = getFltSemanticForLLT(Ty.getScalarType());
+    LLT Ty = MRI.getType(Val).getScalarType();
+    const fltSemantics &FPType = getFltSemanticForLLT(Ty);
     DenormalMode DenormMode = MF->getDenormalMode(FPType);
     if (DenormMode == DenormalMode::getIEEE()) {
       if (KnownSrc.isKnownNever(fcPosZero))
@@ -1167,6 +1185,8 @@ void GISelValueTracking::computeKnownFPClass(Register R,
     if (KnownSrc.isKnownNeverNaN()) {
       Known.knownNot(fcNan);
       Known.signBitMustBeZero();
+    } else {
+      Known.knownNot(fcSNan);
     }
 
     break;
@@ -1197,8 +1217,8 @@ void GISelValueTracking::computeKnownFPClass(Register R,
     if (KnownSrc.isKnownNeverNaN() && KnownSrc.cannotBeOrderedLessThanZero())
       Known.knownNot(fcNan);
 
-    LLT Ty = MRI.getType(Val);
-    const fltSemantics &FltSem = getFltSemanticForLLT(Ty.getScalarType());
+    LLT Ty = MRI.getType(Val).getScalarType();
+    const fltSemantics &FltSem = getFltSemanticForLLT(Ty);
     DenormalMode Mode = MF->getDenormalMode(FltSem);
 
     if (KnownSrc.isKnownNeverLogicalZero(Mode))
@@ -1277,6 +1297,7 @@ void GISelValueTracking::computeKnownFPClass(Register R,
     Register LHS = MI.getOperand(1).getReg();
     Register RHS = MI.getOperand(2).getReg();
     KnownFPClass KnownLHS, KnownRHS;
+
     bool WantNegative =
         (Opcode == TargetOpcode::G_FADD ||
          Opcode == TargetOpcode::G_STRICT_FADD) &&
@@ -1316,19 +1337,19 @@ void GISelValueTracking::computeKnownFPClass(Register R,
           Known.knownNot(KnownFPClass::OrderedLessThanZeroMask);
 
         // (fadd x, 0.0) is guaranteed to return +0.0, not -0.0.
-        if ((KnownLHS.isKnownNeverLogicalNegZero(
-                 MF->getDenormalMode(getFltSemanticForLLT(DstTy))) ||
-             KnownRHS.isKnownNeverLogicalNegZero(
-                 MF->getDenormalMode(getFltSemanticForLLT(DstTy)))) &&
+        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))) ||
-             KnownRHS.isKnownNeverLogicalPosZero(
-                 MF->getDenormalMode(getFltSemanticForLLT(DstTy)))) &&
+        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);
@@ -1341,6 +1362,7 @@ void GISelValueTracking::computeKnownFPClass(Register R,
   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);
@@ -1374,11 +1396,11 @@ void GISelValueTracking::computeKnownFPClass(Register R,
     }
 
     if ((KnownRHS.isKnownNeverInfinity() ||
-         KnownLHS.isKnownNeverLogicalZero(
-             MF->getDenormalMode(getFltSemanticForLLT(DstTy)))) &&
+         KnownLHS.isKnownNeverLogicalZero(MF->getDenormalMode(
+             getFltSemanticForLLT(DstTy.getScalarType())))) &&
         (KnownLHS.isKnownNeverInfinity() ||
          KnownRHS.isKnownNeverLogicalZero(
-             MF->getDenormalMode(getFltSemanticForLLT(DstTy)))))
+             MF->getDenormalMode(getFltSemanticForLLT(DstTy.getScalarType())))))
       Known.knownNot(fcNan);
 
     break;
@@ -1430,10 +1452,10 @@ void GISelValueTracking::computeKnownFPClass(Register R,
       if (KnownLHS.isKnownNeverNaN() && KnownRHS.isKnownNeverNaN() &&
           (KnownLHS.isKnownNeverInfinity() ||
            KnownRHS.isKnownNeverInfinity()) &&
-          ((KnownLHS.isKnownNeverLogicalZero(
-               MF->getDenormalMode(getFltSemanticForLLT(DstTy)))) ||
-           (KnownRHS.isKnownNeverLogicalZero(
-               MF->getDenormalMode(getFltSemanticForLLT(DstTy)))))) {
+          ((KnownLHS.isKnownNeverLogicalZero(MF->getDenormalMode(
+               getFltSemanticForLLT(DstTy.getScalarType())))) ||
+           (KnownRHS.isKnownNeverLogicalZero(MF->getDenormalMode(
+               getFltSemanticForLLT(DstTy.getScalarType())))))) {
         Known.knownNot(fcNan);
       }
 
@@ -1446,8 +1468,8 @@ void GISelValueTracking::computeKnownFPClass(Register R,
       // Inf REM x and x REM 0 produce NaN.
       if (KnownLHS.isKnownNeverNaN() && KnownRHS.isKnownNeverNaN() &&
           KnownLHS.isKnownNeverInfinity() &&
-          KnownRHS.isKnownNeverLogicalZero(
-              MF->getDenormalMode(getFltSemanticForLLT(DstTy)))) {
+          KnownRHS.isKnownNeverLogicalZero(MF->getDenormalMode(
+              getFltSemanticForLLT(DstTy.getScalarType())))) {
         Known.knownNot(fcNan);
       }
 
@@ -1471,11 +1493,12 @@ void GISelValueTracking::computeKnownFPClass(Register R,
     Register Src = MI.getOperand(1).getReg();
     // Infinity, nan and zero propagate from source.
     computeKnownFPClass(R, DemandedElts, InterestedClasses, Known, Depth + 1);
+    Known.knownNot(fcSNan);
 
-    LLT DstTy = MRI.getType(Dst);
-    const fltSemantics &DstSem = getFltSemanticForLLT(DstTy.getScalarType());
-    LLT SrcTy = MRI.getType(Src);
-    const fltSemantics &SrcSem = getFltSemanticForLLT(SrcTy.getScalarType());
+    LLT DstTy = MRI.getType(Dst).getScalarType();
+    const fltSemantics &DstSem = getFltSemanticForLLT(DstTy);
+    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)) {
@@ -1494,6 +1517,7 @@ void GISelValueTracking::computeKnownFPClass(Register R,
   case TargetOpcode::G_FPTRUNC: {
     computeKnownFPClassForFPTrunc(MI, DemandedElts, InterestedClasses, Known,
                                   Depth);
+    Known.knownNot(fcSNan);
     break;
   }
   case TargetOpcode::G_SITOFP:
@@ -1671,6 +1695,126 @@ void GISelValueTracking::computeKnownFPClass(Register R,
     computeKnownFPClass(Src, DemandedElts, InterestedClasses, Known, Depth + 1);
     break;
   }
+  case TargetOpcode::G_FATAN: {
+    Register Val = MI.getOperand(1).getReg();
+    KnownFPClass KnownSrc;
+
+    computeKnownFPClass(Val, DemandedElts, InterestedClasses, KnownSrc,
+                        Depth + 1);
+
+    if (KnownSrc.isKnownAlways(fcInf))
+      Known.KnownFPClasses = fcNan;
+
+    break;
+  }
+  case TargetOpcode::G_FATAN2: {
+    Register LHS = MI.getOperand(1).getReg();
+    Register RHS = MI.getOperand(2).getReg();
+    KnownFPClass KnownLHS;
+    KnownFPClass KnownRHS;
+
+    computeKnownFPClass(LHS, DemandedElts, InterestedClasses, KnownLHS,
+                        Depth + 1);
+
+    computeKnownFPClass(RHS, DemandedElts, InterestedClasses, KnownRHS,
+                        Depth + 1);
+
+    if (!KnownRHS.isKnownNeverNaN() || !KnownRHS.isKnownNeverNaN())
+      break;
+
+    if (KnownLHS.isKnownAlways(fcZero)) {
+      // atan2(+-0, −0) -> +-pi
+      // atan2(+-0, x) -> +-pi for x < 0
+      if (KnownRHS.isKnownAlways(fcNegFinite)) {
+        Known.KnownFPClasses = fcFinite;
+        break;
+      }
+
+      // atan2(+-0, +0) -> +-0
+      // atan2(+-0, x) -> +-0 for x > 0
+      if (KnownRHS.isKnownAlways(fcPosFinite)) {
+        Known.KnownFPClasses = fcZero;
+        break;
+      }
+    }
+
+    if (KnownRHS.isKnownAlways(fcZero)) {
+      // atan2(y, +-0) -> -pi/2 for y < 0
+      if (KnownLHS.isKnownNeverZero() && KnownLHS.isKnownAlways(fcNegFinite)) {
+        Known.KnownFPClasses = fcNegFinite;
+        break;
+      }
+
+      // atan2(y, +-0) -> +pi/2 for y > 0
+      if (KnownLHS.isKnownNeverZero() && KnownLHS.isKnownAlways(fcPosFinite)) {
+        Known.KnownFPClasses = fcPosFinite;
+        break;
+      }
+    }
+
+    if (KnownLHS.isKnownAlways(fcPosFinite) && KnownLHS.isKnownNeverZero()) {
+      // atan2(+-y, -inf) -> +-pi for finite y > 0
+      if (KnownRHS.isKnownAlways(fcNegInf)) {
+        Known.KnownFPClasses = fcFinite;
+        break;
+      }
+
+      // atan2(+-y, +inf) -> +-0 for finite y > 0
+      if (KnownRHS.isKnownAlways(fcPosInf)) {
+        Known.KnownFPClasses = fcZero;
+        break;
+      }
+    }
+
+    if (KnownLHS.isKnownAlways(fcInf)) {
+      // atan2(+-inf, x) -> +-pi/2 for finite x
+      // atan2(+-inf, -inf) -> +-3pi/4
+      // atan2(+-inf, +inf) -> +-pi/4
+      Known.KnownFPClasses = fcFinite;
+      break;
+    }
+
+    break;
+  }
+  case TargetOpcode::G_FCOSH: {
+    Register Val = MI.getOperand(1).getReg();
+    KnownFPClass KnownSrc;
+
+    computeKnownFPClass(Val, DemandedElts, InterestedClasses, KnownSrc,
+                        Depth + 1);
+
+    // cosh(+-inf) -> +inf
+    if (KnownSrc.isKnownAlways(fcInf))
+      Known.KnownFPClasses = fcPosInf;
+
+    break;
+  }
+  case TargetOpcode::G_FSINH: {
+    Register Val = MI.getOperand(1).getReg();
+    KnownFPClass KnownSrc;
+
+    computeKnownFPClass(Val, DemandedElts, InterestedClasses, KnownSrc,
+                        Depth + 1);
+
+    // sinh(±∞) is ±∞
+    if (KnownSrc.isKnownAlways(fcInf))
+      Known.KnownFPClasses = fcInf;
+
+    break;
+  }
+  case TargetOpcode::G_FTANH: {
+    Register Val = MI.getOperand(1).getReg();
+    KnownFPClass KnownSrc;
+
+    computeKnownFPClass(Val, DemandedElts, InterestedClasses, KnownSrc,
+                        Depth + 1);
+
+    // tanh(+-inf) is +-1
+    if (KnownSrc.isKnownAlways(fcInf))
+      Known.KnownFPClasses = fcFinite;
+
+    break;
+  }
   }
 }
 
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index 7b18a98d7f3ca..e242df04a5d80 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -8179,10 +8179,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 (!isKnownNeverSNaN(Src0, MRI, VT))
       Src0 = MIRBuilder.buildFCanonicalize(Ty, Src0, MI.getFlags()).getReg(0);
 
-    if (!isKnownNeverSNaN(Src1, MRI))
+    if (!isKnownNeverSNaN(Src1, MRI, VT))
       Src1 = MIRBuilder.buildFCanonicalize(Ty, Src1, MI.getFlags()).getReg(0);
   }
 
diff --git a/llvm/lib/CodeGen/GlobalISel/Utils.cpp b/llvm/lib/CodeGen/GlobalISel/Utils.cpp
index 64af7a57e8d12..cf8ded67ac679 100644
--- a/llvm/lib/CodeGen/GlobalISel/Utils.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/Utils.cpp
@@ -12,6 +12,7 @@
 #include "llvm/CodeGen/GlobalISel/Utils.h"
 #include "llvm/ADT/APFloat.h"
 #include "llvm/ADT/APInt.h"
+#include "llvm/ADT/FloatingPointMode.h"
 #include "llvm/Analysis/ValueTracking.h"
 #include "llvm/CodeGen/CodeGenCommonISel.h"
 #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
@@ -807,7 +808,7 @@ llvm::ConstantFoldVectorBinop(unsigned Opcode, const Register Op1,
 }
 
 bool llvm::isKnownNeverNaN(Register Val, const MachineRegisterInfo &MRI,
-                           bool SNaN) {
+                           GISelValueTracking *VT, bool SNaN) {
   const MachineInstr *DefMI = MRI.getVRegDef(Val);
   if (!DefMI)
     return false;
@@ -816,78 +817,11 @@ bool llvm::isKnownNeverNaN(Register Val, const MachineRegisterInfo &MRI,
   if (DefMI->getFlag(MachineInstr::FmNoNans) || TM.Options.NoNaNsFPMath)
     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;
-  }
+  KnownFPClass FPClass = VT->computeKnownFPClass(Val, fcNan);
+  if (SNaN)
+    return FPClass.isKnownNever(fcSNan);
 
-  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 ...
[truncated]

Comment on lines +77 to +78
; GFX10-NEXT: v_mul_f32_e32 v0, 2.0, v0
; GFX10-NEXT: v_med3_f32 v0, v0, 1.0, 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regression

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All regressions stem from the difference in handling SNaNs. Not sure how to proceed.

Comment on lines +88 to 91
; GFX12-NEXT: v_mul_f32_e32 v0, 2.0, v0
; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_1)
; GFX12-NEXT: v_med3_num_f32 v0, v0, 1.0, 0
; GFX12-NEXT: s_setpc_b64 s[30:31]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regression

@@ -337,11 +337,12 @@ bool isKnownToBeAPowerOfTwo(Register Val, const MachineRegisterInfo &MRI,
/// 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.
bool isKnownNeverNaN(Register Val, const MachineRegisterInfo &MRI,
bool SNaN = false);
GISelValueTracking *ValueTracking, bool SNaN = false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is optional it should be default initialized to null. If it's required it should be a reference. It should probably be required?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not right now. But we could make it.

@tgymnich tgymnich force-pushed the tim/use-gisel-compute-known-fpclass branch from b075896 to 8571023 Compare June 9, 2025 11:14
@tgymnich tgymnich force-pushed the tim/use-gisel-compute-known-fpclass branch from 8571023 to afcba08 Compare June 17, 2025 14:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants