Commit 1f3f1f68 by Kaveh R. Ghazi Committed by Kaveh Ghazi

re PR middle-end/29335 (transcendental functions with constant arguments should…

re PR middle-end/29335 (transcendental functions with constant arguments should be resolved at compile-time)

	PR middle-end/29335
	* builtins.c (fold_builtin_sin, fold_builtin_cos,
	fold_builtin_tan): Fold all constant arguments.  Take a "type"
	argument as necessary.
	(do_mpfr_arg1): New.
	* real.c, real.h (real_from_mpfr, mpfr_from_real): New.

From-SVN: r117983
parent b544aa7b
2006-10-23 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
PR middle-end/29335
* builtins.c (fold_builtin_sin, fold_builtin_cos,
fold_builtin_tan): Fold all constant arguments. Take a "type"
argument as necessary.
(do_mpfr_arg1): New.
* real.c, real.h (real_from_mpfr, mpfr_from_real): New.
2006-10-23 Bob Wilson <bob.wilson@acm.org> 2006-10-23 Bob Wilson <bob.wilson@acm.org>
* config/xtensa/lib1funcs.asm: Use C-style comments. * config/xtensa/lib1funcs.asm: Use C-style comments.
......
...@@ -150,9 +150,9 @@ static tree fold_builtin_sqrt (tree, tree); ...@@ -150,9 +150,9 @@ static tree fold_builtin_sqrt (tree, tree);
static tree fold_builtin_cbrt (tree, tree); static tree fold_builtin_cbrt (tree, tree);
static tree fold_builtin_pow (tree, tree, tree); static tree fold_builtin_pow (tree, tree, tree);
static tree fold_builtin_powi (tree, tree, tree); static tree fold_builtin_powi (tree, tree, tree);
static tree fold_builtin_sin (tree); static tree fold_builtin_sin (tree, tree);
static tree fold_builtin_cos (tree, tree, tree); static tree fold_builtin_cos (tree, tree, tree);
static tree fold_builtin_tan (tree); static tree fold_builtin_tan (tree, tree);
static tree fold_builtin_atan (tree, tree); static tree fold_builtin_atan (tree, tree);
static tree fold_builtin_trunc (tree, tree); static tree fold_builtin_trunc (tree, tree);
static tree fold_builtin_floor (tree, tree); static tree fold_builtin_floor (tree, tree);
...@@ -205,6 +205,7 @@ static unsigned HOST_WIDE_INT target_s; ...@@ -205,6 +205,7 @@ static unsigned HOST_WIDE_INT target_s;
static char target_percent_c[3]; static char target_percent_c[3];
static char target_percent_s[3]; static char target_percent_s[3];
static char target_percent_s_newline[4]; static char target_percent_s_newline[4];
static tree do_mpfr_arg1 (tree, tree, int (*)(mpfr_ptr, mpfr_srcptr, mp_rnd_t));
/* Return true if NODE should be considered for inline expansion regardless /* Return true if NODE should be considered for inline expansion regardless
of the optimization level. This means whenever a function is invoked with of the optimization level. This means whenever a function is invoked with
...@@ -7206,17 +7207,17 @@ fold_builtin_cbrt (tree arglist, tree type) ...@@ -7206,17 +7207,17 @@ fold_builtin_cbrt (tree arglist, tree type)
/* Fold function call to builtin sin, sinf, or sinl. Return /* Fold function call to builtin sin, sinf, or sinl. Return
NULL_TREE if no simplification can be made. */ NULL_TREE if no simplification can be made. */
static tree static tree
fold_builtin_sin (tree arglist) fold_builtin_sin (tree arglist, tree type)
{ {
tree arg = TREE_VALUE (arglist); tree arg = TREE_VALUE (arglist), res;
if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
return NULL_TREE; return NULL_TREE;
/* Optimize sin (0.0) = 0.0. */ /* Calculate the result when the argument is a constant. */
if (real_zerop (arg)) if ((res = do_mpfr_arg1 (arg, type, mpfr_sin)))
return arg; return res;
return NULL_TREE; return NULL_TREE;
} }
...@@ -7225,15 +7226,15 @@ fold_builtin_sin (tree arglist) ...@@ -7225,15 +7226,15 @@ fold_builtin_sin (tree arglist)
static tree static tree
fold_builtin_cos (tree arglist, tree type, tree fndecl) fold_builtin_cos (tree arglist, tree type, tree fndecl)
{ {
tree arg = TREE_VALUE (arglist); tree arg = TREE_VALUE (arglist), res;
if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
return NULL_TREE; return NULL_TREE;
/* Optimize cos (0.0) = 1.0. */ /* Calculate the result when the argument is a constant. */
if (real_zerop (arg)) if ((res = do_mpfr_arg1 (arg, type, mpfr_cos)))
return build_real (type, dconst1); return res;
/* Optimize cos(-x) into cos (x). */ /* Optimize cos(-x) into cos (x). */
if (TREE_CODE (arg) == NEGATE_EXPR) if (TREE_CODE (arg) == NEGATE_EXPR)
{ {
...@@ -7248,18 +7249,18 @@ fold_builtin_cos (tree arglist, tree type, tree fndecl) ...@@ -7248,18 +7249,18 @@ fold_builtin_cos (tree arglist, tree type, tree fndecl)
/* Fold function call to builtin tan, tanf, or tanl. Return /* Fold function call to builtin tan, tanf, or tanl. Return
NULL_TREE if no simplification can be made. */ NULL_TREE if no simplification can be made. */
static tree static tree
fold_builtin_tan (tree arglist) fold_builtin_tan (tree arglist, tree type)
{ {
enum built_in_function fcode; enum built_in_function fcode;
tree arg = TREE_VALUE (arglist); tree arg = TREE_VALUE (arglist), res;
if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
return NULL_TREE; return NULL_TREE;
/* Optimize tan(0.0) = 0.0. */ /* Calculate the result when the argument is a constant. */
if (real_zerop (arg)) if ((res = do_mpfr_arg1 (arg, type, mpfr_tan)))
return arg; return res;
/* Optimize tan(atan(x)) = x. */ /* Optimize tan(atan(x)) = x. */
fcode = builtin_mathfn_code (arg); fcode = builtin_mathfn_code (arg);
if (flag_unsafe_math_optimizations if (flag_unsafe_math_optimizations
...@@ -9039,7 +9040,7 @@ fold_builtin_1 (tree fndecl, tree arglist, bool ignore) ...@@ -9039,7 +9040,7 @@ fold_builtin_1 (tree fndecl, tree arglist, bool ignore)
return fold_builtin_cbrt (arglist, type); return fold_builtin_cbrt (arglist, type);
CASE_FLT_FN (BUILT_IN_SIN): CASE_FLT_FN (BUILT_IN_SIN):
return fold_builtin_sin (arglist); return fold_builtin_sin (arglist, type);
CASE_FLT_FN (BUILT_IN_COS): CASE_FLT_FN (BUILT_IN_COS):
return fold_builtin_cos (arglist, type, fndecl); return fold_builtin_cos (arglist, type, fndecl);
...@@ -9064,7 +9065,7 @@ fold_builtin_1 (tree fndecl, tree arglist, bool ignore) ...@@ -9064,7 +9065,7 @@ fold_builtin_1 (tree fndecl, tree arglist, bool ignore)
return fold_builtin_logarithm (fndecl, arglist, &dconst10); return fold_builtin_logarithm (fndecl, arglist, &dconst10);
CASE_FLT_FN (BUILT_IN_TAN): CASE_FLT_FN (BUILT_IN_TAN):
return fold_builtin_tan (arglist); return fold_builtin_tan (arglist, type);
CASE_FLT_FN (BUILT_IN_ATAN): CASE_FLT_FN (BUILT_IN_ATAN):
return fold_builtin_atan (arglist, type); return fold_builtin_atan (arglist, type);
...@@ -11278,3 +11279,48 @@ init_target_chars (void) ...@@ -11278,3 +11279,48 @@ init_target_chars (void)
} }
return true; return true;
} }
/* If argument ARG is a REAL_CST, call the one-argument mpfr function
FUNC on it and return the resulting value as a tree with type TYPE.
The mpfr precision is set to the precision of TYPE. We assume that
function FUNC returns zero if the result could be calculated
exactly within the requested precision. */
static tree
do_mpfr_arg1 (tree arg, tree type, int (*func)(mpfr_ptr, mpfr_srcptr, mp_rnd_t))
{
tree result = NULL_TREE;
STRIP_NOPS (arg);
if (TREE_CODE (arg) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg))
{
REAL_VALUE_TYPE r = TREE_REAL_CST (arg);
if (!real_isnan (&r) && !real_isinf (&r))
{
const enum machine_mode mode = TYPE_MODE (type);
const int prec = REAL_MODE_FORMAT (mode)->p;
int exact;
mpfr_t m;
mpfr_init2 (m, prec);
mpfr_from_real (m, &r);
exact = func (m, m, GMP_RNDN);
/* Proceed iff we get a normal number, i.e. not NaN or Inf.
If -frounding-math is set, proceed iff the result of
calling FUNC was exact, i.e. FUNC returned zero. */
if (mpfr_number_p (m)
&& (! flag_rounding_math || exact == 0))
{
real_from_mpfr (&r, m);
real_convert (&r, mode, &r);
result = build_real (type, r);
}
mpfr_clear (m);
}
}
return result;
}
...@@ -4922,3 +4922,47 @@ real_copysign (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *x) ...@@ -4922,3 +4922,47 @@ real_copysign (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *x)
r->sign = x->sign; r->sign = x->sign;
} }
/* Convert from REAL_VALUE_TYPE to MPFR. The caller is responsible
for initializing and clearing the MPFR parmeter. */
void
mpfr_from_real (mpfr_ptr m, const REAL_VALUE_TYPE *r)
{
/* We use a string as an intermediate type. */
char buf[128];
real_to_hexadecimal (buf, r, sizeof (buf), 0, 1);
/* mpfr_set_str() parses hexadecimal floats from strings in the same
format that GCC will output them. Nothing extra is needed. */
gcc_assert (mpfr_set_str (m, buf, 16, GMP_RNDN) == 0);
}
/* Convert from MPFR to REAL_VALUE_TYPE. */
void
real_from_mpfr (REAL_VALUE_TYPE *r, mpfr_srcptr m)
{
/* We use a string as an intermediate type. */
char buf[128], *rstr;
mp_exp_t exp;
rstr = mpfr_get_str (NULL, &exp, 16, 0, m, GMP_RNDN);
/* The additional 12 chars add space for the sprintf below. This
leaves 6 digits for the exponent which is supposedly enough. */
gcc_assert (rstr != NULL && strlen (rstr) < sizeof (buf) - 12);
/* REAL_VALUE_ATOF expects the exponent for mantissa * 2**exp,
mpfr_get_str returns the exponent for mantissa * 16**exp, adjust
for that. */
exp *= 4;
if (rstr[0] == '-')
sprintf (buf, "-0x.%sp%d", &rstr[1], (int) exp);
else
sprintf (buf, "0x.%sp%d", rstr, (int) exp);
mpfr_free_str (rstr);
real_from_string (r, buf);
}
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
#ifndef GCC_REAL_H #ifndef GCC_REAL_H
#define GCC_REAL_H #define GCC_REAL_H
#include <gmp.h>
#include <mpfr.h>
#include "machmode.h" #include "machmode.h"
/* An expanded form of the represented number. */ /* An expanded form of the represented number. */
...@@ -425,4 +427,10 @@ extern void real_round (REAL_VALUE_TYPE *, enum machine_mode, ...@@ -425,4 +427,10 @@ extern void real_round (REAL_VALUE_TYPE *, enum machine_mode,
/* Set the sign of R to the sign of X. */ /* Set the sign of R to the sign of X. */
extern void real_copysign (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *); extern void real_copysign (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *);
/* Convert between MPFR and REAL_VALUE_TYPE. The caller is
responsible for initializing and clearing the MPFR parameter. */
extern void real_from_mpfr (REAL_VALUE_TYPE *, mpfr_srcptr);
extern void mpfr_from_real (mpfr_ptr, const REAL_VALUE_TYPE *);
#endif /* ! GCC_REAL_H */ #endif /* ! GCC_REAL_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment