re PR middle-end/29335 (transcendental functions with constant arguments should be resolved at compile-time)

PR middle-end/29335
	* builtins.c (fold_builtin_cbrt, fold_builtin_logarithm):
	Calculate compile-time constants using MPFR.
	(fold_builtin_1): Likewise handle BUILT_IN_ERF, BUILT_IN_ERFC,
	BUILT_IN_EXPM1 and BUILT_IN_LOG1P.
	
testsuite:
	* gcc.dg/torture/builtin-math-2.c (TESTIT): Use new helper macro.
	Add checks for log, log2, log10 and log1p.

	* gcc.dg/torture/builtin-math-3.c: Add checks for -0.0 everywhere
	we already test 0.0.  Add checks for expm1, log, log2, log10,
	log1p, cbrt, erf and erfc.

From-SVN: r118042
This commit is contained in:
Kaveh R. Ghazi 2006-10-25 20:44:09 +00:00 committed by Kaveh Ghazi
parent 4f0abdc91b
commit cf1491f0e5
5 changed files with 184 additions and 76 deletions

View File

@ -1,3 +1,11 @@
2006-10-25 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
PR middle-end/29335
* builtins.c (fold_builtin_cbrt, fold_builtin_logarithm):
Calculate compile-time constants using MPFR.
(fold_builtin_1): Likewise handle BUILT_IN_ERF, BUILT_IN_ERFC,
BUILT_IN_EXPM1 and BUILT_IN_LOG1P.
2006-10-25 Bob Wilson <bob.wilson@acm.org>
* config/xtensa/lib2funcs.S: Use C-style comments.

View File

