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
This commit is contained in:
parent
ea010af6b4
commit
121ef08b0b
8 changed files with 309 additions and 0 deletions
|
@ -1,3 +1,11 @@
|
|||
2018-10-11 Giuliano Belinassi <giuliano.belinassi@usp.br>
|
||||
|
||||
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 <will_schmidt@vnet.ibm.com>
|
||||
|
||||
* config/rs6000/rs6000.c (map_to_integral_tree_type): New helper
|
||||
|
|
39
gcc/match.pd
39
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))
|
||||
|
|
26
gcc/real.c
26
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);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
2018-10-09 Giuliano Belinassi <giuliano.belinassi@usp.br>
|
||||
|
||||
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 <will_schmidt@vnet.ibm.com>
|
||||
|
||||
* gcc.target/powerpc/fold-vec-mergeeo-floatdouble.c: New.
|
||||
|
|
101
gcc/testsuite/gcc.dg/sinatan-1.c
Normal file
101
gcc/testsuite/gcc.dg/sinatan-1.c
Normal file
|
@ -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;
|
||||
}
|
59
gcc/testsuite/gcc.dg/sinatan-2.c
Normal file
59
gcc/testsuite/gcc.dg/sinatan-2.c
Normal file
|
@ -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" }} */
|
65
gcc/testsuite/gcc.dg/sinatan-3.c
Normal file
65
gcc/testsuite/gcc.dg/sinatan-3.c
Normal file
|
@ -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" } } */
|
Loading…
Add table
Reference in a new issue