This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] More constant folding of math built-ins.
- From: Roger Sayle <roger at eyesopen dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 28 May 2003 20:23:16 -0600 (MDT)
- Subject: [PATCH] More constant folding of math built-ins.
The following patch implements some more constant folding optimizations
of GCC's mathematical builtins. We now optimize tan(0.0) = 0.0,
atan(0.0) = 0.0, exp(1.0) = e, atan(1) = pi/4, atan(tan(x)) = x
(with -funsafe-math-optimizations) and evaluate exp(x) when x is
an integer constant (also with -funsafe-math-optimizations).
This patch also includes a bug fix. The IEEE standard requires that
sin(-0.0) = -0.0, and similarly for tan and atan. This is corrected
with this patch, which also contains a new test case to catch this.
I'm particularly happy with the atan(1.0) = pi/4. It is a common
idiom, to write code such as double "pi = 4*atan(1);", indeed it
occurs several times in the SPEC benchmark suite, and can now be
evaluated at compile-time. Indeed, on x86, "4*atanl(1)" will now
generate the x87's "fldpi" instruction!
The following patch has been tested on i686-pc-linux-gnu with a
complete bootstrap, all languages except treelang (including Ada),
and regression tested with a top-level "make -k check" with no new
failures.
Ok for mainline?
2003-05-28 Roger Sayle <roger@eyesopen.com>
* builtins.c (dconstpi, dconste): New mathematical constants.
(init_builtin_dconsts): New function to initialize dconstpi
and dconste.
(fold_builtin): Optimize exp(1.0) = e. Evaluate exp(x) at
compile time with -ffast-math when x is an integer constant.
Optimize tan(0.0) = 0.0. Optimize atan(0.0) = 0.0,
atan(1.0) = pi/4 and atan(tan(x)) = x with -ffast-math.
* gcc.dg/builtins-2.c: Add tests for atan(tan(x)).
* gcc.dg/builtins-3.c: Add tests for tan(0.0) and atan(0.0).
* gcc.dg/builtins-7.c: Add tests for atan(tan(x)) == x.
* gcc.dg/builtins-17.c: New test case.
* gcc.dg/i386-387-4.c: New test case.
* gcc.c-torture/execute/ieee/mzero4.c: New test case.
Index: builtins.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/builtins.c,v
retrieving revision 1.203
diff -c -3 -p -r1.203 builtins.c
*** builtins.c 23 May 2003 20:45:38 -0000 1.203
--- builtins.c 27 May 2003 13:06:22 -0000
*************** tree built_in_decls[(int) END_BUILTINS];
*** 79,84 ****
--- 79,89 ----
required to implement the function call in all cases. */
tree implicit_built_in_decls[(int) END_BUILTINS];
+ /* Trigonometric and mathematical constants used in builtin folding. */
+ static bool builtin_dconsts_init = 0;
+ static REAL_VALUE_TYPE dconstpi;
+ static REAL_VALUE_TYPE dconste;
+
static int get_pointer_alignment PARAMS ((tree, unsigned int));
static tree c_strlen PARAMS ((tree));
static const char *c_getstr PARAMS ((tree));
*************** static tree fold_builtin_nan PARAMS ((t
*** 169,174 ****
--- 174,194 ----
static int validate_arglist PARAMS ((tree, ...));
static tree fold_trunc_transparent_mathfn PARAMS ((tree));
static bool readonly_data_expr PARAMS ((tree));
+ static void init_builtin_dconsts PARAMS ((void));
+
+ /* Initialize mathematical constants for constant folding builtins.
+ These constants need to be given to atleast 160 bits precision. */
+
+ static void
+ init_builtin_dconsts ()
+ {
+ real_from_string (&dconstpi,
+ "3.1415926535897932384626433832795028841971693993751058209749445923078");
+ real_from_string (&dconste,
+ "2.7182818284590452353602874713526624977572470936999595749669676277241");
+
+ builtin_dconsts_init = true;
+ }
/* Return the alignment in bits of EXP, a pointer valued expression.
But don't return more than MAX_ALIGN no matter what.
*************** fold_builtin (exp)
*** 5117,5123 ****
/* Optimize sin(0.0) = 0.0. */
if (real_zerop (arg))
! return build_real (type, dconst0);
}
break;
--- 5137,5143 ----
/* Optimize sin(0.0) = 0.0. */
if (real_zerop (arg))
! return arg;
}
break;
*************** fold_builtin (exp)
*** 5146,5151 ****
--- 5166,5206 ----
if (real_zerop (arg))
return build_real (type, dconst1);
+ /* Optimize exp(1.0) = e. */
+ if (real_onep (arg))
+ {
+ REAL_VALUE_TYPE cst;
+
+ if (! builtin_dconsts_init)
+ init_builtin_dconsts ();
+ real_convert (&cst, TYPE_MODE (type), &dconste);
+ return build_real (type, cst);
+ }
+
+ /* Attempt to evaluate exp 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;
+
+ if (! builtin_dconsts_init)
+ init_builtin_dconsts ();
+ real_powi (&x, TYPE_MODE (type), &dconste, n);
+ return build_real (type, x);
+ }
+ }
+
/* Optimize exp(log(x)) = x. */
fcode = builtin_mathfn_code (arg);
if (flag_unsafe_math_optimizations
*************** fold_builtin (exp)
*** 5205,5210 ****
--- 5260,5312 ----
}
break;
+ case BUILT_IN_TAN:
+ case BUILT_IN_TANF:
+ case BUILT_IN_TANL:
+ if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+ {
+ tree arg = TREE_VALUE (arglist);
+
+ /* Optimize tan(0.0) = 0.0. */
+ if (real_zerop (arg))
+ return arg;
+ }
+ break;
+
+ case BUILT_IN_ATAN:
+ case BUILT_IN_ATANF:
+ case BUILT_IN_ATANL:
+ if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+ {
+ enum built_in_function fcode;
+ tree arg = TREE_VALUE (arglist);
+
+ /* Optimize atan(0.0) = 0.0. */
+ if (real_zerop (arg))
+ return arg;
+
+ /* Optimize atan(1.0) = pi/4. */
+ if (real_onep (arg))
+ {
+ REAL_VALUE_TYPE cst;
+
+ if (! builtin_dconsts_init)
+ init_builtin_dconsts ();
+ real_convert (&cst, TYPE_MODE (type), &dconstpi);
+ cst.exp -= 2;
+ return build_real (type, cst);
+ }
+
+ /* Optimize atan(tan(x)) = x. */
+ fcode = builtin_mathfn_code (arg);
+ if (flag_unsafe_math_optimizations
+ && (fcode == BUILT_IN_TAN
+ || fcode == BUILT_IN_TANF
+ || fcode == BUILT_IN_TANL))
+ return TREE_VALUE (TREE_OPERAND (arg, 1));
+ }
+ break;
+
case BUILT_IN_POW:
case BUILT_IN_POWF:
case BUILT_IN_POWL:
*************** fold_builtin (exp)
*** 5291,5297 ****
REAL_VALUE_TYPE cint;
HOST_WIDE_INT n;
! n = real_to_integer(&c);
real_from_integer (&cint, VOIDmode, n,
n < 0 ? -1 : 0, 0);
if (real_identical (&c, &cint))
--- 5393,5399 ----
REAL_VALUE_TYPE cint;
HOST_WIDE_INT n;
! n = real_to_integer (&c);
real_from_integer (&cint, VOIDmode, n,
n < 0 ? -1 : 0, 0);
if (real_identical (&c, &cint))
Index: builtins-2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/gcc.dg/builtins-2.c,v
retrieving revision 1.2
diff -c -3 -p -r1.2 builtins-2.c
*** builtins-2.c 16 Dec 2002 18:22:43 -0000 1.2
--- builtins-2.c 26 May 2003 17:40:17 -0000
*************** double test9(double x)
*** 53,58 ****
--- 53,63 ----
return fabs(exp(x));
}
+ double test10(double x)
+ {
+ return atan(tan(x));
+ }
+
float test1f(float x)
{
return logf(expf(x));
*************** float test9f(float x)
*** 98,103 ****
--- 103,113 ----
return fabsf(expf(x));
}
+ float test10f(float x)
+ {
+ return atanf(tanf(x));
+ }
+
long double test1l(long double x)
{
return logl(expl(x));
*************** long double test9l(long double x)
*** 143,146 ****
--- 153,160 ----
return fabsl(expl(x));
}
+ long double test10l(long double x)
+ {
+ return atanl(tanl(x));
+ }
Index: builtins-3.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/gcc.dg/builtins-3.c,v
retrieving revision 1.3
diff -c -3 -p -r1.3 builtins-3.c
*** builtins-3.c 31 Mar 2003 14:30:29 -0000 1.3
--- builtins-3.c 26 May 2003 17:40:17 -0000
*************** int main()
*** 30,35 ****
--- 30,41 ----
if (cos (0.0) != 1.0)
link_error ();
+ if (tan (0.0) != 0.0)
+ link_error ();
+
+ if (atan (0.0) != 0.0)
+ link_error ();
+
if (sqrtf (0.0f) != 0.0f)
link_error ();
*************** int main()
*** 49,54 ****
--- 55,65 ----
if (cosf (0.0f) != 1.0f)
link_error ();
+ if (tanf (0.0f) != 0.0f)
+ link_error ();
+
+ if (atanf (0.0f) != 0.0f)
+ link_error ();
if (sqrtl (0.0l) != 0.0l)
link_error ();
*************** int main()
*** 66,71 ****
--- 77,88 ----
link_error ();
if (cosl (0.0l) != 1.0l)
+ link_error ();
+
+ if (tanl (0.0l) != 0.0l)
+ link_error ();
+
+ if (atanl (0.0) != 0.0l)
link_error ();
return 0;
Index: builtins-7.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/gcc.dg/builtins-7.c,v
retrieving revision 1.1
diff -c -3 -p -r1.1 builtins-7.c
*** builtins-7.c 31 Mar 2003 14:30:29 -0000 1.1
--- builtins-7.c 26 May 2003 17:40:17 -0000
*************** void test(double x)
*** 14,30 ****
--- 14,36 ----
{
if (pow (x, 1.0) != x)
link_error ();
+ if (atan (tan (x)) != x)
+ link_error ();
}
void testf(float x)
{
if (powf (x, 1.0f) != x)
link_error ();
+ if (atanf (tanf (x)) != x)
+ link_error ();
}
void testl(long double x)
{
if (powl (x, 1.0l) != x)
+ link_error ();
+ if (atanl (tanl (x)) != x)
link_error ();
}
/* Copyright (C) 2003 Free Software Foundation.
Check that constant folding of built-in math functions doesn't
break anything and produces the expected results.
Written by Roger Sayle, 25th May 2003. */
/* { dg-do link } */
/* { dg-options "-O2 -ffast-math" } */
extern void link_error(void);
extern double exp(double);
int main()
{
if (exp (1.0) < 2.71 || exp (1.0) > 2.72)
link_error ();
if (exp (2.0) < 7.38 || exp (2.0) > 7.39)
link_error ();
if (exp (-2.0) < 0.13 || exp (-2.0) > 0.14)
link_error ();
if (atan (1.0) < 0.78 || atan (1.0) > 0.79)
link_error ();
return 0;
}
/* { dg-do compile { target "i?86-*-*" } } */
/* { dg-options "-O2 -march=i686" } */
/* { dg-final { scan-assembler "fldpi" } } */
long double atanl (long double);
long double pi()
{
return 4.0 * atanl (1.0);
}
/* Copyright (C) 2003 Free Software Foundation.
by Roger Sayle <roger@eyesopen.com>, derived from mzero3.c
Constant folding of sin(-0.0), tan(-0.0) and atan(-0.0) should
all return -0.0, for both double and float forms. */
void abort (void);
typedef __SIZE_TYPE__ size_t;
extern int memcmp (const void *, const void *, size_t);
double sin (double);
double tan (double);
double atan (double);
float sinf (float);
float tanf (float);
float atanf (float);
void expectd (double, double);
void expectf (float, float);
void
expectd (double value, double expected)
{
if (value != expected
|| memcmp ((void *)&value, (void *) &expected, sizeof (double)) != 0)
abort ();
}
void
expectf (float value, float expected)
{
if (value != expected
|| memcmp ((void *)&value, (void *) &expected, sizeof (float)) != 0)
abort ();
}
int main ()
{
expectd (sin (0.0), 0.0);
expectd (tan (0.0), 0.0);
expectd (atan (0.0), 0.0);
expectd (sin (-0.0), -0.0);
expectd (tan (-0.0), -0.0);
expectd (atan (-0.0), -0.0);
expectf (sinf (0.0f), 0.0f);
expectf (tanf (0.0f), 0.0f);
expectf (atanf (0.0f), 0.0f);
expectf (sinf (-0.0f), -0.0f);
expectf (tanf (-0.0f), -0.0f);
expectf (atanf (-0.0f), -0.0f);
return 0;
}
Roger
--
Roger Sayle, E-mail: roger@eyesopen.com
OpenEye Scientific Software, WWW: http://www.eyesopen.com/
Suite 1107, 3600 Cerrillos Road, Tel: (+1) 505-473-7385
Santa Fe, New Mexico, 87507. Fax: (+1) 505-473-0833