From b1896e61038b3c63b567393ba12ddaa99f6f4a43 Mon Sep 17 00:00:00 2001
From: Mark Mitchell <mark@codesourcery.com>
Date: Sat, 6 Apr 2002 19:42:22 +0000
Subject: [PATCH] re PR rtl-optimization/5120 (tail recursion incorrect using
 -O2)

	PR opt/5120
	* sibcall.c (optimize_sibling_and_tail_recursive_call): Clear
	RTX_UNCHANGING_P for the functions arguments when a tail call
	is made.

From-SVN: r51969
---
 gcc/ChangeLog                                 |   7 +
 gcc/sibcall.c                                 |  12 ++
 gcc/testsuite/ChangeLog                       |   5 +
 .../gcc.c-torture/execute/20020406-1.c        | 123 ++++++++++++++++++
 4 files changed, 147 insertions(+)
 create mode 100644 gcc/testsuite/gcc.c-torture/execute/20020406-1.c

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 6c451f949abc..548caa9c81f7 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,10 @@
+2002-04-06  Mark Mitchell  <mark@codesourcery.com>
+
+	PR opt/5120
+	* sibcall.c (optimize_sibling_and_tail_recursive_call): Clear
+	RTX_UNCHANGING_P for the functions arguments when a tail call
+	is made.
+
 2002-04-06  Jason Merrill  <jason@redhat.com>
 
 	* toplev.c (flag_no_inline, flag_really_no_inline): Default to 2.
diff --git a/gcc/sibcall.c b/gcc/sibcall.c
index 5a7997cb0387..6e753fa2fa99 100644
--- a/gcc/sibcall.c
+++ b/gcc/sibcall.c
@@ -31,6 +31,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "basic-block.h"
 #include "output.h"
 #include "except.h"
