aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Hubicka <jh@suse.cz>2003-09-09 02:31:39 +0200
committerJan Hubicka <hubicka@gcc.gnu.org>2003-09-09 00:31:39 +0000
commitd853a20e6cf622329c8f005cc97be8813f935323 (patch)
tree623ba3114b93c04e4e5929e3ff36073432517a82
parentc05e3efaa4bf6c6ad3ebad148a44d84b4054c799 (diff)
downloadgcc-d853a20e6cf622329c8f005cc97be8813f935323.zip
gcc-d853a20e6cf622329c8f005cc97be8813f935323.tar.gz
gcc-d853a20e6cf622329c8f005cc97be8813f935323.tar.bz2
cgraph.c (cgraph_varpool_finalize_decl): Sanity check duplicated finalization.
* 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. From-SVN: r71221
-rw-r--r--gcc/ChangeLog14
-rw-r--r--gcc/cgraph.c10
-rw-r--r--gcc/cgraphunit.c78
3 files changed, 87 insertions, 15 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 166ce7f..21ca4af 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index 4eaa60e..52a3bf6 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -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;
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index 1476c8b..a41182f 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -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)