aboutsummaryrefslogtreecommitdiff
path: root/gcc/builtins.c
diff options
context:
space:
mode:
authorKaveh R. Ghazi <ghazi@caip.rutgers.edu>2006-11-10 04:26:31 +0000
committerKaveh Ghazi <ghazi@gcc.gnu.org>2006-11-10 04:26:31 +0000
commite61e5ddcceb34c5a5dc09febaedb44059d5bc96d (patch)
treed2a42a3fc751ccbee76f918df6150e8a533f1ba2 /gcc/builtins.c
parentf5bf550c9dc6510b4f89262d767a37c2966786ed (diff)
downloadgcc-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.c70
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