diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 22d70924a92dd5a2465a4917b46a9e469e44c51d..34696c61235eb8078da5ba2577aa4f0fd3ff05b5 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,8 @@
+Tue Feb 18 23:50:59 CET 2003  Jan Hubicka  <jh@suse.cz>
+
+	* cgraph.c (NPREDECESORC, SET_NPREDECESORS): Kill.
+	(cgraph_expand_function): Rewrite.
+
 2003-02-18  Matt Austern <austern@apple.com>
 	* toplev.c, langhooks.c, langhooks-def.h: Move
 	write_global_declarations from toplev.c to langhooks.c. 
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index 5b580491bd1f1b4f2c60abfa6b420ff420a26a54..f1fffcac4215d0ee3ca592f128174e7dd8fac2c7 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -420,11 +420,6 @@ cgraph_finalize_compilation_unit ()
   ggc_collect ();
 }
 
-/* Expand all functions that must be output.  */
-
-#define NPREDECESORS(node) ((size_t) (node)->aux)
-#define SET_NPREDECESORS(node, n) ((node)->aux = (void *) (size_t) (n))
-
 /* Figure out what functions we want to assemble.  */
 
 static void
@@ -476,56 +471,75 @@ cgraph_expand_function (node)
 static void
 cgraph_expand_functions ()
 {
-  struct cgraph_node *node;
+  struct cgraph_node *node, *node2;
   struct cgraph_node **stack =
     xcalloc (sizeof (struct cgraph_node *), cgraph_n_nodes);
+  struct cgraph_node **order =
+    xcalloc (sizeof (struct cgraph_node *), cgraph_n_nodes);
   int stack_size = 0;
-  struct cgraph_edge *edge;
+  int order_pos = 0;
+  struct cgraph_edge *edge, last;
+  int i;
 
   cgraph_mark_functions_to_output ();
 
+  /*  We have to deal with cycles nicely, so use depth first traversal
+      algorithm.  Ignore the fact that some functions won't need to be output
+      and put them into order as well, so we get dependencies right trought inlined
+      functions.  */
+  for (node = cgraph_nodes; node; node = node->next)
+    node->aux = NULL;
   for (node = cgraph_nodes; node; node = node->next)
-    if (node->output)
+    if (node->output && !node->aux)
       {
-	int n = 0;
-	for (edge = node->callees; edge; edge = edge->next_callee)
-	  if (edge->callee->output)
-	    n++;
-	SET_NPREDECESORS (node, n);
-	if (n == 0)
-	  stack[stack_size++] = node;
+	node2 = node;
+	if (!node->callers)
+	  node->aux = &last;
+	else
+	  node->aux = node->callers;
+	while (node2)
+	  {
+	    while (node2->aux != &last)
+	      {
+		edge = node2->aux;
+		if (edge->next_caller)
+		  node2->aux = edge->next_caller;
+		else
+		  node2->aux = &last;
+		if (!edge->caller->aux)
+		  {
+		    if (!edge->caller->callers)
+		      edge->caller->aux = &last;
+		    else
+		      edge->caller->aux = edge->caller->callers;
+		    stack[stack_size++] = node2;
+		    node2 = edge->caller;
+		    break;
+		  }
+	      }
+	    if (node2->aux == &last)
+	      {
+		order[order_pos++] = node2;
+		if (stack_size)
+		  node2 = stack[--stack_size];
+		else
+		  node2 = NULL;
+	      }
+	  }
       }
-  while (1)
+  for (i = order_pos - 1; i >=0; i--)
     {
-      struct cgraph_node *minnode;
-      while (stack_size)
+      node = order[i];
+      if (node->output)
 	{
-	  node = stack[--stack_size];
-	  node->output = 0;
-
-	  for (edge = node->callers; edge; edge = edge->next_caller)
-	    if (edge->caller->output)
-	      {
-	        SET_NPREDECESORS (edge->caller,
-		    		  NPREDECESORS (edge->caller) - 1);
-		if (!NPREDECESORS (edge->caller))
-		  stack[stack_size++] = edge->caller;
-	      }
 	  if (!node->reachable)
 	    abort ();
+	  node->output = 0;
 	  cgraph_expand_function (node);
 	}
-      minnode = NULL;
-      /* We found cycle.  Break it and try again.  */
-      for (node = cgraph_nodes; node; node = node->next)
-	if (node->output
-	    && (!minnode
-	        || NPREDECESORS (minnode) > NPREDECESORS (node)))
-	  minnode = node;
-      if (!minnode)
-	return;
-      stack[stack_size++] = minnode;
     }
+  free (stack);
+  free (order);
 }
 
 /* Perform simple optimizations based on callgraph.  */
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 9d41b1af62a010abbc9382693b6114f31fff6aa5..0c352aec172a483f862b3f4c4bf80c8d3fce025c 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+Tue Feb 18 23:28:53 CET 2003  Jan Hubicka  <jh@suse.cz>
+
+	* gcc.dg/funcorder.c: New test.
+
 2003-02-18  Kazu Hirata  <kazu@cs.umass.edu>
 
 	* gcc.c-torture/execute/20030218-1.c: New.
diff --git a/gcc/testsuite/gcc.dg/funcorder.c b/gcc/testsuite/gcc.dg/funcorder.c
new file mode 100644
index 0000000000000000000000000000000000000000..0dec72c7d02b7a40cf40c55afaa3b7f3b921241b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/funcorder.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -funit-at-a-time" } */
+/* { dg-final { scan-assembler-not "link_error" } } */
+/*  In unit-at-time the functions should be assembled in order
+    e q t main, so we realize that they are pure.  */
+ 
+static int mem;
+static int e(void) __attribute__ ((noinline));
+static int q(void) __attribute__ ((noinline));
+static int t(void) __attribute__ ((noinline));
+main()
+{
+	return t();
+}
+static t()
+{
+	int r,e;
+	if (mem)
+		t();
+	e=mem;
+	r=q();
+	if (e!=mem)
+		link_error();
+	return r;
+}
+static int e()
+{
+	return 0;
+}
+static int q()
+{
+	int t=mem,r;
+	r=e();
+	if (t!=mem)
+		link_error();
+	return r;
+}