diff options
author | Kaveh R. Ghazi <ghazi@caip.rutgers.edu> | 2007-05-19 04:18:05 +0000 |
---|---|---|
committer | Kaveh Ghazi <ghazi@gcc.gnu.org> | 2007-05-19 04:18:05 +0000 |
commit | 752b7d38db4314d146297c6736ec9ab65068ffa8 (patch) | |
tree | f61dbc1f8b3d760ebbede40c819cb5f93b517e5c /gcc/builtins.c | |
parent | 0470f5730bb47ea53e379beda804f6eb8c57f735 (diff) | |
download | gcc-752b7d38db4314d146297c6736ec9ab65068ffa8.zip gcc-752b7d38db4314d146297c6736ec9ab65068ffa8.tar.gz gcc-752b7d38db4314d146297c6736ec9ab65068ffa8.tar.bz2 |
re PR middle-end/30250 (Evaluate lgamma/gamma at compile-time)
PR middle-end/30250
* builtins.c (do_mpfr_lgamma_r): New.
(fold_builtin_2): Handle builtin gamma_r/lgamma_r.
* tree.h (CASE_FLT_FN_REENT): New.
testsuite:
* gcc.dg/torture/builtin-math-2.c: Add gamma_r/lgamma_r tests.
* gcc.dg/torture/builtin-math-4.c: Likewise.
From-SVN: r124849
Diffstat (limited to 'gcc/builtins.c')
-rw-r--r-- | gcc/builtins.c | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/gcc/builtins.c b/gcc/builtins.c index de62d15..9a987ea 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -236,6 +236,7 @@ static tree do_mpfr_bessel_n (tree, tree, tree, int (*)(mpfr_ptr, long, mpfr_srcptr, mp_rnd_t), const REAL_VALUE_TYPE *, bool); static tree do_mpfr_remquo (tree, tree, tree); +static tree do_mpfr_lgamma_r (tree, tree, tree); #endif /* Return true if NODE should be considered for inline expansion regardless @@ -9935,6 +9936,13 @@ fold_builtin_2 (tree fndecl, tree arg0, tree arg1, bool ignore) && validate_arg(arg1, REAL_TYPE)) return do_mpfr_arg2 (arg0, arg1, type, mpfr_remainder); break; + + CASE_FLT_FN_REENT (BUILT_IN_GAMMA): /* GAMMA_R */ + CASE_FLT_FN_REENT (BUILT_IN_LGAMMA): /* LGAMMA_R */ + if (validate_arg (arg0, REAL_TYPE) + && validate_arg(arg1, POINTER_TYPE)) + return do_mpfr_lgamma_r (arg0, arg1, type); + break; #endif CASE_FLT_FN (BUILT_IN_ATAN2): @@ -12692,4 +12700,67 @@ do_mpfr_remquo (tree arg0, tree arg1, tree arg_quo) } return result; } + +/* If ARG is a REAL_CST, call mpfr_lgamma() 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 this mpfr function + returns zero if the result could be calculated exactly within the + requested precision. In addition, the integer pointer represented + by ARG_SG will be dereferenced and set to the appropriate signgam + (-1,1) value. */ + +static tree +do_mpfr_lgamma_r (tree arg, tree arg_sg, tree type) +{ + tree result = NULL_TREE; + + STRIP_NOPS (arg); + + /* To proceed, MPFR must exactly represent the target floating point + format, which only happens when the target base equals two. Also + verify ARG is a constant and that ARG_SG is an int pointer. */ + if (REAL_MODE_FORMAT (TYPE_MODE (type))->b == 2 + && TREE_CODE (arg) == REAL_CST && !TREE_OVERFLOW (arg) + && TREE_CODE (TREE_TYPE (arg_sg)) == POINTER_TYPE + && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (arg_sg))) == integer_type_node) + { + const REAL_VALUE_TYPE *const ra = TREE_REAL_CST_PTR (arg); + + /* In addition to NaN and Inf, the argument cannot be zero or a + negative integer. */ + if (!real_isnan (ra) && !real_isinf (ra) + && ra->cl != rvc_zero + && !(real_isneg(ra) && real_isinteger(ra, TYPE_MODE (type)))) + { + const int prec = REAL_MODE_FORMAT (TYPE_MODE (type))->p; + int inexact, sg; + mpfr_t m; + tree result_lg; + + mpfr_init2 (m, prec); + mpfr_from_real (m, ra, GMP_RNDN); + mpfr_clear_flags (); + inexact = mpfr_lgamma (m, &sg, m, GMP_RNDN); + result_lg = do_mpfr_ckconv (m, type, inexact); + mpfr_clear (m); + if (result_lg) + { + tree result_sg; + + /* Dereference the arg_sg pointer argument. */ + arg_sg = build_fold_indirect_ref (arg_sg); + /* Assign the signgam value into *arg_sg. */ + result_sg = fold_build2 (MODIFY_EXPR, + TREE_TYPE (arg_sg), arg_sg, + build_int_cst (NULL, sg)); + TREE_SIDE_EFFECTS (result_sg) = 1; + /* Combine the signgam assignment with the lgamma result. */ + result = non_lvalue (fold_build2 (COMPOUND_EXPR, type, + result_sg, result_lg)); + } + } + } + + return result; +} #endif |