[llvm-branch-commits] [llvm] 21ef2dd - [KnownFPClass] Do not propagate non-NaN through `asin` and `acos` (#213812)
Tobias Hieta via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Wed Sep 30 02:07:55 PDT 2026
Author: ZERICO2005
Date: 2026-09-30T11:07:37+02:00
New Revision: 21ef2ddb806006eba611b8a769ae72e5f86f9418
URL: https://github.com/llvm/llvm-project/commit/21ef2ddb806006eba611b8a769ae72e5f86f9418
DIFF: https://github.com/llvm/llvm-project/commit/21ef2ddb806006eba611b8a769ae72e5f86f9418.diff
LOG: [KnownFPClass] Do not propagate non-NaN through `asin` and `acos` (#213812)
`KnownFPClass` incorrectly assumed that a non-NaN input to `asin` or
`acos` implies a non-NaN result. However, both `asin` and `acos` can
return NaN from a finite input when `|x| > 1.0`, such as `asin(2.0)` or
`acos(2.0)`.
I have fixed this by removing the calls to
`Known.propagateNaN(KnownSrc)`, which incorrectly propagated that
`asin(non-NaN) == non-NaN`.
I discovered this while working on
https://github.com/llvm/llvm-project/issues/211686. The same issue was
previously noted in a post-merge review comment on
https://github.com/llvm/llvm-project/pull/190609#discussion_r3632814122
AI disclosure:
I used OpenAI Codex (GPT-5.6-sol) to help generate the test updates,
which I reviewed and tested locally.
(cherry picked from commit 0130acf8430b64a8da97217ea57bea64abb51685)
Added:
Modified:
llvm/lib/Support/KnownFPClass.cpp
llvm/test/Transforms/Attributor/nofpclass-trig.ll
llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp
index 4fb1d4cd4723e..8e97781e45389 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -649,8 +649,6 @@ KnownFPClass KnownFPClass::asin(const KnownFPClass &KnownSrc) {
// NaN propagates. asin(x) is also NaN for |x| > 1, so we cannot rule
// out NaN without knowing the source is in [-1, 1].
- Known.propagateNaN(KnownSrc);
-
return Known;
}
@@ -663,8 +661,6 @@ KnownFPClass KnownFPClass::acos(const KnownFPClass &KnownSrc) {
// NaN propagates. acos(x) is also NaN for |x| > 1, so we cannot rule
// out NaN without knowing the source is in [-1, 1].
- Known.propagateNaN(KnownSrc);
-
return Known;
}
diff --git a/llvm/test/Transforms/Attributor/nofpclass-trig.ll b/llvm/test/Transforms/Attributor/nofpclass-trig.ll
index ba96ecfa776b8..5f50b580d9eea 100644
--- a/llvm/test/Transforms/Attributor/nofpclass-trig.ll
+++ b/llvm/test/Transforms/Attributor/nofpclass-trig.ll
@@ -137,9 +137,9 @@ define float @ret_asin_nonneg(float nofpclass(ninf nzero nsub nnorm) %arg) {
}
define float @ret_asin_nonan(float nofpclass(nan) %arg) {
-; CHECK-LABEL: define nofpclass(nan inf) float @ret_asin_nonan
+; CHECK-LABEL: define nofpclass(inf) float @ret_asin_nonan
; CHECK-SAME: (float nofpclass(nan) [[ARG:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan inf) float @llvm.asin.f32(float nofpclass(nan) [[ARG]]) #[[ATTR2]]
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf) float @llvm.asin.f32(float nofpclass(nan) [[ARG]]) #[[ATTR2]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.asin.f32(float %arg)
@@ -158,9 +158,9 @@ define float @ret_acos(float %arg) {
}
define float @ret_acos_nonan(float nofpclass(nan) %arg) {
-; CHECK-LABEL: define nofpclass(nan inf nzero nsub nnorm) float @ret_acos_nonan
+; CHECK-LABEL: define nofpclass(inf nzero nsub nnorm) float @ret_acos_nonan
; CHECK-SAME: (float nofpclass(nan) [[ARG:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan inf nzero nsub nnorm) float @llvm.acos.f32(float nofpclass(nan) [[ARG]]) #[[ATTR2]]
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf nzero nsub nnorm) float @llvm.acos.f32(float nofpclass(nan) [[ARG]]) #[[ATTR2]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.acos.f32(float %arg)
diff --git a/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp b/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp
index 8d888d8c50f4a..6b17d708d058a 100644
--- a/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp
+++ b/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp
@@ -1500,7 +1500,8 @@ TEST_F(AArch64GISelMITest, TestFPClassFAsin) {
}
TEST_F(AArch64GISelMITest, TestFPClassFAsinPos) {
- // asin is sign-preserving and bounded: non-negative finite output.
+ // For 0 <= x <= 1, asin is sign-preserving and returns a non-negative
+ // finite value. For x > 1, it returns NaN.
StringRef MIRString = R"(
%ptr:_(p0) = G_IMPLICIT_DEF
%val:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
@@ -1516,8 +1517,8 @@ TEST_F(AArch64GISelMITest, TestFPClassFAsinPos) {
Register SrcReg = FinalCopy->getOperand(1).getReg();
GISelValueTracking Info(*MF);
KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
- EXPECT_EQ(fcPosFinite, Known.KnownFPClasses);
- EXPECT_EQ(false, Known.SignBit);
+ EXPECT_EQ(fcPosFinite | fcNan, Known.KnownFPClasses);
+ EXPECT_EQ(std::nullopt, Known.SignBit);
}
TEST_F(AArch64GISelMITest, TestFPClassFAcos) {
@@ -1540,6 +1541,28 @@ TEST_F(AArch64GISelMITest, TestFPClassFAcos) {
EXPECT_EQ(std::nullopt, Known.SignBit);
}
+TEST_F(AArch64GISelMITest, TestFPClassFAcosPos) {
+ // For 0 <= x <= 1, acos returns a non-negative finite value.
+ // For x > 1, acos returns NaN.
+ StringRef MIRString = R"(
+ %ptr:_(p0) = G_IMPLICIT_DEF
+ %val:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
+ %fabs:_(s32) = nnan ninf G_FABS %val
+ %facos:_(s32) = G_FACOS %fabs
+ %copy:_(s32) = COPY %facos
+)";
+ setUp(MIRString);
+ if (!TM)
+ GTEST_SKIP();
+ Register CopyReg = Copies[Copies.size() - 1];
+ MachineInstr *FinalCopy = MRI->getVRegDef(CopyReg);
+ Register SrcReg = FinalCopy->getOperand(1).getReg();
+ GISelValueTracking Info(*MF);
+ KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
+ EXPECT_EQ(fcPosFinite | fcNan, Known.KnownFPClasses);
+ EXPECT_EQ(std::nullopt, Known.SignBit);
+}
+
TEST_F(AArch64GISelMITest, TestFPClassFAtan) {
// atan is bounded to (-π/2, π/2): never Inf (atan(±Inf) = ±π/2, finite).
StringRef MIRString = R"(
More information about the llvm-branch-commits
mailing list