This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
cgraphunit cleanups and fixes
- From: Jan Hubicka <jh at suse dot cz>
- To: gcc-patches at gcc dot gnu dot org
- Date: Tue, 9 Sep 2003 02:27:56 +0200
- Subject: cgraphunit cleanups and fixes
Hi,
this patch fixes several corner cases I noticed while working on C++
support and handling of extern inline functions as discussed earlier.
I have more cleanups to come, but I would like to proceed in small
steps.
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.
Index: cgraph.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cgraph.c,v
retrieving revision 1.27
diff -c -3 -p -r1.27 cgraph.c
*** cgraph.c 6 Sep 2003 22:47:19 -0000 1.27
--- cgraph.c 9 Sep 2003 00:19:28 -0000
*************** void
*** 481,488 ****
cgraph_varpool_finalize_decl (tree decl)
{
struct cgraph_varpool_node *node = cgraph_varpool_node (decl);
!
! if (node->needed && !node->finalized)
{
node->next_needed = cgraph_varpool_nodes_queue;
cgraph_varpool_nodes_queue = node;
--- 481,494 ----
cgraph_varpool_finalize_decl (tree decl)
{
struct cgraph_varpool_node *node = cgraph_varpool_node (decl);
!
! /* 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: cgraphunit.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cgraphunit.c,v
retrieving revision 1.24
diff -c -3 -p -r1.24 cgraphunit.c
*** cgraphunit.c 5 Sep 2003 04:24:26 -0000 1.24
--- cgraphunit.c 9 Sep 2003 00:19:28 -0000
*************** decide_is_function_needed (struct cgraph
*** 106,113 ****
/* "extern inline" functions are never output locally. */
if (DECL_EXTERNAL (decl))
return false;
! /* ??? */
! if (node->origin)
return false;
if (!DECL_INLINE (decl)
|| (!node->local.disregard_inline_limits
--- 106,113 ----
/* "extern inline" functions are never output locally. */
if (DECL_EXTERNAL (decl))
return false;
! /* 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
*************** decide_is_function_needed (struct cgraph
*** 120,125 ****
--- 120,147 ----
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. */
*************** cgraph_finalize_function (tree decl, tre
*** 128,133 ****
--- 150,187 ----
{
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;
*************** cgraph_finalize_function (tree decl, tre
*** 140,154 ****
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);
! }
/* If we've not yet emitted decl, tell the debug info about it. */
if (flag_unit_at_a_time || !node->reachable)
--- 194,202 ----
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. 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)
*************** record_call_1 (tree *tp, int *walk_subtr
*** 163,169 ****
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)
{
tree decl = TREE_OPERAND (*tp, 0);
if (TREE_CODE (decl) == FUNCTION_DECL)
--- 211,217 ----
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 && flag_unit_at_a_time)
{
tree decl = TREE_OPERAND (*tp, 0);
if (TREE_CODE (decl) == FUNCTION_DECL)
*************** cgraph_analyze_function (struct cgraph_n
*** 243,248 ****
--- 291,297 ----
}
node->lowered = true;
+ current_function_decl = NULL;
}
/* Analyze the whole compilation unit once it is parsed completely. */
*************** cgraph_finalize_compilation_unit (void)
*** 253,259 ****
struct cgraph_node *node;
if (!flag_unit_at_a_time)
! return;
cgraph_varpool_assemble_pending_decls ();
if (!quiet_flag)
--- 302,311 ----
struct cgraph_node *node;
if (!flag_unit_at_a_time)
! {
! cgraph_assemble_pending_functions ();
! return;
! }
cgraph_varpool_assemble_pending_decls ();
if (!quiet_flag)