[llvm] Added ISD::FMAXIMUM/ISD::FMINIMUM + ISD::FMAXIMUMNUM/ISD::FMINIMUMNUM (PR #190465)

Kartik Ohlan via llvm-commits llvm-commits at lists.llvm.org
Sun Apr 5 09:57:13 PDT 2026


https://github.com/Ko496-glitch updated https://github.com/llvm/llvm-project/pull/190465

>From e21ace3e12b12a9a56ee8a24eb5ff33164c3fcd7 Mon Sep 17 00:00:00 2001
From: kartikohlan <kartik7ohlan at gmail.com>
Date: Sat, 4 Apr 2026 11:22:01 -0400
Subject: [PATCH 1/2] Added (early out and exit and enum style block

---
 .../lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 40 +++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 137922aa62557..6f4540a81f237 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -6106,6 +6106,46 @@ KnownFPClass SelectionDAG::computeKnownFPClass(SDValue Op,
     Known.fabs();
     break;
   }
+  case ISD::FMAXNUM:
+  case ISD::FMINNUM:
+  case ISD::FMAXIMUM:
+  case ISD::FMINIMUM:
+  case ISD::FMAXIMUMNUM:
+  case ISD::FMINIMUMNUM: {
+    KnownFPClass KnownRHS = computeKnownFPClass(Op.getOperand(1), DemandedElts,
+                                                InterestedClasses, Depth + 1);
+    if (KnownRHS.isUnknown()) {
+      break;
+    }
+    KnownFPClass KnownLHS = computeKnownFPClass(Op.getOperand(0), DemandedElts,
+                                                InterestedClasses, Depth + 1);
+    KnownFPClass::MinMaxKind Kind;
+    switch (Opcode) {
+    case ISD::FMAXNUM:
+      Kind = KnownFPClass::MinMaxKind::maxnum;
+      break;
+    case ISD::FMINNUM:
+      Kind = KnownFPClass::MinMaxKind::minnum;
+      break;
+    case ISD::FMAXIMUM:
+      Kind = KnownFPClass::MinMaxKind::maximum;
+      break;
+    case ISD::FMINIMUM:
+      Kind = KnownFPClass::MinMaxKind::minimum;
+      break;
+    case ISD::FMAXIMUMNUM:
+      Kind = KnownFPClass::MinMaxKind::maximumnum;
+      break;
+    case ISD::FMINIMUMNUM:
+      Kind = KnownFPClass::MinMaxKind::minimumnum;
+      break;
+    default:
+      llvm_unreachable("Illegal FP min/max opcode");
+    }
+    DenormalMode Mode = getDenormalMode(VT);
+    Known = KnownFPClass::minMaxLike(KnownLHS, KnownRHS, Kind, Mode);
+    break;
+  }
   default:
     if (Opcode >= ISD::BUILTIN_OP_END || Opcode == ISD::INTRINSIC_WO_CHAIN ||
         Opcode == ISD::INTRINSIC_W_CHAIN || Opcode == ISD::INTRINSIC_VOID) {

>From 0dc57d5c9c22717134e62a263e5dc9621747e0bf Mon Sep 17 00:00:00 2001
From: kartikohlan <kartik7ohlan at gmail.com>
Date: Sun, 5 Apr 2026 12:56:01 -0400
Subject: [PATCH 2/2] Refactor the block code and added the tests

---
 .../lib/CodeGen/SelectionDAG/SelectionDAG.cpp |  25 ++-
 ...s-minimum-maximum-minimumnum-maximumnum.ll | 212 ++++++++++++++++++
 2 files changed, 228 insertions(+), 9 deletions(-)
 create mode 100644 llvm/test/Transforms/Attributor/nofpclass-minimum-maximum-minimumnum-maximumnum.ll

diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 6f4540a81f237..e7523c0675a55 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -6030,6 +6030,20 @@ KnownFPClass SelectionDAG::computeKnownFPClass(SDValue Op,
                                                const APInt &DemandedElts,
                                                FPClassTest InterestedClasses,
                                                unsigned Depth) const {
+
+  auto GetMinMaxKnownFPClass = [&](SDValue LHS, SDValue RHS,
+                                   KnownFPClass::MinMaxKind Kind) {
+    KnownFPClass KnownRHS =
+        computeKnownFPClass(RHS, DemandedElts, InterestedClasses, Depth + 1);
+    if (KnownRHS.isUnknown())
+      return KnownRHS;
+    KnownFPClass KnownLHS =
+        computeKnownFPClass(LHS, DemandedElts, InterestedClasses, Depth + 1);
+
+    return KnownFPClass::minMaxLike(KnownLHS, KnownRHS, Kind,
+                                    getDenormalMode(Op.getValueType()));
+  };
+
   KnownFPClass Known;
 
   if (const auto *CFP = dyn_cast<ConstantFPSDNode>(Op))
@@ -6112,13 +6126,7 @@ KnownFPClass SelectionDAG::computeKnownFPClass(SDValue Op,
   case ISD::FMINIMUM:
   case ISD::FMAXIMUMNUM:
   case ISD::FMINIMUMNUM: {
-    KnownFPClass KnownRHS = computeKnownFPClass(Op.getOperand(1), DemandedElts,
-                                                InterestedClasses, Depth + 1);
-    if (KnownRHS.isUnknown()) {
-      break;
-    }
-    KnownFPClass KnownLHS = computeKnownFPClass(Op.getOperand(0), DemandedElts,
-                                                InterestedClasses, Depth + 1);
+
     KnownFPClass::MinMaxKind Kind;
     switch (Opcode) {
     case ISD::FMAXNUM:
@@ -6142,8 +6150,7 @@ KnownFPClass SelectionDAG::computeKnownFPClass(SDValue Op,
     default:
       llvm_unreachable("Illegal FP min/max opcode");
     }
-    DenormalMode Mode = getDenormalMode(VT);
-    Known = KnownFPClass::minMaxLike(KnownLHS, KnownRHS, Kind, Mode);
+    Known = GetMinMaxKnownFPClass(Op.getOperand(0), Op.getOperand(1), Kind);
     break;
   }
   default:
diff --git a/llvm/test/Transforms/Attributor/nofpclass-minimum-maximum-minimumnum-maximumnum.ll b/llvm/test/Transforms/Attributor/nofpclass-minimum-maximum-minimumnum-maximumnum.ll
new file mode 100644
index 0000000000000..0ce31464fe3d0
--- /dev/null
+++ b/llvm/test/Transforms/Attributor/nofpclass-minimum-maximum-minimumnum-maximumnum.ll
@@ -0,0 +1,212 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
+
+define float @ret_minimum(float %arg0, float %arg1) #0 {
+; CHECK-LABEL: define float @ret_minimum
+; CHECK-SAME: (float [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR1:[0-9]+]] {
+; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.minimum.f32(float [[ARG0]], float [[ARG1]]) #[[ATTR7:[0-9]+]]
+; CHECK-NEXT:    ret float [[CALL]]
+;
+  %call = call float @llvm.minimum.f32(float %arg0, float %arg1)
+  ret float %call
+}
+
+define float @ret_minimum_noinf__noinf(float nofpclass(inf) %arg0, float nofpclass(inf) %arg1) #0 {
+; CHECK-LABEL: define float @ret_minimum_noinf__noinf
+; CHECK-SAME: (float nofpclass(inf) [[ARG0:%.*]], float nofpclass(inf) [[ARG1:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.minimum.f32(float nofpclass(inf) [[ARG0]], float nofpclass(inf) [[ARG1]]) #[[ATTR7]]
+; CHECK-NEXT:    ret float [[CALL]]
+;
+  %call = call float @llvm.minimum.f32(float %arg0, float %arg1)
+  ret float %call
+}
+
+define float @ret_minimum_noinf__nonan(float nofpclass(inf) %arg0, float nofpclass(nan) %arg1) #0 {
+; CHECK-LABEL: define float @ret_minimum_noinf__nonan
+; CHECK-SAME: (float nofpclass(inf) [[ARG0:%.*]], float nofpclass(nan) [[ARG1:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.minimum.f32(float nofpclass(inf) [[ARG0]], float nofpclass(nan) [[ARG1]]) #[[ATTR7]]
+; CHECK-NEXT:    ret float [[CALL]]
+;
+  %call = call float @llvm.minimum.f32(float %arg0, float %arg1)
+  ret float %call
+}
+
+define float @ret_minimum_nonan__noinf(float nofpclass(nan) %arg0, float nofpclass(inf) %arg1) #0 {
+; CHECK-LABEL: define float @ret_minimum_nonan__noinf
+; CHECK-SAME: (float nofpclass(nan) [[ARG0:%.*]], float nofpclass(inf) [[ARG1:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.minimum.f32(float nofpclass(nan) [[ARG0]], float nofpclass(inf) [[ARG1]]) #[[ATTR7]]
+; CHECK-NEXT:    ret float [[CALL]]
+;
+  %call = call float @llvm.minimum.f32(float %arg0, float %arg1)
+  ret float %call
+}
+
+define float @ret_minimum_norm_zero__norm_sub(float nofpclass(norm zero) %arg0, float nofpclass(norm sub) %arg1) #0 {
+; CHECK-LABEL: define float @ret_minimum_norm_zero__norm_sub
+; CHECK-SAME: (float nofpclass(zero norm) [[ARG0:%.*]], float nofpclass(sub norm) [[ARG1:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.minimum.f32(float nofpclass(zero norm) [[ARG0]], float nofpclass(sub norm) [[ARG1]]) #[[ATTR7]]
+; CHECK-NEXT:    ret float [[CALL]]
+;
+  %call = call float @llvm.minimum.f32(float %arg0, float %arg1)
+  ret float %call
+}
+
+define float @ret_minimum_daz_daz(float %arg0, float %arg1) #1 {
+; CHECK-LABEL: define float @ret_minimum_daz_daz
+; CHECK-SAME: (float [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR2:[0-9]+]] {
+; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.minimum.f32(float [[ARG0]], float [[ARG1]]) #[[ATTR7]]
+; CHECK-NEXT:    ret float [[CALL]]
+;
+  %call = call float @llvm.minimum.f32(float %arg0, float %arg1)
+  ret float %call
+}
+
+define float @ret_minimum_dynamic_dynamic(float %arg0, float %arg1) #3 {
+; CHECK-LABEL: define float @ret_minimum_dynamic_dynamic
+; CHECK-SAME: (float [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR3:[0-9]+]] {
+; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.minimum.f32(float [[ARG0]], float [[ARG1]]) #[[ATTR7]]
+; CHECK-NEXT:    ret float [[CALL]]
+;
+  %call = call float @llvm.minimum.f32(float %arg0, float %arg1)
+  ret float %call
+}
+
+define float @ret_minimum_noinf_nozero__noinf_nozero(float nofpclass(inf zero) %arg0, float nofpclass(inf zero) %arg1) #1 {
+; CHECK-LABEL: define float @ret_minimum_noinf_nozero__noinf_nozero
+; CHECK-SAME: (float nofpclass(inf zero) [[ARG0:%.*]], float nofpclass(inf zero) [[ARG1:%.*]]) #[[ATTR2]] {
+; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.minimum.f32(float nofpclass(inf zero) [[ARG0]], float nofpclass(inf zero) [[ARG1]]) #[[ATTR7]]
+; CHECK-NEXT:    ret float [[CALL]]
+;
+  %call = call float @llvm.minimum.f32(float %arg0, float %arg1)
+  ret float %call
+}
+
+define <2 x float> @ret_minimum_noinf_nozero__noinf_nozero_v2f32(<2 x float> nofpclass(inf zero) %arg0, <2 x float> nofpclass(inf zero) %arg1) #1 {
+; CHECK-LABEL: define <2 x float> @ret_minimum_noinf_nozero__noinf_nozero_v2f32
+; CHECK-SAME: (<2 x float> nofpclass(inf zero) [[ARG0:%.*]], <2 x float> nofpclass(inf zero) [[ARG1:%.*]]) #[[ATTR2]] {
+; CHECK-NEXT:    [[CALL:%.*]] = call <2 x float> @llvm.minimum.v2f32(<2 x float> nofpclass(inf zero) [[ARG0]], <2 x float> nofpclass(inf zero) [[ARG1]]) #[[ATTR7]]
+; CHECK-NEXT:    ret <2 x float> [[CALL]]
+;
+  %call = call <2 x float> @llvm.minimum.v2f32(<2 x float> %arg0, <2 x float> %arg1)
+  ret <2 x float> %call
+}
+
+define float @ret_minimum_daz_daz_nozero__nozero(float nofpclass(zero) %arg0, float nofpclass(zero) %arg1) #1 {
+; CHECK-LABEL: define float @ret_minimum_daz_daz_nozero__nozero
+; CHECK-SAME: (float nofpclass(zero) [[ARG0:%.*]], float nofpclass(zero) [[ARG1:%.*]]) #[[ATTR2]] {
+; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.minimum.f32(float nofpclass(zero) [[ARG0]], float nofpclass(zero) [[ARG1]]) #[[ATTR7]]
+; CHECK-NEXT:    ret float [[CALL]]
+;
+  %call = call float @llvm.minimum.f32(float %arg0, float %arg1)
+  ret float %call
+}
+
+define float @ret_minimum_daz_daz_nozero_nosub__nozero_nosub(float nofpclass(zero sub) %arg0, float nofpclass(zero sub) %arg1) #1 {
+; CHECK-LABEL: define float @ret_minimum_daz_daz_nozero_nosub__nozero_nosub
+; CHECK-SAME: (float nofpclass(zero sub) [[ARG0:%.*]], float nofpclass(zero sub) [[ARG1:%.*]]) #[[ATTR2]] {
+; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.minimum.f32(float nofpclass(zero sub) [[ARG0]], float nofpclass(zero sub) [[ARG1]]) #[[ATTR7]]
+; CHECK-NEXT:    ret float [[CALL]]
+;
+  %call = call float @llvm.minimum.f32(float %arg0, float %arg1)
+  ret float %call
+}
+
+define float @ret_minimum_dynamic_dynamic_nozero__nozero(float nofpclass(zero) %arg0, float nofpclass(zero) %arg1) #3 {
+; CHECK-LABEL: define float @ret_minimum_dynamic_dynamic_nozero__nozero
+; CHECK-SAME: (float nofpclass(zero) [[ARG0:%.*]], float nofpclass(zero) [[ARG1:%.*]]) #[[ATTR3]] {
+; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.minimum.f32(float nofpclass(zero) [[ARG0]], float nofpclass(zero) [[ARG1]]) #[[ATTR7]]
+; CHECK-NEXT:    ret float [[CALL]]
+;
+  %call = call float @llvm.minimum.f32(float %arg0, float %arg1)
+  ret float %call
+}
+
+define float @ret_minimum_dynamic_dynamic_nozero_nosub__nozero_nosub(float nofpclass(zero sub) %arg0, float nofpclass(zero sub) %arg1) #3 {
+; CHECK-LABEL: define float @ret_minimum_dynamic_dynamic_nozero_nosub__nozero_nosub
+; CHECK-SAME: (float nofpclass(zero sub) [[ARG0:%.*]], float nofpclass(zero sub) [[ARG1:%.*]]) #[[ATTR3]] {
+; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.minimum.f32(float nofpclass(zero sub) [[ARG0]], float nofpclass(zero sub) [[ARG1]]) #[[ATTR7]]
+; CHECK-NEXT:    ret float [[CALL]]
+;
+  %call = call float @llvm.minimum.f32(float %arg0, float %arg1)
+  ret float %call
+}
+
+define float @ret_minimum_dapz_dapz_nozero__nozero(float nofpclass(zero) %arg0, float nofpclass(zero) %arg1) #2 {
+; CHECK-LABEL: define float @ret_minimum_dapz_dapz_nozero__nozero
+; CHECK-SAME: (float nofpclass(zero) [[ARG0:%.*]], float nofpclass(zero) [[ARG1:%.*]]) #[[ATTR4:[0-9]+]] {
+; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.minimum.f32(float nofpclass(zero) [[ARG0]], float nofpclass(zero) [[ARG1]]) #[[ATTR7]]
+; CHECK-NEXT:    ret float [[CALL]]
+;
+  %call = call float @llvm.minimum.f32(float %arg0, float %arg1)
+  ret float %call
+}
+
+define float @ret_minimum_dapz_dapz_nopzero_nopsub__nopzero_nopsub(float nofpclass(pzero psub) %arg0, float nofpclass(pzero psub) %arg1) #2 {
+; CHECK-LABEL: define float @ret_minimum_dapz_dapz_nopzero_nopsub__nopzero_nopsub
+; CHECK-SAME: (float nofpclass(pzero psub) [[ARG0:%.*]], float nofpclass(pzero psub) [[ARG1:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.minimum.f32(float nofpclass(pzero psub) [[ARG0]], float nofpclass(pzero psub) [[ARG1]]) #[[ATTR7]]
+; CHECK-NEXT:    ret float [[CALL]]
+;
+  %call = call float @llvm.minimum.f32(float %arg0, float %arg1)
+  ret float %call
+}
+
+define float @ret_minimum_ieee_daz_nozero__nozero(float nofpclass(zero) %arg0, float nofpclass(zero) %arg1) #4 {
+; CHECK-LABEL: define float @ret_minimum_ieee_daz_nozero__nozero
+; CHECK-SAME: (float nofpclass(zero) [[ARG0:%.*]], float nofpclass(zero) [[ARG1:%.*]]) #[[ATTR5:[0-9]+]] {
+; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.minimum.f32(float nofpclass(zero) [[ARG0]], float nofpclass(zero) [[ARG1]]) #[[ATTR7]]
+; CHECK-NEXT:    ret float [[CALL]]
+;
+  %call = call float @llvm.minimum.f32(float %arg0, float %arg1)
+  ret float %call
+}
+
+define float @ret_minimum_daz_ieee_nozero__nozero(float nofpclass(zero) %arg0, float nofpclass(zero) %arg1) #5 {
+; CHECK-LABEL: define float @ret_minimum_daz_ieee_nozero__nozero
+; CHECK-SAME: (float nofpclass(zero) [[ARG0:%.*]], float nofpclass(zero) [[ARG1:%.*]]) #[[ATTR6:[0-9]+]] {
+; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.minimum.f32(float nofpclass(zero) [[ARG0]], float nofpclass(zero) [[ARG1]]) #[[ATTR7]]
+; CHECK-NEXT:    ret float [[CALL]]
+;
+  %call = call float @llvm.minimum.f32(float %arg0, float %arg1)
+  ret float %call
+}
+
+define float @ret_minimum_noneg_nan__any(float nofpclass(ninf nsub nnorm nan) %arg0, float %arg1) #3 {
+; CHECK-LABEL: define float @ret_minimum_noneg_nan__any
+; CHECK-SAME: (float nofpclass(nan ninf nsub nnorm) [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR3]] {
+; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.minimum.f32(float nofpclass(nan ninf nsub nnorm) [[ARG0]], float [[ARG1]]) #[[ATTR7]]
+; CHECK-NEXT:    ret float [[CALL]]
+;
+  %call = call float @llvm.minimum.f32(float %arg0, float %arg1)
+  ret float %call
+}
+
+define float @ret_minimum_any__noneg_nan(float %arg0, float nofpclass(ninf nsub nnorm nan) %arg1) #3 {
+; CHECK-LABEL: define float @ret_minimum_any__noneg_nan
+; CHECK-SAME: (float [[ARG0:%.*]], float nofpclass(nan ninf nsub nnorm) [[ARG1:%.*]]) #[[ATTR3]] {
+; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.minimum.f32(float [[ARG0]], float nofpclass(nan ninf nsub nnorm) [[ARG1]]) #[[ATTR7]]
+; CHECK-NEXT:    ret float [[CALL]]
+;
+  %call = call float @llvm.minimum.f32(float %arg0, float %arg1)
+  ret float %call
+}
+
+define float @ret_minimum_nopos_nan__any(float nofpclass(pinf psub pnorm nan) %arg0, float %arg1) #3 {
+; CHECK-LABEL: define float @ret_minimum_nopos_nan__any
+; CHECK-SAME: (float nofpclass(nan pinf psub pnorm) [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR3]] {
+; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.minimum.f32(float nofpclass(nan pinf psub pnorm) [[ARG0]], float [[ARG1]]) #[[ATTR7]]
+; CHECK-NEXT:    ret float [[CALL]]
+;
+  %call = call float @llvm.minimum.f32(float %arg0, float %arg1)
+  ret float %call
+}
+
+define float @ret_minimum_any__nopos_nan(float %arg0, float nofpclass(pinf psub pnorm nan) %arg1) #3 {
+; CHECK-LABEL: define float @ret_minimum_any__nopos_nan
+; CHECK-SAME: (float [[ARG0:%.*]], float nofpclass(nan pinf psub pnorm) [[ARG1:%.*]]) #[[ATTR3]] {
+; CHECK-NEXT:    [[CALL:%.*]] = call float @llvm.minimum.f32(float [[ARG0]], float nofpclass(nan pinf psub pnorm) [[ARG1]]) #[[ATTR7]]
+; CHECK-NEXT:    ret float [[CALL]]
+;
+  %call = call float @llvm.minimum.f32(float %arg0, float %arg1)
+  ret float %call
+}



More information about the llvm-commits mailing list