Hi.

This patch adds a new optimization to avoid the redundant calculation
tanh(x)/sinh(x) by replacing it for 1.0/cosh(x), for all cases where x is a
double, a long double or a float.

There should be no need for numerical stability testing, since the division
of the two functions only adds numerical noise. The correctness of the
operation is justified by the definition of tanh(x) = sinh(x)/cosh(x). If
you think it is wise to write a test, please let me know.

As far as testing goes, I ran a check-gcc test under Ubuntu 19.04 by adding
the test in tanhbysinh.c and found no issues.

Best regards,

Vitor.

in gcc/ChangeLog:
2020-08-28  Vitor Guidi <vitor.gu...@usp.br>

        * match.pd: New substitution rule for tanh(x)/sinh(x) ->
1.0/cosh(x).

in gcc/testsuite/ChangeLog:
2020-08-28  Vitor Guidi <vitor.gu...@usp.br>

        * gcc.dg/tanhbysinh.c (new): Verify if simplification is applied.

> diff --git gcc/match.pd gcc/match.pd
> index 5fee394e7af..3933fcaf9fa 100644
> --- gcc/match.pd
> +++ gcc/match.pd
> @@ -5069,6 +5069,11 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
>    (rdiv (SINH:s @0) (COSH:s @0))
>     (TANH @0))
>
> + /* Simplify tanh (x) / sinh (x) -> 1.0 / cosh (x). */
> + (simplify
> +   (rdiv (TANH @0) (SINH @0))
> +   (rdiv {build_one_cst (type);} (COSH @0)))
> +
>   /* Simplify cos(x) / sin(x) -> 1 / tan(x). */
>   (simplify
>    (rdiv (COS:s @0) (SIN:s @0))
> diff --git gcc/testsuite/gcc.dg/tanhbysinh.c
gcc/testsuite/gcc.dg/tanhbysinh.c
> new file mode 100644
> index 00000000000..fde72c2f93b
> --- /dev/null
> +++ gcc/testsuite/gcc.dg/tanhbysinh.c
> @@ -0,0 +1,40 @@
> +/* { dg-do compile } */
> +/* { dg-options "-Ofast -fdump-tree-optimized" } */
> +
> +extern float sinhf (float);
> +extern float tanhf (float);
> +extern double sinh (double);
> +extern double tanh (double);
> +extern long double sinhl (long double);
> +extern long double tanhl (long double);
> +
> +double __attribute__ ((noinline))
> +tanhbysinh_ (double x)
> +{
> +    return tanh (x) / sinh (x);
> +}
> +
> +float __attribute__ ((noinline))
> +tanhbysinhf_ (float x)
> +{
> +    return tanhf (x) / sinhf (x);
> +}
> +
> +long double __attribute__ ((noinline))
> +tanhbysinhl_ (long double x)
> +{
> +    return tanhl (x) / sinhl (x);
> +}
> +
> +
> +/* There must be no calls to sinh or atanh */
> +/* There must be calls to cosh */
> +/* {dg-final { scan-tree-dump-not "sinh " "optimized" } } */
> +/* {dg-final { scan-tree-dump-not "tanh " "optimized" }} */
> +/* {dg-final { scan-tree-dump-not "sinhf " "optimized" } } */
> +/* {dg-final { scan-tree-dump-not "tanhf " "optimized" }} */
> +/* {dg-final { scan-tree-dump-not "sinhl " "optimized" } } */
> +/* {dg-final { scan-tree-dump-not "tanhl " "optimized" }} */
> +/* { dg-final { scan-tree-dump "cosh " "optimized" } } */
> +/* { dg-final { scan-tree-dump "coshf " "optimized" } } */
> +/* { dg-final { scan-tree-dump "coshl " "optimized" } } */
> \ No newline at end of file

Reply via email to