[llvm] 8223635 - [AMDGPU] Fix miscompile in performSelectCombine for fcmp one with NaN (#213029)

via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 30 09:51:11 PDT 2026


Author: Arseniy Obolenskiy
Date: 2026-07-30T18:51:03+02:00
New Revision: 8223635500c61d10820c011371498b96cd4ffbc7

URL: https://github.com/llvm/llvm-project/commit/8223635500c61d10820c011371498b96cd4ffbc7
DIFF: https://github.com/llvm/llvm-project/commit/8223635500c61d10820c011371498b96cd4ffbc7.diff

LOG: [AMDGPU] Fix miscompile in performSelectCombine for fcmp one with NaN (#213029)

The fold `select (fcmp one x, K), y, K -> ..., x` returned x instead of
K when x was NaN, changing the result

Added: 
    

Modified: 
    llvm/lib/Target/AMDGPU/SIISelLowering.cpp
    llvm/test/CodeGen/AMDGPU/select-cmp-shared-constant-fp.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index b3e8982d52fee..5091340e2c894 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -18701,8 +18701,10 @@ SDValue SITargetLowering::performSelectCombine(SDNode *N,
   if (!isFloatingPoint && !isInteger)
     return SDValue();
 
-  bool isEquality = CC == (isFloatingPoint ? ISD::SETOEQ : ISD::SETEQ);
-  bool isNonEquality = CC == (isFloatingPoint ? ISD::SETONE : ISD::SETNE);
+  // Bare SETEQ/SETNE is the builder's NaN-impossible downgrade.
+  bool isEquality = CC == ISD::SETEQ || (isFloatingPoint && CC == ISD::SETOEQ);
+  bool isNonEquality =
+      CC == ISD::SETNE || (isFloatingPoint && CC == ISD::SETONE);
   if (!isEquality && !isNonEquality)
     return SDValue();
 
@@ -18738,6 +18740,11 @@ SDValue SITargetLowering::performSelectCombine(SDNode *N,
       !(isNonEquality && FalseVal == ConstVal))
     return SDValue();
 
+  // SETONE's false arm is also taken for NaN ArgVal, so require NaN excluded.
+  if (isFloatingPoint && isNonEquality && FalseVal == ConstVal &&
+      !Cond->getFlags().hasNoNaNs() && !DCI.DAG.isKnownNeverNaN(ArgVal))
+    return SDValue();
+
   SDValue SelectLHS = (isEquality && TrueVal == ConstVal) ? ArgVal : TrueVal;
   SDValue SelectRHS =
       (isNonEquality && FalseVal == ConstVal) ? ArgVal : FalseVal;

diff  --git a/llvm/test/CodeGen/AMDGPU/select-cmp-shared-constant-fp.ll b/llvm/test/CodeGen/AMDGPU/select-cmp-shared-constant-fp.ll
index 41ad7cb34552c..d26c8aec789f1 100644
--- a/llvm/test/CodeGen/AMDGPU/select-cmp-shared-constant-fp.ll
+++ b/llvm/test/CodeGen/AMDGPU/select-cmp-shared-constant-fp.ll
@@ -70,7 +70,7 @@ define float @fcmp_select_fold_one_f32_imm(float %arg, float %other) {
 ; GFX1010-NEXT:    v_cndmask_b32_e32 v0, v0, v1, vcc_lo
 ; GFX1010-NEXT:    s_setpc_b64 s[30:31]
 entry:
-  %cmp = fcmp one float %arg, 0x4005BF0A00000000
+  %cmp = fcmp nnan one float %arg, 0x4005BF0A00000000
   %sel = select i1 %cmp, float %other, float 0x4005BF0A00000000
   ret float %sel
 }
@@ -92,7 +92,30 @@ define float @fcmp_select_fold_one_imm_f32(float %arg, float %other) {
 ; GFX1010-NEXT:    v_cndmask_b32_e32 v0, v0, v1, vcc_lo
 ; GFX1010-NEXT:    s_setpc_b64 s[30:31]
 entry:
-  %cmp = fcmp one float 0x4005BF0A00000000, %arg
+  %cmp = fcmp nnan one float 0x4005BF0A00000000, %arg
+  %sel = select i1 %cmp, float %other, float 0x4005BF0A00000000
+  ret float %sel
+}
+
+; Should NOT be folded: fcmp one without nnan, %arg may be NaN
+define float @fcmp_select_no_fold_one_f32_arg_maybe_nan(float %arg, float %other) {
+; GFX900-LABEL: fcmp_select_no_fold_one_f32_arg_maybe_nan:
+; GFX900:       ; %bb.0: ; %entry
+; GFX900-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX900-NEXT:    s_mov_b32 s4, 0x402df850
+; GFX900-NEXT:    v_mov_b32_e32 v2, 0x402df850
+; GFX900-NEXT:    v_cmp_lg_f32_e32 vcc, s4, v0
+; GFX900-NEXT:    v_cndmask_b32_e32 v0, v2, v1, vcc
+; GFX900-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX1010-LABEL: fcmp_select_no_fold_one_f32_arg_maybe_nan:
+; GFX1010:       ; %bb.0: ; %entry
+; GFX1010-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX1010-NEXT:    v_cmp_lg_f32_e32 vcc_lo, 0x402df850, v0
+; GFX1010-NEXT:    v_cndmask_b32_e32 v0, 0x402df850, v1, vcc_lo
+; GFX1010-NEXT:    s_setpc_b64 s[30:31]
+entry:
+  %cmp = fcmp one float %arg, 0x4005BF0A00000000
   %sel = select i1 %cmp, float %other, float 0x4005BF0A00000000
   ret float %sel
 }
@@ -419,7 +442,7 @@ define double @fcmp_select_fold_one_f64_imm(double %arg, double %other) {
 ; GFX1010-NEXT:    v_cndmask_b32_e32 v1, v1, v3, vcc_lo
 ; GFX1010-NEXT:    s_setpc_b64 s[30:31]
 entry:
-  %cmp = fcmp one double %arg, 2.718281828459045
+  %cmp = fcmp nnan one double %arg, 2.718281828459045
   %sel = select i1 %cmp, double %other, double 2.718281828459045
   ret double %sel
 }
@@ -444,6 +467,35 @@ define double @fcmp_select_fold_one_imm_f64(double %arg, double %other) {
 ; GFX1010-NEXT:    v_cndmask_b32_e32 v0, v0, v2, vcc_lo
 ; GFX1010-NEXT:    v_cndmask_b32_e32 v1, v1, v3, vcc_lo
 ; GFX1010-NEXT:    s_setpc_b64 s[30:31]
+entry:
+  %cmp = fcmp nnan one double 2.718281828459045, %arg
+  %sel = select i1 %cmp, double %other, double 2.718281828459045
+  ret double %sel
+}
+
+; Should NOT be folded: fcmp one without nnan, %arg may be NaN
+define double @fcmp_select_no_fold_one_f64_arg_maybe_nan(double %arg, double %other) {
+; GFX900-LABEL: fcmp_select_no_fold_one_f64_arg_maybe_nan:
+; GFX900:       ; %bb.0: ; %entry
+; GFX900-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX900-NEXT:    s_mov_b32 s4, 0x8b145769
+; GFX900-NEXT:    s_mov_b32 s5, 0x4005bf0a
+; GFX900-NEXT:    v_cmp_lg_f64_e32 vcc, s[4:5], v[0:1]
+; GFX900-NEXT:    v_mov_b32_e32 v4, 0x8b145769
+; GFX900-NEXT:    v_mov_b32_e32 v1, 0x4005bf0a
+; GFX900-NEXT:    v_cndmask_b32_e32 v0, v4, v2, vcc
+; GFX900-NEXT:    v_cndmask_b32_e32 v1, v1, v3, vcc
+; GFX900-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX1010-LABEL: fcmp_select_no_fold_one_f64_arg_maybe_nan:
+; GFX1010:       ; %bb.0: ; %entry
+; GFX1010-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX1010-NEXT:    s_mov_b32 s4, 0x8b145769
+; GFX1010-NEXT:    s_mov_b32 s5, 0x4005bf0a
+; GFX1010-NEXT:    v_cmp_lg_f64_e32 vcc_lo, s[4:5], v[0:1]
+; GFX1010-NEXT:    v_cndmask_b32_e32 v0, 0x8b145769, v2, vcc_lo
+; GFX1010-NEXT:    v_cndmask_b32_e32 v1, 0x4005bf0a, v3, vcc_lo
+; GFX1010-NEXT:    s_setpc_b64 s[30:31]
 entry:
   %cmp = fcmp one double 2.718281828459045, %arg
   %sel = select i1 %cmp, double %other, double 2.718281828459045
@@ -895,7 +947,7 @@ define half @fcmp_select_fold_one_f16_imm(half %arg, half %other) {
 ; GFX1010-NEXT:    v_cndmask_b32_e32 v0, v0, v1, vcc_lo
 ; GFX1010-NEXT:    s_setpc_b64 s[30:31]
 entry:
-  %cmp = fcmp one half %arg, 0xH4020
+  %cmp = fcmp nnan one half %arg, 0xH4020
   %sel = select i1 %cmp, half %other, half 0xH4020
   ret half %sel
 }
@@ -917,7 +969,30 @@ define half @fcmp_select_fold_one_imm_f16(half %arg, half %other) {
 ; GFX1010-NEXT:    v_cndmask_b32_e32 v0, v0, v1, vcc_lo
 ; GFX1010-NEXT:    s_setpc_b64 s[30:31]
 entry:
-  %cmp = fcmp one half 0xH4020, %arg
+  %cmp = fcmp nnan one half 0xH4020, %arg
+  %sel = select i1 %cmp, half %other, half 0xH4020
+  ret half %sel
+}
+
+; Should NOT be folded: fcmp one without nnan, %arg may be NaN
+define half @fcmp_select_no_fold_one_f16_arg_maybe_nan(half %arg, half %other) {
+; GFX900-LABEL: fcmp_select_no_fold_one_f16_arg_maybe_nan:
+; GFX900:       ; %bb.0: ; %entry
+; GFX900-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX900-NEXT:    s_movk_i32 s4, 0x4020
+; GFX900-NEXT:    v_mov_b32_e32 v2, 0x4020
+; GFX900-NEXT:    v_cmp_lg_f16_e32 vcc, s4, v0
+; GFX900-NEXT:    v_cndmask_b32_e32 v0, v2, v1, vcc
+; GFX900-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX1010-LABEL: fcmp_select_no_fold_one_f16_arg_maybe_nan:
+; GFX1010:       ; %bb.0: ; %entry
+; GFX1010-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX1010-NEXT:    v_cmp_lg_f16_e32 vcc_lo, 0x4020, v0
+; GFX1010-NEXT:    v_cndmask_b32_e32 v0, 0x4020, v1, vcc_lo
+; GFX1010-NEXT:    s_setpc_b64 s[30:31]
+entry:
+  %cmp = fcmp one half %arg, 0xH4020
   %sel = select i1 %cmp, half %other, half 0xH4020
   ret half %sel
 }
@@ -1188,7 +1263,7 @@ define bfloat @fcmp_select_fold_one_bf16_imm(bfloat %arg, bfloat %other) {
 ; GFX1010-NEXT:    v_cndmask_b32_e32 v0, v0, v1, vcc_lo
 ; GFX1010-NEXT:    s_setpc_b64 s[30:31]
 entry:
-  %cmp = fcmp one bfloat %arg, 0xR4020
+  %cmp = fcmp nnan one bfloat %arg, 0xR4020
   %sel = select i1 %cmp, bfloat %other, bfloat 0xR4020
   ret bfloat %sel
 }
@@ -1212,7 +1287,32 @@ define bfloat @fcmp_select_fold_one_imm_bf16(bfloat %arg, bfloat %other) {
 ; GFX1010-NEXT:    v_cndmask_b32_e32 v0, v0, v1, vcc_lo
 ; GFX1010-NEXT:    s_setpc_b64 s[30:31]
 entry:
-  %cmp = fcmp one bfloat 0xR4020, %arg
+  %cmp = fcmp nnan one bfloat 0xR4020, %arg
+  %sel = select i1 %cmp, bfloat %other, bfloat 0xR4020
+  ret bfloat %sel
+}
+
+; Should NOT be folded: fcmp one without nnan, %arg may be NaN
+define bfloat @fcmp_select_no_fold_one_bf16_arg_maybe_nan(bfloat %arg, bfloat %other) {
+; GFX900-LABEL: fcmp_select_no_fold_one_bf16_arg_maybe_nan:
+; GFX900:       ; %bb.0: ; %entry
+; GFX900-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX900-NEXT:    v_lshlrev_b32_e32 v0, 16, v0
+; GFX900-NEXT:    s_mov_b32 s4, 0x40200000
+; GFX900-NEXT:    v_mov_b32_e32 v2, 0x4020
+; GFX900-NEXT:    v_cmp_lg_f32_e32 vcc, s4, v0
+; GFX900-NEXT:    v_cndmask_b32_e32 v0, v2, v1, vcc
+; GFX900-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX1010-LABEL: fcmp_select_no_fold_one_bf16_arg_maybe_nan:
+; GFX1010:       ; %bb.0: ; %entry
+; GFX1010-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX1010-NEXT:    v_lshlrev_b32_e32 v0, 16, v0
+; GFX1010-NEXT:    v_cmp_lg_f32_e32 vcc_lo, 0x40200000, v0
+; GFX1010-NEXT:    v_cndmask_b32_e32 v0, 0x4020, v1, vcc_lo
+; GFX1010-NEXT:    s_setpc_b64 s[30:31]
+entry:
+  %cmp = fcmp one bfloat %arg, 0xR4020
   %sel = select i1 %cmp, bfloat %other, bfloat 0xR4020
   ret bfloat %sel
 }


        


More information about the llvm-commits mailing list