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

via llvm-commits llvm-commits at lists.llvm.org
Sun Apr 19 20:41:35 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-amdgpu

Author: Kartik Ohlan (Ko496-glitch)

<details>
<summary>Changes</summary>

Resolves #<!-- -->189694

Added implementation for ISD::FMAXIMUM/ISD::FMINIMUM + ISD::FMAXIMUMNUM/ISD::FMINIMUMNUM in SelectionDag.cpp



---
Full diff: https://github.com/llvm/llvm-project/pull/190465.diff


2 Files Affected:

- (modified) llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp (+41) 
- (added) llvm/test/CodeGen/AMDGPU/fminimum-fmaximum-nofpclass.ll (+170) 


``````````diff
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 86245e4044925..9bb6fba7031a4 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -6045,6 +6045,17 @@ 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))
@@ -6135,6 +6146,36 @@ KnownFPClass SelectionDAG::computeKnownFPClass(SDValue Op,
     Known.KnownFPClasses &= ~AssertedClasses;
     break;
   }
+  case ISD::FMAXNUM: {
+    Known = GetMinMaxKnownFPClass(Op.getOperand(0), Op.getOperand(1),
+                                  KnownFPClass::MinMaxKind::maxnum);
+    break;
+  }
+  case ISD::FMINNUM: {
+    Known = GetMinMaxKnownFPClass(Op.getOperand(0), Op.getOperand(1),
+                                  KnownFPClass::MinMaxKind::minnum);
+    break;
+  }
+  case ISD::FMAXIMUM: {
+    Known = GetMinMaxKnownFPClass(Op.getOperand(0), Op.getOperand(1),
+                                  KnownFPClass::MinMaxKind::maximum);
+    break;
+  }
+  case ISD::FMINIMUM: {
+    Known = GetMinMaxKnownFPClass(Op.getOperand(0), Op.getOperand(1),
+                                  KnownFPClass::MinMaxKind::minimum);
+    break;
+  }
+  case ISD::FMAXIMUMNUM: {
+    Known = GetMinMaxKnownFPClass(Op.getOperand(0), Op.getOperand(1),
+                                  KnownFPClass::MinMaxKind::maximumnum);
+    break;
+  }
+  case ISD::FMINIMUMNUM: {
+    Known = GetMinMaxKnownFPClass(Op.getOperand(0), Op.getOperand(1),
+                                  KnownFPClass::MinMaxKind::minimumnum);
+    break;
+  }
   default:
     if (Opcode >= ISD::BUILTIN_OP_END || Opcode == ISD::INTRINSIC_WO_CHAIN ||
         Opcode == ISD::INTRINSIC_W_CHAIN || Opcode == ISD::INTRINSIC_VOID) {
diff --git a/llvm/test/CodeGen/AMDGPU/fminimum-fmaximum-nofpclass.ll b/llvm/test/CodeGen/AMDGPU/fminimum-fmaximum-nofpclass.ll
new file mode 100644
index 0000000000000..dde7353f9556d
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/fminimum-fmaximum-nofpclass.ll
@@ -0,0 +1,170 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=fiji -global-isel=0 < %s | FileCheck %s --check-prefixes=GCN,GFX8
+; RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 -global-isel=0 < %s | FileCheck %s --check-prefixes=GCN,GFX9
+
+
+define float @v_test_known_not_snan_maxnum_input_fmed3_r_i_i_f32(float %a, float %b) #0 {
+; GCN-LABEL: v_test_known_not_snan_maxnum_input_fmed3_r_i_i_f32:
+; GCN:       ; %bb.0:
+; GCN-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GCN-NEXT:    v_rcp_f32_e32 v0, v0
+; GCN-NEXT:    v_add_f32_e32 v1, 1.0, v1
+; GCN-NEXT:    v_max_f32_e32 v0, v0, v1
+; GCN-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; GCN-NEXT:    s_setpc_b64 s[30:31]
+  %a.nnan.add = fdiv nnan float 1.0, %a, !fpmath !0
+  %b.nnan.add = fadd nnan float %b, 1.0
+  %known.not.snan = call float @llvm.maxnum.f32(float %a.nnan.add, float %b.nnan.add)
+  %max = call float @llvm.maxnum.f32(float %known.not.snan, float 2.0)
+  %med = call float @llvm.minnum.f32(float %max, float 4.0)
+  ret float %med
+}
+
+define float @v_maxnum_possible_nan_lhs_input_fmed3_r_i_i_f32(float %a, float %b) #0 {
+; GFX8-LABEL: v_maxnum_possible_nan_lhs_input_fmed3_r_i_i_f32:
+; GFX8:       ; %bb.0:
+; GFX8-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX8-NEXT:    v_add_f32_e32 v1, 1.0, v1
+; GFX8-NEXT:    v_mul_f32_e32 v0, 1.0, v0
+; GFX8-NEXT:    v_max_f32_e32 v0, v0, v1
+; GFX8-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; GFX8-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: v_maxnum_possible_nan_lhs_input_fmed3_r_i_i_f32:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_add_f32_e32 v1, 1.0, v1
+; GFX9-NEXT:    v_max_f32_e32 v0, v0, v0
+; GFX9-NEXT:    v_max_f32_e32 v0, v0, v1
+; GFX9-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+  %b.nnan.add = fadd nnan float %b, 1.0
+  %known.not.snan = call float @llvm.maxnum.f32(float %a, float %b.nnan.add)
+  %max = call float @llvm.maxnum.f32(float %known.not.snan, float 2.0)
+  %med = call float @llvm.minnum.f32(float %max, float 4.0)
+  ret float %med
+}
+
+define float @v_maxnum_possible_nan_rhs_input_fmed3_r_i_i_f32(float %a, float %b) #0 {
+; GFX8-LABEL: v_maxnum_possible_nan_rhs_input_fmed3_r_i_i_f32:
+; GFX8:       ; %bb.0:
+; GFX8-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX8-NEXT:    v_rcp_f32_e32 v0, v0
+; GFX8-NEXT:    v_mul_f32_e32 v1, 1.0, v1
+; GFX8-NEXT:    v_max_f32_e32 v0, v0, v1
+; GFX8-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; GFX8-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: v_maxnum_possible_nan_rhs_input_fmed3_r_i_i_f32:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_rcp_f32_e32 v0, v0
+; GFX9-NEXT:    v_max_f32_e32 v1, v1, v1
+; GFX9-NEXT:    v_max_f32_e32 v0, v0, v1
+; GFX9-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+  %a.nnan.add = fdiv nnan float 1.0, %a, !fpmath !0
+  %known.not.snan = call float @llvm.maxnum.f32(float %a.nnan.add, float %b)
+  %max = call float @llvm.maxnum.f32(float %known.not.snan, float 2.0)
+  %med = call float @llvm.minnum.f32(float %max, float 4.0)
+  ret float %med
+}
+
+define amdgpu_kernel void @v_nnan_inputs_med3_f32_pat0(ptr addrspace(1) %out, ptr addrspace(1) %aptr, ptr addrspace(1) %bptr, ptr addrspace(1) %cptr) {
+; GFX8-LABEL: v_nnan_inputs_med3_f32_pat0:
+; GFX8:       ; %bb.0:
+; GFX8-NEXT:    s_load_dwordx8 s[0:7], s[8:9], 0x0
+; GFX8-NEXT:    v_lshlrev_b32_e32 v6, 2, v0
+; GFX8-NEXT:    s_add_i32 s12, s12, s17
+; GFX8-NEXT:    s_mov_b32 flat_scratch_lo, s13
+; GFX8-NEXT:    s_lshr_b32 flat_scratch_hi, s12, 8
+; GFX8-NEXT:    s_waitcnt lgkmcnt(0)
+; GFX8-NEXT:    v_mov_b32_e32 v1, s3
+; GFX8-NEXT:    v_add_u32_e32 v0, vcc, s2, v6
+; GFX8-NEXT:    v_addc_u32_e32 v1, vcc, 0, v1, vcc
+; GFX8-NEXT:    v_mov_b32_e32 v3, s5
+; GFX8-NEXT:    v_add_u32_e32 v2, vcc, s4, v6
+; GFX8-NEXT:    v_addc_u32_e32 v3, vcc, 0, v3, vcc
+; GFX8-NEXT:    v_mov_b32_e32 v5, s7
+; GFX8-NEXT:    v_add_u32_e32 v4, vcc, s6, v6
+; GFX8-NEXT:    v_addc_u32_e32 v5, vcc, 0, v5, vcc
+; GFX8-NEXT:    flat_load_dword v7, v[0:1] glc
+; GFX8-NEXT:    s_waitcnt vmcnt(0)
+; GFX8-NEXT:    flat_load_dword v2, v[2:3] glc
+; GFX8-NEXT:    s_waitcnt vmcnt(0)
+; GFX8-NEXT:    flat_load_dword v3, v[4:5] glc
+; GFX8-NEXT:    s_waitcnt vmcnt(0)
+; GFX8-NEXT:    v_mov_b32_e32 v1, s1
+; GFX8-NEXT:    v_add_u32_e32 v0, vcc, s0, v6
+; GFX8-NEXT:    v_addc_u32_e32 v1, vcc, 0, v1, vcc
+; GFX8-NEXT:    v_add_f32_e32 v4, 1.0, v7
+; GFX8-NEXT:    v_add_f32_e32 v2, 2.0, v2
+; GFX8-NEXT:    v_add_f32_e32 v3, 4.0, v3
+; GFX8-NEXT:    v_med3_f32 v2, v4, v2, v3
+; GFX8-NEXT:    flat_store_dword v[0:1], v2
+; GFX8-NEXT:    s_endpgm
+;
+; GFX9-LABEL: v_nnan_inputs_med3_f32_pat0:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_load_dwordx8 s[0:7], s[8:9], 0x0
+; GFX9-NEXT:    v_lshlrev_b32_e32 v0, 2, v0
+; GFX9-NEXT:    s_waitcnt lgkmcnt(0)
+; GFX9-NEXT:    global_load_dword v1, v0, s[2:3] glc
+; GFX9-NEXT:    s_waitcnt vmcnt(0)
+; GFX9-NEXT:    global_load_dword v2, v0, s[4:5] glc
+; GFX9-NEXT:    s_waitcnt vmcnt(0)
+; GFX9-NEXT:    global_load_dword v3, v0, s[6:7] glc
+; GFX9-NEXT:    s_waitcnt vmcnt(0)
+; GFX9-NEXT:    v_add_f32_e32 v1, 1.0, v1
+; GFX9-NEXT:    v_add_f32_e32 v2, 2.0, v2
+; GFX9-NEXT:    v_add_f32_e32 v3, 4.0, v3
+; GFX9-NEXT:    v_med3_f32 v1, v1, v2, v3
+; GFX9-NEXT:    global_store_dword v0, v1, s[0:1]
+; GFX9-NEXT:    s_endpgm
+  %tid = call i32 @llvm.amdgcn.workitem.id.x()
+  %gep0 = getelementptr float, ptr addrspace(1) %aptr, i32 %tid
+  %gep1 = getelementptr float, ptr addrspace(1) %bptr, i32 %tid
+  %gep2 = getelementptr float, ptr addrspace(1) %cptr, i32 %tid
+  %outgep = getelementptr float, ptr addrspace(1) %out, i32 %tid
+  %a = load volatile float, ptr addrspace(1) %gep0
+  %b = load volatile float, ptr addrspace(1) %gep1
+  %c = load volatile float, ptr addrspace(1) %gep2
+
+  %a.nnan = fadd nnan float %a, 1.0
+  %b.nnan = fadd nnan float %b, 2.0
+  %c.nnan = fadd nnan float %c, 4.0
+
+  %tmp0 = call float @llvm.minnum.f32(float %a.nnan, float %b.nnan)
+  %tmp1 = call float @llvm.maxnum.f32(float %a.nnan, float %b.nnan)
+  %tmp2 = call float @llvm.minnum.f32(float %tmp1, float %c.nnan)
+  %med3 = call float @llvm.maxnum.f32(float %tmp0, float %tmp2)
+  store float %med3, ptr addrspace(1) %outgep
+  ret void
+}
+
+define float @v_test_nnan_input_fmed3_r_i_i_f32_maximum_minimum(float %a) {
+; GCN-LABEL: v_test_nnan_input_fmed3_r_i_i_f32_maximum_minimum:
+; GCN:       ; %bb.0:
+; GCN-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GCN-NEXT:    v_add_f32_e32 v0, 1.0, v0
+; GCN-NEXT:    v_med3_f32 v0, v0, 2.0, 4.0
+; GCN-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)
+  ret float %med
+}
+
+declare float @llvm.maxnum.f32(float, float) #1
+declare float @llvm.minnum.f32(float, float) #1
+declare float @llvm.maximum.f32(float, float) #1
+declare float @llvm.minimum.f32(float, float) #1
+declare i32 @llvm.amdgcn.workitem.id.x() #1
+
+attributes #0 = { nounwind denormal_fpenv(float: preservesign) }
+attributes #1 = { nounwind readnone speculatable }
+
+!0 = !{float 2.500000e+00}
+
+
+

``````````

</details>


https://github.com/llvm/llvm-project/pull/190465


More information about the llvm-commits mailing list