[llvm] [AMDGPU] Fix wrong min/max for amdgcn.fmed3 NaN 3rd operand (PR #203822)

Arseniy Obolenskiy via llvm-commits llvm-commits at lists.llvm.org
Sun Jun 14 21:56:15 PDT 2026


https://github.com/aobolensk created https://github.com/llvm/llvm-project/pull/203822

With ieee=0, a NaN or undef third operand wrongly folded to maximumnum

Only +inf should give maximumnum, everything else gives minimumnum

>From 7aec0f89db46504049041cb2fed7e157fbeb29c8 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Mon, 15 Jun 2026 06:52:18 +0200
Subject: [PATCH] [AMDGPU] Fix wrong min/max for amdgcn.fmed3 NaN 3rd operand

With ieee=0, a NaN or undef third operand wrongly folded to maximumnum

Only +inf should give maximumnum, everything else gives minimumnum
---
 .../AMDGPU/AMDGPUInstCombineIntrinsic.cpp     |  6 ++--
 .../Transforms/InstCombine/AMDGPU/fmed3.ll    | 36 ++++++++-----------
 2 files changed, 17 insertions(+), 25 deletions(-)

diff --git a/llvm/lib/Target/AMDGPU/AMDGPUInstCombineIntrinsic.cpp b/llvm/lib/Target/AMDGPU/AMDGPUInstCombineIntrinsic.cpp
index b17ccef685b21..28d33f3f2a2c0 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUInstCombineIntrinsic.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUInstCombineIntrinsic.cpp
@@ -1575,9 +1575,9 @@ GCNTTIImpl::instCombineIntrinsic(InstCombiner &IC, IntrinsicInst &II) const {
                 : IC.Builder.CreateMinNum(Src0, Src1);
         break;
       case KnownIEEEMode::Off:
-        V = (ConstSrc2 && ConstSrc2->isNegInfinity())
-                ? IC.Builder.CreateMinimumNum(Src0, Src1)
-                : IC.Builder.CreateMaximumNum(Src0, Src1);
+        V = (ConstSrc2 && ConstSrc2->isPosInfinity())
+                ? IC.Builder.CreateMaximumNum(Src0, Src1)
+                : IC.Builder.CreateMinimumNum(Src0, Src1);
         break;
       case KnownIEEEMode::Unknown:
         break;
diff --git a/llvm/test/Transforms/InstCombine/AMDGPU/fmed3.ll b/llvm/test/Transforms/InstCombine/AMDGPU/fmed3.ll
index 86b78ea5770de..11443bafc42fe 100644
--- a/llvm/test/Transforms/InstCombine/AMDGPU/fmed3.ll
+++ b/llvm/test/Transforms/InstCombine/AMDGPU/fmed3.ll
@@ -137,7 +137,7 @@ define float @fmed3_x_y_undef_f32(float %x, float %y) #1 {
 ;
 ; IEEE0-LABEL: define float @fmed3_x_y_undef_f32(
 ; IEEE0-SAME: float [[X:%.*]], float [[Y:%.*]]) #[[ATTR1]] {
-; IEEE0-NEXT:    [[MED3:%.*]] = call float @llvm.maximumnum.f32(float [[X]], float [[Y]])
+; IEEE0-NEXT:    [[MED3:%.*]] = call float @llvm.minimumnum.f32(float [[X]], float [[Y]])
 ; IEEE0-NEXT:    ret float [[MED3]]
 ;
   %med3 = call float @llvm.amdgcn.fmed3.f32(float %x, float %y, float undef)
@@ -182,7 +182,7 @@ define float @fmed3_x_y_qnan0_f32(float %x, float %y) #1 {
 ;
 ; IEEE0-LABEL: define float @fmed3_x_y_qnan0_f32(
 ; IEEE0-SAME: float [[X:%.*]], float [[Y:%.*]]) #[[ATTR1]] {
-; IEEE0-NEXT:    [[MED3:%.*]] = call float @llvm.maximumnum.f32(float [[X]], float [[Y]])
+; IEEE0-NEXT:    [[MED3:%.*]] = call float @llvm.minimumnum.f32(float [[X]], float [[Y]])
 ; IEEE0-NEXT:    ret float [[MED3]]
 ;
   %med3 = call float @llvm.amdgcn.fmed3.f32(float %x, float %y, float 0x7FF8000000000000)
@@ -374,13 +374,9 @@ define float @fmed3_0_nan_1_f32() #1 {
 }
 
 define float @fmed3_0_1_nan_f32() #1 {
-; IEEE1-LABEL: define float @fmed3_0_1_nan_f32(
-; IEEE1-SAME: ) #[[ATTR1]] {
-; IEEE1-NEXT:    ret float 0.000000e+00
-;
-; IEEE0-LABEL: define float @fmed3_0_1_nan_f32(
-; IEEE0-SAME: ) #[[ATTR1]] {
-; IEEE0-NEXT:    ret float 1.000000e+00
+; CHECK-LABEL: define float @fmed3_0_1_nan_f32(
+; CHECK-SAME: ) #[[ATTR1]] {
+; CHECK-NEXT:    ret float 0.000000e+00
 ;
   %med = call float @llvm.amdgcn.fmed3.f32(float 0.0, float 1.0, float 0x7FF8001000000000)
   ret float %med
@@ -405,13 +401,9 @@ define float @fmed3_0_undef_1_f32() #1 {
 }
 
 define float @fmed3_0_1_undef_f32() #1 {
