diff mbox series

[PATCHv2] Add sinh(atanh(x)) and cosh(atanh(x)) optimizations

Message ID CAEFO=4AW3r6RsH2zNfUMO+9b3OTFLvLxN2sSQ+vEOJkiS46=oA@mail.gmail.com
State New
Headers show
Series [PATCHv2] Add sinh(atanh(x)) and cosh(atanh(x)) optimizations | expand

Commit Message

Giuliano Belinassi Oct. 29, 2018, 11:46 p.m. UTC
Improves the numerical precision, as suggested on the previous iteration.

Before, the code used 1 - x*x, which can be problematic when x is near
1. Wilco Dijkstra suggested to replace it with 2*(1-fabs(x)) -
(1-fabs(x))*(1-fabs(x)) when fabs(x) > 0.5 to greatly improve
precision, however after some experiments i found that just
factorizing 1 - x*x to (1+x)*(1-x) was just as precise as his
suggestion, and works very well for both cases when fabs(x) > 0.5 and
fabs(x) <= 0.5, therefore it is faster and the code is simpler because
no check is needed.

The largest ULP error I could find with this formula when comparing it
with the correctly rounded result was 2.

gcc/ChangeLog
2018-10-29  Giuliano Belinassi  <giuliano.belinassi@usp.br>

    * match.pd (sinh (atanh (x))): New simplification rules.
    (cosh (atanh (x))): Likewise.

gcc/testsuite/ChangeLog
2018-10-29  Giuliano Belinassi  <giuliano.belinassi@usp.br>

    * gcc.dg/sinhatanh-1.c: New test.
    * gcc.dg/sinhatanh-2.c: New test.

There are no tests in trunk that seems to be breaking because of this patch.
diff mbox series

Patch

Index: gcc/match.pd
===================================================================
--- gcc/match.pd	(revision 265608)
+++ gcc/match.pd	(working copy)
@@ -4310,6 +4310,24 @@ 
       (rdiv { t_one; } (sqrts (plus (mult @0 @0) { t_one; })))
       (copysigns { t_zero; } @0))))))
 
+ /* Simplify sinh(atanh(x)) -> x / sqrt((1 - x)*(1 + x)). */
+ (for sinhs (SINH)
+      atanhs (ATANH)
+      sqrts (SQRT)
+  (simplify
+   (sinhs (atanhs:s @0))
+   (with { tree t_one = build_one_cst (type); }
+   (rdiv @0 (sqrts (mult (minus { t_one; } @0) (plus { t_one; } @0)))))))
+
+ /* Simplify cosh(atanh(x)) -> 1 / sqrt((1 - x)*(1 + x)) */
+ (for coshs (COSH)
+      atanhs (ATANH)
+      sqrts (SQRT)
+  (simplify
+   (coshs (atanhs:s @0))
+   (with { tree t_one = build_real (type, dconst1); }
+   (rdiv { t_one; } (sqrts (mult (minus { t_one; } @0) (plus { t_one; } @0)))))))
+
 /* cabs(x+0i) or cabs(0+xi) -> abs(x).  */
 (simplify
  (CABS (complex:C @0 real_zerop@1))
Index: gcc/testsuite/gcc.dg/sinhatanh-1.c
===================================================================
--- gcc/testsuite/gcc.dg/sinhatanh-1.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/sinhatanh-1.c	(working copy)
@@ -0,0 +1,62 @@ 
+/* { dg-do compile } */
+/* { dg-options "-Ofast -fdump-tree-optimized" } */
+
+extern float sinhf (float);
+extern float coshf (float);
+extern float atanhf (float);
+extern float sqrtf (float);
+extern double sinh (double);
+extern double cosh (double);
+extern double atanh (double);
+extern double sqrt (double);
+extern long double sinhl (long double);
+extern long double coshl (long double);
+extern long double atanhl (long double);
+extern long double sqrtl (long double);
+
+double __attribute__ ((noinline))
+sinhatanh_ (double x)
+{
+    return sinh (atanh (x));
+}
+
+double __attribute__ ((noinline))
+coshatanh_ (double x)
+{
+    return cosh (atanh (x));
+}
+
+float __attribute__ ((noinline))
+sinhatanhf_(float x)
+{
+    return sinhf (atanhf (x));
+}
+
+float __attribute__ ((noinline))
+coshatanhf_(float x)
+{
+    return coshf (atanhf (x));
+}
+
+long double __attribute__ ((noinline))
+sinhatanhl_ (long double x)
+{
+    return sinhl (atanhl (x));
+}
+
+long double __attribute__ ((noinline))
+coshatanhl_ (long double x)
+{
+    return coshl (atanhl (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 "atanh " "optimized" }} */
+/* {dg-final { scan-tree-dump-not "sinfh " "optimized" } } */
+/* {dg-final { scan-tree-dump-not "cosfh " "optimized" } } */
+/* {dg-final { scan-tree-dump-not "atanfh " "optimized" }} */
+/* {dg-final { scan-tree-dump-not "sinlh " "optimized" } } */
+/* {dg-final { scan-tree-dump-not "coslh " "optimized" } } */
+/* {dg-final { scan-tree-dump-not "atanlh " "optimized" }} */
Index: gcc/testsuite/gcc.dg/sinhatanh-2.c
===================================================================
--- gcc/testsuite/gcc.dg/sinhatanh-2.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/sinhatanh-2.c	(working copy)
@@ -0,0 +1,68 @@ 
+/* { dg-do compile } */
+/* { dg-options "-Ofast -fdump-tree-optimized" } */
+
+extern float sinhf (float);
+extern float coshf (float);
+extern float atanhf (float);
+extern float sqrtf (float);
+extern double sinh (double);
+extern double cosh (double);
+extern double atanh (double);
+extern double sqrt (double);
+extern long double sinhl (long double);
+extern long double coshl (long double);
+extern long double atanhl (long double);
+extern long double sqrtl (long double);
+
+float __attribute__ ((noinline)) 
+coshatanhf_(float x)
+{
+    float atg = atanhf(x);
+    return coshf(atg) + atg;
+}
+
+double __attribute__ ((noinline)) 
+cosatan_(double x)
+{
+    double atg = atanh(x);
+    return cosh(atg) + atg;
+}
+
+long double __attribute__ ((noinline)) 
+cosatanl_(long double x)
+{
+    long double atg = atanhl(x);
+    return coshl(atg) + atg;
+}
+
+float __attribute__ ((noinline)) 
+sinatanf_(float x)
+{
+    float atg = atanhf(x);
+    return sinhf(atg) + atg;
+}
+
+double __attribute__ ((noinline)) 
+sinatan_(double x)
+{
+    double atg = atanh(x);
+    return sinh(atg) + atg;
+}
+
+long double __attribute__ ((noinline)) 
+sinatanl_(long double x)
+{
+    long double atg = atanhl(x);
+    return sinhl(atg) + atg;
+}
+
+/* There should be calls to sinh, cosh and atanh */
+/* { dg-final { scan-tree-dump "cosh " "optimized" } } */
+/* { dg-final { scan-tree-dump "sinh " "optimized" } } */
+/* { dg-final { scan-tree-dump "atanh " "optimized" } } */
+/* { dg-final { scan-tree-dump "coshf " "optimized" } } */
+/* { dg-final { scan-tree-dump "sinhf " "optimized" } } */
+/* { dg-final { scan-tree-dump "atanhf " "optimized" } } */
+/* { dg-final { scan-tree-dump "coshl " "optimized" } } */
+/* { dg-final { scan-tree-dump "sinhl " "optimized" } } */
+/* { dg-final { scan-tree-dump "atanhl " "optimized" } } */