From: Giuliano Belinassi Date: Thu, 11 Oct 2018 21:06:12 +0000 (+0000) Subject: re PR tree-optimization/86829 (Missing sin(atan(x)) and cos(atan(x)) optimizations) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=121ef08b0b964ff4e7072a6af14613e68788abc4;p=gcc.git re PR tree-optimization/86829 (Missing sin(atan(x)) and cos(atan(x)) optimizations) PR tree-optimization/86829 * match.pd (sin (atan (x))): New simplification rules. (cos (atan (x))): Likewise. * real.c (build_sinatan_real): New function. * real.h (build_sinatan_real): Prototype. PR tree-optimization/86829 * gcc.dg/sinatan-1.c: New test. * gcc.dg/sinatan-2.c: New test. * gcc.dg/sinatan-3.c: New test. From-SVN: r265064 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d6a4cade483..307d64ac881 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2018-10-11 Giuliano Belinassi + + PR tree-optimization/86829 + * match.pd (sin (atan (x))): New simplification rules. + (cos (atan (x))): Likewise. + * real.c (build_sinatan_real): New function. + * real.h (build_sinatan_real): Prototype. + 2018-10-11 Will Schmidt * config/rs6000/rs6000.c (map_to_integral_tree_type): New helper diff --git a/gcc/match.pd b/gcc/match.pd index 7cc2374ffeb..94fbab841f5 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -4223,6 +4223,45 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (tans (atans @0)) @0))) + /* Simplify sin(atan(x)) -> x / sqrt(x*x + 1). */ + (for sins (SIN) + atans (ATAN) + sqrts (SQRT) + copysigns (COPYSIGN) + (simplify + (sins (atans:s @0)) + (with + { + REAL_VALUE_TYPE r_cst; + build_sinatan_real (&r_cst, type); + tree t_cst = build_real (type, r_cst); + tree t_one = build_one_cst (type); + } + (if (SCALAR_FLOAT_TYPE_P (type)) + (cond (le (abs @0) { t_cst; }) + (rdiv @0 (sqrts (plus (mult @0 @0) { t_one; }))) + (copysigns { t_one; } @0)))))) + +/* Simplify cos(atan(x)) -> 1 / sqrt(x*x + 1). */ + (for coss (COS) + atans (ATAN) + sqrts (SQRT) + copysigns (COPYSIGN) + (simplify + (coss (atans:s @0)) + (with + { + REAL_VALUE_TYPE r_cst; + build_sinatan_real (&r_cst, type); + tree t_cst = build_real (type, r_cst); + tree t_one = build_one_cst (type); + tree t_zero = build_zero_cst (type); + } + (if (SCALAR_FLOAT_TYPE_P (type)) + (cond (le (abs @0) { t_cst; }) + (rdiv { t_one; } (sqrts (plus (mult @0 @0) { t_one; }))) + (copysigns { t_zero; } @0)))))) + /* cabs(x+0i) or cabs(0+xi) -> abs(x). */ (simplify (CABS (complex:C @0 real_zerop@1)) diff --git a/gcc/real.c b/gcc/real.c index f822ae82d61..51f8fd5b3ae 100644 --- a/gcc/real.c +++ b/gcc/real.c @@ -5279,3 +5279,29 @@ HONOR_SIGN_DEPENDENT_ROUNDING (const_rtx x) { return HONOR_SIGN_DEPENDENT_ROUNDING (GET_MODE (x)); } + +/* Fills r with the largest value such that 1 + r*r won't overflow. + This is used in both sin (atan (x)) and cos (atan(x)) optimizations. */ + +void +build_sinatan_real (REAL_VALUE_TYPE * r, tree type) +{ + REAL_VALUE_TYPE maxval; + mpfr_t mpfr_const1, mpfr_c, mpfr_maxval; + machine_mode mode = TYPE_MODE (type); + const struct real_format * fmt = REAL_MODE_FORMAT (mode); + + real_maxval (&maxval, 0, mode); + + mpfr_inits (mpfr_const1, mpfr_c, mpfr_maxval, NULL); + + mpfr_from_real (mpfr_const1, &dconst1, GMP_RNDN); + mpfr_from_real (mpfr_maxval, &maxval, GMP_RNDN); + + mpfr_sub (mpfr_c, mpfr_maxval, mpfr_const1, GMP_RNDN); + mpfr_sqrt (mpfr_c, mpfr_c, GMP_RNDZ); + + real_from_mpfr (r, mpfr_c, fmt, GMP_RNDZ); + + mpfr_clears (mpfr_const1, mpfr_c, mpfr_maxval, NULL); +} diff --git a/gcc/real.h b/gcc/real.h index 0ce42565708..561d0fda129 100644 --- a/gcc/real.h +++ b/gcc/real.h @@ -523,4 +523,8 @@ extern void real_from_integer (REAL_VALUE_TYPE *, format_helper, const wide_int_ref &, signop); #endif +/* Fills r with the largest value such that 1 + r*r won't overflow. + This is used in both sin (atan (x)) and cos (atan(x)) optimizations. */ +extern void build_sinatan_real (REAL_VALUE_TYPE *, tree); + #endif /* ! GCC_REAL_H */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 3b19068fcd5..c8d0d3fbd35 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2018-10-09 Giuliano Belinassi + + PR tree-optimization/86829 + * gcc.dg/sinatan-1.c: New test. + * gcc.dg/sinatan-2.c: New test. + * gcc.dg/sinatan-3.c: New test. + 2018-10-11 Will Schmidt * gcc.target/powerpc/fold-vec-mergeeo-floatdouble.c: New. diff --git a/gcc/testsuite/gcc.dg/sinatan-1.c b/gcc/testsuite/gcc.dg/sinatan-1.c new file mode 100644 index 00000000000..194926ce8d4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/sinatan-1.c @@ -0,0 +1,101 @@ +/* { dg-do run } */ +/* { dg-options "-Ofast" } */ + +extern float sinf (float); +extern float cosf (float); +extern float atanf (float); +extern float sqrtf (float); +extern float nextafterf (float, float); +extern double sin (double); +extern double cos (double); +extern double atan (double); +extern double sqrt (double); +extern double nextafter (double, double); +extern long double sinl (long double); +extern long double cosl (long double); +extern long double atanl (long double); +extern long double sqrtl (long double); +extern long double nextafterl (long double, long double); + +extern void abort (); + +double __attribute__ ((noinline, optimize("Ofast"))) +sinatan (double x) +{ + return sin (atan (x)); +} + +double __attribute__ ((noinline, optimize("Ofast"))) +cosatan (double x) +{ + return cos (atan (x)); +} + +float __attribute__ ((noinline, optimize("Ofast"))) +sinatanf(float x) +{ + return sinf (atanf (x)); +} + +float __attribute__ ((noinline, optimize("Ofast"))) +cosatanf(float x) +{ + return cosf (atanf (x)); +} + +long double __attribute__ ((noinline, optimize("Ofast"))) +sinatanl (long double x) +{ + return sinl (atanl (x)); +} + +long double __attribute__ ((noinline, optimize("Ofast"))) +cosatanl (long double x) +{ + return cosl (atanl (x)); +} + +int +main() +{ + /* Get first x such that 1 + x*x will overflow */ + float fc = nextafterf (sqrtf (__FLT_MAX__ - 1), __FLT_MAX__); + double c = nextafter (sqrt (__DBL_MAX__ - 1), __DBL_MAX__); + long double lc = nextafter (sqrtl (__LDBL_MAX__ - 1), __LDBL_MAX__); + + /* Force move from FPU to memory, otherwise comparison may + fail due to possible more accurate registers (see 387) */ + volatile float fy; + volatile double y; + volatile long double ly; + + fy = sinatanf (fc); + y = sinatan (c); + ly = sinatanl (lc); + + if (fy != 1.f || y != 1 || ly != 1.L) + abort (); + + fy = cosatanf (fc); + y = cosatan (c); + ly = cosatanl (lc); + + if (fy != 0.f || y != 0. || ly != 0.L) + abort (); + + fy = sinatanf (-fc); + y = sinatan (-c); + ly = sinatanl (-lc); + + if (fy != -1.f || y != -1. || ly != -1.L) + abort (); + + fy = cosatanf (-fc); + y = cosatan (-c); + ly = cosatanl (-lc); + + if (fy != 0.f || y != 0. || ly != 0.L) + abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/sinatan-2.c b/gcc/testsuite/gcc.dg/sinatan-2.c new file mode 100644 index 00000000000..07a1e1e0c19 --- /dev/null +++ b/gcc/testsuite/gcc.dg/sinatan-2.c @@ -0,0 +1,59 @@ +/* { dg-do compile } */ +/* { dg-options "-Ofast -fdump-tree-optimized" } */ + +extern float sinf (float); +extern float cosf (float); +extern float atanf (float); +extern double sin (double); +extern double cos (double); +extern double atan (double); +extern long double sinl (long double); +extern long double cosl (long double); +extern long double atanl (long double); + +double __attribute__ ((noinline)) +sinatan_ (double x) +{ + return sin (atan (x)); +} + +double __attribute__ ((noinline)) +cosatan_ (double x) +{ + return cos (atan (x)); +} + +float __attribute__ ((noinline)) +sinatanf_(float x) +{ + return sinf (atanf (x)); +} + +float __attribute__ ((noinline)) +cosatanf_(float x) +{ + return cosf (atanf (x)); +} + +long double __attribute__ ((noinline)) +sinatanl_ (long double x) +{ + return sinl (atanl (x)); +} + +long double __attribute__ ((noinline)) +cosatanl_ (long double x) +{ + return cosl (atanl (x)); +} + +/* There must be no calls to sin, cos, or atan */ +/* {dg-final { scan-tree-dump-not "sin " "optimized" } } */ +/* {dg-final { scan-tree-dump-not "cos " "optimized" } } */ +/* {dg-final { scan-tree-dump-not "atan " "optimized" }} */ +/* {dg-final { scan-tree-dump-not "sinf " "optimized" } } */ +/* {dg-final { scan-tree-dump-not "cosf " "optimized" } } */ +/* {dg-final { scan-tree-dump-not "atanf " "optimized" }} */ +/* {dg-final { scan-tree-dump-not "sinl " "optimized" } } */ +/* {dg-final { scan-tree-dump-not "cosl " "optimized" } } */ +/* {dg-final { scan-tree-dump-not "atanl " "optimized" }} */ diff --git a/gcc/testsuite/gcc.dg/sinatan-3.c b/gcc/testsuite/gcc.dg/sinatan-3.c new file mode 100644 index 00000000000..600d475ba55 --- /dev/null +++ b/gcc/testsuite/gcc.dg/sinatan-3.c @@ -0,0 +1,65 @@ +/* { dg-do compile } */ +/* { dg-options "-Ofast -fdump-tree-optimized" } */ + +extern float sinf (float); +extern float cosf (float); +extern float atanf (float); +extern double sin (double); +extern double cos (double); +extern double atan (double); +extern long double sinl (long double); +extern long double cosl (long double); +extern long double atanl (long double); + +float __attribute__ ((noinline)) +cosatanf_(float x) +{ + float atg = atanf(x); + return cosf(atg) + atg; +} + +double __attribute__ ((noinline)) +cosatan_(double x) +{ + double atg = atan(x); + return cos(atg) + atg; +} + +long double __attribute__ ((noinline)) +cosatanl_(long double x) +{ + long double atg = atanl(x); + return cosl(atg) + atg; +} + +float __attribute__ ((noinline)) +sinatanf_(float x) +{ + float atg = atanf(x); + return sinf(atg) + atg; +} + +double __attribute__ ((noinline)) +sinatan_(double x) +{ + double atg = atan(x); + return sin(atg) + atg; +} + +long double __attribute__ ((noinline)) +sinatanl_(long double x) +{ + long double atg = atanl(x); + return sinl(atg) + atg; +} + +/* There should be calls to both sin and atan */ +/* { dg-final { scan-tree-dump "cos " "optimized" } } */ +/* { dg-final { scan-tree-dump "sin " "optimized" } } */ +/* { dg-final { scan-tree-dump "atan " "optimized" } } */ +/* { dg-final { scan-tree-dump "cosf " "optimized" } } */ +/* { dg-final { scan-tree-dump "sinf " "optimized" } } */ +/* { dg-final { scan-tree-dump "atanf " "optimized" } } */ +/* { dg-final { scan-tree-dump "cosl " "optimized" } } */ +/* { dg-final { scan-tree-dump "sinl " "optimized" } } */ +/* { dg-final { scan-tree-dump "atanl " "optimized" } } */