Skip to content

ValueTracking: Add baseline tests for computeKnownFPClass exp#173429

Merged
arsenm merged 5 commits intomainfrom
users/arsenm/valuetracking/add-tests-computeknownfpclass-exp-positive-negative
Dec 29, 2025
Merged

ValueTracking: Add baseline tests for computeKnownFPClass exp#173429
arsenm merged 5 commits intomainfrom
users/arsenm/valuetracking/add-tests-computeknownfpclass-exp-positive-negative

Conversation

@arsenm
Copy link
Contributor

@arsenm arsenm commented Dec 24, 2025

This is already handled, but misses opportunities. Test cases
where the input is known positive or negative.

@arsenm arsenm added floating-point Floating-point math llvm:analysis Includes value tracking, cost tables and constant folding llvm:instcombine Covers the InstCombine, InstSimplify and AggressiveInstCombine passes llvm:support llvm:transforms labels Dec 24, 2025 — with Graphite App
@llvmbot
Copy link
Member

llvmbot commented Dec 24, 2025

@llvm/pr-subscribers-llvm-transforms

@llvm/pr-subscribers-llvm-analysis

Author: Matt Arsenault (arsenm)

Changes

This is already handled, but misses opportunities. Test cases
where the input is known positive or negative.


Full diff: https://github.com/llvm/llvm-project/pull/173429.diff

1 Files Affected:

  • (modified) llvm/test/Transforms/Attributor/nofpclass-exp.ll (+101)
diff --git a/llvm/test/Transforms/Attributor/nofpclass-exp.ll b/llvm/test/Transforms/Attributor/nofpclass-exp.ll
index 490d3da5505eb..ea5c26d101186 100644
--- a/llvm/test/Transforms/Attributor/nofpclass-exp.ll
+++ b/llvm/test/Transforms/Attributor/nofpclass-exp.ll
@@ -349,5 +349,106 @@ define float @ret_exp10_unknown_sign(float nofpclass(nan) %arg0, float nofpclass
   %call = call float @llvm.exp10.f32(float %unknown.sign.not.nan)
   ret float %call
 }
