[llvm] [SelectionDAG] Use `KnownBits` to determine if an operand may be NaN. (PR #188606)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Apr 1 10:53:27 PDT 2026
https://github.com/zGoldthorpe updated https://github.com/llvm/llvm-project/pull/188606
>From f0fb561bb4e75fa1b5733359923f28d6fad08483 Mon Sep 17 00:00:00 2001
From: Zach Goldthorpe <Zach.Goldthorpe at amd.com>
Date: Wed, 25 Mar 2026 15:37:09 -0500
Subject: [PATCH 01/14] [SelectionDAG] Use `KnownBits` to determine if an
operand may be NaN.
---
.../lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 23 +++++++++++++++++++
.../CodeGen/AMDGPU/fneg-modifier-casting.ll | 4 ++--
2 files changed, 25 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 028c9955a6bb1..eaf24fa8bdf06 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -6193,6 +6193,29 @@ bool SelectionDAG::isKnownNeverNaN(SDValue Op, const APInt &DemandedElts,
Depth);
}
+ // Try to infer NaN from known bits, but only for detecting signaling or
+ // nonsignaling NaNs
+ if (!SNaN) {
+ EVT VT = Op.getValueType().getScalarType();
+ const unsigned Mantissa = VT == MVT::f16 ? 10
+ : VT == MVT::f32 ? 23
+ : VT == MVT::f64 ? 52
+ : VT == MVT::f128 ? 112
+ : 0;
+ const unsigned Exponent = VT == MVT::f16 ? 5
+ : VT == MVT::f32 ? 8
+ : VT == MVT::f64 ? 11
+ : VT == MVT::f128 ? 15
+ : 0;
+
+ if (Mantissa) {
+ KnownBits Known = computeKnownBits(Op, DemandedElts);
+ KnownBits KnownMan = Known.extractBits(Mantissa, 0);
+ KnownBits KnownExp = Known.extractBits(Exponent, Mantissa);
+ if (!KnownExp.getMaxValue().isAllOnes() || KnownMan.isZero())
+ return true;
+ }
+ }
return false;
}
}
diff --git a/llvm/test/CodeGen/AMDGPU/fneg-modifier-casting.ll b/llvm/test/CodeGen/AMDGPU/fneg-modifier-casting.ll
index 9b44acd5c0716..64431cb31ea6e 100644
--- a/llvm/test/CodeGen/AMDGPU/fneg-modifier-casting.ll
+++ b/llvm/test/CodeGen/AMDGPU/fneg-modifier-casting.ll
@@ -1680,7 +1680,7 @@ define amdgpu_kernel void @fnge_select_f32_multi_use_regression(float %.i2369) {
; GCN-NEXT: s_waitcnt lgkmcnt(0)
; GCN-NEXT: v_cmp_nlt_f32_e64 s[0:1], s0, 0
; GCN-NEXT: v_cndmask_b32_e64 v0, 0, 1, s[0:1]
-; GCN-NEXT: v_cmp_nge_f32_e32 vcc, 0, v0
+; GCN-NEXT: v_cmp_lt_f32_e32 vcc, 0, v0
; GCN-NEXT: v_cndmask_b32_e32 v1, 0, v0, vcc
; GCN-NEXT: v_mul_f32_e64 v0, -v0, v1
; GCN-NEXT: v_cmp_le_f32_e32 vcc, 0, v0
@@ -1694,7 +1694,7 @@ define amdgpu_kernel void @fnge_select_f32_multi_use_regression(float %.i2369) {
; GFX11-NEXT: v_cmp_nlt_f32_e64 s0, s0, 0
; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
; GFX11-NEXT: v_cndmask_b32_e64 v0, 0, 1, s0
-; GFX11-NEXT: v_cmp_nge_f32_e32 vcc_lo, 0, v0
+; GFX11-NEXT: v_cmp_lt_f32_e32 vcc_lo, 0, v0
; GFX11-NEXT: v_cndmask_b32_e32 v1, 0, v0, vcc_lo
; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
; GFX11-NEXT: v_mul_f32_e64 v0, -v0, v1
>From fcfd5a757ab1f3e64c4a68d92e99642b3c242107 Mon Sep 17 00:00:00 2001
From: Zach Goldthorpe <Zach.Goldthorpe at amd.com>
Date: Wed, 25 Mar 2026 16:43:52 -0500
Subject: [PATCH 02/14] Use `fltSemantics`
---
.../lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 40 +++++++++++--------
1 file changed, 24 insertions(+), 16 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index eaf24fa8bdf06..bb76e08894e20 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -6196,24 +6196,32 @@ bool SelectionDAG::isKnownNeverNaN(SDValue Op, const APInt &DemandedElts,
// Try to infer NaN from known bits, but only for detecting signaling or
// nonsignaling NaNs
if (!SNaN) {
- EVT VT = Op.getValueType().getScalarType();
- const unsigned Mantissa = VT == MVT::f16 ? 10
- : VT == MVT::f32 ? 23
- : VT == MVT::f64 ? 52
- : VT == MVT::f128 ? 112
- : 0;
- const unsigned Exponent = VT == MVT::f16 ? 5
- : VT == MVT::f32 ? 8
- : VT == MVT::f64 ? 11
- : VT == MVT::f128 ? 15
- : 0;
-
- if (Mantissa) {
- KnownBits Known = computeKnownBits(Op, DemandedElts);
- KnownBits KnownMan = Known.extractBits(Mantissa, 0);
- KnownBits KnownExp = Known.extractBits(Exponent, Mantissa);
+ const fltSemantics &FltSem = Op.getValueType().getFltSemantics();
+ const KnownBits Known = computeKnownBits(Op, DemandedElts);
+ const unsigned Mantissa = FltSem.precision - 1;
+ const unsigned Exponent = FltSem.sizeInBits - FltSem.precision;
+ const KnownBits KnownMan = Known.extractBits(Mantissa, 0);
+ const KnownBits KnownExp = Known.extractBits(Exponent, Mantissa);
+
+ switch (FltSem.nanEncoding) {
+ default:
+ break;
+ case fltNanEncoding::IEEE: {
if (!KnownExp.getMaxValue().isAllOnes() || KnownMan.isZero())
return true;
+ break;
+ }
+ case fltNanEncoding::AllOnes: {
+ if (!KnownExp.getMaxValue().isAllOnes() ||
+ !KnownMan.getMaxValue().isAllOnes())
+ return true;
+ break;
+ }
+ case fltNanEncoding::NegativeZero:
+ if (Known.Zero.isSignBitSet() || !KnownExp.isZero() ||
+ !KnownMan.isZero())
+ return true;
+ break;
}
}
return false;
>From e427b07c5e1422108478cbf57dc84a61715861ad Mon Sep 17 00:00:00 2001
From: Zach Goldthorpe <Zach.Goldthorpe at amd.com>
Date: Wed, 25 Mar 2026 17:34:12 -0500
Subject: [PATCH 03/14] Remove unnecessary `default` block.
---
llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 2 --
1 file changed, 2 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index bb76e08894e20..872efa20c3587 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -6204,8 +6204,6 @@ bool SelectionDAG::isKnownNeverNaN(SDValue Op, const APInt &DemandedElts,
const KnownBits KnownExp = Known.extractBits(Exponent, Mantissa);
switch (FltSem.nanEncoding) {
- default:
- break;
case fltNanEncoding::IEEE: {
if (!KnownExp.getMaxValue().isAllOnes() || KnownMan.isZero())
return true;
>From f45aaee4ecf5b8323d1370290f32fce601b24980 Mon Sep 17 00:00:00 2001
From: Zach Goldthorpe <Zach.Goldthorpe at amd.com>
Date: Thu, 26 Mar 2026 09:45:23 -0500
Subject: [PATCH 04/14] Added guards and removed consts.
---
.../lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 53 ++++++++++---------
1 file changed, 28 insertions(+), 25 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 872efa20c3587..53cee1970f739 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -6195,31 +6195,34 @@ bool SelectionDAG::isKnownNeverNaN(SDValue Op, const APInt &DemandedElts,
// Try to infer NaN from known bits, but only for detecting signaling or
// nonsignaling NaNs
- if (!SNaN) {
- const fltSemantics &FltSem = Op.getValueType().getFltSemantics();
- const KnownBits Known = computeKnownBits(Op, DemandedElts);
- const unsigned Mantissa = FltSem.precision - 1;
- const unsigned Exponent = FltSem.sizeInBits - FltSem.precision;
- const KnownBits KnownMan = Known.extractBits(Mantissa, 0);
- const KnownBits KnownExp = Known.extractBits(Exponent, Mantissa);
-
- switch (FltSem.nanEncoding) {
- case fltNanEncoding::IEEE: {
- if (!KnownExp.getMaxValue().isAllOnes() || KnownMan.isZero())
- return true;
- break;
- }
- case fltNanEncoding::AllOnes: {
- if (!KnownExp.getMaxValue().isAllOnes() ||
- !KnownMan.getMaxValue().isAllOnes())
- return true;
- break;
- }
- case fltNanEncoding::NegativeZero:
- if (Known.Zero.isSignBitSet() || !KnownExp.isZero() ||
- !KnownMan.isZero())
- return true;
- break;
+ EVT VT = Op.getValueType();
+ if (!SNaN && VT.isFloatingPoint()) {
+ const fltSemantics &FltSem = VT.getFltSemantics();
+ if (FltSem.precision > 0) {
+ KnownBits Known = computeKnownBits(Op, DemandedElts);
+ unsigned Mantissa = FltSem.precision - 1;
+ unsigned Exponent = FltSem.sizeInBits - FltSem.precision;
+ KnownBits KnownMan = Known.extractBits(Mantissa, 0);
+ KnownBits KnownExp = Known.extractBits(Exponent, Mantissa);
+
+ switch (FltSem.nanEncoding) {
+ case fltNanEncoding::IEEE: {
+ if (!KnownExp.getMaxValue().isAllOnes() || KnownMan.isZero())
+ return true;
+ break;
+ }
+ case fltNanEncoding::AllOnes: {
+ if (!KnownExp.getMaxValue().isAllOnes() ||
+ !KnownMan.getMaxValue().isAllOnes())
+ return true;
+ break;
+ }
+ case fltNanEncoding::NegativeZero:
+ if (Known.Zero.isSignBitSet() || !KnownExp.isZero() ||
+ !KnownMan.isZero())
+ return true;
+ break;
+ }
}
}
return false;
>From 9992ad8298ea442ecece1a8282b4f60ab13570c9 Mon Sep 17 00:00:00 2001
From: Zach Goldthorpe <Zach.Goldthorpe at amd.com>
Date: Thu, 26 Mar 2026 09:53:17 -0500
Subject: [PATCH 05/14] Remove unnecessary parentheses.
---
llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 53cee1970f739..bbe8cd5fc41af 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -6206,17 +6206,15 @@ bool SelectionDAG::isKnownNeverNaN(SDValue Op, const APInt &DemandedElts,
KnownBits KnownExp = Known.extractBits(Exponent, Mantissa);
switch (FltSem.nanEncoding) {
- case fltNanEncoding::IEEE: {
+ case fltNanEncoding::IEEE:
if (!KnownExp.getMaxValue().isAllOnes() || KnownMan.isZero())
return true;
break;
- }
- case fltNanEncoding::AllOnes: {
+ case fltNanEncoding::AllOnes:
if (!KnownExp.getMaxValue().isAllOnes() ||
!KnownMan.getMaxValue().isAllOnes())
return true;
break;
- }
case fltNanEncoding::NegativeZero:
if (Known.Zero.isSignBitSet() || !KnownExp.isZero() ||
!KnownMan.isZero())
>From 6e602684db39f3744f93aba36b89a3edaab15a9e Mon Sep 17 00:00:00 2001
From: Zach Goldthorpe <Zach.Goldthorpe at amd.com>
Date: Thu, 26 Mar 2026 11:02:24 -0500
Subject: [PATCH 06/14] Corrected `NegativeZero` logic error.
---
llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index bbe8cd5fc41af..d3895c447182e 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -6216,8 +6216,8 @@ bool SelectionDAG::isKnownNeverNaN(SDValue Op, const APInt &DemandedElts,
return true;
break;
case fltNanEncoding::NegativeZero:
- if (Known.Zero.isSignBitSet() || !KnownExp.isZero() ||
- !KnownMan.isZero())
+ if (Known.Zero.isSignBitSet() || !KnownExp.getMinValue().isZero() ||
+ !KnownMan.getMinValue().isZero())
return true;
break;
}
>From cafb465f538c6cf0313f9677ef057aba80c0aa6f Mon Sep 17 00:00:00 2001
From: Zach Goldthorpe <Zach.Goldthorpe at amd.com>
Date: Mon, 30 Mar 2026 13:50:07 -0500
Subject: [PATCH 07/14] Moved `KnownBits` usage into `ISD::BITCAST`
---
llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index cb269d73d793e..e53ca6c2c8a8d 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -6323,13 +6323,7 @@ bool SelectionDAG::isKnownNeverNaN(SDValue Op, const APInt &DemandedElts,
return true;
return isKnownNeverNaN(Op.getOperand(0), DemandedElts, SNaN, Depth + 1);
}
- default:
- if (Opcode >= ISD::BUILTIN_OP_END || Opcode == ISD::INTRINSIC_WO_CHAIN ||
- Opcode == ISD::INTRINSIC_W_CHAIN || Opcode == ISD::INTRINSIC_VOID) {
- return TLI->isKnownNeverNaNForTargetNode(Op, DemandedElts, *this, SNaN,
- Depth);
- }
-
+ case ISD::BITCAST: {
// Try to infer NaN from known bits, but only for detecting signaling or
// nonsignaling NaNs
EVT VT = Op.getValueType();
@@ -6362,6 +6356,14 @@ bool SelectionDAG::isKnownNeverNaN(SDValue Op, const APInt &DemandedElts,
}
return false;
}
+ default:
+ if (Opcode >= ISD::BUILTIN_OP_END || Opcode == ISD::INTRINSIC_WO_CHAIN ||
+ Opcode == ISD::INTRINSIC_W_CHAIN || Opcode == ISD::INTRINSIC_VOID) {
+ return TLI->isKnownNeverNaNForTargetNode(Op, DemandedElts, *this, SNaN,
+ Depth);
+ }
+ return false;
+ }
}
bool SelectionDAG::isKnownNeverZeroFloat(SDValue Op) const {
>From 22da0a57b394c6c0c8bf43587cc7f52eabe28ed7 Mon Sep 17 00:00:00 2001
From: Zach Goldthorpe <Zach.Goldthorpe at amd.com>
Date: Mon, 30 Mar 2026 14:27:18 -0500
Subject: [PATCH 08/14] Use `KnownFPClass::bitcast`
---
.../lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 28 ++-----------------
1 file changed, 3 insertions(+), 25 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index e53ca6c2c8a8d..8cf4ebecd1b33 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -6328,31 +6328,9 @@ bool SelectionDAG::isKnownNeverNaN(SDValue Op, const APInt &DemandedElts,
// nonsignaling NaNs
EVT VT = Op.getValueType();
if (!SNaN && VT.isFloatingPoint()) {
- const fltSemantics &FltSem = VT.getFltSemantics();
- if (FltSem.precision > 0) {
- KnownBits Known = computeKnownBits(Op, DemandedElts);
- unsigned Mantissa = FltSem.precision - 1;
- unsigned Exponent = FltSem.sizeInBits - FltSem.precision;
- KnownBits KnownMan = Known.extractBits(Mantissa, 0);
- KnownBits KnownExp = Known.extractBits(Exponent, Mantissa);
-
- switch (FltSem.nanEncoding) {
- case fltNanEncoding::IEEE:
- if (!KnownExp.getMaxValue().isAllOnes() || KnownMan.isZero())
- return true;
- break;
- case fltNanEncoding::AllOnes:
- if (!KnownExp.getMaxValue().isAllOnes() ||
- !KnownMan.getMaxValue().isAllOnes())
- return true;
- break;
- case fltNanEncoding::NegativeZero:
- if (Known.Zero.isSignBitSet() || !KnownExp.getMinValue().isZero() ||
- !KnownMan.getMinValue().isZero())
- return true;
- break;
- }
- }
+ KnownBits Bits = computeKnownBits(Op, DemandedElts, Depth + 1);
+ const auto FPClass = KnownFPClass::bitcast(VT.getFltSemantics(), Bits);
+ return FPClass.isKnownNeverNaN();
}
return false;
}
>From f3972f7153226481b696e922acb6cf7e6c1434b7 Mon Sep 17 00:00:00 2001
From: Zach Goldthorpe <Zach.Goldthorpe at amd.com>
Date: Mon, 30 Mar 2026 17:01:13 -0500
Subject: [PATCH 09/14] Added scalar and vector tests.
---
.../AArch64/AArch64SelectionDAGTest.cpp | 41 +++++++++++++++++++
1 file changed, 41 insertions(+)
diff --git a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
index 12b7763274f6c..18f104a849437 100644
--- a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
+++ b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
@@ -1576,6 +1576,47 @@ TEST_F(AArch64SelectionDAGTest, KnownNeverZero_Select) {
EXPECT_TRUE(DAG->isKnownNeverZero(VSelect4444, DemandAll));
}
+TEST_F(AArch64SelectionDAGTest, KnownNeverNaN_Bitcast) {
+ SDLoc Loc;
+
+ auto UnknownI32 = DAG->getRegister(1, MVT::i32);
+ auto FiniteMask = DAG->getConstant(0x3fff'ffff, Loc, MVT::i32);
+ auto NeverNaNI32 =
+ DAG->getNode(ISD::AND, Loc, MVT::i32, FiniteMask, UnknownI32);
+
+ auto NeverNaNF32 = DAG->getBitcast(MVT::f32, NeverNaNI32);
+ EXPECT_TRUE(DAG->isKnownNeverNaN(NeverNaNF32));
+
+ auto UnknownF32 = DAG->getBitcast(MVT::f32, UnknownI32);
+ EXPECT_FALSE(DAG->isKnownNeverNaN(UnknownF32));
+
+ auto NeverNaNV2I32 = DAG->getSplat(MVT::v2i32, Loc, NeverNaNI32);
+ auto NeverNaNV2F32 = DAG->getBitcast(MVT::v2f32, NeverNaNV2I32);
+ EXPECT_TRUE(DAG->isKnownNeverNaN(NeverNaNV2F32));
+
+ auto PartialNaNV2I32 =
+ DAG->getBuildVector(MVT::v2i32, Loc, {UnknownI32, NeverNaNI32});
+ auto PartialNaNV2F32 = DAG->getBitcast(MVT::v2f32, PartialNaNV2I32);
+ EXPECT_FALSE(DAG->isKnownNeverNaN(PartialNaNV2F32));
+ APInt DemandLo(2, 1);
+ EXPECT_FALSE(DAG->isKnownNeverNaN(PartialNaNV2F32, DemandLo));
+ APInt DemandHi(2, 2);
+ EXPECT_TRUE(DAG->isKnownNeverNaN(PartialNaNV2F32, DemandHi));
+
+ auto PartialNaNAsF64 = DAG->getBitcast(MVT::f64, PartialNaNV2I32);
+ EXPECT_TRUE(DAG->isKnownNeverNaN(PartialNaNAsF64));
+
+ auto UnknownI64 = DAG->getRegister(2, MVT::i64);
+ auto Lo32NeverNaNMask =
+ DAG->getConstant(0xffff'ffff'3fff'ffff, Loc, MVT::i64);
+ auto PartialNaNPack64 =
+ DAG->getNode(ISD::AND, Loc, MVT::i64, Lo32NeverNaNMask, UnknownI64);
+ auto PartialNaNUnpackV2F32 = DAG->getBitcast(MVT::v2f32, PartialNaNPack64);
+ EXPECT_FALSE(DAG->isKnownNeverNaN(PartialNaNUnpackV2F32));
+ EXPECT_TRUE(DAG->isKnownNeverNaN(PartialNaNUnpackV2F32, DemandLo));
+ EXPECT_FALSE(DAG->isKnownNeverNaN(PartialNaNUnpackV2F32, DemandHi));
+}
+
// tests for SelectionDAG::computeKnownFPClass
TEST_F(AArch64SelectionDAGTest, ComputeKnownFPClass_ConstantScalar) {
SDLoc Loc;
>From 4a036c7e4a4854edb937aa12f7fd1e7c73f845c8 Mon Sep 17 00:00:00 2001
From: Zach Goldthorpe <Zach.Goldthorpe at amd.com>
Date: Mon, 30 Mar 2026 17:26:53 -0500
Subject: [PATCH 10/14] Move logic into `computeKnownFPClass`
---
.../lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 21 +++++++++----------
1 file changed, 10 insertions(+), 11 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index b87836233bc33..58e7b9daafa1b 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -6112,6 +6112,16 @@ KnownFPClass SelectionDAG::computeKnownFPClass(SDValue Op,
}
break;
}
+ case ISD::BITCAST: {
+ // Try to infer NaN from known bits, but only for detecting signaling or
+ // nonsignaling NaNs
+ EVT VT = Op.getValueType();
+ if (VT.isFloatingPoint()) {
+ KnownBits Bits = computeKnownBits(Op, DemandedElts, Depth + 1);
+ Known = KnownFPClass::bitcast(VT.getFltSemantics(), Bits);
+ }
+ break;
+ }
default:
if (Opcode >= ISD::BUILTIN_OP_END || Opcode == ISD::INTRINSIC_WO_CHAIN ||
Opcode == ISD::INTRINSIC_W_CHAIN || Opcode == ISD::INTRINSIC_VOID) {
@@ -6317,17 +6327,6 @@ bool SelectionDAG::isKnownNeverNaN(SDValue Op, const APInt &DemandedElts,
return true;
return isKnownNeverNaN(Op.getOperand(0), DemandedElts, SNaN, Depth + 1);
}
- case ISD::BITCAST: {
- // Try to infer NaN from known bits, but only for detecting signaling or
- // nonsignaling NaNs
- EVT VT = Op.getValueType();
- if (!SNaN && VT.isFloatingPoint()) {
- KnownBits Bits = computeKnownBits(Op, DemandedElts, Depth + 1);
- const auto FPClass = KnownFPClass::bitcast(VT.getFltSemantics(), Bits);
- return FPClass.isKnownNeverNaN();
- }
- return false;
- }
default:
if (Opcode >= ISD::BUILTIN_OP_END || Opcode == ISD::INTRINSIC_WO_CHAIN ||
Opcode == ISD::INTRINSIC_W_CHAIN || Opcode == ISD::INTRINSIC_VOID) {
>From 04d231629a1bbe44d1c5caf6876f367884001db7 Mon Sep 17 00:00:00 2001
From: Zach Goldthorpe <Zach.Goldthorpe at amd.com>
Date: Tue, 31 Mar 2026 09:18:31 -0500
Subject: [PATCH 11/14] Remove unnecessary recomputation of `VT`
---
llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 58e7b9daafa1b..2dec1873de864 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -6076,7 +6076,7 @@ KnownFPClass SelectionDAG::computeKnownFPClass(SDValue Op,
if (Op.getOpcode() == ISD::UNDEF)
return Known;
- [[maybe_unused]] EVT VT = Op.getValueType();
+ EVT VT = Op.getValueType();
assert((!VT.isFixedLengthVector() ||
DemandedElts.getBitWidth() == VT.getVectorNumElements()) &&
"Unexpected vector size");
@@ -6115,7 +6115,6 @@ KnownFPClass SelectionDAG::computeKnownFPClass(SDValue Op,
case ISD::BITCAST: {
// Try to infer NaN from known bits, but only for detecting signaling or
// nonsignaling NaNs
- EVT VT = Op.getValueType();
if (VT.isFloatingPoint()) {
KnownBits Bits = computeKnownBits(Op, DemandedElts, Depth + 1);
Known = KnownFPClass::bitcast(VT.getFltSemantics(), Bits);
>From 9df080c874722be978443282ea3b6e237b7642d3 Mon Sep 17 00:00:00 2001
From: Zach Goldthorpe <Zach.Goldthorpe at amd.com>
Date: Tue, 31 Mar 2026 14:31:08 -0500
Subject: [PATCH 12/14] Restrict to elementwise bitcasts
---
llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 2dec1873de864..b7273fd599350 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -6113,8 +6113,19 @@ KnownFPClass SelectionDAG::computeKnownFPClass(SDValue Op,
break;
}
case ISD::BITCAST: {
- // Try to infer NaN from known bits, but only for detecting signaling or
- // nonsignaling NaNs
+ // FIXME: It should not be necessary to check for an elementwise bitcast.
+ // If a bitcast is not elementwise between vector / scalar types,
+ // computeKnownBits already splices the known bits of the source elements
+ // appropriately so as to line up with the bits of the result's demanded
+ // elements.
+ EVT SrcVT = Op.getOperand(0).getValueType();
+ if (VT.isScalableVector() || SrcVT.isScalableVector())
+ break;
+ unsigned VTNumElts = VT.isVector() ? VT.getVectorNumElements() : 1;
+ unsigned SrcVTNumElts = SrcVT.isVector() ? SrcVT.getVectorNumElements() : 1;
+ if (VTNumElts != SrcVTNumElts)
+ break;
+
if (VT.isFloatingPoint()) {
KnownBits Bits = computeKnownBits(Op, DemandedElts, Depth + 1);
Known = KnownFPClass::bitcast(VT.getFltSemantics(), Bits);
>From 71e2fc0e17e3106c7549f6a997da54c57e597f9b Mon Sep 17 00:00:00 2001
From: Zach Goldthorpe <Zach.Goldthorpe at amd.com>
Date: Tue, 31 Mar 2026 14:34:02 -0500
Subject: [PATCH 13/14] Create `KnownFPClass` test coverage for bitcasts.
---
.../lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 1 +
.../AArch64/AArch64SelectionDAGTest.cpp | 98 ++++++++++++-------
2 files changed, 63 insertions(+), 36 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index b7273fd599350..f734227a4135d 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -6126,6 +6126,7 @@ KnownFPClass SelectionDAG::computeKnownFPClass(SDValue Op,
if (VTNumElts != SrcVTNumElts)
break;
+ // FIXME: assert VT.isFloatingPoint() at top level of function.
if (VT.isFloatingPoint()) {
KnownBits Bits = computeKnownBits(Op, DemandedElts, Depth + 1);
Known = KnownFPClass::bitcast(VT.getFltSemantics(), Bits);
diff --git a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
index 18f104a849437..b144060afe925 100644
--- a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
+++ b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
@@ -1576,45 +1576,71 @@ TEST_F(AArch64SelectionDAGTest, KnownNeverZero_Select) {
EXPECT_TRUE(DAG->isKnownNeverZero(VSelect4444, DemandAll));
}
-TEST_F(AArch64SelectionDAGTest, KnownNeverNaN_Bitcast) {
+TEST_F(AArch64SelectionDAGTest, KnownFPClass_Bitcast) {
SDLoc Loc;
-
- auto UnknownI32 = DAG->getRegister(1, MVT::i32);
- auto FiniteMask = DAG->getConstant(0x3fff'ffff, Loc, MVT::i32);
- auto NeverNaNI32 =
- DAG->getNode(ISD::AND, Loc, MVT::i32, FiniteMask, UnknownI32);
-
- auto NeverNaNF32 = DAG->getBitcast(MVT::f32, NeverNaNI32);
- EXPECT_TRUE(DAG->isKnownNeverNaN(NeverNaNF32));
-
- auto UnknownF32 = DAG->getBitcast(MVT::f32, UnknownI32);
- EXPECT_FALSE(DAG->isKnownNeverNaN(UnknownF32));
-
- auto NeverNaNV2I32 = DAG->getSplat(MVT::v2i32, Loc, NeverNaNI32);
- auto NeverNaNV2F32 = DAG->getBitcast(MVT::v2f32, NeverNaNV2I32);
- EXPECT_TRUE(DAG->isKnownNeverNaN(NeverNaNV2F32));
-
- auto PartialNaNV2I32 =
- DAG->getBuildVector(MVT::v2i32, Loc, {UnknownI32, NeverNaNI32});
- auto PartialNaNV2F32 = DAG->getBitcast(MVT::v2f32, PartialNaNV2I32);
- EXPECT_FALSE(DAG->isKnownNeverNaN(PartialNaNV2F32));
+ SDValue Cond = DAG->getRegister(1, MVT::i1);
+
+ SDValue ConstZeroI32 = DAG->getConstant(0x0000'0000, Loc, MVT::i32);
+ SDValue ConstFiniteI32 = DAG->getConstant(0xbfff'ffff, Loc, MVT::i32);
+ SDValue AlwaysFiniteI32 =
+ DAG->getSelect(Loc, MVT::i32, Cond, ConstZeroI32, ConstFiniteI32);
+ SDValue AlwaysFiniteF32 = DAG->getBitcast(MVT::f32, AlwaysFiniteI32);
+ KnownFPClass AlwaysFiniteFPClass =
+ DAG->computeKnownFPClass(AlwaysFiniteF32, fcAllFlags);
+ EXPECT_TRUE(AlwaysFiniteFPClass.isKnownNeverInfOrNaN());
+
+ SDValue ConstNegInfI32 = DAG->getConstant(0xff80'0000, Loc, MVT::i32);
+ SDValue NeverNaNI32 =
+ DAG->getSelect(Loc, MVT::i32, Cond, ConstZeroI32, ConstNegInfI32);
+ SDValue NeverNaNF32 = DAG->getBitcast(MVT::f32, NeverNaNI32);
+ KnownFPClass NeverNaNFPClass =
+ DAG->computeKnownFPClass(NeverNaNF32, fcAllFlags);
+ EXPECT_FALSE(NeverNaNFPClass.isKnownNeverInfinity());
+ EXPECT_TRUE(NeverNaNFPClass.isKnownNeverNaN());
+
+ SDValue ConstPosNaNI32 = DAG->getConstant(0x7f80'0001, Loc, MVT::i32);
+ SDValue MaybeNaNI32 =
+ DAG->getSelect(Loc, MVT::i32, Cond, ConstPosNaNI32, ConstNegInfI32);
+ SDValue MaybeNaNF32 = DAG->getBitcast(MVT::f32, MaybeNaNI32);
+ KnownFPClass MaybeNaNFPClass =
+ DAG->computeKnownFPClass(MaybeNaNF32, fcAllFlags);
+ EXPECT_FALSE(MaybeNaNFPClass.isKnownNeverNaN());
+ EXPECT_FALSE(MaybeNaNFPClass.isKnownAlwaysNaN());
+
+ SDValue ConstNegNaNI32 = DAG->getConstant(0xffff'ffff, Loc, MVT::i32);
+ SDValue AlwaysNaNI32 =
+ DAG->getSelect(Loc, MVT::i32, Cond, ConstPosNaNI32, ConstNegNaNI32);
+ SDValue AlwaysNaNF32 = DAG->getBitcast(MVT::f32, AlwaysNaNI32);
+ KnownFPClass AlwaysNaNFPClass =
+ DAG->computeKnownFPClass(AlwaysNaNF32, fcAllFlags);
+ EXPECT_TRUE(AlwaysNaNFPClass.isKnownAlwaysNaN());
+
+ SDValue AlwaysFiniteSplat = DAG->getSplat(MVT::v2i32, Loc, AlwaysFiniteI32);
+ SDValue AlwaysFiniteV2F32 = DAG->getBitcast(MVT::v2f32, AlwaysFiniteSplat);
+ KnownFPClass AlwaysFiniteV2FPClass =
+ DAG->computeKnownFPClass(AlwaysFiniteV2F32, fcAllFlags);
+ EXPECT_TRUE(AlwaysFiniteV2FPClass.isKnownNeverInfOrNaN());
+
+ SDValue UpperAlwaysNaN =
+ DAG->getBuildVector(MVT::v2i32, Loc, {NeverNaNI32, AlwaysNaNI32});
+ SDValue UpperAlwaysNaNV2F32 = DAG->getBitcast(MVT::v2f32, UpperAlwaysNaN);
+ KnownFPClass UpperAlwaysNaNFullFPClass =
+ DAG->computeKnownFPClass(UpperAlwaysNaNV2F32, fcAllFlags);
+ EXPECT_FALSE(UpperAlwaysNaNFullFPClass.isKnownNeverNaN());
APInt DemandLo(2, 1);
- EXPECT_FALSE(DAG->isKnownNeverNaN(PartialNaNV2F32, DemandLo));
+ KnownFPClass UpperAlwaysNaNLoFPClass =
+ DAG->computeKnownFPClass(UpperAlwaysNaNV2F32, DemandLo, fcAllFlags);
+ EXPECT_TRUE(UpperAlwaysNaNLoFPClass.isKnownNeverNaN());
APInt DemandHi(2, 2);
- EXPECT_TRUE(DAG->isKnownNeverNaN(PartialNaNV2F32, DemandHi));
-
- auto PartialNaNAsF64 = DAG->getBitcast(MVT::f64, PartialNaNV2I32);
- EXPECT_TRUE(DAG->isKnownNeverNaN(PartialNaNAsF64));
-
- auto UnknownI64 = DAG->getRegister(2, MVT::i64);
- auto Lo32NeverNaNMask =
- DAG->getConstant(0xffff'ffff'3fff'ffff, Loc, MVT::i64);
- auto PartialNaNPack64 =
- DAG->getNode(ISD::AND, Loc, MVT::i64, Lo32NeverNaNMask, UnknownI64);
- auto PartialNaNUnpackV2F32 = DAG->getBitcast(MVT::v2f32, PartialNaNPack64);
- EXPECT_FALSE(DAG->isKnownNeverNaN(PartialNaNUnpackV2F32));
- EXPECT_TRUE(DAG->isKnownNeverNaN(PartialNaNUnpackV2F32, DemandLo));
- EXPECT_FALSE(DAG->isKnownNeverNaN(PartialNaNUnpackV2F32, DemandHi));
+ KnownFPClass UpperAlwaysNaNHiFPClass =
+ DAG->computeKnownFPClass(UpperAlwaysNaNV2F32, DemandHi, fcAllFlags);
+ EXPECT_TRUE(UpperAlwaysNaNHiFPClass.isKnownAlwaysNaN());
+
+ SDValue UpperAlwaysNaNAsF64 = DAG->getBitcast(MVT::f64, UpperAlwaysNaN);
+ KnownFPClass UpperAlwaysNaNAsF64FPClass =
+ DAG->computeKnownFPClass(UpperAlwaysNaNAsF64, fcAllFlags);
+ EXPECT_FALSE(UpperAlwaysNaNAsF64FPClass.isKnownNeverNaN());
+ EXPECT_FALSE(UpperAlwaysNaNAsF64FPClass.isKnownAlwaysNaN());
}
// tests for SelectionDAG::computeKnownFPClass
>From 06fceac4b8c99cb057474c54c1b6f06a040f8268 Mon Sep 17 00:00:00 2001
From: Zach Goldthorpe <Zach.Goldthorpe at amd.com>
Date: Wed, 1 Apr 2026 12:46:44 -0500
Subject: [PATCH 14/14] Remove unnecessary FP check.
---
llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 081456bd97c00..4d0ec32b1bfca 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -6127,11 +6127,8 @@ KnownFPClass SelectionDAG::computeKnownFPClass(SDValue Op,
if (VTNumElts != SrcVTNumElts)
break;
- // FIXME: assert VT.isFloatingPoint() at top level of function.
- if (VT.isFloatingPoint()) {
- KnownBits Bits = computeKnownBits(Op, DemandedElts, Depth + 1);
- Known = KnownFPClass::bitcast(VT.getFltSemantics(), Bits);
- }
+ KnownBits Bits = computeKnownBits(Op, DemandedElts, Depth + 1);
+ Known = KnownFPClass::bitcast(VT.getFltSemantics(), Bits);
break;
}
default:
More information about the llvm-commits
mailing list