[llvm] c118f34 - [KnownFPClass] Improve known classes for `acos` (#214603)

via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 26 02:33:20 PDT 2026


Author: ZERICO2005
Date: 2026-08-26T09:33:14Z
New Revision: c118f3407d1b69b2a9ae9d4f1e9e0eba7c5bd90a

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

LOG: [KnownFPClass] Improve known classes for `acos` (#214603)

Finishes the last remaining TODO from
https://github.com/llvm/llvm-project/issues/211686

Improves the KnownFPClass for `acos` in two ways:
- `acos(x) == +0.0 iff x == +1.0`, so if `x` is not a positive normal
then `acos(x)` cannot return zero.
- `acos(x)` can never return a subnormal value.

Proof that `acos(x)` never produces a subnormal result:
The smallest non-zero value occurs when `x` is close to `1.0`, where
`acos(x)` can be approximated by `sqrt(2 * (1 - x))` (which is a lower
bound for `acos(x)`). Since `sqrt` cannot produce a subnormal result, we
can conclude that `acos(x)` will also never produce a subnormal result.

AI disclosure:
I used OpenAI Codex (GPT-5.6-terra) to help generate the test updates,
which I reviewed and tested locally.

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 a1f2bff5dc257..525f85100b34e 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -703,9 +703,16 @@ KnownFPClass KnownFPClass::asin(const KnownFPClass &KnownSrc) {
 KnownFPClass KnownFPClass::acos(const KnownFPClass &KnownSrc) {
   KnownFPClass Known;
 
-  // acos is bounded to [0, pi], never Inf or negative.
-  Known.knownNot(fcInf);
-  Known.knownNot(fcNegative);
+  // acos(x) is bounded to [0, pi] for -1 <= x <= 1, and is never negative,
+  // infinite, or subnormal. The smallest non-zero value occurs when x is
+  // close to 1.0, where acos(x) can be approximated by sqrt(2 * (1 - x)).
+  // Since sqrt cannot produce a subnormal result, we can conclude that
+  // acos(x) will also never produce a subnormal result.
+  Known.knownNot(fcNegative | fcInf | fcSubnormal);
+
+  // acos(x) == +0.0 iff x == +1.0
+  if (KnownSrc.isKnownNever(fcPosNormal))
+    Known.knownNot(fcZero);
 
   Known.propagateNonSNaN(KnownSrc);
 

diff  --git a/llvm/test/Transforms/Attributor/nofpclass-trig.ll b/llvm/test/Transforms/Attributor/nofpclass-trig.ll
index 7a6c583653650..1a1ade239ce59 100644
--- a/llvm/test/Transforms/Attributor/nofpclass-trig.ll
+++ b/llvm/test/Transforms/Attributor/nofpclass-trig.ll
@@ -156,11 +156,11 @@ define float @ret_asin_nonan(float nofpclass(nan) %arg) {
   ret float %call
 }
 
-; acos is bounded to [0, pi], never Inf or negative.
+; acos is bounded to [0, pi], never infinite, negative, or subnormal.
 define float @ret_acos(float %arg) {
-; CHECK-LABEL: define nofpclass(inf nzero nsub nnorm) float @ret_acos
+; CHECK-LABEL: define nofpclass(inf nzero sub nnorm) float @ret_acos
 ; CHECK-SAME: (float [[ARG:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(inf nzero nsub nnorm) float @llvm.acos.f32(float [[ARG]]) #[[ATTR2]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(inf nzero sub nnorm) float @llvm.acos.f32(float [[ARG]]) #[[ATTR2]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.acos.f32(float %arg)
@@ -168,9 +168,30 @@ define float @ret_acos(float %arg) {
 }
 
 define float @ret_acos_nonan(float nofpclass(nan) %arg) {
-; CHECK-LABEL: define nofpclass(snan inf nzero nsub nnorm) float @ret_acos_nonan
+; CHECK-LABEL: define nofpclass(snan inf nzero sub nnorm) float @ret_acos_nonan
 ; CHECK-SAME: (float nofpclass(nan) [[ARG:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(snan inf nzero nsub nnorm) float @llvm.acos.f32(float nofpclass(nan) [[ARG]]) #[[ATTR2]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(snan inf nzero sub nnorm) float @llvm.acos.f32(float nofpclass(nan) [[ARG]]) #[[ATTR2]]
+; CHECK-NEXT:    ret float [[CALL]]
+;
+  %call = call float @llvm.acos.f32(float %arg)
+  ret float %call
+}
+
+; acos(x) == +0.0 iff x == +1.0
+define float @ret_acos_no_pos_normal(float nofpclass(pnorm) %arg) {
+; CHECK-LABEL: define nofpclass(inf zero sub nnorm) float @ret_acos_no_pos_normal
+; CHECK-SAME: (float nofpclass(pnorm) [[ARG:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(inf zero sub nnorm) float @llvm.acos.f32(float nofpclass(pnorm) [[ARG]]) #[[ATTR2]]
+; CHECK-NEXT:    ret float [[CALL]]
+;
+  %call = call float @llvm.acos.f32(float %arg)
+  ret float %call
+}
+
+define float @ret_acos_no_neg_normal(float nofpclass(nnorm) %arg) {
+; CHECK-LABEL: define nofpclass(inf nzero sub nnorm) float @ret_acos_no_neg_normal
+; CHECK-SAME: (float nofpclass(nnorm) [[ARG:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(inf nzero sub nnorm) float @llvm.acos.f32(float nofpclass(nnorm) [[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 dc73ab751da68..bdd2b3faf6d5c 100644
--- a/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp
+++ b/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp
@@ -1656,7 +1656,7 @@ TEST_F(AArch64GISelMITest, TestFPClassFAsinPos) {
 }
 
 TEST_F(AArch64GISelMITest, TestFPClassFAcos) {
-  // acos is bounded to [0, π]: never Inf, never negative.
+  // acos is bounded to [0, π]: never infinite, negative, or subnormal.
   StringRef MIRString = R"(
     %ptr:_(p0) = G_IMPLICIT_DEF
     %val:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
@@ -1671,7 +1671,7 @@ TEST_F(AArch64GISelMITest, TestFPClassFAcos) {
   Register SrcReg = FinalCopy->getOperand(1).getReg();
   GISelValueTracking Info(*MF);
   KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
-  EXPECT_EQ(fcPosFinite | fcNan, Known.KnownFPClasses);
+  EXPECT_EQ(fcPosZero | fcPosNormal | fcNan, Known.KnownFPClasses);
   EXPECT_EQ(std::nullopt, Known.SignBit);
 }
 
@@ -1693,7 +1693,7 @@ TEST_F(AArch64GISelMITest, TestFPClassFAcosPos) {
   Register SrcReg = FinalCopy->getOperand(1).getReg();
   GISelValueTracking Info(*MF);
   KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
-  EXPECT_EQ(fcPosFinite | fcQNan, Known.KnownFPClasses);
+  EXPECT_EQ(fcPosZero | fcPosNormal | fcQNan, Known.KnownFPClasses);
   EXPECT_EQ(std::nullopt, Known.SignBit);
 }
 


        


More information about the llvm-commits mailing list