diff options
author | Kaveh R. Ghazi <ghazi@caip.rutgers.edu> | 2007-05-18 01:31:20 +0000 |
---|---|---|
committer | Kaveh Ghazi <ghazi@gcc.gnu.org> | 2007-05-18 01:31:20 +0000 |
commit | ea91f95764aaa7a1ab8ceb78e81414dc28fb6b42 (patch) | |
tree | d397abaa47309791779548be5eedc00901d236bb /gcc/builtins.c | |
parent | fd2ef596b5fe6bfdf10bed1c8a4b4100d8a0772a (diff) | |
download | gcc-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.c | 89 |
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 |