This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Constant fold sqrt at compile time (take 2)
- From: Roger Sayle <roger at eyesopen dot com>
- To: <gcc-patches at gcc dot gnu dot org>
- Cc: Richard Henderson <rth at redhat dot com>
- Date: Sat, 2 Nov 2002 21:29:19 -0700 (MST)
- Subject: [PATCH] Constant fold sqrt at compile time (take 2)
On Thu, 31 Oct 2002, Richard Henderson wrote:
> > Can this now be replaced with the less restrictive
> > "flag_signaling_nans", and evaluate everything
> > except "sqrt(sNaN)"?
>
> I expect so.
This is the next iteration of my patch to evaluate sqrt with a constant
argument at compile time. Richard Henderson pointed out that there
was no reason worry about errno in real.c, as GCC always generates
code to test for a NaN return value if errno needs to be updated.
This both simplifies the real_sqrt interface and produces better code.
The final form and implementation of real_sqrt is still under
development. As with my original patch, the implementation below
serves as a framework for further investigation, and approximates
sqrt to about 2 ulps. For this reason, this functionality is
currently guarded by "-ffast-math" until a "perfectly rounded"
solution is implemented/contributed.
One feature that would be nice, is for real.c to provide a
real_issnan (for testing for signaling NaNs) in addition to
the current real_isnan.
The revision below has been tested on the 3.4 BIB with a complete
bootstrap (all languages except Ada and treelang) and "make -k check"
on i686-pc-linux-gnu with no new regressions.
Ok for the gcc-3_4-basic-improvements-branch?
2002-11-02 Roger Sayle <roger@eyesopen.com>
* real.c (real_sqrt): New function to calculate square roots.
* real.h (real_sqrt): Add function prototype.
* builtins.c (fold_builtin): Fold sqrt of constant argument.
* simplify-rtx.c (simplify_unary_operation): Simplify sqrt
of constant argument.
Index: real.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/real.c,v
retrieving revision 1.75.4.7
diff -c -3 -p -r1.75.4.7 real.c
*** real.c 28 Oct 2002 19:47:07 -0000 1.75.4.7
--- real.c 2 Nov 2002 11:10:37 -0000
*************** const struct real_format *real_format_fo
*** 4381,4383 ****
--- 4381,4456 ----
NULL, /* XFmode */
&ieee_quad_format /* TFmode */
};
+
+
+ /* Calculate the square root of X in mode MODE, and store the result
+ in R. */
+
+ void
+ real_sqrt (r, mode, x)
+ REAL_VALUE_TYPE *r;
+ enum machine_mode mode;
+ const REAL_VALUE_TYPE *x;
+ {
+ static REAL_VALUE_TYPE halfthree;
+ static REAL_VALUE_TYPE half;
+ static bool init = false;
+ REAL_VALUE_TYPE h, t, i;
+ int iter, exp;
+
+ /* sqrt(-0.0) is -0.0. */
+ if (real_isnegzero (x))
+ {
+ *r = *x;
+ return;
+ }
+
+ /* Negative arguments return NaN. */
+ if (real_isneg (x))
+ {
+ /* Mode is ignored for canonical NaN. */
+ real_nan (r, "", 1, SFmode);
+ return;
+ }
+
+ /* Infinity and NaN return themselves. */
+ if (real_isinf (x) || real_isnan (x))
+ {
+ *r = *x;
+ return;
+ }
+
+ if (!init)
+ {
+ real_arithmetic (&half, RDIV_EXPR, &dconst1, &dconst2);
+ real_arithmetic (&halfthree, PLUS_EXPR, &dconst1, &half);
+ init = true;
+ }
+
+ /* Initial guess for reciprocal sqrt, i. */
+ exp = real_exponent (x);
+ real_ldexp (&i, &dconst1, -exp/2);
+
+ /* Newton's iteration for reciprocal sqrt, i */
+ for (iter = 0; iter < 16; iter++)
+ {
+ /* i(n+1) = i(n) * (1.5 - 0.5*i(n)*i(n)*x). */
+ real_arithmetic (&t, MULT_EXPR, x, &i);
+ real_arithmetic (&h, MULT_EXPR, &t, &i);
+ real_arithmetic (&t, MULT_EXPR, &h, &half);
+ real_arithmetic (&h, MINUS_EXPR, &halfthree, &t);
+ real_arithmetic (&t, MULT_EXPR, &i, &h);
+
+ /* Check for early convergence. */
+ if (iter >= 6 && real_identical (&i, &t))
+ break;
+
+ /* ??? Unroll loop to avoid copying. */
+ i = t;
+ }
+
+ /* Final result is original value, x, multiplied by i. */
+ real_arithmetic (&t, MULT_EXPR, &i, x);
+ real_convert (r, mode, &t);
+ }
+
Index: real.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/real.h,v
retrieving revision 1.44.8.6
diff -c -3 -p -r1.44.8.6 real.h
*** real.h 28 Oct 2002 19:47:08 -0000 1.44.8.6
--- real.h 2 Nov 2002 11:10:38 -0000
*************** extern bool exact_real_inverse PARAMS ((
*** 346,350 ****
--- 346,354 ----
/* In tree.c: wrap up a REAL_VALUE_TYPE in a tree node. */
extern tree build_real PARAMS ((tree, REAL_VALUE_TYPE));
+ /* Calculate R as the square root of X in the given machine mode. */
+ extern void real_sqrt PARAMS ((REAL_VALUE_TYPE *,
+ enum machine_mode,
+ const REAL_VALUE_TYPE *));
#endif /* ! GCC_REAL_H */
Index: builtins.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/builtins.c,v
retrieving revision 1.159.4.3
diff -c -3 -p -r1.159.4.3 builtins.c
*** builtins.c 17 Sep 2002 22:58:36 -0000 1.159.4.3
--- builtins.c 2 Nov 2002 11:10:38 -0000
*************** fold_builtin (exp)
*** 4241,4249 ****
enum built_in_function fcode;
tree arg = TREE_VALUE (arglist);
! /* Optimize sqrt(0.0) = 0.0 and sqrt(1.0) = 1.0. */
! if (real_zerop (arg) || real_onep (arg))
! return arg;
/* Optimize sqrt(exp(x)) = exp(x/2.0). */
fcode = builtin_mathfn_code (arg);
--- 4241,4260 ----
enum built_in_function fcode;
tree arg = TREE_VALUE (arglist);
! /* Optimize sqrt of constant value. */
! if (flag_unsafe_math_optimizations
! && TREE_CODE (arg) == REAL_CST
! && ! TREE_CONSTANT_OVERFLOW (arg))
! {
! REAL_VALUE_TYPE r, x;
!
! x = TREE_REAL_CST (arg);
! if (!flag_signaling_nans || !real_isnan (&x))
! {
! real_sqrt (&r, TYPE_MODE (TREE_TYPE (arg)), &x);
! return build_real (TREE_TYPE (arg), r);
! }
! }
/* Optimize sqrt(exp(x)) = exp(x/2.0). */
fcode = builtin_mathfn_code (arg);
Index: simplify-rtx.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/simplify-rtx.c,v
retrieving revision 1.118.4.6
diff -c -3 -p -r1.118.4.6 simplify-rtx.c
*** simplify-rtx.c 21 Oct 2002 17:52:02 -0000 1.118.4.6
--- simplify-rtx.c 2 Nov 2002 11:10:39 -0000
*************** simplify_unary_operation (code, mode, op
*** 571,585 ****
else if (GET_CODE (trueop) == CONST_DOUBLE
&& GET_MODE_CLASS (mode) == MODE_FLOAT)
{
! REAL_VALUE_TYPE d;
REAL_VALUE_FROM_CONST_DOUBLE (d, trueop);
switch (code)
{
case SQRT:
! /* We don't attempt to optimize this. */
! return 0;
!
case ABS:
d = REAL_VALUE_ABS (d);
break;
--- 571,589 ----
else if (GET_CODE (trueop) == CONST_DOUBLE
&& GET_MODE_CLASS (mode) == MODE_FLOAT)
{
! REAL_VALUE_TYPE d, t;
REAL_VALUE_FROM_CONST_DOUBLE (d, trueop);
switch (code)
{
case SQRT:
! if (! flag_unsafe_math_optimizations)
! return 0;
! if (flag_signaling_nans && real_isnan (&d))
! return 0;
! real_sqrt (&t, mode, &d);
! d = t;
! break;
case ABS:
d = REAL_VALUE_ABS (d);
break;
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