From d853a20e6cf622329c8f005cc97be8813f935323 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Tue, 9 Sep 2003 02:31:39 +0200 Subject: [PATCH] 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 --- gcc/ChangeLog | 14 +++++++++ gcc/cgraph.c | 10 +++++-- gcc/cgraphunit.c | 78 ++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 87 insertions(+), 15 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 166ce7f8f74..21ca4af5cc6 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,17 @@ +Tue Sep 9 02:18:06 CEST 2003 Jan Hubicka + + * 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 * mklibgcc.in (libcc.a): Depend on stmp-dirs. diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 4eaa60e8e76..52a3bf631be 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 1476c8b3b23..a41182f7d3e 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) -- 2.30.2