This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: Tail calls and floating-point types
Richard Henderson <rth@redhat.com> writes:
> Yeah, a check for HONOR_SIGNED_ZEROS would do the trick.
I realised later that the transformed code was doing the multiplications
and additions in the opposite order to the original. That's obviously
much more serious than the toy -0 example from my earlier message.
New testcases attached.
The patch below fixes all three tests. Would it be OK if it passes
bootstrap? Or would a different check be better? The tree-ssa code
is still new to me so I'm not sure how this sort of thing should
be written.
Richard
* tree-tailcall.c (process_assignment): Only do accumulator
optimisations if the function has an integral return type.
testsuite/
* gcc.c-torture/execute/ieee/acc1.c: New test.
* gcc.c-torture/execute/ieee/acc2.c: New test.
* gcc.c-torture/execute/ieee/mzero6.c: New test.
Index: tree-tailcall.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-tailcall.c,v
retrieving revision 2.24
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r2.24 tree-tailcall.c
*** tree-tailcall.c 7 Sep 2004 10:22:44 -0000 2.24
--- tree-tailcall.c 10 Sep 2004 06:51:36 -0000
*************** process_assignment (tree ass, tree stmt,
*** 283,288 ****
--- 283,295 ----
if (TREE_CODE_CLASS (code) != '2')
return false;
+ /* Accumulator optimizations will reverse the order of operations.
+ We can only do that for floating-point types if we're assuming
+ that addition and multiplication are associative. */
+ if (!flag_unsafe_math_optimizations)
+ if (FLOAT_TYPE_P (TREE_TYPE (DECL_RESULT (current_function_decl))))
+ return false;
+
/* We only handle the code like
x = call ();
*** /dev/null Fri Apr 23 00:21:55 2004
--- testsuite/gcc.c-torture/execute/ieee/acc1.c Thu Sep 9 22:09:12 2004
***************
*** 0 ****
--- 1,18 ----
+ /* Tail call optimizations would reverse the order of additions in func(). */
+
+ double func (const double *array)
+ {
+ double d = *array;
+ if (d == 0.0)
+ return d;
+ else
+ return d + func (array + 1);
+ }
+
+ int main ()
+ {
+ double values[] = { 0.1e-100, 1.0, -1.0, 0.0 };
+ if (func (values) != 0.1e-100)
+ abort ();
+ exit (0);
+ }
*** /dev/null Fri Apr 23 00:21:55 2004
--- testsuite/gcc.c-torture/execute/ieee/acc2.c Fri Sep 10 07:50:19 2004
***************
*** 0 ****
--- 1,19 ----
+ /* Tail call optimizations would reverse the order of multiplications
+ in func(). */
+
+ double func (const double *array)
+ {
+ double d = *array;
+ if (d == 1.0)
+ return d;
+ else
+ return d * func (array + 1);
+ }
+
+ int main ()
+ {
+ double values[] = { __DBL_MAX__, 2.0, 0.5, 1.0 };
+ if (func (values) != __DBL_MAX__)
+ abort ();
+ exit (0);
+ }
*** /dev/null Fri Apr 23 00:21:55 2004
--- testsuite/gcc.c-torture/execute/ieee/mzero6.c Thu Sep 9 22:07:33 2004
***************
*** 0 ****
--- 1,24 ----
+ /* Tail call optimizations would convert func() into the moral equivalent of:
+
+ double acc = 0.0;
+ for (int i = 0; i <= n; i++)
+ acc += d;
+ return acc;
+
+ which mishandles the case where 'd' is -0. They also initialised 'acc'
+ to a zero int rather than a zero double. */
+
+ double func (double d, int n)
+ {
+ if (n == 0)
+ return d;
+ else
+ return d + func (d, n - 1);
+ }
+
+ int main ()
+ {
+ if (__builtin_copysign (1.0, func (0.0 / -5.0, 10)) != -1.0)
+ abort ();
+ exit (0);
+ }