This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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)


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]