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"( _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
