diff options
author | Kaveh R. Ghazi <ghazi@caip.rutgers.edu> | 2006-11-10 04:26:31 +0000 |
---|---|---|
committer | Kaveh Ghazi <ghazi@gcc.gnu.org> | 2006-11-10 04:26:31 +0000 |
commit | e61e5ddcceb34c5a5dc09febaedb44059d5bc96d (patch) | |
tree | d2a42a3fc751ccbee76f918df6150e8a533f1ba2 /gcc/builtins.c | |
parent | f5bf550c9dc6510b4f89262d767a37c2966786ed (diff) | |
download | gcc-e61e5ddcceb34c5a5dc09febaedb44059d5bc96d.zip gcc-e61e5ddcceb34c5a5dc09febaedb44059d5bc96d.tar.gz gcc-e61e5ddcceb34c5a5dc09febaedb44059d5bc96d.tar.bz2 |
builtins.c (do_mpfr_arg3): New.
* builtins.c (do_mpfr_arg3): New.
(fold_builtin_1): Handle builtins fma, fmin and fmax.
testsuite:
* gcc.dg/torture/builtin-math-2.c: Test builtin fma.
* gcc.dg/torture/builtin-math-3.c (CKSGN_F, CKSGN, CKSGN_L):
New macros. Use them in exact tests.
(TESTIT3): New macro.
Add tests for fmin, fmax and fma.
From-SVN: r118648
Diffstat (limited to 'gcc/builtins.c')
-rw-r--r-- | gcc/builtins.c | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/gcc/builtins.c b/gcc/builtins.c index 17355f7..9d27243 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -207,6 +207,8 @@ 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_arg3 (tree, tree, tree, tree, + int (*)(mpfr_ptr, mpfr_srcptr, 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 @@ -9256,6 +9258,28 @@ fold_builtin_1 (tree fndecl, tree arglist, bool ignore) type, mpfr_atan2); break; + CASE_FLT_FN (BUILT_IN_FMA): + if (validate_arglist (arglist, REAL_TYPE, REAL_TYPE, REAL_TYPE, VOID_TYPE)) + return do_mpfr_arg3 (TREE_VALUE (arglist), + TREE_VALUE (TREE_CHAIN (arglist)), + TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))), + type, mpfr_fma); + break; + + CASE_FLT_FN (BUILT_IN_FMIN): + if (validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE)) + return do_mpfr_arg2 (TREE_VALUE (arglist), + TREE_VALUE (TREE_CHAIN (arglist)), + type, mpfr_min); + break; + + CASE_FLT_FN (BUILT_IN_FMAX): + if (validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE)) + return do_mpfr_arg2 (TREE_VALUE (arglist), + TREE_VALUE (TREE_CHAIN (arglist)), + type, mpfr_max); + break; + CASE_FLT_FN (BUILT_IN_HYPOT): return fold_builtin_hypot (fndecl, arglist, type); @@ -11593,6 +11617,52 @@ do_mpfr_arg2 (tree arg1, tree arg2, tree type, return result; } +/* If argument ARG is a REAL_CST, call the three-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_arg3 (tree arg1, tree arg2, tree arg3, tree type, + int (*func)(mpfr_ptr, mpfr_srcptr, mpfr_srcptr, mpfr_srcptr, mp_rnd_t)) +{ + tree result = NULL_TREE; + + STRIP_NOPS (arg1); + STRIP_NOPS (arg2); + STRIP_NOPS (arg3); + + if (TREE_CODE (arg1) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg1) + && TREE_CODE (arg2) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg2) + && TREE_CODE (arg3) == REAL_CST && ! TREE_CONSTANT_OVERFLOW (arg3)) + { + const REAL_VALUE_TYPE *const ra1 = &TREE_REAL_CST (arg1); + const REAL_VALUE_TYPE *const ra2 = &TREE_REAL_CST (arg2); + const REAL_VALUE_TYPE *const ra3 = &TREE_REAL_CST (arg3); + + if (!real_isnan (ra1) && !real_isinf (ra1) + && !real_isnan (ra2) && !real_isinf (ra2) + && !real_isnan (ra3) && !real_isinf (ra3)) + { + const int prec = REAL_MODE_FORMAT (TYPE_MODE (type))->p; + int inexact; + mpfr_t m1, m2, m3; + + mpfr_inits2 (prec, m1, m2, m3, NULL); + mpfr_from_real (m1, ra1); + mpfr_from_real (m2, ra2); + mpfr_from_real (m3, ra3); + mpfr_clear_flags(); + inexact = func (m1, m1, m2, m3, GMP_RNDN); + result = do_mpfr_ckconv (m1, type, inexact); + mpfr_clears (m1, m2, m3, NULL); + } + } + + 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 |