-; IEEE1-LABEL: define float @fmed3_0_1_undef_f32(
-; IEEE1-SAME: ) #[[ATTR1]] {
-; IEEE1-NEXT:    ret float 0.000000e+00
-;
-; IEEE0-LABEL: define float @fmed3_0_1_undef_f32(
-; IEEE0-SAME: ) #[[ATTR1]] {
-; IEEE0-NEXT:    ret float 1.000000e+00
+; CHECK-LABEL: define float @fmed3_0_1_undef_f32(
+; CHECK-SAME: ) #[[ATTR1]] {
+; CHECK-NEXT:    ret float 0.000000e+00
 ;
   %med = call float @llvm.amdgcn.fmed3.f32(float 0.0, float 1.0, float undef)
   ret float %med
@@ -479,7 +471,7 @@ define float @fmed3_x_y_snan1_f32(float %x, float %y) #1 {
 ;
 ; IEEE0-LABEL: define float @fmed3_x_y_snan1_f32(
 ; IEEE0-SAME: float [[X:%.*]], float [[Y:%.*]]) #[[ATTR1]] {
-; IEEE0-NEXT:    [[MED3:%.*]] = call float @llvm.maximumnum.f32(float [[X]], float [[Y]])
+; IEEE0-NEXT:    [[MED3:%.*]] = call float @llvm.minimumnum.f32(float [[X]], float [[Y]])
 ; IEEE0-NEXT:    ret float [[MED3]]
 ;
   %med3 = call float @llvm.amdgcn.fmed3.f32(float %x, float %y, float 0x7FF4000000000000)
@@ -558,7 +550,7 @@ define float @fmed3_neg2_3_snan1_f32(float %x, float %y) #1 {
 ;
 ; IEEE0-LABEL: define float @fmed3_neg2_3_snan1_f32(
 ; IEEE0-SAME: float [[X:%.*]], float [[Y:%.*]]) #[[ATTR1]] {
-; IEEE0-NEXT:    ret float 3.000000e+00
+; IEEE0-NEXT:    ret float -2.000000e+00
 ;
   %med3 = call float @llvm.amdgcn.fmed3.f32(float -2.0, float 3.0, float 0x7FF4000000000000)
   ret float %med3
@@ -699,12 +691,12 @@ define amdgpu_ps float @amdgpu_ps_default_fmed3_x_snan1_y_f32(float %x, float %y
 define amdgpu_ps float @amdgpu_ps_default_fmed3_x_y_snan1_f32(float %x, float %y) {
 ; HAS-IEEE-BIT1-LABEL: define amdgpu_ps float @amdgpu_ps_default_fmed3_x_y_snan1_f32(
 ; HAS-IEEE-BIT1-SAME: float [[X:%.*]], float [[Y:%.*]]) #[[ATTR2]] {
-; HAS-IEEE-BIT1-NEXT:    [[MED3:%.*]] = call float @llvm.maximumnum.f32(float [[X]], float [[Y]])
+; HAS-IEEE-BIT1-NEXT:    [[MED3:%.*]] = call float @llvm.minimumnum.f32(float [[X]], float [[Y]])
 ; HAS-IEEE-BIT1-NEXT:    ret float [[MED3]]
 ;
 ; IEEE0-LABEL: define amdgpu_ps float @amdgpu_ps_default_fmed3_x_y_snan1_f32(
 ; IEEE0-SAME: float [[X:%.*]], float [[Y:%.*]]) #[[ATTR2]] {
-; IEEE0-NEXT:    [[MED3:%.*]] = call float @llvm.maximumnum.f32(float [[X]], float [[Y]])
+; IEEE0-NEXT:    [[MED3:%.*]] = call float @llvm.minimumnum.f32(float [[X]], float [[Y]])
 ; IEEE0-NEXT:    ret float [[MED3]]
 ;
 ; NO-IEEE-BIT-LABEL: define amdgpu_ps float @amdgpu_ps_default_fmed3_x_y_snan1_f32(
@@ -753,7 +745,7 @@ define amdgpu_ps float @amdgpu_ps_attr_fmed3_x_y_snan1_f32(float %x, float %y) #
 ;
 ; IEEE0-LABEL: define amdgpu_ps float @amdgpu_ps_attr_fmed3_x_y_snan1_f32(
 ; IEEE0-SAME: float [[X:%.*]], float [[Y:%.*]]) #[[ATTR1]] {
-; IEEE0-NEXT:    [[MED3:%.*]] = call float @llvm.maximumnum.f32(float [[X]], float [[Y]])
+; IEEE0-NEXT:    [[MED3:%.*]] = call float @llvm.minimumnum.f32(float [[X]], float [[Y]])
 ; IEEE0-NEXT:    ret float [[MED3]]
 ;
   %med3 = call float @llvm.amdgcn.fmed3.f32(float %x, float %y, float 0x7FF4000000000000)
@@ -893,7 +885,7 @@ define float @fmed3_x_y_qnan0_f32_flags(float %x, float %y) #1 {
 ;
 ; IEEE0-LABEL: define float @fmed3_x_y_qnan0_f32_flags(
 ; IEEE0-SAME: float [[X:%.*]], float [[Y:%.*]]) #[[ATTR1]] {
-; IEEE0-NEXT:    [[MED3:%.*]] = call ninf nsz float @llvm.maximumnum.f32(float [[X]], float [[Y]])
+; IEEE0-NEXT:    [[MED3:%.*]] = call ninf nsz float @llvm.minimumnum.f32(float [[X]], float [[Y]])
 ; IEEE0-NEXT:    ret float [[MED3]]
 ;
   %med3 = call nsz ninf float @llvm.amdgcn.fmed3.f32(float %x, float %y, float 0x7FF8000000000000)



More information about the llvm-commits mailing list