This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH]: PR29335 add code for exp, exp2, exp10/pow10
- From: "Kaveh R. GHAZI" <ghazi at caip dot rutgers dot edu>
- To: gcc-patches at gcc dot gnu dot org
- Date: Mon, 23 Oct 2006 10:53:15 -0400 (EDT)
- Subject: [PATCH]: PR29335 add code for exp, exp2, exp10/pow10
This patch builds on the one to evaluate sin/cos/tan at compile-time
posted here:
http://gcc.gnu.org/ml/gcc-patches/2006-10/msg01053.html
Below I've written a patch to add code for exp/exp2/exp10/pow10.
Two changes I made were to do_mpfr_arg1(). First, the logical boolean
sense of the variable `exact' was reversed. I renamed it to `inexact'.
Second, I added code to that function to detect overflow/underflow.
I added a testcase to check that GCC avoids folding in those cases so libc
can set errors or exceptions as necessary.
Tested in combination with the previous patch on sparc-sun-solaris2.10,
including the new testcase, no regressions. I also ran the `exp' test in
the transcendental accuracy suite and got perfect results. (There is no
exp2 or exp10/pow10 in the suite.) The previous sin/cos/tan still pass
with perfect scores as well.
The existing test gcc.dg/torture/builtin-explog-1.c still passes. This
testcase does check exp2 and exp10/pow10, albeit superficially with only a
few cases. But at least it shows I've hooked mpfr up correctly for these
functions and not made a silly typo or something like reversing two of
them.
Okay for mainline?
Thanks,
--Kaveh
2006-10-22 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* builtins.c (fold_builtin_exponent): Evaluate constant arguments
at compile-time using MPFR. Change parameter VALUE to FUNC,
update all callers.
(do_mpfr_arg1): Rename `exact' to `inexact'. Carefully check
for overflow and underflow at all times and avoid folding in
those cases.
testsuite:
* gcc.dg/builtin-notdone-1.c: New test.
diff -rup orig/egcc-SVN20061021/gcc/builtins.c egcc-SVN20061021/gcc/builtins.c
--- orig/egcc-SVN20061021/gcc/builtins.c 2006-10-22 12:45:48.422136516 -0400
+++ egcc-SVN20061021/gcc/builtins.c 2006-10-22 17:57:18.145562518 -0400
@@ -7827,67 +7827,36 @@ fold_builtin_powi (tree fndecl ATTRIBUTE
}
/* A subroutine of fold_builtin to fold the various exponent
- functions. EXP is the CALL_EXPR of a call to a builtin function.
- VALUE is the value which will be raised to a power. */
+ functions. Return NULL_TREE if no simplification can me made.
+ FUNC is the corresponding MPFR exponent function. */
static tree
fold_builtin_exponent (tree fndecl, tree arglist,
- const REAL_VALUE_TYPE *value)
+ int (*func)(mpfr_ptr, mpfr_srcptr, mp_rnd_t))
{
if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
{
tree type = TREE_TYPE (TREE_TYPE (fndecl));
- tree arg = TREE_VALUE (arglist);
-
- /* Optimize exp*(0.0) = 1.0. */
- if (real_zerop (arg))
- return build_real (type, dconst1);
-
- /* Optimize expN(1.0) = N. */
- if (real_onep (arg))
- {
- REAL_VALUE_TYPE cst;
-
- real_convert (&cst, TYPE_MODE (type), value);
- return build_real (type, cst);
- }
-
- /* Attempt to evaluate expN(integer) at compile-time. */
- if (flag_unsafe_math_optimizations
- && TREE_CODE (arg) == REAL_CST
- && ! TREE_CONSTANT_OVERFLOW (arg))
- {
- REAL_VALUE_TYPE cint;
- REAL_VALUE_TYPE c;
- HOST_WIDE_INT n;
-
- c = TREE_REAL_CST (arg);
- n = real_to_integer (&c);
- real_from_integer (&cint, VOIDmode, n,
- n < 0 ? -1 : 0, 0);
- if (real_identical (&c, &cint))
- {
- REAL_VALUE_TYPE x;
-
- real_powi (&x, TYPE_MODE (type), value, n);
- return build_real (type, x);
- }
- }
+ tree arg = TREE_VALUE (arglist), res;
+
+ /* Calculate the result when the argument is a constant. */
+ if ((res = do_mpfr_arg1 (arg, type, func)))
+ return res;
/* Optimize expN(logN(x)) = x. */
if (flag_unsafe_math_optimizations)
{
const enum built_in_function fcode = builtin_mathfn_code (arg);
- if ((value == &dconste
+ if ((func == mpfr_exp
&& (fcode == BUILT_IN_LOG
|| fcode == BUILT_IN_LOGF
|| fcode == BUILT_IN_LOGL))
- || (value == &dconst2
+ || (func == mpfr_exp2
&& (fcode == BUILT_IN_LOG2
|| fcode == BUILT_IN_LOG2F
|| fcode == BUILT_IN_LOG2L))
- || (value == &dconst10
+ || (func == mpfr_exp10
&& (fcode == BUILT_IN_LOG10
|| fcode == BUILT_IN_LOG10F
|| fcode == BUILT_IN_LOG10L)))
@@ -8959,14 +8928,14 @@ fold_builtin_1 (tree fndecl, tree arglis
return fold_builtin_cos (arglist, type, fndecl);
CASE_FLT_FN (BUILT_IN_EXP):
- return fold_builtin_exponent (fndecl, arglist, &dconste);
+ return fold_builtin_exponent (fndecl, arglist, mpfr_exp);
CASE_FLT_FN (BUILT_IN_EXP2):
- return fold_builtin_exponent (fndecl, arglist, &dconst2);
+ return fold_builtin_exponent (fndecl, arglist, mpfr_exp2);
CASE_FLT_FN (BUILT_IN_EXP10):
CASE_FLT_FN (BUILT_IN_POW10):
- return fold_builtin_exponent (fndecl, arglist, &dconst10);
+ return fold_builtin_exponent (fndecl, arglist, mpfr_exp10);
CASE_FLT_FN (BUILT_IN_LOG):
return fold_builtin_logarithm (fndecl, arglist, &dconste);
@@ -11193,22 +11162,34 @@ do_mpfr_arg1 (tree arg, tree type, int (
{
const enum machine_mode mode = TYPE_MODE (type);
const int prec = REAL_MODE_FORMAT (mode)->p;
- int exact;
+ int inexact;
mpfr_t m;
mpfr_init2 (m, prec);
mpfr_from_real (m, &r);
- exact = func (m, m, GMP_RNDN);
+ mpfr_clear_flags();
+ inexact = func (m, m, GMP_RNDN);
- /* Proceed iff we get a normal number, i.e. not NaN or Inf.
- If -frounding-math is set, proceed iff the result of
- calling FUNC was exact, i.e. FUNC returned zero. */
- if (mpfr_number_p (m)
- && (! flag_rounding_math || exact == 0))
+ /* Proceed iff we get a normal number, i.e. not NaN or Inf
+ and no overflow/underflow occurred. If -frounding-math,
+ proceed iff the result of calling FUNC was exact. */
+ if (mpfr_number_p (m) && !mpfr_overflow_p() && !mpfr_underflow_p()
+ && (!flag_rounding_math || !inexact))
{
real_from_mpfr (&r, m);
- real_convert (&r, mode, &r);
- result = build_real (type, r);
+ /* Proceed iff GCC's REAL_VALUE_TYPE can hold the MPFR
+ value, check for overflow/underflow. If the
+ REAL_VALUE_TYPE is zero but the mpft_t is not, then
+ we underflowed in the conversion. */
+ if (!real_isnan (&r) && !real_isinf (&r)
+ && (r.cl == rvc_zero) == (mpfr_zero_p (m) != 0))
+ {
+ REAL_VALUE_TYPE rmode;
+ real_convert (&rmode, mode, &r);
+ /* Proceed iff the specified mode can hold the value. */
+ if (real_identical (&rmode, &r))
+ result = build_real (type, rmode);
+ }
}
mpfr_clear (m);
}
/* Test things that should block GCC from optimizing compile-time
constants passed to a builtin transcendental function.
Origin: Kaveh R. Ghazi 10/22/2006. */
/* { dg-do compile } */
/* { dg-options "-fdump-tree-original" } */
extern void foof (float);
extern void foo (double);
extern void fool (long double);
void bar()
{
/* An argument of NaN is not evaluated at compile-time. */
foof (__builtin_exp2f (__builtin_nanf("")));
foo (__builtin_exp2 (__builtin_nan("")));
fool (__builtin_exp2l (__builtin_nanl("")));
/* An argument of Inf/-Inf is not evaluated at compile-time. */
foof (__builtin_exp2f (__builtin_inff()));
foo (__builtin_exp2 (__builtin_inf()));
fool (__builtin_exp2l (__builtin_infl()));
foof (__builtin_exp2f (-__builtin_inff()));
foo (__builtin_exp2 (-__builtin_inf()));
fool (__builtin_exp2l (-__builtin_infl()));
/* Result overflows MPFR, which in version 2.2.x has 30 exponent bits. */
foof (__builtin_exp2f (0x1p50F));
foo (__builtin_exp2 (0x1p50));
fool (__builtin_exp2l (0x1p50L));
/* Result underflows MPFR, which in version 2.2.x has 30 exponent bits. */
foof (__builtin_exp2f (-0x1p50F));
foo (__builtin_exp2 (-0x1p50));
fool (__builtin_exp2l (-0x1p50L));
/* Result overflows GCC's REAL_VALUE_TYPE, which has 26 exponent bits. */
foof (__builtin_exp2f (0x1p28F));
foo (__builtin_exp2 (0x1p28));
fool (__builtin_exp2l (0x1p28L));
/* Result underflows GCC's REAL_VALUE_TYPE, which has 26 exponent bits. */
foof (__builtin_exp2f (-0x1p28F));
foo (__builtin_exp2 (-0x1p28));
fool (__builtin_exp2l (-0x1p28L));
/* Result overflows (even an extended) C double's mode. */
foof (__builtin_exp2f (0x1p24F));
foo (__builtin_exp2 (0x1p24));
fool (__builtin_exp2l (0x1p24L));
/* Result underflows (even an extended) C double's mode. */
foof (__builtin_exp2f (-0x1p24F));
foo (__builtin_exp2 (-0x1p24));
fool (__builtin_exp2l (-0x1p24L));
/* Ensure that normal arguments/results are folded. */
foof (__builtin_exp2f (1.5F));
foo (__builtin_exp2 (1.5));
fool (__builtin_exp2l (1.5L));
foof (__builtin_exp2f (-1.5F));
foo (__builtin_exp2 (-1.5));
fool (__builtin_exp2l (-1.5L));
}
/* { dg-final { scan-tree-dump-times "exp2 " 9 "original" } } */
/* { dg-final { scan-tree-dump-times "exp2f" 9 "original" } } */
/* { dg-final { scan-tree-dump-times "exp2l" 9 "original" } } */
/* { dg-final { cleanup-tree-dump "original" } } */