@ -7110,13 +7110,14 @@ fold_builtin_cbrt (tree arglist, tree type)
{
tree arg = TREE_VALUE (arglist);
const enum built_in_function fcode = builtin_mathfn_code (arg);
tree res;
if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
return NULL_TREE;
/* Optimize cbrt of constant value. */
if (real_zerop (arg) || real_onep (arg) || real_minus_onep (arg))
return arg;
/* Calculate the result when the argument is a constant. */
if ((res = do_mpfr_arg1 (arg, type, mpfr_cbrt, NULL, NULL, 0)))
return res;
if (flag_unsafe_math_optimizations)
{
@ -7203,7 +7204,8 @@ fold_builtin_cbrt (tree arglist, tree type)
static tree
fold_builtin_cos (tree arglist, tree type, tree fndecl)
{
tree arg = TREE_VALUE (arglist), res;
tree arg = TREE_VALUE (arglist);
tree res;
if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
return NULL_TREE;
@ -7229,7 +7231,8 @@ static tree
fold_builtin_tan (tree arglist, tree type)
{
enum built_in_function fcode;
tree arg = TREE_VALUE (arglist), res;
tree arg = TREE_VALUE (arglist);
tree res;
if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
return NULL_TREE;
@ -7552,45 +7555,46 @@ real_dconstp (tree expr, const REAL_VALUE_TYPE *value)
}
/* A subroutine of fold_builtin to fold the various logarithmic
functions. EXP is the CALL_EXPR of a call to a builtin logN
function. VALUE is the base of the logN function. */
functions. Return NULL_TREE if no simplification can me made.
FUNC is the corresponding MPFR logarithm function. */
static tree
fold_builtin_logarithm (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);
tree res;
const enum built_in_function fcode = builtin_mathfn_code (arg);
/* Optimize logN(1.0) = 0.0. */
if (real_onep (arg))
return build_real (type, dconst0);
/* Optimize logN(N) = 1.0. If N can't be truncated to MODE
exactly, then only do this if flag_unsafe_math_optimizations. */
if (exact_real_truncate (TYPE_MODE (type), value)
|| flag_unsafe_math_optimizations)
{
const REAL_VALUE_TYPE value_truncate =
real_value_truncate (TYPE_MODE (type), *value);
if (real_dconstp (arg, &value_truncate))
/* Optimize log(e) = 1.0. We're never passed an exact 'e',
instead we'll look for 'e' truncated to MODE. So only do
this if flag_unsafe_math_optimizations is set. */
if (flag_unsafe_math_optimizations && func == mpfr_log)
{
const REAL_VALUE_TYPE e_truncated =
real_value_truncate (TYPE_MODE (type), dconste);
if (real_dconstp (arg, &e_truncated))
return build_real (type, dconst1);
}
/* Calculate the result when the argument is a constant. */
if ((res = do_mpfr_arg1 (arg, type, func, &dconst0, NULL, false)))
return res;
/* Special case, optimize logN(expN(x)) = x. */
if (flag_unsafe_math_optimizations
&& ((value == &dconste
&& ((func == mpfr_log
&& (fcode == BUILT_IN_EXP
|| fcode == BUILT_IN_EXPF
|| fcode == BUILT_IN_EXPL))
|| (value == &dconst2
|| (func == mpfr_log2
&& (fcode == BUILT_IN_EXP2
|| fcode == BUILT_IN_EXP2F
|| fcode == BUILT_IN_EXP2L))
|| (value == &dconst10 && (BUILTIN_EXP10_P (fcode)))))
|| (func == mpfr_log10 && (BUILTIN_EXP10_P (fcode)))))
return fold_convert (type, TREE_VALUE (TREE_OPERAND (arg, 1)));
/* Optimize logN(func()) for various exponential functions. We
@ -7869,7 +7873,8 @@ fold_builtin_exponent (tree fndecl, tree arglist,
if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
{
tree type = TREE_TYPE (TREE_TYPE (fndecl));
tree arg = TREE_VALUE (arglist), res;
tree arg = TREE_VALUE (arglist);
tree res;
/* Calculate the result when the argument is a constant. */
if ((res = do_mpfr_arg1 (arg, type, func, NULL, NULL, 0)))
@ -9040,6 +9045,18 @@ fold_builtin_1 (tree fndecl, tree arglist, bool ignore)
NULL, NULL, 0);
break;
CASE_FLT_FN (BUILT_IN_ERF):
if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
return do_mpfr_arg1 (TREE_VALUE (arglist), type, mpfr_erf,
NULL, NULL, 0);
break;
CASE_FLT_FN (BUILT_IN_ERFC):
if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
return do_mpfr_arg1 (TREE_VALUE (arglist), type, mpfr_erfc,
NULL, NULL, 0);
break;
CASE_FLT_FN (BUILT_IN_EXP):
return fold_builtin_exponent (fndecl, arglist, mpfr_exp);
@ -9050,14 +9067,26 @@ fold_builtin_1 (tree fndecl, tree arglist, bool ignore)
CASE_FLT_FN (BUILT_IN_POW10):
return fold_builtin_exponent (fndecl, arglist, mpfr_exp10);
CASE_FLT_FN (BUILT_IN_EXPM1):
if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
return do_mpfr_arg1 (TREE_VALUE (arglist), type, mpfr_expm1,
NULL, NULL, 0);
break;
CASE_FLT_FN (BUILT_IN_LOG):
return fold_builtin_logarithm (fndecl, arglist, &dconste);
return fold_builtin_logarithm (fndecl, arglist, mpfr_log);
CASE_FLT_FN (BUILT_IN_LOG2):
return fold_builtin_logarithm (fndecl, arglist, &dconst2);
return fold_builtin_logarithm (fndecl, arglist, mpfr_log2);
CASE_FLT_FN (BUILT_IN_LOG10):
return fold_builtin_logarithm (fndecl, arglist, &dconst10);
return fold_builtin_logarithm (fndecl, arglist, mpfr_log10);
CASE_FLT_FN (BUILT_IN_LOG1P):
if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
return do_mpfr_arg1 (TREE_VALUE (arglist), type, mpfr_log1p,
&dconstm1, NULL, false);
break;
CASE_FLT_FN (BUILT_IN_POW):
return fold_builtin_pow (fndecl, arglist, type);

View File

@ -1,3 +1,12 @@
2006-10-25 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* gcc.dg/torture/builtin-math-2.c (TESTIT): Use new helper macro.
Add checks for log, log2, log10 and log1p.
* gcc.dg/torture/builtin-math-3.c: Add checks for -0.0 everywhere
we already test 0.0. Add checks for expm1, log, log2, log10,
log1p, cbrt, erf and erfc.
2006-10-25 Steve Ellcey <sje@cup.hp.com>
* gcc.dg/pthread-init-2.c: Define _POSIX_C_SOURCE on ia64 HP-UX.

View File

@ -12,6 +12,12 @@ extern void foof (float);
extern void foo (double);
extern void fool (long double);
#define TESTIT(FUNC, ARG) do { \
foof (__builtin_##FUNC##f (ARG##F)); \
foo (__builtin_##FUNC (ARG)); \
fool (__builtin_##FUNC##l (ARG##L)); \
} while (0)
void bar()
{
/* An argument of NaN is not evaluated at compile-time. */
@ -28,68 +34,55 @@ void bar()
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));
TESTIT (exp2, 0x1p50);
/* 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));
TESTIT (exp2, -0x1p50);
/* Result overflows GCC's REAL_VALUE_TYPE, which has 26 exponent bits. */
foof (__builtin_exp2f (0x1p28F));
foo (__builtin_exp2 (0x1p28));
fool (__builtin_exp2l (0x1p28L));
TESTIT (exp2, 0x1p28);
/* Result underflows GCC's REAL_VALUE_TYPE, which has 26 exponent bits. */
foof (__builtin_exp2f (-0x1p28F));
foo (__builtin_exp2 (-0x1p28));
fool (__builtin_exp2l (-0x1p28L));
TESTIT (exp2, -0x1p28);
/* Result overflows (even an extended) C double's mode. */
foof (__builtin_exp2f (0x1p24F));
foo (__builtin_exp2 (0x1p24));
fool (__builtin_exp2l (0x1p24L));
TESTIT (exp2, 0x1p24);
/* Result underflows (even an extended) C double's mode. */
foof (__builtin_exp2f (-0x1p24F));
foo (__builtin_exp2 (-0x1p24));
fool (__builtin_exp2l (-0x1p24L));
TESTIT (exp2, -0x1p24);
/* 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));
TESTIT (exp2, 1.5);
TESTIT (exp2, -1.5);
/* The asin arg must be [-1 ... 1] inclusive. */
foof (__builtin_asinf (-1.5F));
foof (__builtin_asinf (1.5F));
foo (__builtin_asin (-1.5));
foo (__builtin_asin (1.5));
fool (__builtin_asinl (-1.5L));
fool (__builtin_asinl (1.5L));
TESTIT (asin, -1.5);
TESTIT (asin, 1.5);
/* The acos arg must be [-1 ... 1] inclusive. */
foof (__builtin_acosf (-1.5F));
foof (__builtin_acosf (1.5F));
foo (__builtin_acos (-1.5));
foo (__builtin_acos (1.5));
fool (__builtin_acosl (-1.5L));
fool (__builtin_acosl (1.5L));
TESTIT (acos, -1.5);
TESTIT (acos, 1.5);
/* The acosh arg must be [1 ... Inf] inclusive. */
foof (__builtin_acoshf (0.5F));
foo (__builtin_acosh (0.5));
fool (__builtin_acoshl (0.5L));
TESTIT (acosh, 0.5);
/* The atanh arg must be [-1 ... 1] exclusive. */
foof (__builtin_atanhf (-1.0F));
foof (__builtin_atanhf (1.0F));
foo (__builtin_atanh (-1.0));
foo (__builtin_atanh (1.0));
fool (__builtin_atanhl (-1.0L));
fool (__builtin_atanhl (1.0L));
/* The atanh arg must be [-1 ... 1] EXclusive. */
TESTIT (atanh, -1.0);
TESTIT (atanh, 1.0);
/* The log* arg must be [0 ... Inf] EXclusive. */
TESTIT (log, -1.0);
TESTIT (log, 0.0);
TESTIT (log, -0.0);
TESTIT (log2, -1.0);
TESTIT (log2, 0.0);
TESTIT (log2, -0.0);
TESTIT (log10, -1.0);
TESTIT (log10, 0.0);
TESTIT (log10, -0.0);
/* The log1p arg must be [-1 ... Inf] EXclusive. */
TESTIT (log1p, -2.0);
TESTIT (log1p, -1.0);
}
/* { dg-final { scan-tree-dump-times "exp2 " 9 "original" } } */
@ -107,4 +100,16 @@ void bar()
/* { dg-final { scan-tree-dump-times "atanh " 2 "original" } } */
/* { dg-final { scan-tree-dump-times "atanhf" 2 "original" } } */
/* { dg-final { scan-tree-dump-times "atanhl" 2 "original" } } */
/* { dg-final { scan-tree-dump-times "log " 3 "original" } } */
/* { dg-final { scan-tree-dump-times "logf" 3 "original" } } */
/* { dg-final { scan-tree-dump-times "logl" 3 "original" } } */
/* { dg-final { scan-tree-dump-times "log2 " 3 "original" } } */
/* { dg-final { scan-tree-dump-times "log2f" 3 "original" } } */
/* { dg-final { scan-tree-dump-times "log2l" 3 "original" } } */
/* { dg-final { scan-tree-dump-times "log10 " 3 "original" } } */
/* { dg-final { scan-tree-dump-times "log10f" 3 "original" } } */
/* { dg-final { scan-tree-dump-times "log10l" 3 "original" } } */
/* { dg-final { scan-tree-dump-times "log1p " 2 "original" } } */
/* { dg-final { scan-tree-dump-times "log1pf" 2 "original" } } */
/* { dg-final { scan-tree-dump-times "log1pl" 2 "original" } } */
/* { dg-final { cleanup-tree-dump "original" } } */

View File

@ -7,6 +7,9 @@
/* { dg-do link } */
/* Define "e" with as many bits as found in builtins.c:dconste. */
#define M_E 2.7182818284590452353602874713526624977572470936999595749669676277241
/* All references to link_error should go away at compile-time. */
extern void link_error(int);
@ -34,18 +37,22 @@ int main (void)
{
TESTIT2 (asin, -1.0, -3.15/2.0, -3.14/2.0); /* asin(-1) == -pi/2 */
TESTIT (asin, 0.0, 0.0); /* asin(0) == 0 */
TESTIT (asin, -0.0, -0.0); /* asin(-0) == -0 */
TESTIT2 (asin, 1.0, 3.14/2.0, 3.15/2.0); /* asin(1) == pi/2 */
TESTIT2 (acos, -1.0, 3.14, 3.15); /* acos(-1) == pi */
TESTIT2 (acos, 0.0, 3.14/2.0, 3.15/2.0); /* acos(0) == pi/2 */
TESTIT2 (acos, -0.0, 3.14/2.0, 3.15/2.0); /* acos(-0) == pi/2 */
TESTIT (acos, 1.0, 0.0); /* acos(1) == 0 */
TESTIT2 (atan, -1.0, -3.15/4.0, -3.14/4.0); /* atan(-1) == -pi/4 */
TESTIT (atan, 0.0, 0.0); /* atan(0) == 0 */
TESTIT (atan, -0.0, -0.0); /* atan(-0) == -0 */
TESTIT2 (atan, 1.0, 3.14/4.0, 3.15/4.0); /* atan(1) == pi/4 */
TESTIT2 (asinh, -1.0, -0.89, -0.88); /* asinh(-1) == -0.881... */
TESTIT (asinh, 0.0, 0.0); /* asinh(0) == 0 */
TESTIT (asinh, -0.0, -0.0); /* asinh(-0) == -0 */
TESTIT2 (asinh, 1.0, 0.88, 0.89); /* asinh(1) == 0.881... */
TESTIT (acosh, 1.0, 0.0); /* acosh(1) == 0. */
@ -53,47 +60,97 @@ int main (void)
TESTIT2 (atanh, -0.5, -0.55, -0.54); /* atanh(-0.5) == -0.549... */
TESTIT (atanh, 0.0, 0.0); /* atanh(0) == 0 */
TESTIT (atanh, -0.0, -0.0); /* atanh(-0) == -0 */
TESTIT2 (atanh, 0.5, 0.54, 0.55); /* atanh(0.5) == 0.549... */
TESTIT2 (sin, -1.0, -0.85, -0.84); /* sin(-1) == -0.841... */
TESTIT (sin, 0.0, 0.0); /* sin(0) == 0 */
TESTIT (sin, -0.0, -0.0); /* sin(-0) == -0 */
TESTIT2 (sin, 1.0, 0.84, 0.85); /* sin(1) == 0.841... */
TESTIT2 (cos, -1.0, 0.54, 0.55); /* cos(-1) == 0.5403... */
TESTIT (cos, 0.0, 1.0); /* cos(0) == 1 */
TESTIT (cos, -0.0, 1.0); /* cos(-0) == 1 */
TESTIT2 (cos, 1.0, 0.54, 0.55); /* cos(1) == 0.5403... */
TESTIT2 (tan, -1.0, -1.56, 1.55); /* tan(-1) == -1.557... */
TESTIT (tan, 0.0, 0.0); /* tan(0) == 0 */
TESTIT (tan, -0.0, -0.0); /* tan(-0) == -0 */
TESTIT2 (tan, 1.0, 1.55, 1.56); /* tan(1) == 1.557... */
TESTIT2 (sinh, -1.0, -1.18, -1.17); /* sinh(-1) == -1.175... */
TESTIT (sinh, 0.0, 0.0); /* sinh(0) == 0 */
TESTIT (sinh, -0.0, -0.0); /* sinh(-0) == -0 */
TESTIT2 (sinh, 1.0, 1.17, 1.18); /* sinh(1) == 1.175... */
TESTIT2 (cosh, -1.0, 1.54, 1.55); /* cosh(-1) == 1.543... */
TESTIT (cosh, 0.0, 1.0); /* cosh(0) == 1 */
TESTIT (cosh, -0.0, 1.0); /* cosh(-0) == 1 */
TESTIT2 (cosh, 1.0, 1.54, 1.55); /* cosh(1) == 1.543... */
TESTIT2 (tanh, -1.0, -0.77, -0.76); /* tanh(-1) == -0.761... */
TESTIT (tanh, -0.0, -0.0); /* tanh(-0) == -0 */
TESTIT (tanh, 0.0, 0.0); /* tanh(0) == 0 */
TESTIT2 (tanh, 1.0, 0.76, 0.77); /* tanh(1) == 0.761... */
TESTIT2 (exp, -1.0, 0.36, 0.37); /* exp(-1) == 1/e */
TESTIT (exp, -0.0, 1.0); /* exp(-0) == 1 */
TESTIT (exp, 0.0, 1.0); /* exp(0) == 1 */
TESTIT2 (exp, 1.0, 2.71, 2.72); /* exp(1) == e */
TESTIT (exp2, -1.0, 0.5); /* exp2(-1) == 1/2 */
TESTIT (exp2, -0.0, 1.0); /* exp2(-0) == 1 */
TESTIT (exp2, 0.0, 1.0); /* exp2(0) == 1 */
TESTIT (exp2, 1.0, 2.0); /* exp2(1) == 2 */
TESTIT (exp10, -1.0, 0.1); /* exp10(-1) == 1/10 */
TESTIT (exp10, -0.0, 1.0); /* exp10(-0) == 1 */
TESTIT (exp10, 0.0, 1.0); /* exp10(0) == 1 */
TESTIT (exp10, 1.0, 10.0); /* exp10(1) == 10 */
TESTIT (pow10, -1.0, 0.1); /* pow10(-1) == 1/10 */
TESTIT (pow10, -0.0, 1.0); /* pow10(-0) == 1 */
TESTIT (pow10, 0.0, 1.0); /* pow10(0) == 1 */
TESTIT (pow10, 1.0, 10.0); /* pow10(1) == 10 */
TESTIT2 (expm1, -1.0, -0.64, -0.63); /* expm1(-1) == 1/e - 1 */
TESTIT (expm1, -0.0, -0.0); /* expm1(-0) == 0 */
TESTIT (expm1, 0.0, 0.0); /* expm1(0) == 0 */
TESTIT2 (expm1, 1.0, 1.71, 1.72); /* expm1(1) == e - 1 */
TESTIT (log, 1.0, 0.0); /* log(1) == 0 */
TESTIT2 (log, M_E, 0.99, 1.01); /* log(e) == 1.000... */
TESTIT2 (log, M_E*M_E, 1.99, 2.01); /* log(e*e) == 2.000... */
TESTIT (log2, 1.0, 0.0); /* log2(1) == 0 */
TESTIT (log2, 2.0, 1.0); /* log2(2) == 1 */
TESTIT (log2, 4.0, 2.0); /* log2(4) == 2 */
TESTIT (log10, 1.0, 0.0); /* log10(1) == 0 */
TESTIT (log10, 10.0, 1.0); /* log10(10) == 1 */
TESTIT (log10, 100.0, 2.0); /* log10(100) == 2 */
TESTIT (log1p, 0.0, 0.0); /* log1p(0) == 0 */
TESTIT (log1p, -0.0, -0.0); /* log1p(-0) == -0 */
TESTIT2 (log1p, M_E-1, 0.99, 1.01); /* log1p(e-1) == 1.000... */
TESTIT2 (log1p, M_E*M_E-1, 1.99, 2.01); /* log1p(e*e-1) == 2.000... */
TESTIT (cbrt, -0.0, -0.0); /* cbrt(-0) == -0 */
TESTIT (cbrt, 0.0, 0.0); /* cbrt(0) == 0 */
TESTIT (cbrt, 1.0, 1.0); /* cbrt(1) == 1 */
TESTIT (cbrt, -1.0, -1.0); /* cbrt(-1) == -1 */
TESTIT (cbrt, 8.0, 2.0); /* cbrt(8) == 2 */
TESTIT (cbrt, -8.0, -2.0); /* cbrt(-8) == -2 */
TESTIT (erf, -0.0, -0.0); /* erf(-0) == -0 */
TESTIT (erf, 0.0, 0.0); /* erf(0) == 0 */
TESTIT2 (erf, 1.0, 0.84, 0.85); /* erf(1) == 0.842... */
TESTIT2 (erf, -1.0, -0.85, -0.84); /* erf(-1) == -0.842... */
TESTIT (erfc, -0.0, 1.0); /* erfc(-0) == 1 */
TESTIT (erfc, 0.0, 1.0); /* erfc(0) == 1 */
TESTIT2 (erfc, 1.0, 0.15, 0.16); /* erfc(1) == 0.157... */
TESTIT2 (erfc, -1.0, 1.84, 1.85); /* erfc(-1) == 1.842... */
return 0;
}