[llvm-branch-commits] [llvm] ValueTracking: Improve handling of exp intrinsic for overflow (PR #173430)

Matt Arsenault via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Mon Dec 29 02:09:08 PST 2025


https://github.com/arsenm updated https://github.com/llvm/llvm-project/pull/173430

>From 1887d0252e0fd48a8aed6ba1fa201389ff44d10c Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Sat, 20 Dec 2025 23:55:32 +0100
Subject: [PATCH 1/4] ValueTracking: Improve handling of exp intrinsic for
 overflow

Teach exp handling that positive inputs cannot introduce overflow,
and negative inputs cannot introduce underflow.
---
 llvm/lib/Analysis/ValueTracking.cpp           | 16 +++++++
 .../Attributor/AMDGPU/nofpclass-amdgcn-exp.ll |  4 +-
 .../Transforms/Attributor/nofpclass-exp.ll    | 48 +++++++++----------
 3 files changed, 42 insertions(+), 26 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 29301ad090902..520df9e6bb519 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5361,6 +5361,22 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
         Known.signBitMustBeZero();
       }
 
+      if (KnownSrc.cannotBeOrderedLessThanZero()) {
+        // If the source is positive, and cannot be ~0, this cannot underflow.
+        Known.knownNot(fcPosZero);
+
+        // Cannot introduce new denormal values.
+        if (KnownSrc.isKnownNever(fcPosSubnormal))
+          Known.knownNot(fcPosSubnormal);
+      }
+
+      if (KnownSrc.cannotBeOrderedGreaterThanZero()) {
+        // If the source is negative, and cannot be infinity, this cannot
+        // overflow to infinity.
+        if (KnownSrc.isKnownNeverPosInfinity())
+          Known.knownNot(fcPosInf);
+      }
+
       break;
     }
     case Intrinsic::fptrunc_round: {
diff --git a/llvm/test/Transforms/Attributor/AMDGPU/nofpclass-amdgcn-exp.ll b/llvm/test/Transforms/Attributor/AMDGPU/nofpclass-amdgcn-exp.ll
index e7c41e9be7e33..5ba9d74c6386d 100644
--- a/llvm/test/Transforms/Attributor/AMDGPU/nofpclass-amdgcn-exp.ll
+++ b/llvm/test/Transforms/Attributor/AMDGPU/nofpclass-amdgcn-exp.ll
@@ -104,10 +104,10 @@ define float @ret_exp_noinf_nonegzero(float nofpclass(inf nzero) %arg0) {
 }
 
 define float @ret_exp_positive_source(i32 %arg) {
-; CHECK-LABEL: define nofpclass(nan ninf nzero sub nnorm) float @ret_exp_positive_source(
+; CHECK-LABEL: define nofpclass(nan ninf zero sub nnorm) float @ret_exp_positive_source(
 ; CHECK-SAME: i32 [[ARG:%.*]]) #[[ATTR1]] {
 ; CHECK-NEXT:    [[UITOFP:%.*]] = uitofp i32 [[ARG]] to float
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nan ninf nzero sub nnorm) float @llvm.amdgcn.exp2.f32(float [[UITOFP]]) #[[ATTR2]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nan ninf zero sub nnorm) float @llvm.amdgcn.exp2.f32(float [[UITOFP]]) #[[ATTR2]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %uitofp = uitofp i32 %arg to float
diff --git a/llvm/test/Transforms/Attributor/nofpclass-exp.ll b/llvm/test/Transforms/Attributor/nofpclass-exp.ll
index ea5c26d101186..941e1d3981af5 100644
--- a/llvm/test/Transforms/Attributor/nofpclass-exp.ll
+++ b/llvm/test/Transforms/Attributor/nofpclass-exp.ll
@@ -96,10 +96,10 @@ define float @ret_exp_noinf_nonegzero(float nofpclass(inf nzero) %arg0) {
 }
 
 define float @ret_exp_positive_source(i32 %arg) {
-; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @ret_exp_positive_source
+; CHECK-LABEL: define nofpclass(nan ninf zero sub nnorm) float @ret_exp_positive_source
 ; CHECK-SAME: (i32 [[ARG:%.*]]) #[[ATTR1]] {
 ; CHECK-NEXT:    [[UITOFP:%.*]] = uitofp i32 [[ARG]] to float
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nan ninf nzero nsub nnorm) float @llvm.exp.f32(float [[UITOFP]]) #[[ATTR2]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nan ninf zero sub nnorm) float @llvm.exp.f32(float [[UITOFP]]) #[[ATTR2]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %uitofp = uitofp i32 %arg to float
@@ -211,10 +211,10 @@ define float @ret_exp2_noinf_nonegzero(float nofpclass(inf nzero) %arg0) {
 }
 
 define float @ret_exp2_positive_source(i32 %arg) {
-; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @ret_exp2_positive_source
+; CHECK-LABEL: define nofpclass(nan ninf zero sub nnorm) float @ret_exp2_positive_source
 ; CHECK-SAME: (i32 [[ARG:%.*]]) #[[ATTR1]] {
 ; CHECK-NEXT:    [[UITOFP:%.*]] = uitofp i32 [[ARG]] to float
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nan ninf nzero nsub nnorm) float @llvm.exp2.f32(float [[UITOFP]]) #[[ATTR2]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nan ninf zero sub nnorm) float @llvm.exp2.f32(float [[UITOFP]]) #[[ATTR2]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %uitofp = uitofp i32 %arg to float
@@ -326,10 +326,10 @@ define float @ret_exp10_noinf_nonegzero(float nofpclass(inf nzero) %arg0) {
 }
 
 define float @ret_exp10_positive_source(i32 %arg) {
-; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @ret_exp10_positive_source
+; CHECK-LABEL: define nofpclass(nan ninf zero sub nnorm) float @ret_exp10_positive_source
 ; CHECK-SAME: (i32 [[ARG:%.*]]) #[[ATTR1]] {
 ; CHECK-NEXT:    [[UITOFP:%.*]] = uitofp i32 [[ARG]] to float
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nan ninf nzero nsub nnorm) float @llvm.exp10.f32(float [[UITOFP]]) #[[ATTR2]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(nan ninf zero sub nnorm) float @llvm.exp10.f32(float [[UITOFP]]) #[[ATTR2]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %uitofp = uitofp i32 %arg to float
@@ -352,9 +352,9 @@ define float @ret_exp10_unknown_sign(float nofpclass(nan) %arg0, float nofpclass
 
 ; Can infer this doesn't return any inf
 define float @ret_exp_src_known_negative_or_zero_or_nan(float nofpclass(pinf psub pnorm) %arg0) {
-; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_exp_src_known_negative_or_zero_or_nan
+; CHECK-LABEL: define nofpclass(inf nzero nsub nnorm) float @ret_exp_src_known_negative_or_zero_or_nan
 ; CHECK-SAME: (float nofpclass(pinf psub pnorm) [[ARG0:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.exp.f32(float nofpclass(pinf psub pnorm) [[ARG0]]) #[[ATTR2]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(inf nzero nsub nnorm) float @llvm.exp.f32(float nofpclass(pinf psub pnorm) [[ARG0]]) #[[ATTR2]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.exp.f32(float %arg0)
@@ -363,9 +363,9 @@ define float @ret_exp_src_known_negative_or_zero_or_nan(float nofpclass(pinf psu
 
 ; Can infer this doesn't return any inf
 define float @ret_exp_src_known_negative_nonzero_or_nan(float nofpclass(pinf psub pnorm zero) %arg0) {
-; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_exp_src_known_negative_nonzero_or_nan
+; CHECK-LABEL: define nofpclass(inf nzero nsub nnorm) float @ret_exp_src_known_negative_nonzero_or_nan
 ; CHECK-SAME: (float nofpclass(pinf zero psub pnorm) [[ARG0:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.exp.f32(float nofpclass(pinf zero psub pnorm) [[ARG0]]) #[[ATTR2]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(inf nzero nsub nnorm) float @llvm.exp.f32(float nofpclass(pinf zero psub pnorm) [[ARG0]]) #[[ATTR2]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.exp.f32(float %arg0)
@@ -373,9 +373,9 @@ define float @ret_exp_src_known_negative_nonzero_or_nan(float nofpclass(pinf psu
 }
 
 define float @ret_exp_src_known_positive_or_zero_or_nan(float nofpclass(ninf nsub nnorm) %arg0) {
-; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_exp_src_known_positive_or_zero_or_nan
+; CHECK-LABEL: define nofpclass(ninf zero nsub nnorm) float @ret_exp_src_known_positive_or_zero_or_nan
 ; CHECK-SAME: (float nofpclass(ninf nsub nnorm) [[ARG0:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.exp.f32(float nofpclass(ninf nsub nnorm) [[ARG0]]) #[[ATTR2]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf zero nsub nnorm) float @llvm.exp.f32(float nofpclass(ninf nsub nnorm) [[ARG0]]) #[[ATTR2]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.exp.f32(float %arg0)
@@ -383,9 +383,9 @@ define float @ret_exp_src_known_positive_or_zero_or_nan(float nofpclass(ninf nsu
 }
 
 define float @ret_exp_src_known_positive_non0_or_nan(float nofpclass(ninf nsub nnorm zero) %arg0) {
-; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_exp_src_known_positive_non0_or_nan
+; CHECK-LABEL: define nofpclass(ninf zero nsub nnorm) float @ret_exp_src_known_positive_non0_or_nan
 ; CHECK-SAME: (float nofpclass(ninf zero nsub nnorm) [[ARG0:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.exp.f32(float nofpclass(ninf zero nsub nnorm) [[ARG0]]) #[[ATTR2]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf zero nsub nnorm) float @llvm.exp.f32(float nofpclass(ninf zero nsub nnorm) [[ARG0]]) #[[ATTR2]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.exp.f32(float %arg0)
@@ -394,9 +394,9 @@ define float @ret_exp_src_known_positive_non0_or_nan(float nofpclass(ninf nsub n
 
 ; Can't underflow to 0, can't be denormal.
 define float @ret_exp_src_known_positive_non0_nonsub_or_nan(float nofpclass(ninf sub nnorm zero) %arg0) {
-; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_exp_src_known_positive_non0_nonsub_or_nan
+; CHECK-LABEL: define nofpclass(ninf zero sub nnorm) float @ret_exp_src_known_positive_non0_nonsub_or_nan
 ; CHECK-SAME: (float nofpclass(ninf zero sub nnorm) [[ARG0:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.exp.f32(float nofpclass(ninf zero sub nnorm) [[ARG0]]) #[[ATTR2]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf zero sub nnorm) float @llvm.exp.f32(float nofpclass(ninf zero sub nnorm) [[ARG0]]) #[[ATTR2]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.exp.f32(float %arg0)
@@ -405,9 +405,9 @@ define float @ret_exp_src_known_positive_non0_nonsub_or_nan(float nofpclass(ninf
 
 ; Can't underflow to denormal, but can have an input denormal stay denormal.
 define float @ret_exp_src_known_positive_or_nan(float nofpclass(ninf nsub nnorm) %arg0) {
-; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_exp_src_known_positive_or_nan
+; CHECK-LABEL: define nofpclass(ninf zero nsub nnorm) float @ret_exp_src_known_positive_or_nan
 ; CHECK-SAME: (float nofpclass(ninf nsub nnorm) [[ARG0:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.exp.f32(float nofpclass(ninf nsub nnorm) [[ARG0]]) #[[ATTR2]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf zero nsub nnorm) float @llvm.exp.f32(float nofpclass(ninf nsub nnorm) [[ARG0]]) #[[ATTR2]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.exp.f32(float %arg0)
@@ -415,9 +415,9 @@ define float @ret_exp_src_known_positive_or_nan(float nofpclass(ninf nsub nnorm)
 }
 
 define float @ret_exp_src_known_positive_nonsub_or_nan(float nofpclass(ninf sub nnorm) %arg0) {
-; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_exp_src_known_positive_nonsub_or_nan
+; CHECK-LABEL: define nofpclass(ninf zero sub nnorm) float @ret_exp_src_known_positive_nonsub_or_nan
 ; CHECK-SAME: (float nofpclass(ninf sub nnorm) [[ARG0:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.exp.f32(float nofpclass(ninf sub nnorm) [[ARG0]]) #[[ATTR2]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf zero sub nnorm) float @llvm.exp.f32(float nofpclass(ninf sub nnorm) [[ARG0]]) #[[ATTR2]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.exp.f32(float %arg0)
@@ -425,10 +425,10 @@ define float @ret_exp_src_known_positive_nonsub_or_nan(float nofpclass(ninf sub
 }
 
 define float @ret_exp_fabs(float %arg) {
-; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_exp_fabs
+; CHECK-LABEL: define nofpclass(ninf zero nsub nnorm) float @ret_exp_fabs
 ; CHECK-SAME: (float [[ARG:%.*]]) #[[ATTR1]] {
 ; CHECK-NEXT:    [[ARG_FABS:%.*]] = call float @llvm.fabs.f32(float [[ARG]]) #[[ATTR2]]
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.exp.f32(float [[ARG_FABS]]) #[[ATTR2]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf zero nsub nnorm) float @llvm.exp.f32(float [[ARG_FABS]]) #[[ATTR2]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %arg.fabs = call float @llvm.fabs.f32(float %arg)
@@ -437,11 +437,11 @@ define float @ret_exp_fabs(float %arg) {
 }
 
 define float @ret_exp_fneg_fabs(float %arg) {
-; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_exp_fneg_fabs
+; CHECK-LABEL: define nofpclass(inf nzero nsub nnorm) float @ret_exp_fneg_fabs
 ; CHECK-SAME: (float [[ARG:%.*]]) #[[ATTR1]] {
 ; CHECK-NEXT:    [[ARG_FABS:%.*]] = call float @llvm.fabs.f32(float [[ARG]]) #[[ATTR2]]
 ; CHECK-NEXT:    [[ARG_NEG_FABS:%.*]] = fneg float [[ARG_FABS]]
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf nzero nsub nnorm) float @llvm.exp.f32(float [[ARG_NEG_FABS]]) #[[ATTR2]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(inf nzero nsub nnorm) float @llvm.exp.f32(float [[ARG_NEG_FABS]]) #[[ATTR2]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %arg.fabs = call float @llvm.fabs.f32(float %arg)

>From 2d3766aef0fe49beafaf5f3e885f7af7d30f4aac Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Wed, 24 Dec 2025 21:30:04 +0100
Subject: [PATCH 2/4] positive values never denormal

---
 llvm/lib/Analysis/ValueTracking.cpp              |  5 ++---
 llvm/test/Transforms/Attributor/nofpclass-exp.ll | 16 ++++++++--------
 2 files changed, 10 insertions(+), 11 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 520df9e6bb519..158dd5fc81eae 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5365,9 +5365,8 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
         // If the source is positive, and cannot be ~0, this cannot underflow.
         Known.knownNot(fcPosZero);
 
-        // Cannot introduce new denormal values.
-        if (KnownSrc.isKnownNever(fcPosSubnormal))
-          Known.knownNot(fcPosSubnormal);
+        // Cannot introduce denormal values.
+        Known.knownNot(fcPosSubnormal);
       }
 
       if (KnownSrc.cannotBeOrderedGreaterThanZero()) {
diff --git a/llvm/test/Transforms/Attributor/nofpclass-exp.ll b/llvm/test/Transforms/Attributor/nofpclass-exp.ll
index 941e1d3981af5..670e5bce06788 100644
--- a/llvm/test/Transforms/Attributor/nofpclass-exp.ll
+++ b/llvm/test/Transforms/Attributor/nofpclass-exp.ll
@@ -373,9 +373,9 @@ define float @ret_exp_src_known_negative_nonzero_or_nan(float nofpclass(pinf psu
 }
 
 define float @ret_exp_src_known_positive_or_zero_or_nan(float nofpclass(ninf nsub nnorm) %arg0) {
-; CHECK-LABEL: define nofpclass(ninf zero nsub nnorm) float @ret_exp_src_known_positive_or_zero_or_nan
+; CHECK-LABEL: define nofpclass(ninf zero sub nnorm) float @ret_exp_src_known_positive_or_zero_or_nan
 ; CHECK-SAME: (float nofpclass(ninf nsub nnorm) [[ARG0:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf zero nsub nnorm) float @llvm.exp.f32(float nofpclass(ninf nsub nnorm) [[ARG0]]) #[[ATTR2]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf zero sub nnorm) float @llvm.exp.f32(float nofpclass(ninf nsub nnorm) [[ARG0]]) #[[ATTR2]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.exp.f32(float %arg0)
@@ -383,9 +383,9 @@ define float @ret_exp_src_known_positive_or_zero_or_nan(float nofpclass(ninf nsu
 }
 
 define float @ret_exp_src_known_positive_non0_or_nan(float nofpclass(ninf nsub nnorm zero) %arg0) {
-; CHECK-LABEL: define nofpclass(ninf zero nsub nnorm) float @ret_exp_src_known_positive_non0_or_nan
+; CHECK-LABEL: define nofpclass(ninf zero sub nnorm) float @ret_exp_src_known_positive_non0_or_nan
 ; CHECK-SAME: (float nofpclass(ninf zero nsub nnorm) [[ARG0:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf zero nsub nnorm) float @llvm.exp.f32(float nofpclass(ninf zero nsub nnorm) [[ARG0]]) #[[ATTR2]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf zero sub nnorm) float @llvm.exp.f32(float nofpclass(ninf zero nsub nnorm) [[ARG0]]) #[[ATTR2]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.exp.f32(float %arg0)
@@ -405,9 +405,9 @@ define float @ret_exp_src_known_positive_non0_nonsub_or_nan(float nofpclass(ninf
 
 ; Can't underflow to denormal, but can have an input denormal stay denormal.
 define float @ret_exp_src_known_positive_or_nan(float nofpclass(ninf nsub nnorm) %arg0) {
-; CHECK-LABEL: define nofpclass(ninf zero nsub nnorm) float @ret_exp_src_known_positive_or_nan
+; CHECK-LABEL: define nofpclass(ninf zero sub nnorm) float @ret_exp_src_known_positive_or_nan
 ; CHECK-SAME: (float nofpclass(ninf nsub nnorm) [[ARG0:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf zero nsub nnorm) float @llvm.exp.f32(float nofpclass(ninf nsub nnorm) [[ARG0]]) #[[ATTR2]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf zero sub nnorm) float @llvm.exp.f32(float nofpclass(ninf nsub nnorm) [[ARG0]]) #[[ATTR2]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %call = call float @llvm.exp.f32(float %arg0)
@@ -425,10 +425,10 @@ define float @ret_exp_src_known_positive_nonsub_or_nan(float nofpclass(ninf sub
 }
 
 define float @ret_exp_fabs(float %arg) {
-; CHECK-LABEL: define nofpclass(ninf zero nsub nnorm) float @ret_exp_fabs
+; CHECK-LABEL: define nofpclass(ninf zero sub nnorm) float @ret_exp_fabs
 ; CHECK-SAME: (float [[ARG:%.*]]) #[[ATTR1]] {
 ; CHECK-NEXT:    [[ARG_FABS:%.*]] = call float @llvm.fabs.f32(float [[ARG]]) #[[ATTR2]]
-; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf zero nsub nnorm) float @llvm.exp.f32(float [[ARG_FABS]]) #[[ATTR2]]
+; CHECK-NEXT:    [[CALL:%.*]] = call nofpclass(ninf zero sub nnorm) float @llvm.exp.f32(float [[ARG_FABS]]) #[[ATTR2]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ;
   %arg.fabs = call float @llvm.fabs.f32(float %arg)

>From bdaddf40fc66c65de27b541c81fc9404d08c3b64 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Wed, 24 Dec 2025 21:30:58 +0100
Subject: [PATCH 3/4] Remove redundant check

---
 llvm/lib/Analysis/ValueTracking.cpp | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 158dd5fc81eae..d674aca59848e 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5369,12 +5369,9 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
         Known.knownNot(fcPosSubnormal);
       }
 
-      if (KnownSrc.cannotBeOrderedGreaterThanZero()) {
-        // If the source is negative, and cannot be infinity, this cannot
-        // overflow to infinity.
-        if (KnownSrc.isKnownNeverPosInfinity())
-          Known.knownNot(fcPosInf);
-      }
+      // If the source is negative, this cannot overflow to infinity.
+      if (KnownSrc.cannotBeOrderedGreaterThanZero())
+        Known.knownNot(fcPosInf);
 
       break;
     }

>From 650471cce2c041ae63eb42b207ef3f4a2c414ca4 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Thu, 25 Dec 2025 17:53:52 +0100
Subject: [PATCH 4/4] Adjust comment

---
 llvm/lib/Analysis/ValueTracking.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index d674aca59848e..ec7fe89848d41 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5362,7 +5362,7 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
       }
 
       if (KnownSrc.cannotBeOrderedLessThanZero()) {
-        // If the source is positive, and cannot be ~0, this cannot underflow.
+        // If the source is positive this cannot underflow.
         Known.knownNot(fcPosZero);
 
         // Cannot introduce denormal values.



More information about the llvm-branch-commits mailing list