]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
* cgraph.c (cgraph_varpool_finalize_decl): Sanity check duplicated
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 9 Sep 2003 00:31:39 +0000 (00:31 +0000)
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 9 Sep 2003 00:31:39 +0000 (00:31 +0000)
finalization.
* cgraphunit.c (decide_is_fnction_needed): Avoid special case of nested
functions, check for COMDAT.
(cgraph_assemble_pending_functions): Break out from...
(cgraph_finalize_function): ... here; allow redefinig of extern inline
functions.
(record_call_1): Record function references only in non-unit-at-a-time
mode.
(cgraph_analyze_function): Reset current_function_decl.
(cgraph_finalize_compilation_unit):  Assemble pending functions.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@71221 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/cgraph.c
gcc/cgraphunit.c

index 166ce7f8f7462d0136ea75132714fe70fb565d65..21ca4af5cc6024cbca46f1d57b52df2cd157d147 100644 (file)
@@ -1,3 +1,17 @@
+Tue Sep  9 02:18:06 CEST 2003  Jan Hubicka  <jh@suse.cz>
+
+       * cgraph.c (cgraph_varpool_finalize_decl): Sanity check duplicated
+       finalization.
+       * cgraphunit.c (decide_is_fnction_needed): Avoid special case of nested
+       functions, check for COMDAT.
+       (cgraph_assemble_pending_functions): Break out from...
+       (cgraph_finalize_function): ... here; allow redefinig of extern inline
+       functions.
+       (record_call_1): Record function references only in non-unit-at-a-time
+       mode.
+       (cgraph_analyze_function): Reset current_function_decl.
+       (cgraph_finalize_compilation_unit):  Assemble pending functions.
+
 2003-09-08  Mark Mitchell  <mark@codesourcery.com>
 
        * mklibgcc.in (libcc.a): Depend on stmp-dirs.
index 4eaa60e8e76c17f02b4670eb0d78a742eac998fd..52a3bf631becd1d7b77735c8766b3c3199bba647 100644 (file)
@@ -481,8 +481,14 @@ void
 cgraph_varpool_finalize_decl (tree decl)
 {
   struct cgraph_varpool_node *node = cgraph_varpool_node (decl);
-
-  if (node->needed && !node->finalized)
+  /* The first declaration of a variable that comes through this function
+     decides whether it is global (in C, has external linkage)
+     or local (in C, has internal linkage).  So do nothing more
+     if this function has already run.  */
+  if (node->finalized)
+    return;
+  if (node->needed)
     {
       node->next_needed = cgraph_varpool_nodes_queue;
       cgraph_varpool_nodes_queue = node;
index 1476c8b3b23ca04649f59e15d34bd0e93ce79140..a41182f7d3e4a5160091a4c319db36ee036b057a 100644 (file)
@@ -106,8 +106,8 @@ decide_is_function_needed (struct cgraph_node *node, tree decl)
   /* "extern inline" functions are never output locally.  */
   if (DECL_EXTERNAL (decl))
     return false;
-  /* ??? */
-  if (node->origin)
+  /* We want to emit COMDAT functions only when they turns out to be neccesary.  */
+  if (DECL_COMDAT (decl))
     return false;
   if (!DECL_INLINE (decl)
       || (!node->local.disregard_inline_limits
@@ -120,6 +120,28 @@ decide_is_function_needed (struct cgraph_node *node, tree decl)
   return false;
 }
 
+/* When not doing unit-at-a-time, output all functions enqueued.
+   Return true when such a functions were found.  */
+static bool
+cgraph_assemble_pending_functions (void)
+{
+  bool output = false;
+
+  if (flag_unit_at_a_time)
+    return false;
+
+  while (cgraph_nodes_queue)
+    {
+      struct cgraph_node *n = cgraph_nodes_queue;
+
+      cgraph_nodes_queue = cgraph_nodes_queue->next_needed;
+      if (!n->origin && !DECL_EXTERNAL (n->decl))
+       cgraph_expand_function (n);
+      output = true;
+    }
+  return output;
+}
+
 /* Analyze function once it is parsed.  Set up the local information
    available - create cgraph edges for function calls via BODY.  */
 
@@ -128,6 +150,38 @@ cgraph_finalize_function (tree decl, tree body ATTRIBUTE_UNUSED)
 {
   struct cgraph_node *node = cgraph_node (decl);
 
+  if (node->local.finalized)
+    {
+      /* As an GCC extension we allow redefinition of the function.  The
+        semantics when both copies of bodies differ is not well defined.  We
+        replace the old body with new body so in unit at a time mode we always
+        use new body, while in normal mode we may end up with old body inlined
+        into some functions and new body expanded and inlined in others.
+        
+        ??? It may make more sense to use one body for inlining and other body
+        for expanding the function but this is dificult to do.  */
+      if (!node->needed)
+       {
+         /* Reset our datastructures so we can analyze the function body
+            again.  */
+         memset (&node->local, 0, sizeof (node->local));
+         memset (&node->global, 0, sizeof (node->global));
+         memset (&node->rtl, 0, sizeof (node->rtl));
+         node->lowered = false;
+         if (node->output)
+           abort ();
+         while (node->callees)
+           cgraph_remove_call (node->decl, node->callees->callee->decl);
+       }
+      else
+      /* Frontend may call finalize_function twice when it is incorrectly
+         redefined.  */
+      if (errorcount || sorrycount)
+       return;
+      else
+        abort ();
+    }
+  notice_global_symbol (decl);
   node->decl = decl;
   node->local.finalized = true;
 
@@ -140,15 +194,9 @@ cgraph_finalize_function (tree decl, tree body ATTRIBUTE_UNUSED)
     cgraph_mark_needed_node (node);
 
   /* If not unit at a time, go ahead and emit everything we've
-     found to be reachable at this time.  */
-  if (!flag_unit_at_a_time)
-    while (cgraph_nodes_queue)
-      {
-        struct cgraph_node *n = cgraph_nodes_queue;
-        cgraph_nodes_queue = cgraph_nodes_queue->next_needed;
-        if (!n->origin)
-          cgraph_expand_function (n);
-      }
+     found to be reachable at this time.  Do this only at top-level.  */
+  if (!node->origin)
+    cgraph_assemble_pending_functions ();
 
   /* If we've not yet emitted decl, tell the debug info about it.  */
   if (flag_unit_at_a_time || !node->reachable)
@@ -163,7 +211,7 @@ record_call_1 (tree *tp, int *walk_subtrees, void *data)
     cgraph_varpool_mark_needed_node (cgraph_varpool_node (*tp));
   /* Record dereferences to the functions.  This makes the functions
      reachable unconditionally.  */
-  else if (TREE_CODE (*tp) == ADDR_EXPR)
+  else if (TREE_CODE (*tp) == ADDR_EXPR && flag_unit_at_a_time)
     {
       tree decl = TREE_OPERAND (*tp, 0);
       if (TREE_CODE (decl) == FUNCTION_DECL)
@@ -243,6 +291,7 @@ cgraph_analyze_function (struct cgraph_node *node)
     }
 
   node->lowered = true;
+  current_function_decl = NULL;
 }
 
 /* Analyze the whole compilation unit once it is parsed completely.  */
@@ -253,7 +302,10 @@ cgraph_finalize_compilation_unit (void)
   struct cgraph_node *node;
 
   if (!flag_unit_at_a_time)
-    return;
+    {
+      cgraph_assemble_pending_functions ();
+      return;
+    }
 
   cgraph_varpool_assemble_pending_decls ();
   if (!quiet_flag)