This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[3.4 only] PR middle-end/21964: tail recursion and postincrements


This patch fixes a 3.4-only regression from 2.95.  We try to apply
tail call optimisations to functions like:

   void foo (int n) { ... foo (new_n); }

giving the equivalent of:

   void foo (int n) { lab: ... n = new_n'; goto lab; }

However, because of the way the code is expanded, if new_n contains a
post-modification of "n", the post-modification will win.  For example,
the tail-recursion optimisers will treat:

   void foo (int n) { ... foo (n++); }

like:

   void foo (int n) { ... foo (n + 1); }

rather than the correct:

   void foo (int n) { ... foo (n); }

I think the problem is simply a missing "emit_queue ()".  The assignments
to the argument variables are simulating a function call, and since there's
a sequence point before the call, we should flush all post-modifications
at that point.

Bootstrapped & regression tested on i686-pc-linux-gnu.  OK for 3.4?
If so, I'll apply the (working) testcase to 4.0 and 4.1 too.

Richard


	PR middle-end/21964
	* stmt.c (tail_recursion_args): Insert a call to emit_queue.

testsuite/
	PR middle-end/21964
	* gcc.c-torture/execute/pr21964-1.c: New test.

Index: stmt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/stmt.c,v
retrieving revision 1.342.2.3
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.342.2.3 stmt.c
*** stmt.c 6 May 2004 23:32:47 -0000 1.342.2.3
--- stmt.c 1 Aug 2005 08:54:23 -0000
*************** tail_recursion_args (tree actuals, tree 
*** 3353,3358 ****
--- 3353,3364 ----
  	argvec[i] = copy_to_reg (argvec[i]);
      }
  
+   /* Insert the pre-call sequence point.  This is important in cases
+      where the actual values post-modify the formals: we want the final
+      values of the formals to be the ones that we assign below, not the
+      result of the post-modification.  */
+   emit_queue ();
+ 
    /* Store the values of the actuals into the formals.  */
  
    for (f = formals, a = actuals, i = 0; f;
diff -c /dev/null testsuite/gcc.c-torture/execute/pr21964-1.c
*** /dev/null	2005-06-16 22:49:09.000000000 +0100
--- testsuite/gcc.c-torture/execute/pr21964-1.c	2005-08-01 09:51:02.000000000 +0100
***************
*** 0 ****
--- 1,16 ----
+ void
+ foo (int n, int m)
+ {
+   if (m == 0)
+     exit (0);
+   else if (n != 0)
+     abort ();
+   else
+     foo (n++, m - 1);
+ }
+  
+ int
+ main (void)
+ {
+   foo (0, 4);
+ }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]