[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