aboutsummaryrefslogtreecommitdiff
path: root/gcc/builtins.c
diff options
context:
space:
mode:
authorKaveh R. Ghazi <ghazi@caip.rutgers.edu>2007-05-18 01:31:20 +0000
committerKaveh Ghazi <ghazi@gcc.gnu.org>2007-05-18 01:31:20 +0000
commitea91f95764aaa7a1ab8ceb78e81414dc28fb6b42 (patch)
treed397abaa47309791779548be5eedc00901d236bb /gcc/builtins.c
parentfd2ef596b5fe6bfdf10bed1c8a4b4100d8a0772a (diff)
downloadgcc-ea91f95764aaa7a1ab8ceb78e81414dc28fb6b42.zip
gcc-ea91f95764aaa7a1ab8ceb78e81414dc28fb6b42.tar.gz
gcc-ea91f95764aaa7a1ab8ceb78e81414dc28fb6b42.tar.bz2
re PR middle-end/31796 (Evaluate remquo/remainder/drem at compile-time)
PR middle-end/31796 * builtins.c (do_mpfr_remquo): New. (fold_builtin_2): Handle BUILT_IN_DREM/BUILT_IN_REMAINDER. (fold_builtin_3): Handle BUILT_IN_REMQUO. testsuite: * gcc.dg/torture/builtin-math-2.c: Add tests for remquo, remainder and drem. * gcc.dg/torture/builtin-math-4.c: Likewise. From-SVN: r124820
Diffstat (limited to 'gcc/builtins.c')
-rw-r--r--gcc/builtins.c89
1 files changed, 89 insertions, 0 deletions
diff --git a/gcc/builtins.c b/gcc/builtins.c
index da6bbc6..96c1c03 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -235,6 +235,7 @@ static tree do_mpfr_sincos (tree, tree, tree);
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);
#endif
/* Return true if NODE should be considered for inline expansion regardless
@@ -9920,6 +9921,13 @@ fold_builtin_2 (tree fndecl, tree arg0, tree arg1, bool ignore)
return do_mpfr_bessel_n (arg0, arg1, type, mpfr_yn,
&dconst0, false);
break;
+
+ CASE_FLT_FN (BUILT_IN_DREM):
+ CASE_FLT_FN (BUILT_IN_REMAINDER):
+ if (validate_arg (arg0, REAL_TYPE)
+ && validate_arg(arg1, REAL_TYPE))
+ return do_mpfr_arg2 (arg0, arg1, type, mpfr_remainder);
+ break;
#endif
CASE_FLT_FN (BUILT_IN_ATAN2):
@@ -10077,6 +10085,15 @@ fold_builtin_3 (tree fndecl, tree arg0, tree arg1, tree arg2, bool ignore)
return do_mpfr_arg3 (arg0, arg1, arg2, type, mpfr_fma);
break;
+#if MPFR_VERSION >= MPFR_VERSION_NUM(2,3,0)
+ CASE_FLT_FN (BUILT_IN_REMQUO):
+ if (validate_arg (arg0, REAL_TYPE)
+ && validate_arg(arg1, REAL_TYPE)
+ && validate_arg(arg2, POINTER_TYPE))
+ return do_mpfr_remquo (arg0, arg1, arg2);
+ break;
+#endif
+
case BUILT_IN_MEMSET:
return fold_builtin_memset (arg0, arg1, arg2, type, ignore);
@@ -12596,4 +12613,76 @@ do_mpfr_bessel_n (tree arg1, tree arg2, tree type,
return result;
}
+
+/* If arguments ARG0 and ARG1 are REAL_CSTs, call mpfr_remquo() to set
+ the pointer *(ARG_QUO) and return the result. The type is taken
+ from the type of ARG0 and is used for setting the precision of the
+ calculation and results. */
+
+static tree
+do_mpfr_remquo (tree arg0, tree arg1, tree arg_quo)
+{
+ tree const type = TREE_TYPE (arg0);
+ tree result = NULL_TREE;
+
+ STRIP_NOPS (arg0);
+ STRIP_NOPS (arg1);
+
+ /* To proceed, MPFR must exactly represent the target floating point
+ format, which only happens when the target base equals two. */
+ if (REAL_MODE_FORMAT (TYPE_MODE (type))->b == 2
+ && TREE_CODE (arg0) == REAL_CST && !TREE_OVERFLOW (arg0)
+ && TREE_CODE (arg1) == REAL_CST && !TREE_OVERFLOW (arg1))
+ {
+ const REAL_VALUE_TYPE *const ra0 = TREE_REAL_CST_PTR (arg0);
+ const REAL_VALUE_TYPE *const ra1 = TREE_REAL_CST_PTR (arg1);
+
+ if (!real_isnan (ra0) && !real_isinf (ra0)
+ && !real_isnan (ra1) && !real_isinf (ra1))
+ {
+ const int prec = REAL_MODE_FORMAT (TYPE_MODE (type))->p;
+ tree result_rem;
+ long integer_quo;
+ mpfr_t m0, m1;
+
+ mpfr_inits2 (prec, m0, m1, NULL);
+ mpfr_from_real (m0, ra0, GMP_RNDN);
+ mpfr_from_real (m1, ra1, GMP_RNDN);
+ mpfr_clear_flags ();
+ mpfr_remquo (m0, &integer_quo, m0, m1, GMP_RNDN);
+ /* Remquo is independent of the rounding mode, so pass
+ inexact=0 to do_mpfr_ckconv(). */
+ result_rem = do_mpfr_ckconv (m0, type, /*inexact=*/ 0);
+ mpfr_clears (m0, m1, NULL);
+ if (result_rem)
+ {
+ /* MPFR calculates quo in the host's long so it may
+ return more bits in quo than the target int can hold
+ if sizeof(host long) > sizeof(target int). This can
+ happen even for native compilers in LP64 mode. In
+ these cases, modulo the quo value with the largest
+ number that the target int can hold while leaving one
+ bit for the sign. */
+ if (sizeof (integer_quo) * CHAR_BIT > INT_TYPE_SIZE)
+ integer_quo %= (long)(1UL << (INT_TYPE_SIZE - 1));
+
+ /* Dereference the quo pointer argument. */
+ arg_quo = build_fold_indirect_ref (arg_quo);
+ /* Proceed iff a valid pointer type was passed in. */
+ if (TYPE_MAIN_VARIANT (TREE_TYPE (arg_quo)) == integer_type_node)
+ {
+ /* Set the value. */
+ tree result_quo = fold_build2 (MODIFY_EXPR,
+ TREE_TYPE (arg_quo), arg_quo,
+ build_int_cst (NULL, integer_quo));
+ TREE_SIDE_EFFECTS (result_quo) = 1;
+ /* Combine the quo assignment with the rem. */
+ result = non_lvalue (fold_build2 (COMPOUND_EXPR, type,
+ result_quo, result_rem));
+ }
+ }
+ }
+ }
+ return result;
+}
#endif