[llvm] 18b9d72 - [KnownFPClass] Add sNaN deductions for log/log2/log10 (#219703)

via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 11 01:17:08 PDT 2026


Author: Eric Ross
Date: 2026-09-11T10:17:04+02:00
New Revision: 18b9d7282c067d83edda8006c25542d9490e3c6e

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

LOG: [KnownFPClass] Add sNaN deductions for log/log2/log10 (#219703)

`log(x)` can only produce `sNaN` if `x` is `sNaN`.

This also affects tests for `llvm.amdgcn.log.f16` and
`llvm.amdgcn.log.f32`.

Added: 
    

Modified: 
    llvm/lib/Support/KnownFPClass.cpp
    llvm/test/Transforms/Attributor/AMDGPU/nofpclass-amdgcn-log.ll
    llvm/test/Transforms/Attributor/nofpclass-log.ll
    llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp
index 1f596edd74100..75636ffc73361 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -623,6 +623,8 @@ KnownFPClass KnownFPClass::log(const KnownFPClass &KnownSrc,
   KnownFPClass Known;
   Known.knownNot(fcNegZero | fcSubnormal);
 
+  Known.propagateNonSNaN(KnownSrc);
+
   if (KnownSrc.isKnownNeverPosInfinity())
     Known.knownNot(fcPosInf);
 

diff  --git a/llvm/test/Transforms/Attributor/AMDGPU/nofpclass-amdgcn-log.ll b/llvm/test/Transforms/Attributor/AMDGPU/nofpclass-amdgcn-log.ll
index c7186d1cb12af..776848a1c1843 100644
--- a/llvm/test/Transforms/Attributor/AMDGPU/nofpclass-amdgcn-log.ll
+++ b/llvm/test/Transforms/Attributor/AMDGPU/nofpclass-amdgcn-log.ll
@@ -11,6 +11,26 @@ define half @ret_log_f16(half %arg) #1 {
   ret half %call
 }
 
+define half @ret_log_f16_nonan(half nofpclass(nan) %arg) #1 {
+; CHECK-LABEL: define nofpclass(snan nzero sub) half @ret_log_f16_nonan(
+; CHECK-SAME: half nofpclass(nan) [[ARG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(snan nzero sub) half @llvm.amdgcn.log.f16(half nofpclass(nan) [[ARG]]) #[[ATTR6]]
+; CHECK-NEXT:    ret half [[CALL]]
+;
+  %call = call half @llvm.amdgcn.log.f16(half %arg)
+  ret half %call
+}
+
+define half @ret_log_f16_nosnan(half nofpclass(snan) %arg) #1 {
+; CHECK-LABEL: define nofpclass(snan nzero sub) half @ret_log_f16_nosnan(
+; CHECK-SAME: half nofpclass(snan) [[ARG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(snan nzero sub) half @llvm.amdgcn.log.f16(half nofpclass(snan) [[ARG]]) #[[ATTR6]]
+; CHECK-NEXT:    ret half [[CALL]]
+;
+  %call = call half @llvm.amdgcn.log.f16(half %arg)
+  ret half %call
+}
+
 define float @ret_log_f32(float %arg) #1 {
 ; CHECK-LABEL: define nofpclass(nzero sub) float @ret_log_f32(
 ; CHECK-SAME: float [[ARG:%.*]]) #[[ATTR0]] {
@@ -71,6 +91,26 @@ define float @ret_log_noinf_noneg_nonan(float nofpclass(nan inf nsub nnorm) %arg
   ret float %call
 }
 
+define float @ret_log_noinf_noneg_nosnan(float nofpclass(snan inf nsub nnorm) %arg) #1 {
+; CHECK-LABEL: define nofpclass(snan pinf nzero sub) float @ret_log_noinf_noneg_nosnan(
+; CHECK-SAME: float nofpclass(snan inf nsub nnorm) [[ARG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(snan pinf nzero sub) float @llvm.amdgcn.log.f32(float nofpclass(snan inf nsub nnorm) [[ARG]]) #[[ATTR6]]
+; CHECK-NEXT:    ret float [[CALL]]
+;
+  %call = call float @llvm.amdgcn.log.f32(float %arg)
+  ret float %call
+}
+
+define float @ret_log_noinf_noneg_noqnan(float nofpclass(qnan inf nsub nnorm) %arg) #1 {
+; CHECK-LABEL: define nofpclass(pinf nzero sub) float @ret_log_noinf_noneg_noqnan(
+; CHECK-SAME: float nofpclass(qnan inf nsub nnorm) [[ARG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(pinf nzero sub) float @llvm.amdgcn.log.f32(float nofpclass(qnan inf nsub nnorm) [[ARG]]) #[[ATTR6]]
+; CHECK-NEXT:    ret float [[CALL]]
+;
+  %call = call float @llvm.amdgcn.log.f32(float %arg)
+  ret float %call
+}
+
 define float @ret_log_nopinf(float nofpclass(pinf) %arg) #1 {
 ; CHECK-LABEL: define nofpclass(pinf nzero sub) float @ret_log_nopinf(
 ; CHECK-SAME: float nofpclass(pinf) [[ARG:%.*]]) #[[ATTR0]] {
@@ -92,9 +132,19 @@ define float @ret_log_noninf(float nofpclass(ninf) %arg) #1 {
 }
 
 define float @ret_log_nonan(float nofpclass(nan) %arg) #1 {
-; CHECK-LABEL: define nofpclass(nzero sub) float @ret_log_nonan(
+; CHECK-LABEL: define nofpclass(snan nzero sub) float @ret_log_nonan(
 ; CHECK-SAME: float nofpclass(nan) [[ARG:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nzero sub) float @llvm.amdgcn.log.f32(float nofpclass(nan) [[ARG]]) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(snan nzero sub) float @llvm.amdgcn.log.f32(float nofpclass(nan) [[ARG]]) #[[ATTR6]]
+; CHECK-NEXT:    ret float [[CALL]]
+;
+  %call = call float @llvm.amdgcn.log.f32(float %arg)
+  ret float %call
+}
+
+define float @ret_log_nosnan(float nofpclass(snan) %arg) #1 {
+; CHECK-LABEL: define nofpclass(snan nzero sub) float @ret_log_nosnan(
+; CHECK-SAME: float nofpclass(snan) [[ARG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(snan nzero sub) float @llvm.amdgcn.log.f32(float nofpclass(snan) [[ARG]]) #[[ATTR6]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.amdgcn.log.f32(float %arg)
@@ -102,9 +152,9 @@ define float @ret_log_nonan(float nofpclass(nan) %arg) #1 {
 }
 
 define float @ret_log_nonan_noinf(float nofpclass(nan inf) %arg) #1 {
-; CHECK-LABEL: define nofpclass(pinf nzero sub) float @ret_log_nonan_noinf(
+; CHECK-LABEL: define nofpclass(snan pinf nzero sub) float @ret_log_nonan_noinf(
 ; CHECK-SAME: float nofpclass(nan inf) [[ARG:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(pinf nzero sub) float @llvm.amdgcn.log.f32(float nofpclass(nan inf) [[ARG]]) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(snan pinf nzero sub) float @llvm.amdgcn.log.f32(float nofpclass(nan inf) [[ARG]]) #[[ATTR6]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.amdgcn.log.f32(float %arg)
@@ -112,9 +162,9 @@ define float @ret_log_nonan_noinf(float nofpclass(nan inf) %arg) #1 {
 }
 
 define float @ret_log_nonan_noinf_nozero(float nofpclass(nan inf zero) %arg) #1 {
-; CHECK-LABEL: define nofpclass(inf nzero sub) float @ret_log_nonan_noinf_nozero(
+; CHECK-LABEL: define nofpclass(snan inf nzero sub) float @ret_log_nonan_noinf_nozero(
 ; CHECK-SAME: float nofpclass(nan inf zero) [[ARG:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(inf nzero sub) float @llvm.amdgcn.log.f32(float nofpclass(nan inf zero) [[ARG]]) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(snan inf nzero sub) float @llvm.amdgcn.log.f32(float nofpclass(nan inf zero) [[ARG]]) #[[ATTR6]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.amdgcn.log.f32(float %arg)
@@ -154,10 +204,10 @@ define float @ret_log_positive_source(i32 %arg) #1 {
 }
 
 define float @ret_log_unknown_sign(float nofpclass(nan) %arg, float nofpclass(nan) %arg1) #1 {
-; CHECK-LABEL: define nofpclass(nzero sub) float @ret_log_unknown_sign(
+; CHECK-LABEL: define nofpclass(snan nzero sub) float @ret_log_unknown_sign(
 ; CHECK-SAME: float nofpclass(nan) [[ARG:%.*]], float nofpclass(nan) [[ARG1:%.*]]) #[[ATTR0]] {
 ; CHECK-NEXT:    [[UNKNOWN_SIGN_NOT_NAN:%.*]] = fmul nnan float [[ARG]], [[ARG1]]
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nzero sub) float @llvm.amdgcn.log.f32(float [[UNKNOWN_SIGN_NOT_NAN]]) #[[ATTR6]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(snan nzero sub) float @llvm.amdgcn.log.f32(float [[UNKNOWN_SIGN_NOT_NAN]]) #[[ATTR6]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %unknown.sign.not.nan = fmul nnan float %arg, %arg1

diff  --git a/llvm/test/Transforms/Attributor/nofpclass-log.ll b/llvm/test/Transforms/Attributor/nofpclass-log.ll
index 4bd62d8e903ba..2bd21337f290d 100644
--- a/llvm/test/Transforms/Attributor/nofpclass-log.ll
+++ b/llvm/test/Transforms/Attributor/nofpclass-log.ll
@@ -91,9 +91,9 @@ define float @ret_log_noninf(float nofpclass(ninf) %arg) #0 {
 }
 
 define float @ret_log_nonan(float nofpclass(nan) %arg) #0 {
-; CHECK-LABEL: define nofpclass(nzero sub) float @ret_log_nonan
+; CHECK-LABEL: define nofpclass(snan nzero sub) float @ret_log_nonan
 ; CHECK-SAME: (float nofpclass(nan) [[ARG:%.*]]) #[[ATTR2]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nzero sub) float @llvm.log.f32(float nofpclass(nan) [[ARG]]) #[[ATTR10]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(snan nzero sub) float @llvm.log.f32(float nofpclass(nan) [[ARG]]) #[[ATTR10]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.log.f32(float %arg)
@@ -101,9 +101,9 @@ define float @ret_log_nonan(float nofpclass(nan) %arg) #0 {
 }
 
 define float @ret_log_nonan_noinf(float nofpclass(nan inf) %arg) #0 {
-; CHECK-LABEL: define nofpclass(pinf nzero sub) float @ret_log_nonan_noinf
+; CHECK-LABEL: define nofpclass(snan pinf nzero sub) float @ret_log_nonan_noinf
 ; CHECK-SAME: (float nofpclass(nan inf) [[ARG:%.*]]) #[[ATTR2]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(pinf nzero sub) float @llvm.log.f32(float nofpclass(nan inf) [[ARG]]) #[[ATTR10]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(snan pinf nzero sub) float @llvm.log.f32(float nofpclass(nan inf) [[ARG]]) #[[ATTR10]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.log.f32(float %arg)
@@ -111,9 +111,9 @@ define float @ret_log_nonan_noinf(float nofpclass(nan inf) %arg) #0 {
 }
 
 define float @ret_log_nonan_noinf_nozero(float nofpclass(nan inf zero) %arg) #0 {
-; CHECK-LABEL: define nofpclass(inf nzero sub) float @ret_log_nonan_noinf_nozero
+; CHECK-LABEL: define nofpclass(snan inf nzero sub) float @ret_log_nonan_noinf_nozero
 ; CHECK-SAME: (float nofpclass(nan inf zero) [[ARG:%.*]]) #[[ATTR2]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(inf nzero sub) float @llvm.log.f32(float nofpclass(nan inf zero) [[ARG]]) #[[ATTR10]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(snan inf nzero sub) float @llvm.log.f32(float nofpclass(nan inf zero) [[ARG]]) #[[ATTR10]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.log.f32(float %arg)
@@ -154,10 +154,10 @@ define float @ret_log_positive_source(i32 %arg) #0 {
 
 ; Could produce a nan because we don't know if the multiply is negative.
 define float @ret_log_unknown_sign(float nofpclass(nan) %arg, float nofpclass(nan) %arg1) #0 {
-; CHECK-LABEL: define nofpclass(nzero sub) float @ret_log_unknown_sign
+; CHECK-LABEL: define nofpclass(snan nzero sub) float @ret_log_unknown_sign
 ; CHECK-SAME: (float nofpclass(nan) [[ARG:%.*]], float nofpclass(nan) [[ARG1:%.*]]) #[[ATTR2]] {
 ; CHECK-NEXT:    [[UNKNOWN_SIGN_NOT_NAN:%.*]] = fmul nnan float [[ARG]], [[ARG1]]
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nzero sub) float @llvm.log.f32(float [[UNKNOWN_SIGN_NOT_NAN]]) #[[ATTR10]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(snan nzero sub) float @llvm.log.f32(float [[UNKNOWN_SIGN_NOT_NAN]]) #[[ATTR10]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %unknown.sign.not.nan = fmul nnan float %arg, %arg1
@@ -276,9 +276,9 @@ define float @constrained_log(float %arg) strictfp {
 }
 
 define float @constrained_log_nonan(float nofpclass(nan) %arg) strictfp {
-; CHECK-LABEL: define nofpclass(nzero sub) float @constrained_log_nonan
+; CHECK-LABEL: define nofpclass(snan nzero sub) float @constrained_log_nonan
 ; CHECK-SAME: (float nofpclass(nan) [[ARG:%.*]]) #[[ATTR9]] {
-; CHECK-NEXT:    [[VAL:%.*]] = call nofpclass(nzero sub) float @llvm.experimental.constrained.log.f32(float nofpclass(nan) [[ARG]], metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR11]]
+; CHECK-NEXT:    [[VAL:%.*]] = call nofpclass(snan nzero sub) float @llvm.experimental.constrained.log.f32(float nofpclass(nan) [[ARG]], metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR11]]
 ; CHECK-NEXT:    ret float [[VAL]]
 ;
   %val = call float @llvm.experimental.constrained.log.f32(float %arg, metadata !"round.dynamic", metadata !"fpexcept.strict")
@@ -346,9 +346,9 @@ define float @ret_log2_noinf_noneg_noqnan(float nofpclass(inf nsub nnorm qnan) %
 }
 
 define float @ret_log2_noinf_noneg_nosnan(float nofpclass(inf nsub nnorm snan) %arg) #0 {
-; CHECK-LABEL: define nofpclass(pinf nzero sub) float @ret_log2_noinf_noneg_nosnan
+; CHECK-LABEL: define nofpclass(snan pinf nzero sub) float @ret_log2_noinf_noneg_nosnan
 ; CHECK-SAME: (float nofpclass(snan inf nsub nnorm) [[ARG:%.*]]) #[[ATTR2]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(pinf nzero sub) float @llvm.log2.f32(float nofpclass(snan inf nsub nnorm) [[ARG]]) #[[ATTR10]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(snan pinf nzero sub) float @llvm.log2.f32(float nofpclass(snan inf nsub nnorm) [[ARG]]) #[[ATTR10]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.log2.f32(float %arg)

diff  --git a/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp b/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp
index d1b817934a0fd..8ff84820276d5 100644
--- a/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp
+++ b/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp
@@ -874,7 +874,8 @@ TEST_F(AArch64GISelMITest, TestFPClassFLogNeg) {
 
   KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
 
-  EXPECT_EQ(fcNan | fcNegInf | fcPosZero | fcNormal, Known.getKnownFPClasses());
+  EXPECT_EQ(fcQNan | fcNegInf | fcPosZero | fcNormal,
+            Known.getKnownFPClasses());
   EXPECT_EQ(std::nullopt, Known.getSignBit());
 }
 


        


More information about the llvm-commits mailing list