Hi,
when accumulator transformation is performed on a function like
foo(a)
{
if (a > 0)
return 1 + foo (a - 1)
return bla();
}
this becomes
foo(a)
{
int tmp = 0;
while (a > 0)
tm = 1 + tmp;
return tmp + bla();
}
Before, bla was a tail-call, but after the optimization, it is not (since an
addition
has to be performed after the result of bla is known). However, we used to
mark bla
as tail-call, leading to a misscompilation later. Fixed by not marking
tail-calls
when the transformation is performed. Bootstrapped and regtested on i686.
Zdenek
PR tree-optimization/48837
* tree-tailcall.c (tree_optimize_tail_calls_1): Do not mark tailcalls
when accumulator transformation is performed.
* gcc.dg/pr48837.c: New testcase.
Index: tree-tailcall.c
===================================================================
--- tree-tailcall.c (revision 173354)
+++ tree-tailcall.c (working copy)
@@ -1021,6 +1021,14 @@ tree_optimize_tail_calls_1 (bool opt_tailcalls)
integer_one_node);
}
+ if (a_acc || m_acc)
+ {
+ /* When the tail call elimination using accumulators is performed,
+ statements adding the accumulated value are inserted at all exits.
+ This turns all other tail calls to non-tail ones. */
+ opt_tailcalls = false;
+ }
+
for (; tailcalls; tailcalls = next)
{
next = tailcalls->next;
Index: testsuite/gcc.dg/pr48837.c
===================================================================
--- testsuite/gcc.dg/pr48837.c (revision 0)
+++ testsuite/gcc.dg/pr48837.c (revision 0)
@@ -0,0 +1,30 @@
+/* PR tree-optimization/48837 */
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+void abort (void);
+
+__attribute__((noinline))
+int baz(void)
+{
+ return 1;
+}
+
+inline const int *bar(const int *a, const int *b)
+{
+ return *a ? a : b;
+}
+
+int foo(int a, int b)
+{
+ return a || b ? baz() : foo(*bar(&a, &b), 1) + foo(1, 0);
+}
+
+int main(void)
+{
+ if (foo(0, 0) != 2)
+ abort();
+
+ return 0;
+}
+