[llvm] [InstCombine] Treat `asin`, `asinh`, `atan` and `cbrt` as odd-functions (PR #227336)

via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 30 21:01:12 PDT 2026


https://github.com/suogesi updated https://github.com/llvm/llvm-project/pull/227336

>From d5925e44f064cefec7af31447b20fc292e28b6b0 Mon Sep 17 00:00:00 2001
From: Wu Haoyu <3540385658 at qq.com>
Date: Tue, 29 Sep 2026 22:24:25 +0800
Subject: [PATCH 1/2] [InstCombine] Add tests for a few math functions

---
 .../InstCombine/math-odd-even-parity.ll       | 95 +++++++++++++++++++
 1 file changed, 95 insertions(+)

diff --git a/llvm/test/Transforms/InstCombine/math-odd-even-parity.ll b/llvm/test/Transforms/InstCombine/math-odd-even-parity.ll
index 4c8cf7a99d895..3fcb36632ce15 100644
--- a/llvm/test/Transforms/InstCombine/math-odd-even-parity.ll
+++ b/llvm/test/Transforms/InstCombine/math-odd-even-parity.ll
@@ -2,6 +2,11 @@
 ; RUN: opt < %s -passes=instcombine -S | FileCheck %s
 
 declare double @erf(double)
+declare double @asin(double)
+declare double @asinh(double)
+declare double @atan(double)
+declare double @atan2(double, double)
+declare double @cbrt(double)
 declare double @cos(double)
 declare double @fabs(double)
 
@@ -20,6 +25,96 @@ define double @test_erf(double %x) {
   ret double %neg_res
 }
 
+; Check odd parity: -asin(-x) == asin(x)
+define double @test_asin(double %x) {
+; CHECK-LABEL: define double @test_asin(
+; CHECK-SAME: double [[X:%.*]]) {
+; CHECK-NEXT:    [[NEG_X:%.*]] = fneg double [[X]]
+; CHECK-NEXT:    [[RES:%.*]] = tail call reassoc double @asin(double [[NEG_X]])
+; CHECK-NEXT:    [[NEG_RES:%.*]] = fneg double [[RES]]
+; CHECK-NEXT:    ret double [[NEG_RES]]
+;
+  %neg_x = fneg double %x
+  %res = tail call reassoc double @asin(double %neg_x)
+  %neg_res = fneg double %res
+  ret double %neg_res
+}
+
+; Check odd parity: -asinh(-x) == asinh(x)
+define double @test_asinh(double %x) {
+; CHECK-LABEL: define double @test_asinh(
+; CHECK-SAME: double [[X:%.*]]) {
+; CHECK-NEXT:    [[NEG_X:%.*]] = fneg double [[X]]
+; CHECK-NEXT:    [[RES:%.*]] = tail call reassoc double @asinh(double [[NEG_X]])
+; CHECK-NEXT:    [[NEG_RES:%.*]] = fneg double [[RES]]
+; CHECK-NEXT:    ret double [[NEG_RES]]
+;
+  %neg_x = fneg double %x
+  %res = tail call reassoc double @asinh(double %neg_x)
+  %neg_res = fneg double %res
+  ret double %neg_res
+}
+
+; Check odd parity: -atan(-x) == atan(x)
+define double @test_atan(double %x) {
+; CHECK-LABEL: define double @test_atan(
+; CHECK-SAME: double [[X:%.*]]) {
+; CHECK-NEXT:    [[NEG_X:%.*]] = fneg double [[X]]
+; CHECK-NEXT:    [[RES:%.*]] = tail call reassoc double @atan(double [[NEG_X]])
+; CHECK-NEXT:    [[NEG_RES:%.*]] = fneg double [[RES]]
+; CHECK-NEXT:    ret double [[NEG_RES]]
+;
+  %neg_x = fneg double %x
+  %res = tail call reassoc double @atan(double %neg_x)
+  %neg_res = fneg double %res
+  ret double %neg_res
+}
+
+; Check odd parity: -atan2(-y, x) == atan2(y, x)
+define double @test_atan2(double %y, double %x) {
+; CHECK-LABEL: define double @test_atan2(
+; CHECK-SAME: double [[Y:%.*]], double [[X:%.*]]) {
+; CHECK-NEXT:    [[NEG_Y:%.*]] = fneg double [[Y]]
+; CHECK-NEXT:    [[RES:%.*]] = tail call reassoc double @atan2(double [[NEG_Y]], double [[X]])
+; CHECK-NEXT:    [[NEG_RES:%.*]] = fneg double [[RES]]
+; CHECK-NEXT:    ret double [[NEG_RES]]
+;
+  %neg_y = fneg double %y
+  %res = tail call reassoc double @atan2(double %neg_y, double %x)
+  %neg_res = fneg double %res
+  ret double %neg_res
+}
+
+; Negative test: -atan2(y, -x) != atan2(y, x)
+define double @test_atan2_neg_x_does_not_fold(double %y, double %x) {
+; CHECK-LABEL: define double @test_atan2_neg_x_does_not_fold(
+; CHECK-SAME: double [[Y:%.*]], double [[X:%.*]]) {
+; CHECK-NEXT:    [[NEG_X:%.*]] = fneg double [[X]]
+; CHECK-NEXT:    [[RES:%.*]] = tail call reassoc double @atan2(double [[Y]], double [[NEG_X]])
+; CHECK-NEXT:    [[NEG_RES:%.*]] = fneg double [[RES]]
+; CHECK-NEXT:    ret double [[NEG_RES]]
+;
+  %neg_x = fneg double %x
+  %res = tail call reassoc double @atan2(double %y, double %neg_x)
+  %neg_res = fneg double %res
+  ret double %neg_res
+}
+
+; Check odd parity: -cbrt(-x) == cbrt(x)
+define double @test_cbrt(double %x) {
+; CHECK-LABEL: define double @test_cbrt(
+; CHECK-SAME: double [[X:%.*]]) {
+; CHECK-NEXT:    [[NEG_X:%.*]] = fneg double [[X]]
+; CHECK-NEXT:    [[RES:%.*]] = tail call reassoc double @cbrt(double [[NEG_X]])
+; CHECK-NEXT:    [[NEG_RES:%.*]] = fneg double [[RES]]
+; CHECK-NEXT:    ret double [[NEG_RES]]
+;
+  %neg_x = fneg double %x
+  %res = tail call reassoc double @cbrt(double %neg_x)
+  %neg_res = fneg double %res
+  ret double %neg_res
+}
+
 ; Check even parity: cos(fabs(x)) == cos(x)
 define double @test_cos_fabs(double %x) {
 ; CHECK-LABEL: define double @test_cos_fabs(

>From 75ff2a9c525e0d89bee35dd2bef22b4530b0dd45 Mon Sep 17 00:00:00 2001
From: Wu Haoyu <3540385658 at qq.com>
Date: Wed, 30 Sep 2026 17:23:25 +0800
Subject: [PATCH 2/2] [InstCombine] Treat a few math functions as odd-functions

Math functions asin, asinh, atan and cbrt are added into
the list. `atan2(-y, x) == -atan2(y, x)` so `atan2` is odd, but
it cannot be added because it accepts two arguments and this causes
problems. The tests for `atan2` are still kept.

Partially meets needs of #227011
---
 llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp   | 16 ++++++++++++++++
 .../InstCombine/math-odd-even-parity.ll          | 16 ++++------------
 2 files changed, 20 insertions(+), 12 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
index f6235b5b98fcb..b6f3bd084a54f 100644
--- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
@@ -3164,6 +3164,10 @@ Value *LibCallSimplifier::optimizeSymmetric(CallInst *CI, LibFunc Func,
   case LibFunc_coshl:
     return optimizeSymmetricCall(CI, /*IsEven*/ true, B);
 
+  case LibFunc_cbrt:
+  case LibFunc_cbrtf:
+  case LibFunc_cbrtl:
+
   case LibFunc_sin:
   case LibFunc_sinf:
   case LibFunc_sinl:
@@ -3172,6 +3176,14 @@ Value *LibCallSimplifier::optimizeSymmetric(CallInst *CI, LibFunc Func,
   case LibFunc_sinhf:
   case LibFunc_sinhl:
 
+  case LibFunc_asin:
+  case LibFunc_asinf:
+  case LibFunc_asinl:
+
+  case LibFunc_asinh:
+  case LibFunc_asinhf:
+  case LibFunc_asinhl:
+
   case LibFunc_tan:
   case LibFunc_tanf:
   case LibFunc_tanl:
@@ -3180,6 +3192,10 @@ Value *LibCallSimplifier::optimizeSymmetric(CallInst *CI, LibFunc Func,
   case LibFunc_tanhf:
   case LibFunc_tanhl:
 
+  case LibFunc_atan:
+  case LibFunc_atanf:
+  case LibFunc_atanl:
+
   case LibFunc_erf:
   case LibFunc_erff:
   case LibFunc_erfl:
diff --git a/llvm/test/Transforms/InstCombine/math-odd-even-parity.ll b/llvm/test/Transforms/InstCombine/math-odd-even-parity.ll
index 3fcb36632ce15..1c6776bb60c9b 100644
--- a/llvm/test/Transforms/InstCombine/math-odd-even-parity.ll
+++ b/llvm/test/Transforms/InstCombine/math-odd-even-parity.ll
@@ -29,9 +29,7 @@ define double @test_erf(double %x) {
 define double @test_asin(double %x) {
 ; CHECK-LABEL: define double @test_asin(
 ; CHECK-SAME: double [[X:%.*]]) {
-; CHECK-NEXT:    [[NEG_X:%.*]] = fneg double [[X]]
-; CHECK-NEXT:    [[RES:%.*]] = tail call reassoc double @asin(double [[NEG_X]])
-; CHECK-NEXT:    [[NEG_RES:%.*]] = fneg double [[RES]]
+; CHECK-NEXT:    [[NEG_RES:%.*]] = tail call reassoc double @asin(double [[X]])
 ; CHECK-NEXT:    ret double [[NEG_RES]]
 ;
   %neg_x = fneg double %x
@@ -44,9 +42,7 @@ define double @test_asin(double %x) {
 define double @test_asinh(double %x) {
 ; CHECK-LABEL: define double @test_asinh(
 ; CHECK-SAME: double [[X:%.*]]) {
-; CHECK-NEXT:    [[NEG_X:%.*]] = fneg double [[X]]
-; CHECK-NEXT:    [[RES:%.*]] = tail call reassoc double @asinh(double [[NEG_X]])
-; CHECK-NEXT:    [[NEG_RES:%.*]] = fneg double [[RES]]
+; CHECK-NEXT:    [[NEG_RES:%.*]] = tail call reassoc double @asinh(double [[X]])
 ; CHECK-NEXT:    ret double [[NEG_RES]]
 ;
   %neg_x = fneg double %x
@@ -59,9 +55,7 @@ define double @test_asinh(double %x) {
 define double @test_atan(double %x) {
 ; CHECK-LABEL: define double @test_atan(
 ; CHECK-SAME: double [[X:%.*]]) {
-; CHECK-NEXT:    [[NEG_X:%.*]] = fneg double [[X]]
-; CHECK-NEXT:    [[RES:%.*]] = tail call reassoc double @atan(double [[NEG_X]])
-; CHECK-NEXT:    [[NEG_RES:%.*]] = fneg double [[RES]]
+; CHECK-NEXT:    [[NEG_RES:%.*]] = tail call reassoc double @atan(double [[X]])
 ; CHECK-NEXT:    ret double [[NEG_RES]]
 ;
   %neg_x = fneg double %x
@@ -104,9 +98,7 @@ define double @test_atan2_neg_x_does_not_fold(double %y, double %x) {
 define double @test_cbrt(double %x) {
 ; CHECK-LABEL: define double @test_cbrt(
 ; CHECK-SAME: double [[X:%.*]]) {
-; CHECK-NEXT:    [[NEG_X:%.*]] = fneg double [[X]]
-; CHECK-NEXT:    [[RES:%.*]] = tail call reassoc double @cbrt(double [[NEG_X]])
-; CHECK-NEXT:    [[NEG_RES:%.*]] = fneg double [[RES]]
+; CHECK-NEXT:    [[NEG_RES:%.*]] = tail call reassoc double @cbrt(double [[X]])
 ; CHECK-NEXT:    ret double [[NEG_RES]]
 ;
   %neg_x = fneg double %x



More information about the llvm-commits mailing list