[llvm] [AMDGPU] Guard fneg-into-fmed3 fold with nnan (PR #203827)

Arseniy Obolenskiy via llvm-commits llvm-commits at lists.llvm.org
Sun Jun 14 22:33:53 PDT 2026


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

med3 sorts NaN as smaller than everything regardless of its sign, so negating all operands does not sign-flip the median when an input may be NaN

Propagate the intrinsic flags so the fold still fires for nnan

>From 71c85b50dc49dd88088aa993563a7287950b9ff6 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Mon, 15 Jun 2026 07:32:14 +0200
Subject: [PATCH] [AMDGPU] Guard fneg-into-fmed3 fold with nnan

med3 sorts NaN as smaller than everything regardless of its sign, so negating all operands does not sign-flip the median when an input may be NaN

Propagate the intrinsic flags so the fold still fires for nnan
---
 llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp |  3 +++
 llvm/lib/Target/AMDGPU/SIISelLowering.cpp     |  2 +-
 llvm/test/CodeGen/AMDGPU/llvm.amdgcn.fmed3.ll | 22 ++++++++++++++-----
 3 files changed, 20 insertions(+), 7 deletions(-)

diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
index 278c2dc94c56b..9b483d32b7604 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp
@@ -5392,6 +5392,9 @@ SDValue AMDGPUTargetLowering::performFNegCombine(SDNode *N,
     return Res;
   }
   case AMDGPUISD::FMED3: {
+    if (!N0->getFlags().hasNoNaNs())
+      return SDValue();
+
     SDValue Ops[3];
     for (unsigned I = 0; I < 3; ++I)
       Ops[I] = DAG.getNode(ISD::FNEG, SL, VT, N0->getOperand(I), N0->getFlags());
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index 2817f1ac8c3ad..074a3c07e6c2e 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -11092,7 +11092,7 @@ SDValue SITargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
     return lowerBALLOTIntrinsic(*this, Op.getNode(), DAG);
   case Intrinsic::amdgcn_fmed3:
     return DAG.getNode(AMDGPUISD::FMED3, DL, VT, Op.getOperand(1),
-                       Op.getOperand(2), Op.getOperand(3));
+                       Op.getOperand(2), Op.getOperand(3), Op->getFlags());
   case Intrinsic::amdgcn_fdot2:
     return DAG.getNode(AMDGPUISD::FDOT2, DL, VT, Op.getOperand(1),
                        Op.getOperand(2), Op.getOperand(3), Op.getOperand(4));
diff --git a/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.fmed3.ll b/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.fmed3.ll
index 561f4e37cdfbf..cdc27c6949bf7 100644
--- a/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.fmed3.ll
+++ b/llvm/test/CodeGen/AMDGPU/llvm.amdgcn.fmed3.ll
@@ -21,10 +21,20 @@ define amdgpu_kernel void @test_fmed3_srcmods(ptr addrspace(1) %out, float %src0
   ret void
 }
 
+; GCN-LABEL: {{^}}test_fneg_fmed3_no_nnan:
+; GCN: v_med3_f32 [[MED3:v[0-9]+]], s{{[0-9]+}}, v{{[0-9]+}}, v{{[0-9]+}}
+; GCN: v_xor_b32_e32 v{{[0-9]+}}, 0x80000000, [[MED3]]
+define amdgpu_kernel void @test_fneg_fmed3_no_nnan(ptr addrspace(1) %out, float %src0, float %src1, float %src2) #1 {
+  %med3 = call float @llvm.amdgcn.fmed3.f32(float %src0, float %src1, float %src2)
+  %neg.med3 = fsub float -0.0, %med3
+  store float %neg.med3, ptr addrspace(1) %out
+  ret void
+}
+
 ; GCN-LABEL: {{^}}test_fneg_fmed3:
 ; GCN: v_med3_f32 v{{[0-9]+}}, -s{{[0-9]+}}, -v{{[0-9]+}}, -v{{[0-9]+}}
 define amdgpu_kernel void @test_fneg_fmed3(ptr addrspace(1) %out, float %src0, float %src1, float %src2) #1 {
-  %med3 = call float @llvm.amdgcn.fmed3.f32(float %src0, float %src1, float %src2)
+  %med3 = call nnan float @llvm.amdgcn.fmed3.f32(float %src0, float %src1, float %src2)
   %neg.med3 = fsub float -0.0, %med3
   store float %neg.med3, ptr addrspace(1) %out
   ret void
@@ -34,7 +44,7 @@ define amdgpu_kernel void @test_fneg_fmed3(ptr addrspace(1) %out, float %src0, f
 ; GCN: v_med3_f32 [[MED3:v[0-9]+]], -s{{[0-9]+}}, -v{{[0-9]+}}, -v{{[0-9]+}}
 ; GCN: v_mul_f32_e32 v{{[0-9]+}}, -4.0, [[MED3]]
 define amdgpu_kernel void @test_fneg_fmed3_multi_use(ptr addrspace(1) %out, float %src0, float %src1, float %src2) #1 {
-  %med3 = call float @llvm.amdgcn.fmed3.f32(float %src0, float %src1, float %src2)
+  %med3 = call nnan float @llvm.amdgcn.fmed3.f32(float %src0, float %src1, float %src2)
   %neg.med3 = fsub float -0.0, %med3
   %med3.user = fmul float %med3, 4.0
   store volatile float %med3.user, ptr addrspace(1) %out
@@ -56,7 +66,7 @@ define amdgpu_kernel void @test_fabs_fmed3(ptr addrspace(1) %out, float %src0, f
 ; GCN: v_bfrev_b32_e32 [[NEG0:v[0-9]+]], 1
 ; GCN: v_med3_f32 v{{[0-9]+}}, -s{{[0-9]+}}, -v{{[0-9]+}}, [[NEG0]]
 define amdgpu_kernel void @test_fneg_fmed3_rr_0(ptr addrspace(1) %out, float %src0, float %src1) #1 {
-  %med3 = call float @llvm.amdgcn.fmed3.f32(float %src0, float %src1, float 0.0)
+  %med3 = call nnan float @llvm.amdgcn.fmed3.f32(float %src0, float %src1, float 0.0)
   %neg.med3 = fsub float -0.0, %med3
   store float %neg.med3, ptr addrspace(1) %out
   ret void
@@ -68,7 +78,7 @@ define amdgpu_kernel void @test_fneg_fmed3_rr_0(ptr addrspace(1) %out, float %sr
 ; GCN: v_med3_f32 [[MED3:v[0-9]+]], -s{{[0-9]+}}, -v{{[0-9]+}}, [[NEG0]]
 ; GCN: v_mul_f32_e32 v{{[0-9]+}}, s{{[0-9]+}}, [[MED3]]
 define amdgpu_kernel void @test_fneg_fmed3_rr_0_foldable_user(ptr addrspace(1) %out, float %src0, float %src1, float %mul.arg) #1 {
-  %med3 = call float @llvm.amdgcn.fmed3.f32(float %src0, float %src1, float 0.0)
+  %med3 = call nnan float @llvm.amdgcn.fmed3.f32(float %src0, float %src1, float 0.0)
   %neg.med3 = fsub float -0.0, %med3
   %mul = fmul float %neg.med3, %mul.arg
   store float %mul, ptr addrspace(1) %out
@@ -80,7 +90,7 @@ define amdgpu_kernel void @test_fneg_fmed3_rr_0_foldable_user(ptr addrspace(1) %
 ; GCN-DAG: v_mov_b32_e32 [[NEG_INV:v[0-9]+]], 0xbe22f983
 ; GCN: v_med3_f32 v{{[0-9]+}}, -s{{[0-9]+}}, [[NEG_INV]], [[NEG0]]
 define amdgpu_kernel void @test_fneg_fmed3_r_inv2pi_0(ptr addrspace(1) %out, float %src0) #1 {
-  %med3 = call float @llvm.amdgcn.fmed3.f32(float %src0, float 0x3FC45F3060000000, float 0.0)
+  %med3 = call nnan float @llvm.amdgcn.fmed3.f32(float %src0, float 0x3FC45F3060000000, float 0.0)
   %neg.med3 = fsub float -0.0, %med3
   store float %neg.med3, ptr addrspace(1) %out
   ret void
@@ -92,7 +102,7 @@ define amdgpu_kernel void @test_fneg_fmed3_r_inv2pi_0(ptr addrspace(1) %out, flo
 ; GCN: v_med3_f32 [[MED3:v[0-9]+]], -s{{[0-9]+}}, [[NEG_INV]], [[NEG0]]
 ; GCN: v_mul_f32_e32 v{{[0-9]+}}, s{{[0-9]+}}, [[MED3]]
 define amdgpu_kernel void @test_fneg_fmed3_r_inv2pi_0_foldable_user(ptr addrspace(1) %out, float %src0, float %mul.arg) #1 {
-  %med3 = call float @llvm.amdgcn.fmed3.f32(float %src0, float 0x3FC45F3060000000, float 0.0)
+  %med3 = call nnan float @llvm.amdgcn.fmed3.f32(float %src0, float 0x3FC45F3060000000, float 0.0)
   %neg.med3 = fsub float -0.0, %med3
   %mul = fmul float %neg.med3, %mul.arg
   store float %mul, ptr addrspace(1) %out



More information about the llvm-commits mailing list