+#include "tree.h"
 
 /* In case alternate_exit_block contains copy from pseudo, to return value,
    record the pseudo here.  In such case the pseudo must be set to function
@@ -730,6 +731,7 @@ optimize_sibling_and_tail_recursive_calls ()
   if (successful_sibling_call)
     {
       rtx insn;
+      tree arg;
 
       /* A sibling call sequence invalidates any REG_EQUIV notes made for
 	 this function's incoming arguments. 
@@ -754,6 +756,16 @@ optimize_sibling_and_tail_recursive_calls ()
 	  if (INSN_P (insn))
 	    purge_mem_unchanging_flag (PATTERN (insn));
 	}
+
+      /* Similarly, invalidate RTX_UNCHANGING_P for any incoming
+	 arguments passed in registers. */
+      for (arg = DECL_ARGUMENTS (current_function_decl); 
+	   arg; 
+	   arg = TREE_CHAIN (arg))
+	{
+	  if (REG_P (DECL_RTL (arg)))
+	    RTX_UNCHANGING_P (DECL_RTL (arg)) = false;
+	}
     }
 
   /* There may have been NOTE_INSN_BLOCK_{BEGIN,END} notes in the 
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 7b92bce96e6d..ddd75d41ea88 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2002-04-06  Mark Mitchell  <mark@codesourcery.com>
+
+	PR c/5120
+	* gcc.dg/20020406-1.c: New test.
+
 2002-04-04  David S. Miller  <davem@redhat.com>
 
 	* gcc.c-torture/execute/20020404-1.c: New test.
diff --git a/gcc/testsuite/gcc.c-torture/execute/20020406-1.c b/gcc/testsuite/gcc.c-torture/execute/20020406-1.c
new file mode 100644
index 000000000000..6d4967eae55c
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/20020406-1.c
@@ -0,0 +1,123 @@
+// Origin: abbott@dima.unige.it
+// PR c/5120
+
+typedef unsigned int FFelem;
+
+FFelem FFmul(const FFelem x, const FFelem y)
+{
+  return x;
+}
+
+
+struct DUPFFstruct
+{
+  int maxdeg;
+  int deg;
+  FFelem *coeffs;
+};
+
+typedef struct DUPFFstruct *DUPFF;
+
+
+int DUPFFdeg(const DUPFF f)
+{
+  return f->deg;
+}
+
+
+DUPFF DUPFFnew(const int maxdeg)
+{
+  DUPFF ans = (DUPFF)malloc(sizeof(struct DUPFFstruct));
+  ans->coeffs = 0;
+  if (maxdeg >= 0) ans->coeffs = (FFelem*)malloc((maxdeg+1)*sizeof(FFelem));
+  ans->maxdeg = maxdeg;
+  ans->deg = -1;
+  return ans;
+}
+
+void DUPFFfree(DUPFF x)
+{
+}
+
+void DUPFFswap(DUPFF x, DUPFF y)
+{
+}
+
+
+DUPFF DUPFFcopy(const DUPFF x)
+{
+  return x;
+}
+
+
+void DUPFFshift_add(DUPFF f, const DUPFF g, int deg, const FFelem coeff)
+{
+}
+
+
+DUPFF DUPFFexgcd(DUPFF *fcofac, DUPFF *gcofac, const DUPFF f, const DUPFF g)
+{
+  DUPFF u, v, uf, ug, vf, vg;
+  FFelem q, lcu, lcvrecip, p;
+  int df, dg, du, dv;
+
+  printf("DUPFFexgcd called on degrees %d and %d\n", DUPFFdeg(f), DUPFFdeg(g));
+  if (DUPFFdeg(f) < DUPFFdeg(g)) return DUPFFexgcd(gcofac, fcofac, g, f);  /*** BUG IN THIS LINE ***/
+  if (DUPFFdeg(f) != 2 || DUPFFdeg(g) != 1) abort();
+  if (f->coeffs[0] == 0) return f;
+  /****** NEVER REACH HERE IN THE EXAMPLE ******/
+  p = 2;
+
+  df = DUPFFdeg(f);  if (df < 0) df = 0; /* both inputs are zero */
+  dg = DUPFFdeg(g);  if (dg < 0) dg = 0; /* one input is zero */
+  u = DUPFFcopy(f);
+  v = DUPFFcopy(g);
+
+  uf = DUPFFnew(dg); uf->coeffs[0] = 1; uf->deg = 0;
+  ug = DUPFFnew(df);
+  vf = DUPFFnew(dg);
+  vg = DUPFFnew(df); vg->coeffs[0] = 1; vg->deg = 0;
+
+  while (DUPFFdeg(v) > 0)
+  {
+    dv = DUPFFdeg(v);
+    lcvrecip = FFmul(1, v->coeffs[dv]);
+    while (DUPFFdeg(u) >= dv)
+    {
+      du = DUPFFdeg(u);
+      lcu = u->coeffs[du];
+      q = FFmul(lcu, lcvrecip);
+      DUPFFshift_add(u, v, du-dv, p-q);
+      DUPFFshift_add(uf, vf, du-dv, p-q);
+      DUPFFshift_add(ug, vg, du-dv, p-q);
+    }
+    DUPFFswap(u, v);
+    DUPFFswap(uf, vf);
+    DUPFFswap(ug, vg);
+  }
+  if (DUPFFdeg(v) == 0)
+  {
+    DUPFFswap(u, v);
+    DUPFFswap(uf, vf);
+    DUPFFswap(ug, vg);
+  }
+  DUPFFfree(vf);
+  DUPFFfree(vg);
+  DUPFFfree(v);
+  *fcofac = uf;
+  *gcofac = ug;
+  return u;
+}
+
+
+
+int main()
+{
+  DUPFF f, g, cf, cg, h;
+  f = DUPFFnew(1); f->coeffs[1] = 1; f->deg = 1;
+  g = DUPFFnew(2); g->coeffs[2] = 1; g->deg = 2;
+
+  printf("calling DUPFFexgcd on degrees %d and %d\n", DUPFFdeg(f), DUPFFdeg(g)) ;
+  h = DUPFFexgcd(&cf, &cg, f, g);
+  return 0;
+}
-- 
GitLab