This patch simplifies the expression sinh (x) / cosh (x) to tanh (x). This rule is mathematically valid.
There's a slight difference in the result when applying this optimization with x in the interval 0 < x <= 1e-4951. With the optimization, the result using long double is -0 and without the optimization, the result is +0. When running the testsuite, the test gfortran.dg/pr79966.f90 failed, but it seems unrelated to this patch My architecture is x86_64. gcc/ChangeLog 2019-01-22 Rafael Tsuha <rafael.ts...@usp.br> * match.pd (sinh (x) / cosh (x)): New simplification rule. gcc/testsuite/ChangeLog 2019-01-22 Rafael Tsuha <rafael.ts...@usp.br> * gcc.dg/sinhovercosh-1.c: New test.
Index: gcc/match.pd =================================================================== --- gcc/match.pd (revision 267671) +++ gcc/match.pd (working copy) @@ -4484,6 +4484,11 @@ (rdiv (SIN:s @0) (COS:s @0)) (TAN @0)) + /* Simplify sinh(x) / cosh(x) -> tanh(x). */ + (simplify + (rdiv (SINH:s @0) (COSH:s @0)) + (TANH @0)) + /* Simplify cos(x) / sin(x) -> 1 / tan(x). */ (simplify (rdiv (COS:s @0) (SIN:s @0)) Index: gcc/testsuite/gcc.dg/sinhovercosh-1.c =================================================================== --- gcc/testsuite/gcc.dg/sinhovercosh-1.c (nonexistent) +++ gcc/testsuite/gcc.dg/sinhovercosh-1.c (working copy) @@ -0,0 +1,45 @@ +/* { dg-do compile } */ +/* { dg-options "-Ofast -fdump-tree-optimized" } */ + +extern float sinhf (float); +extern float coshf (float); +extern float tanhf (float); +extern float sqrtf (float); +extern double sinh (double); +extern double cosh (double); +extern double sqrt (double); +extern double tanh (double); +extern long double sinhl (long double); +extern long double coshl (long double); +extern long double tanhl (long double); +extern long double sqrtl (long double); + +double __attribute__ ((noinline)) +sinhovercosh_ (double x) +{ + return sinh (x) / cosh (x); +} + +float __attribute__ ((noinline)) +sinhfovercoshf_(float x) +{ + return sinhf (x) / coshf (x); +} + +long double __attribute__ ((noinline)) +sinhlovercoshl_ (long double x) +{ + return sinhl (x) / coshl (x); +} + +/* There must be no calls to sinh, cosh, or atanh */ +/* {dg-final { scan-tree-dump-not "sinh " "optimized" } } */ +/* {dg-final { scan-tree-dump-not "cosh " "optimized" } } */ +/* {dg-final { scan-tree-dump-not "sinfh " "optimized" } } */ +/* {dg-final { scan-tree-dump-not "cosfh " "optimized" } } */ +/* {dg-final { scan-tree-dump-not "sinlh " "optimized" } } */ +/* {dg-final { scan-tree-dump-not "coslh " "optimized" } } */ +/* {dg-final { scan-tree-dump-times "tanh " "1" "optimized" }} */ +/* {dg-final { scan-tree-dump-times "tanhl " "1" "optimized" }} */ +/* {dg-final { scan-tree-dump-times "tanhf " "1" "optimized" }} */ +