Hi,
this is just a preview, but I decided to send it out early to understand
if I'm on the right track or not. As you can see in the Bug, this
started as a spin-off of a library issue with complex pow, which led us to:
__builtin_exp(-__builtin_huge_val())
not being folded to a constant at compile-time. The reason is simple:
the various do_mpfr_arg*, etc, all check real_isfinite on the arguments.
In the audit trail of the bug we came to the conclusion that allowing
non-NANs could make sense (the mpfr facilities appear to be quite solid
in this case - maybe for NANs too, at least in the non-complex case, but
that's another story). However, when today I started fiddling with this
kind of change, I noticed that isn't enough for the kind of code we
really care about for the original issue, involving logs too, thus
something like:
long double num = __builtin_logl(0L);
long double res = __builtin_expl(num);
because the log isn't folded at all for zero: fold_builtin_logarithm
calls do_mpfr_arg1 with true as last argument. We can make progress if,
when it's safe - is !flag_trapping_math && !flag_errno_math enough? - we
pass true instead. Then we also have to tweak do_mpfr_ckconv, because it
checks mpfr_number_p (and real_isfinite) on the result of the folding,
thus ruling out infinities. Then we are almost there: the latter can be
actually fully folded if -O1 is used, -O0 is not Ok, because otherwise
num isn't const propagated to the evaluation of res. Is this so far by
and large Ok? I'm attaching a corresponding patchlet (it of course lacks
testcases and testsuite adjustments)
Note: in the patchlet I'm not trying to handle NaNs; neither complex
numbers; neither bessel, remquo and lgamma (which could probably be
added?) Also, I suppose we could discover other cases like
fold_builtin_logarithm, where, in the context of folding infinities too,
we may have to tweak a bit the way do_mpfr_* functions are called
Thanks!
Paolo.
PS: there are interesting issues about the non-compile-time constant
case, especially vs long double, which I didn't touch here.
////////////////////////
Index: builtins.c
===================================================================
--- builtins.c (revision 204016)
+++ builtins.c (working copy)
@@ -8191,7 +8191,9 @@ fold_builtin_logarithm (location_t loc, tree fndec
const enum built_in_function fcode = builtin_mathfn_code (arg);
/* Calculate the result when the argument is a constant. */
- if ((res = do_mpfr_arg1 (arg, type, func, &dconst0, NULL, false)))
+ if ((res = do_mpfr_arg1 (arg, type, func, &dconst0, NULL,
+ !flag_trapping_math && !flag_errno_math
+ ? true : false)))
return res;
/* Special case, optimize logN(expN(x)) = x. */
@@ -13527,7 +13529,7 @@ do_mpfr_ckconv (mpfr_srcptr m, tree type, int inex
/* 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 ()
+ if (!mpfr_nan_p (m) && !mpfr_overflow_p () && !mpfr_underflow_p ()
&& (!flag_rounding_math || !inexact))
{
REAL_VALUE_TYPE rr;
@@ -13537,7 +13539,7 @@ do_mpfr_ckconv (mpfr_srcptr m, tree type, int inex
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_isfinite (&rr)
+ if (!real_isnan (&rr)
&& (rr.cl == rvc_zero) == (mpfr_zero_p (m) != 0))
{
REAL_VALUE_TYPE rmode;
@@ -13623,7 +13625,7 @@ do_mpfr_arg1 (tree arg, tree type, int (*func)(mpf
{
const REAL_VALUE_TYPE *const ra = &TREE_REAL_CST (arg);
- if (real_isfinite (ra)
+ if (!real_isnan (ra)
&& (!min || real_compare (inclusive ? GE_EXPR: GT_EXPR , ra, min))
&& (!max || real_compare (inclusive ? LE_EXPR: LT_EXPR , ra, max)))
{
@@ -13669,7 +13671,7 @@ do_mpfr_arg2 (tree arg1, tree arg2, tree type,
const REAL_VALUE_TYPE *const ra1 = &TREE_REAL_CST (arg1);
const REAL_VALUE_TYPE *const ra2 = &TREE_REAL_CST (arg2);
- if (real_isfinite (ra1) && real_isfinite (ra2))
+ if (!real_isnan (ra1) && !real_isnan (ra2))
{
const struct real_format *fmt = REAL_MODE_FORMAT (TYPE_MODE (type));
const int prec = fmt->p;
@@ -13717,7 +13719,7 @@ do_mpfr_arg3 (tree arg1, tree arg2, tree arg3, tre
const REAL_VALUE_TYPE *const ra2 = &TREE_REAL_CST (arg2);
const REAL_VALUE_TYPE *const ra3 = &TREE_REAL_CST (arg3);
- if (real_isfinite (ra1) && real_isfinite (ra2) && real_isfinite (ra3))
+ if (!real_isnan (ra1) && !real_isnan (ra2) && !real_isnan (ra3))
{
const struct real_format *fmt = REAL_MODE_FORMAT (TYPE_MODE (type));
const int prec = fmt->p;
@@ -13762,7 +13764,7 @@ do_mpfr_sincos (tree arg, tree arg_sinp, tree arg_
{
const REAL_VALUE_TYPE *const ra = &TREE_REAL_CST (arg);
- if (real_isfinite (ra))
+ if (!real_isnan (ra))
{
const struct real_format *fmt = REAL_MODE_FORMAT (TYPE_MODE (type));
const int prec = fmt->p;