[llvm] [DAG] Add ISD::FSQRT handling to computeKnownFPClass (PR #213620)
Varad Rahul Kamthe via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 3 01:48:27 PDT 2026
https://github.com/varadk27 created https://github.com/llvm/llvm-project/pull/213620
Fixes #189583
Ports the ISD::FSQRT case from ValueTracking.cpp's computeKnownFPClass to the SelectionDAG version. sqrt can never produce a negative normal or -infinity; with nnan set, it also can't produce NaN.
Related to #195405, which attempted this earlier but stalled on review.
Unlike that attempt, this does not treat nsz as proof that the result can't be negative zero, since nsz is a fast-math hint rather than a guarantee -- doing so risks promoting a value to poison.
Added RISC-V codegen tests (scalar + scalable-vector) covering nnan, neginf, negnormal, nsz+negzero, and posinf cases. check-llvm-codegen-riscv and check-llvm both pass.
>From bda910d3fe47bc71309f2ddddca4d8f8a8d8a008 Mon Sep 17 00:00:00 2001
From: Varad Kamthe <varadk.2704 at gmail.com>
Date: Mon, 3 Aug 2026 14:05:20 +0530
Subject: [PATCH] [DAG] Add ISD::FSQRT handling to computeKnownFPClass
Ports the ISD::FSQRT case from ValueTracking.cpp's computeKnownFPClass
to the SelectionDAG version, per #189583.
sqrt can never produce a negative normal or -infinity; with nnan set,
it also can't produce NaN. Unlike an earlier attempt (#195405), this
does not treat nsz as proof that the result can't be negative zero,
since nsz is a fast-math hint rather than a guarantee -- doing so risks
promoting a value to poison.
Fixes #189583
---
.../lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 19 +++
.../CodeGen/RISCV/fold-is-fpclass-sqrt.ll | 124 ++++++++++++++++++
2 files changed, 143 insertions(+)
create mode 100644 llvm/test/CodeGen/RISCV/fold-is-fpclass-sqrt.ll
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 683cf2517b2f5..21f2727927e60 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -6191,6 +6191,25 @@ KnownFPClass SelectionDAG::computeKnownFPClass(SDValue Op,
Known.fneg();
break;
}
+ case ISD::FSQRT: {
+ FPClassTest InterestedSrcs = InterestedClasses;
+ if (InterestedClasses & fcNan)
+ InterestedSrcs |= KnownFPClass::OrderedLessThanZeroMask;
+
+ KnownFPClass KnownSrc = computeKnownFPClass(Op.getOperand(0), DemandedElts,
+ InterestedSrcs, Depth + 1);
+
+ const fltSemantics &FltSem =
+ Op.getValueType().getScalarType().getFltSemantics();
+ DenormalMode Mode = getMachineFunction().getDenormalMode(FltSem);
+
+ Known = KnownFPClass::sqrt(KnownSrc, Mode);
+
+ if (Op->getFlags().hasNoNaNs())
+ Known.knownNot(fcNan);
+
+ break;
+ }
case ISD::BUILD_VECTOR: {
assert(!VT.isScalableVector());
bool First = true;
diff --git a/llvm/test/CodeGen/RISCV/fold-is-fpclass-sqrt.ll b/llvm/test/CodeGen/RISCV/fold-is-fpclass-sqrt.ll
new file mode 100644
index 0000000000000..9472259c62cc9
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/fold-is-fpclass-sqrt.ll
@@ -0,0 +1,124 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=riscv64 -mattr=+f,+d,+v -target-abi=lp64d < %s | FileCheck %s
+
+define i1 @sqrt_nnan_check_f32(float %a0) {
+; CHECK-LABEL: sqrt_nnan_check_f32:
+; CHECK: # %bb.0:
+; CHECK-NEXT: li a0, 0
+; CHECK-NEXT: ret
+ %sqr = call nnan float @llvm.sqrt.f32(float %a0)
+ %res = tail call i1 @llvm.is.fpclass.f32(float %sqr, i32 3)
+ ret i1 %res
+}
+
+define i1 @sqrt_neginf_f32(float %a0) {
+; CHECK-LABEL: sqrt_neginf_f32:
+; CHECK: # %bb.0:
+; CHECK-NEXT: li a0, 0
+; CHECK-NEXT: ret
+ %sqr = call float @llvm.sqrt.f32(float %a0)
+ %res = tail call i1 @llvm.is.fpclass.f32(float %sqr, i32 4)
+ ret i1 %res
+}
+
+define i1 @sqrt_negnormal_f32(float %a0) {
+; CHECK-LABEL: sqrt_negnormal_f32:
+; CHECK: # %bb.0:
+; CHECK-NEXT: li a0, 0
+; CHECK-NEXT: ret
+ %sqr = call float @llvm.sqrt.f32(float %a0)
+ %res = tail call i1 @llvm.is.fpclass.f32(float %sqr, i32 8)
+ ret i1 %res
+}
+
+define i1 @sqrt_nsz_negzero_f32(float %a0) {
+; CHECK-LABEL: sqrt_nsz_negzero_f32:
+; CHECK: # %bb.0:
+; CHECK-NEXT: fsqrt.s fa5, fa0
+; CHECK-NEXT: fclass.s a0, fa5
+; CHECK-NEXT: slli a0, a0, 60
+; CHECK-NEXT: srli a0, a0, 63
+; CHECK-NEXT: ret
+ %sqr = call nsz float @llvm.sqrt.f32(float %a0)
+ %res = tail call i1 @llvm.is.fpclass.f32(float %sqr, i32 32)
+ ret i1 %res
+}
+
+define i1 @sqrt_posinf_f32(float %a0) {
+; CHECK-LABEL: sqrt_posinf_f32:
+; CHECK: # %bb.0:
+; CHECK-NEXT: fsqrt.s fa5, fa0
+; CHECK-NEXT: fclass.s a0, fa5
+; CHECK-NEXT: slli a0, a0, 56
+; CHECK-NEXT: srli a0, a0, 63
+; CHECK-NEXT: ret
+ %sqr = call float @llvm.sqrt.f32(float %a0)
+ %res = tail call i1 @llvm.is.fpclass.f32(float %sqr, i32 512)
+ ret i1 %res
+}
+
+declare float @llvm.sqrt.f32(float)
+declare i1 @llvm.is.fpclass.f32(float, i32)
+
+declare <vscale x 2 x float> @llvm.sqrt.nxv2f32(<vscale x 2 x float>)
+declare <vscale x 2 x i1> @llvm.is.fpclass.nxv2f32(<vscale x 2 x float>, i32)
+
+define <vscale x 2 x i1> @vsqrt_nnan_check_nxv2f32(<vscale x 2 x float> %a0) {
+; CHECK-LABEL: vsqrt_nnan_check_nxv2f32:
+; CHECK: # %bb.0:
+; CHECK-NEXT: vsetvli a0, zero, e8, mf4, ta, ma
+; CHECK-NEXT: vmclr.m v0
+; CHECK-NEXT: ret
+ %sqr = call nnan <vscale x 2 x float> @llvm.sqrt.nxv2f32(<vscale x 2 x float> %a0)
+ %res = tail call <vscale x 2 x i1> @llvm.is.fpclass.nxv2f32(<vscale x 2 x float> %sqr, i32 3)
+ ret <vscale x 2 x i1> %res
+}
+
+define <vscale x 2 x i1> @vsqrt_neginf_nxv2f32(<vscale x 2 x float> %a0) {
+; CHECK-LABEL: vsqrt_neginf_nxv2f32:
+; CHECK: # %bb.0:
+; CHECK-NEXT: vsetvli a0, zero, e8, mf4, ta, ma
+; CHECK-NEXT: vmclr.m v0
+; CHECK-NEXT: ret
+ %sqr = call <vscale x 2 x float> @llvm.sqrt.nxv2f32(<vscale x 2 x float> %a0)
+ %res = tail call <vscale x 2 x i1> @llvm.is.fpclass.nxv2f32(<vscale x 2 x float> %sqr, i32 4)
+ ret <vscale x 2 x i1> %res
+}
+
+define <vscale x 2 x i1> @vsqrt_negnormal_nxv2f32(<vscale x 2 x float> %a0) {
+; CHECK-LABEL: vsqrt_negnormal_nxv2f32:
+; CHECK: # %bb.0:
+; CHECK-NEXT: vsetvli a0, zero, e8, mf4, ta, ma
+; CHECK-NEXT: vmclr.m v0
+; CHECK-NEXT: ret
+ %sqr = call <vscale x 2 x float> @llvm.sqrt.nxv2f32(<vscale x 2 x float> %a0)
+ %res = tail call <vscale x 2 x i1> @llvm.is.fpclass.nxv2f32(<vscale x 2 x float> %sqr, i32 8)
+ ret <vscale x 2 x i1> %res
+}
+
+define <vscale x 2 x i1> @vsqrt_nsz_negzero_nxv2f32(<vscale x 2 x float> %a0) {
+; CHECK-LABEL: vsqrt_nsz_negzero_nxv2f32:
+; CHECK: # %bb.0:
+; CHECK-NEXT: vsetvli a0, zero, e32, m1, ta, ma
+; CHECK-NEXT: vfsqrt.v v8, v8
+; CHECK-NEXT: vfclass.v v8, v8
+; CHECK-NEXT: vmseq.vi v0, v8, 8
+; CHECK-NEXT: ret
+ %sqr = call nsz <vscale x 2 x float> @llvm.sqrt.nxv2f32(<vscale x 2 x float> %a0)
+ %res = tail call <vscale x 2 x i1> @llvm.is.fpclass.nxv2f32(<vscale x 2 x float> %sqr, i32 32)
+ ret <vscale x 2 x i1> %res
+}
+
+define <vscale x 2 x i1> @vsqrt_posinf_nxv2f32(<vscale x 2 x float> %a0) {
+; CHECK-LABEL: vsqrt_posinf_nxv2f32:
+; CHECK: # %bb.0:
+; CHECK-NEXT: vsetvli a0, zero, e32, m1, ta, ma
+; CHECK-NEXT: vfsqrt.v v8, v8
+; CHECK-NEXT: vfclass.v v8, v8
+; CHECK-NEXT: li a0, 128
+; CHECK-NEXT: vmseq.vx v0, v8, a0
+; CHECK-NEXT: ret
+ %sqr = call <vscale x 2 x float> @llvm.sqrt.nxv2f32(<vscale x 2 x float> %a0)
+ %res = tail call <vscale x 2 x i1> @llvm.is.fpclass.nxv2f32(<vscale x 2 x float> %sqr, i32 512)
+ ret <vscale x 2 x i1> %res
+}
More information about the llvm-commits
mailing list