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]

[tree-ssa] Fix checking failures reproduced by Gerald's application


Hi,
this patch fix problem caught by checking code on Gerald's testcase.  The
problem is realted to extern inline functions: we thread extern inline
functions as ordinary functions with the exception of not emitting out-of-line
copies even when they are referenced.

This works well until we decide to not inline some extern inline function at
all and that extern inline function calls not extern inline function.  In that
case we emit that function for not reason and sanity checking code correctly
complains.

The highlevel idea of fix bellow is to re-run reachability analysis
after inlining and turn all out of line copies of extern inline
functions into ordinary extern functions.  While this looks easy, it is
not so easilly doable in presence of clones, so I've relaxed
requirements on memory management a bit.  I will re-think the strategy
tommorow, but will commit this for now to unbreak tree.  This code
should not be dificult at all :)

Bootstrapped/regtested i686-pc-gnu-linux (after a while by hand so really hope
I didn't messed it up).  Aditionally I've build Gerald's application and
testcase.  I also did x86-64 testing on earlier version of this patch, but
currently Zdenek's testing machine is dead, so I can't re-do the testing.  Hope
nothing breaks till tomorrow.
Honza

2003-12-14  Jan Hubicka  <jh@suse.cz>
	* cgraph.c (cgraph_remove_node): Ignore DECL_EXTERNAL clones.
	* cgraphunit.c (verify_cgraph_node): Do not insist on unemmited extern
	inline functions to be valid.
	(cgraph_finalize_compilation_unit):  Fix ordering.
	(cgraph_mark_functions_to_output): Do not insist on DECL_EXTERNAL
	nodes to be reclaimed.
	(cgraph_remove_unreachable_nodes): New function.
	(cgraph_decide_inlining): use it.
Index: cgraph.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cgraph.c,v
retrieving revision 1.4.4.13
diff -c -3 -p -r1.4.4.13 cgraph.c
*** cgraph.c	13 Dec 2003 19:39:47 -0000	1.4.4.13
--- cgraph.c	15 Dec 2003 23:28:51 -0000
*************** cgraph_remove_node (struct cgraph_node *
*** 309,315 ****
  
        for (n = *slot; n; n = n->next_clone)
  	if (n->global.inlined_to
! 	    || (!n->global.inlined_to && !TREE_ASM_WRITTEN (n->decl)))
  	  break;
        if (!n && !dump_enabled_p (TDI_all))
          DECL_SAVED_TREE (node->decl) = NULL;
--- 310,317 ----
  
        for (n = *slot; n; n = n->next_clone)
  	if (n->global.inlined_to
! 	    || (!n->global.inlined_to
! 		&& !TREE_ASM_WRITTEN (n->decl) && !DECL_EXTERNAL (n->decl)))
  	  break;
        if (!n && !dump_enabled_p (TDI_all))
          DECL_SAVED_TREE (node->decl) = NULL;
Index: cgraphunit.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cgraphunit.c,v
retrieving revision 1.1.4.22
diff -c -3 -p -r1.1.4.22 cgraphunit.c
*** cgraphunit.c	14 Dec 2003 12:16:20 -0000	1.1.4.22
--- cgraphunit.c	15 Dec 2003 23:28:52 -0000
*************** verify_cgraph_node (struct cgraph_node *
*** 411,417 ****
      }
    
    if (node->analyzed
!       && DECL_SAVED_TREE (node->decl) && !TREE_ASM_WRITTEN (node->decl))
      {
        walk_tree_without_duplicates (&DECL_SAVED_TREE (node->decl),
  				    verify_cgraph_node_1, node);
--- 411,418 ----
      }
    
    if (node->analyzed
!       && DECL_SAVED_TREE (node->decl) && !TREE_ASM_WRITTEN (node->decl)
!       && (!DECL_EXTERNAL (node->decl) || node->global.inlined_to))
      {
        walk_tree_without_duplicates (&DECL_SAVED_TREE (node->decl),
  				    verify_cgraph_node_1, node);
*************** cgraph_finalize_compilation_unit (void)
*** 550,558 ****
  
        if (!node->reachable && DECL_SAVED_TREE (decl))
  	{
- 	  cgraph_remove_node (node);
  	  if (cgraph_dump_file)
  	    fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
  	}
      }
    if (cgraph_dump_file)
--- 551,559 ----
  
        if (!node->reachable && DECL_SAVED_TREE (decl))
  	{
  	  if (cgraph_dump_file)
  	    fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
+ 	  cgraph_remove_node (node);
  	}
      }
    if (cgraph_dump_file)
*************** cgraph_mark_functions_to_output (void)
*** 594,600 ****
  	node->output = 1;
        /* We should've reclaimed all functions that are not needed.  */
        else if (!node->global.inlined_to && DECL_SAVED_TREE (decl)
! 	       && !node->origin)
  	{
  	  dump_cgraph_node (stderr, node);
  	  abort ();
--- 595,601 ----
  	node->output = 1;
        /* We should've reclaimed all functions that are not needed.  */
        else if (!node->global.inlined_to && DECL_SAVED_TREE (decl)
! 	       && !node->origin && !DECL_EXTERNAL (decl))
  	{
  	  dump_cgraph_node (stderr, node);
  	  abort ();
*************** cgraph_postorder (struct cgraph_node **o
*** 691,696 ****
--- 692,782 ----
    return order_pos;
  }
  
+ /* Perform reachability analysis and reclaim all unreachable nodes.  */
+ static bool
+ cgraph_remove_unreachable_nodes (void)
+ {
+   static struct cgraph_node footer;
+   struct cgraph_node *first = &footer;
+   struct cgraph_node *node;
+   bool changed = false;
+   int insns = 0;
+ 
+   if (cgraph_dump_file)
+     fprintf (cgraph_dump_file, "\nReclaiming functions:");
+   for (node = cgraph_nodes; node; node = node->next)
+     if (node->needed
+ 	&& (!DECL_EXTERNAL (node->decl) || !DECL_SAVED_TREE (node->decl)))
+       {
+ 	node->aux = first;
+ 	first = node;
+       }
+     else if (node->aux)
+       abort ();
+ 
+   /* Perform reachability analysis.  As a special case do not consider
+      extern inline functions not inlined as live because we won't output
+      them at all.  */
+   while (first != &footer)
+     {
+       struct cgraph_edge *e;
+       node = first;
+       first = first->aux;
+ 
+       for (e = node->callees; e; e = e->next_callee)
+ 	if (!e->callee->aux
+ 	    && (e->inline_call || !DECL_SAVED_TREE (e->callee->decl)
+ 		|| !DECL_EXTERNAL (e->callee->decl)))
+ 	  {
+ 	    e->callee->aux = first;
+ 	    first = e->callee;
+ 	  }
+     }
+ 
+   /* Remove unreachable nodes.  Extern inline functions need special care;
+      when they are still called from some existing edge, we only can make
+      them extern and release their body.  */
+   for (node = cgraph_nodes; node; node = node->next)
+     {
+       if (!node->aux)
+ 	{
+ 	  struct cgraph_edge *e = NULL;
+ 
+ 	  if (cgraph_dump_file)
+ 	    fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
+ 	  insns += node->local.self_insns;
+ 
+ 	  if (DECL_EXTERNAL (node->decl) && DECL_SAVED_TREE (node->decl))
+ 	    {
+ 	      for (e = node->callers; e; e = e->next_caller)
+ 		if (e->caller->aux)
+ 		  break;
+ 	    }
+ 	  if (e || node->needed)
+ 	    {
+ 	      struct cgraph_node *clone;
+ 
+ 	      for (clone = node->next_clone; clone; clone = clone->next_clone)
+ 		if (clone->aux)
+ 		  break;
+ 	      if (!clone)
+ 	        DECL_SAVED_TREE (node->decl) = NULL_TREE;
+ 	      while (node->callees)
+ 	        cgraph_remove_edge (node->callees);
+ 	    }
+ 	  else
+ 	    cgraph_remove_node (node);
+ 	  changed = true;
+ 	}
+     }
+   for (node = cgraph_nodes; node; node = node->next)
+     node->aux = NULL;
+   if (cgraph_dump_file)
+     fprintf (cgraph_dump_file, "\nReclaimed %i insns:", insns);
+   verify_cgraph ();
+   return changed;
+ }
+ 
  /* Estimate size of the function after inlining WHAT into TO.  */
  
  static int
*************** cgraph_decide_inlining (void)
*** 1254,1268 ****
    /* We will never output extern functions we didn't inline. 
       ??? Perhaps we can prevent accounting of growth of external
       inline functions.  */
!   for (node = cgraph_nodes; node; node = node->next)
!     {
!       if (node->global.inlined_to
! 	  && DECL_EXTERNAL (node->global.inlined_to->decl))
!         cgraph_remove_node (node);
!       if (!node->global.inlined_to && DECL_EXTERNAL (node->decl)
! 	  && !dump_enabled_p (TDI_all))
! 	DECL_SAVED_TREE (node->decl) = NULL_TREE;
!     }
  
    if (cgraph_dump_file)
      fprintf (cgraph_dump_file,
--- 1340,1346 ----
    /* We will never output extern functions we didn't inline. 
       ??? Perhaps we can prevent accounting of growth of external
       inline functions.  */
!   cgraph_remove_unreachable_nodes ();
  
    if (cgraph_dump_file)
      fprintf (cgraph_dump_file,
*************** cgraph_optimize (void)
*** 1459,1464 ****
--- 1537,1543 ----
  	       right.  It probably does not worth the effort as these functions
  	       should go away soon.  */
  	    && !node->origin
+ 	    && !DECL_EXTERNAL (node->decl)
  	    && (node->global.inlined_to
  	        || DECL_SAVED_TREE (node->decl)))
  	  {


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