Skip to content

[ConstantFolding] Add support for llvm.atan in constant folding. #143416

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 9, 2025

Conversation

topperc
Copy link
Collaborator

@topperc topperc commented Jun 9, 2025

Fixes #143360

@llvmbot
Copy link
Member

llvmbot commented Jun 9, 2025

@llvm/pr-subscribers-llvm-transforms

Author: Craig Topper (topperc)

Changes

Fixes #143360


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

2 Files Affected:

  • (modified) llvm/lib/Analysis/ConstantFolding.cpp (+3)
  • (added) llvm/test/Transforms/InstSimplify/ConstProp/atan-intrinsic.ll (+88)
diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp
index 7dd7f413783c9..23ea6966fbf6c 100644
--- a/llvm/lib/Analysis/ConstantFolding.cpp
+++ b/llvm/lib/Analysis/ConstantFolding.cpp
@@ -1672,6 +1672,7 @@ bool llvm::canConstantFoldCallTo(const CallBase *Call, const Function *F) {
   case Intrinsic::sincos:
   case Intrinsic::sinh:
   case Intrinsic::cosh:
+  case Intrinsic::atan:
   case Intrinsic::pow:
   case Intrinsic::powi:
   case Intrinsic::ldexp:
@@ -2538,6 +2539,8 @@ static Constant *ConstantFoldScalarCall1(StringRef Name,
         return ConstantFoldFP(sinh, APF, Ty);
       case Intrinsic::cosh:
         return ConstantFoldFP(cosh, APF, Ty);
+      case Intrinsic::atan:
+        return ConstantFoldFP(atan, APF, Ty);
       case Intrinsic::sqrt:
         return ConstantFoldFP(sqrt, APF, Ty);
       case Intrinsic::amdgcn_cos:
diff --git a/llvm/test/Transforms/InstSimplify/ConstProp/atan-intrinsic.ll b/llvm/test/Transforms/InstSimplify/ConstProp/atan-intrinsic.ll
new file mode 100644
index 0000000000000..d824d6d35643d
--- /dev/null
+++ b/llvm/test/Transforms/InstSimplify/ConstProp/atan-intrinsic.ll
@@ -0,0 +1,88 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -S -passes=instsimplify < %s | FileCheck %s
+
+define double @test_atan_0() {
+; CHECK-LABEL: define double @test_atan_0() {
+; CHECK-NEXT:    ret double 0.000000e+00
+;
+  %result = call double @llvm.atan.f64(double 0.0)
+  ret double %result
+}
+
+define double @test_atan_one() {
+; CHECK-LABEL: define double @test_atan_one() {
+; CHECK-NEXT:    ret double 0x3FE921FB54442D18
+;
+  %res = call double @llvm.atan.f64(double 1.0)
+  ret double %res
+}
+
+define <2 x double> @test_atan_v2() {
+; CHECK-LABEL: define <2 x double> @test_atan_v2() {
+; CHECK-NEXT:    ret <2 x double> zeroinitializer
+;
+  %result = call <2 x double> @llvm.atan.v2f64(<2 x double> zeroinitializer)
+  ret <2 x double> %result
+}
+
+define double @test_atan_neg0() {
+; CHECK-LABEL: define double @test_atan_neg0() {
+; CHECK-NEXT:    ret double -0.000000e+00
+;
+  %res = call double @llvm.atan.f64(double -0.0)
+  ret double %res
+}
+
+define double @test_atan_poison() {
+; CHECK-LABEL: define double @test_atan_poison() {
+; CHECK-NEXT:    [[RES:%.*]] = call double @llvm.atan.f64(double poison)
+; CHECK-NEXT:    ret double [[RES]]
+;
+  %res = call double @llvm.atan.f64(double poison)
+  ret double %res
+}
+
+define double @test_atan_undef() {
+; CHECK-LABEL: define double @test_atan_undef() {
+; CHECK-NEXT:    [[RES:%.*]] = call double @llvm.atan.f64(double undef)
+; CHECK-NEXT:    ret double [[RES]]
+;
+  %res = call double @llvm.atan.f64(double undef)
+  ret double %res
+}
+
+define double @test_atan_snan() {
+; CHECK-LABEL: define double @test_atan_snan() {
+; CHECK-NEXT:    [[RES:%.*]] = call double @llvm.atan.f64(double 0x7FF0000000000001)
+; CHECK-NEXT:    ret double [[RES]]
+;
+  %res = call double @llvm.atan.f64(double 0x7ff0000000000001)
+  ret double %res
+}
+
+define double @test_atan_qnan() {
+; CHECK-LABEL: define double @test_atan_qnan() {
+; CHECK-NEXT:    [[RES:%.*]] = call double @llvm.atan.f64(double 0x7FF8000000000000)
+; CHECK-NEXT:    ret double [[RES]]
+;
+  %res = call double @llvm.atan.f64(double 0x7ff8000000000000)
+  ret double %res
+}
+
+define double @test_atan_pos_inf() {
+; CHECK-LABEL: define double @test_atan_pos_inf() {
+; CHECK-NEXT:    [[RES:%.*]] = call double @llvm.atan.f64(double 0x7FF0000000000000)
+; CHECK-NEXT:    ret double [[RES]]
+;
+  %res = call double @llvm.atan.f64(double 0x7ff0000000000000)
+  ret double %res
+}
+
+define double @test_atan_neg_inf() {
+; CHECK-LABEL: define double @test_atan_neg_inf() {
+; CHECK-NEXT:    [[RES:%.*]] = call double @llvm.atan.f64(double 0xFFF0000000000000)
+; CHECK-NEXT:    ret double [[RES]]
+;
+  %res = call double @llvm.atan.f64(double 0xfff0000000000000)
+  ret double %res
+}

@llvmbot
Copy link
Member

llvmbot commented Jun 9, 2025

@llvm/pr-subscribers-llvm-analysis

Author: Craig Topper (topperc)

Changes

Fixes #143360


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

2 Files Affected:

  • (modified) llvm/lib/Analysis/ConstantFolding.cpp (+3)
  • (added) llvm/test/Transforms/InstSimplify/ConstProp/atan-intrinsic.ll (+88)
diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp
index 7dd7f413783c9..23ea6966fbf6c 100644
--- a/llvm/lib/Analysis/ConstantFolding.cpp
+++ b/llvm/lib/Analysis/ConstantFolding.cpp
@@ -1672,6 +1672,7 @@ bool llvm::canConstantFoldCallTo(const CallBase *Call, const Function *F) {
   case Intrinsic::sincos:
   case Intrinsic::sinh:
   case Intrinsic::cosh:
+  case Intrinsic::atan:
   case Intrinsic::pow:
   case Intrinsic::powi:
   case Intrinsic::ldexp:
@@ -2538,6 +2539,8 @@ static Constant *ConstantFoldScalarCall1(StringRef Name,
         return ConstantFoldFP(sinh, APF, Ty);
       case Intrinsic::cosh:
         return ConstantFoldFP(cosh, APF, Ty);
+      case Intrinsic::atan:
+        return ConstantFoldFP(atan, APF, Ty);
       case Intrinsic::sqrt:
         return ConstantFoldFP(sqrt, APF, Ty);
       case Intrinsic::amdgcn_cos:
diff --git a/llvm/test/Transforms/InstSimplify/ConstProp/atan-intrinsic.ll b/llvm/test/Transforms/InstSimplify/ConstProp/atan-intrinsic.ll
new file mode 100644
index 0000000000000..d824d6d35643d
--- /dev/null
+++ b/llvm/test/Transforms/InstSimplify/ConstProp/atan-intrinsic.ll
@@ -0,0 +1,88 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -S -passes=instsimplify < %s | FileCheck %s
+
+define double @test_atan_0() {
+; CHECK-LABEL: define double @test_atan_0() {
+; CHECK-NEXT:    ret double 0.000000e+00
+;
+  %result = call double @llvm.atan.f64(double 0.0)
+  ret double %result
+}
+
+define double @test_atan_one() {
+; CHECK-LABEL: define double @test_atan_one() {
+; CHECK-NEXT:    ret double 0x3FE921FB54442D18
+;
+  %res = call double @llvm.atan.f64(double 1.0)
+  ret double %res
+}
+
+define <2 x double> @test_atan_v2() {
+; CHECK-LABEL: define <2 x double> @test_atan_v2() {
+; CHECK-NEXT:    ret <2 x double> zeroinitializer
+;
+  %result = call <2 x double> @llvm.atan.v2f64(<2 x double> zeroinitializer)
+  ret <2 x double> %result
+}
+
+define double @test_atan_neg0() {
+; CHECK-LABEL: define double @test_atan_neg0() {
+; CHECK-NEXT:    ret double -0.000000e+00
+;
+  %res = call double @llvm.atan.f64(double -0.0)
+  ret double %res
+}
+
+define double @test_atan_poison() {
+; CHECK-LABEL: define double @test_atan_poison() {
+; CHECK-NEXT:    [[RES:%.*]] = call double @llvm.atan.f64(double poison)
+; CHECK-NEXT:    ret double [[RES]]
+;
+  %res = call double @llvm.atan.f64(double poison)
+  ret double %res
+}
+
+define double @test_atan_undef() {
+; CHECK-LABEL: define double @test_atan_undef() {
+; CHECK-NEXT:    [[RES:%.*]] = call double @llvm.atan.f64(double undef)
+; CHECK-NEXT:    ret double [[RES]]
+;
+  %res = call double @llvm.atan.f64(double undef)
+  ret double %res
+}
+
+define double @test_atan_snan() {
+; CHECK-LABEL: define double @test_atan_snan() {
+; CHECK-NEXT:    [[RES:%.*]] = call double @llvm.atan.f64(double 0x7FF0000000000001)
+; CHECK-NEXT:    ret double [[RES]]
+;
+  %res = call double @llvm.atan.f64(double 0x7ff0000000000001)
+  ret double %res
+}
+
+define double @test_atan_qnan() {
+; CHECK-LABEL: define double @test_atan_qnan() {
+; CHECK-NEXT:    [[RES:%.*]] = call double @llvm.atan.f64(double 0x7FF8000000000000)
+; CHECK-NEXT:    ret double [[RES]]
+;
+  %res = call double @llvm.atan.f64(double 0x7ff8000000000000)
+  ret double %res
+}
+
+define double @test_atan_pos_inf() {
+; CHECK-LABEL: define double @test_atan_pos_inf() {
+; CHECK-NEXT:    [[RES:%.*]] = call double @llvm.atan.f64(double 0x7FF0000000000000)
+; CHECK-NEXT:    ret double [[RES]]
+;
+  %res = call double @llvm.atan.f64(double 0x7ff0000000000000)
+  ret double %res
+}
+
+define double @test_atan_neg_inf() {
+; CHECK-LABEL: define double @test_atan_neg_inf() {
+; CHECK-NEXT:    [[RES:%.*]] = call double @llvm.atan.f64(double 0xFFF0000000000000)
+; CHECK-NEXT:    ret double [[RES]]
+;
+  %res = call double @llvm.atan.f64(double 0xfff0000000000000)
+  ret double %res
+}

Copy link

github-actions bot commented Jun 9, 2025

⚠️ undef deprecator found issues in your code. ⚠️

You can test this locally with the following command:
git diff -U0 --pickaxe-regex -S '([^a-zA-Z0-9#_-]undef[^a-zA-Z0-9_-]|UndefValue::get)' 'HEAD~1' HEAD llvm/test/Transforms/InstSimplify/ConstProp/atan-intrinsic.ll llvm/lib/Analysis/ConstantFolding.cpp

The following files introduce new uses of undef:

  • llvm/test/Transforms/InstSimplify/ConstProp/atan-intrinsic.ll

Undef is now deprecated and should only be used in the rare cases where no replacement is possible. For example, a load of uninitialized memory yields undef. You should use poison values for placeholders instead.

In tests, avoid using undef and having tests that trigger undefined behavior. If you need an operand with some unimportant value, you can add a new argument to the function and use that instead.

For example, this is considered a bad practice:

define void @fn() {
  ...
  br i1 undef, ...
}

Please use the following instead:

define void @fn(i1 %cond) {
  ...
  br i1 %cond, ...
}

Please refer to the Undefined Behavior Manual for more information.

@topperc topperc merged commit 112490f into llvm:main Jun 9, 2025
10 of 11 checks passed
@topperc topperc deleted the pr/atan-constant-folding branch June 9, 2025 19:38
@lei137
Copy link
Contributor

lei137 commented Jun 10, 2025

@nikic The testcase is failing for https://lab.llvm.org/buildbot/#/builders/64/builds/4143

The affected test is:

define double @test_atan_neg0() {
; CHECK-LABEL: define double @test_atan_neg0() {
; CHECK-NEXT:    ret double -0.000000e+00
;
  %res = call double @llvm.atan.f64(double -0.0)
  ret double %res
}

This bot is generating:

define double @test_atan_neg0() {
  ret double 0.000000e+00
}

instead of -0.000000e+00. Not sure if the neg is a must for neg0 here.

@jcranmer-intel
Copy link
Contributor

atan(-0.0) is -0.0 per IEEE 754, so it's a problem if it's being folded to +0.0.

@topperc
Copy link
Collaborator Author

topperc commented Jun 10, 2025

atan(-0.0) is -0.0 per IEEE 754, so it's a problem if it's being folded to +0.0.

I think the constant folding just calls the native libm function linked with the compiler.

@jcranmer-intel
Copy link
Contributor

I think the constant folding just calls the native libm function linked with the compiler.

Which we really shouldn't be doing, I know @andykaylor has filed an issue on that in the past. The sooner we can get llvm-libc hand-in-hand with APFloat integration, the better.

@andykaylor
Copy link
Contributor

I think the constant folding just calls the native libm function linked with the compiler.

Which we really shouldn't be doing, I know @andykaylor has filed an issue on that in the past. The sooner we can get llvm-libc hand-in-hand with APFloat integration, the better.

The issue I had (and I seem to be in the minority in caring about this) is that when we constant fold a transcendental function by calling the libm function, we run the risk of getting a different answer than we would have gotten if the call had been evaluated at runtime if the user binary is linked with a different math library than the compiler. That's a problem of bitwise reproducibility of results.

If the math library linked with the compiler is simply returning an incorrect result (as seems to be the case here) that's a much bigger problem, but it's a problem for the library.

rorth pushed a commit to rorth/llvm-project that referenced this pull request Jun 11, 2025
lei137 added a commit to lei137/llvm-project that referenced this pull request Jun 11, 2025
Testcase from llvm#143416 is
causing the AIX bot to be red.  XFAIL for now till issue can be
resolved.
@lei137
Copy link
Contributor

lei137 commented Jun 11, 2025

I would like to xfail this tc for now so we can bring the aix bot back to green.
#143723

lei137 added a commit that referenced this pull request Jun 11, 2025
Testcase from #143416 is
causing the AIX bot to be red. XFAIL for now till issue can be resolved.
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request Jun 11, 2025
Testcase from llvm/llvm-project#143416 is
causing the AIX bot to be red. XFAIL for now till issue can be resolved.
DhruvSrivastavaX pushed a commit to DhruvSrivastavaX/lldb-for-aix that referenced this pull request Jun 12, 2025
@lei137
Copy link
Contributor

lei137 commented Jun 12, 2025

PR to add special handling for -/+0.0: #143962

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Missing constant folding for atan with -ffast-math on llvm 20.1.0
6 participants