diff options
author | Kaveh R. Ghazi <ghazi@caip.rutgers.edu> | 2006-11-02 03:20:49 +0000 |
---|---|---|
committer | Kaveh Ghazi <ghazi@gcc.gnu.org> | 2006-11-02 03:20:49 +0000 |
commit | b68bcfff54bb250ca99d24d03705ae35460732b5 (patch) | |
tree | db45dd5721e26aedaf2e1dfdf4235258d04202b1 /gcc/builtins.c | |
parent | 1d07712df0f27a52bbf6e68c337246fab3c998a3 (diff) | |
download | gcc-b68bcfff54bb250ca99d24d03705ae35460732b5.zip gcc-b68bcfff54bb250ca99d24d03705ae35460732b5.tar.gz gcc-b68bcfff54bb250ca99d24d03705ae35460732b5.tar.bz2 |
re PR middle-end/29335 (transcendental functions with constant arguments should be resolved at compile-time)
PR middle-end/29335
* builtins.c (do_mpfr_sincos): New.
(fold_builtin_1): Use it to fold builtin sincos.
testsuite:
* gcc.dg/torture/builtin-math-3.c: Fix semicolons.
(TESTIT_2P, TESTIT_2P_R): New macros. Test sincos.
From-SVN: r118409
Diffstat (limited to 'gcc/builtins.c')
-rw-r--r-- | gcc/builtins.c | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/gcc/builtins.c b/gcc/builtins.c index 7bbd632..64bb52b 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -207,6 +207,7 @@ static tree do_mpfr_arg1 (tree, tree, int (*)(mpfr_ptr, mpfr_srcptr, mp_rnd_t), const REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *, bool); static tree do_mpfr_arg2 (tree, tree, tree, int (*)(mpfr_ptr, mpfr_srcptr, mpfr_srcptr, mp_rnd_t)); +static tree do_mpfr_sincos (tree, tree, tree); /* Return true if NODE should be considered for inline expansion regardless of the optimization level. This means whenever a function is invoked with @@ -9184,6 +9185,12 @@ fold_builtin_1 (tree fndecl, tree arglist, bool ignore) CASE_FLT_FN (BUILT_IN_TAN): return fold_builtin_tan (arglist, type); + CASE_FLT_FN (BUILT_IN_SINCOS): + if (validate_arglist (arglist, REAL_TYPE, POINTER_TYPE, POINTER_TYPE, VOID_TYPE)) + return do_mpfr_sincos (TREE_VALUE (arglist), TREE_VALUE (TREE_CHAIN (arglist)), + TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)))); + break; + CASE_FLT_FN (BUILT_IN_SINH): if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) return do_mpfr_arg1 (TREE_VALUE (arglist), type, mpfr_sinh, @@ -11594,3 +11601,58 @@ do_mpfr_arg2 (tree arg1, tree arg2, tree type, return result; } + +/* If argument ARG is a REAL_CST, call mpfr_sin_cos() on it and set + the pointers *(ARG_SINP) and *(ARG_COSP) to the resulting values. + The type is taken from the type of ARG and is used for setting the + precision of the calculation and results. */ + +static tree +do_mpfr_sincos (tree arg, tree arg_sinp, tree arg_cosp) +{ + tree result = NULL_TREE; + + STRIP_NOPS (arg); + + if (TREE_CODE (arg) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg)) + { + const REAL_VALUE_TYPE *const ra = &TREE_REAL_CST (arg); + + if (!real_isnan (ra) && !real_isinf (ra)) + { + tree const type = TREE_TYPE (arg); + const int prec = REAL_MODE_FORMAT (TYPE_MODE (type))->p; + tree result_s, result_c; + int inexact; + mpfr_t m, ms, mc; + + mpfr_inits2 (prec, m, ms, mc, NULL); + mpfr_from_real (m, ra); + mpfr_clear_flags(); + inexact = mpfr_sin_cos (ms, mc, m, GMP_RNDN); + result_s = do_mpfr_ckconv (ms, type, inexact); + result_c = do_mpfr_ckconv (mc, type, inexact); + mpfr_clears (m, ms, mc, NULL); + if (result_s && result_c) + { + /* Dereference the sin/cos pointer arguments. */ + arg_sinp = build_fold_indirect_ref (arg_sinp); + arg_cosp = build_fold_indirect_ref (arg_cosp); + /* Proceed if valid pointer type were passed in. */ + if (TYPE_MAIN_VARIANT (TREE_TYPE (arg_sinp)) == TYPE_MAIN_VARIANT (type) + && TYPE_MAIN_VARIANT (TREE_TYPE (arg_cosp)) == TYPE_MAIN_VARIANT (type)) + { + /* Set the values. */ + result_s = fold_build2 (MODIFY_EXPR, type, arg_sinp, result_s); + TREE_SIDE_EFFECTS (result_s) = 1; + result_c = fold_build2 (MODIFY_EXPR, type, arg_cosp, result_c); + TREE_SIDE_EFFECTS (result_c) = 1; + /* Combine the assignments into a compound expr. */ + result = non_lvalue (fold_build2 (COMPOUND_EXPR, type, + result_s, result_c)); + } + } + } + } + return result; +} |