[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