+
+; 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-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:    ret float [[CALL]]
+;
+  %call = call float @llvm.exp.f32(float %arg0)
+  ret float %call
+}
+
+; 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-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:    ret float [[CALL]]
+;
+  %call = call float @llvm.exp.f32(float %arg0)
+  ret float %call
+}
+
+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-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:    ret float [[CALL]]
+;
+  %call = call float @llvm.exp.f32(float %arg0)
+  ret float %call
+}
+
+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-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:    ret float [[CALL]]
+;
+  %call = call float @llvm.exp.f32(float %arg0)
+  ret float %call
+}
+
+; 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-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:    ret float [[CALL]]
+;
+  %call = call float @llvm.exp.f32(float %arg0)
+  ret float %call
+}
+
+; 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-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:    ret float [[CALL]]
+;
+  %call = call float @llvm.exp.f32(float %arg0)
+  ret float %call
+}
+
+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-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:    ret float [[CALL]]
+;
+  %call = call float @llvm.exp.f32(float %arg0)
+  ret float %call
+}
+
+define float @ret_exp_fabs(float %arg) {
+; CHECK-LABEL: define nofpclass(ninf nzero 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:    ret float [[CALL]]
+;
+  %arg.fabs = call float @llvm.fabs.f32(float %arg)
+  %call = call float @llvm.exp.f32(float %arg.fabs)
+  ret float %call
+}
+
+define float @ret_exp_fneg_fabs(float %arg) {
+; CHECK-LABEL: define nofpclass(ninf 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:    ret float [[CALL]]
+;
+  %arg.fabs = call float @llvm.fabs.f32(float %arg)
+  %arg.neg.fabs = fneg float %arg.fabs
+  %call = call float @llvm.exp.f32(float %arg.neg.fabs)
+  ret float %call
+}
+
 ;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
 ; TUNIT: {{.*}}

@llvmbot
Copy link
Member

llvmbot commented Dec 24, 2025

@llvm/pr-subscribers-llvm-support

Author: Matt Arsenault (arsenm)

Changes

This is already handled, but misses opportunities. Test cases
where the input is known positive or negative.


Full diff: https://github.com/llvm/llvm-project/pull/173429.diff

1 Files Affected:

  • (modified) llvm/test/Transforms/Attributor/nofpclass-exp.ll (+101)
diff --git a/llvm/test/Transforms/Attributor/nofpclass-exp.ll b/llvm/test/Transforms/Attributor/nofpclass-exp.ll
index 490d3da5505eb..ea5c26d101186 100644
--- a/llvm/test/Transforms/Attributor/nofpclass-exp.ll
+++ b/llvm/test/Transforms/Attributor/nofpclass-exp.ll
@@ -349,5 +349,106 @@ define float @ret_exp10_unknown_sign(float nofpclass(nan) %arg0, float nofpclass
   %call = call float @llvm.exp10.f32(float %unknown.sign.not.nan)
   ret float %call
 }
+
+; 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-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:    ret float [[CALL]]
+;
+  %call = call float @llvm.exp.f32(float %arg0)
+  ret float %call
+}
+
+; 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-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:    ret float [[CALL]]
+;
+  %call = call float @llvm.exp.f32(float %arg0)
+  ret float %call
+}
+
+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-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:    ret float [[CALL]]
+;
+  %call = call float @llvm.exp.f32(float %arg0)
+  ret float %call
+}
+
+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-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:    ret float [[CALL]]
+;
+  %call = call float @llvm.exp.f32(float %arg0)
+  ret float %call
+}
+
+; 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-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:    ret float [[CALL]]
+;
+  %call = call float @llvm.exp.f32(float %arg0)
+  ret float %call
+}
+
+; 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-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:    ret float [[CALL]]
+;
+  %call = call float @llvm.exp.f32(float %arg0)
+  ret float %call
+}
+
+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-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:    ret float [[CALL]]
+;
+  %call = call float @llvm.exp.f32(float %arg0)
+  ret float %call
+}
+
+define float @ret_exp_fabs(float %arg) {
+; CHECK-LABEL: define nofpclass(ninf nzero 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:    ret float [[CALL]]
+;
+  %arg.fabs = call float @llvm.fabs.f32(float %arg)
+  %call = call float @llvm.exp.f32(float %arg.fabs)
+  ret float %call
+}
+
+define float @ret_exp_fneg_fabs(float %arg) {
+; CHECK-LABEL: define nofpclass(ninf 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:    ret float [[CALL]]
+;
+  %arg.fabs = call float @llvm.fabs.f32(float %arg)
+  %arg.neg.fabs = fneg float %arg.fabs
+  %call = call float @llvm.exp.f32(float %arg.neg.fabs)
+  ret float %call
+}
+
 ;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
 ; TUNIT: {{.*}}

@arsenm arsenm force-pushed the users/arsenm/valuetracking/add-tests-computeknownfpclass-exp-positive-negative branch from d8af1dc to 9632f32 Compare December 24, 2025 10:15
@arsenm arsenm force-pushed the users/arsenm/instcombine/implement-simplifydemandedfpclass-canonicalize branch from 24bbda9 to 22bfe52 Compare December 24, 2025 10:15
@arsenm arsenm force-pushed the users/arsenm/valuetracking/add-tests-computeknownfpclass-exp-positive-negative branch from 9632f32 to bb978d6 Compare December 24, 2025 21:48
@arsenm arsenm force-pushed the users/arsenm/instcombine/implement-simplifydemandedfpclass-canonicalize branch from 22bfe52 to 3c70f79 Compare December 24, 2025 21:48
Doesn't try to handle PositiveZero flushing mode, but I
don't believe it is incorrect with it.
This is already handled, but misses opportunities. Test cases
where the input is known positive or negative.
@arsenm arsenm force-pushed the users/arsenm/instcombine/implement-simplifydemandedfpclass-canonicalize branch from 3c70f79 to 37bd647 Compare December 29, 2025 10:08
@arsenm arsenm force-pushed the users/arsenm/valuetracking/add-tests-computeknownfpclass-exp-positive-negative branch from bb978d6 to 50298d2 Compare December 29, 2025 10:08
Base automatically changed from users/arsenm/instcombine/implement-simplifydemandedfpclass-canonicalize to main December 29, 2025 13:32
@arsenm arsenm merged commit 92e0cd2 into main Dec 29, 2025
13 of 17 checks passed
@arsenm arsenm deleted the users/arsenm/valuetracking/add-tests-computeknownfpclass-exp-positive-negative branch December 29, 2025 13:45
mahesh-attarde pushed a commit to mahesh-attarde/llvm-project that referenced this pull request Jan 6, 2026
…73429)

This is already handled, but misses opportunities. Test cases
where the input is known positive or negative.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

floating-point Floating-point math llvm:analysis Includes value tracking, cost tables and constant folding llvm:instcombine Covers the InstCombine, InstSimplify and AggressiveInstCombine passes llvm:support llvm:transforms

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants