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]

[3.4/mainline] Backport cgrapunit fix for extern inline funcitons


Hi,
while adding sanity checking to tree-SSA version of cgraph implementation I
noticed that non extern-inline functions called from extern-inline function
that is not inlined are output for no reason.  This didn't seem to be big deal
to me so I fixed it in the tree-SSA only, but now while looking for reason for
size differences of object file in LyX, I noticed that it is up to 60% of
garbage in some cases of C++ templates.

This I decided to backport the patch to mainline and 3.4 branch.  I also
noticed pasto in the old inlinining code fixed by the attached patch.
I've bootstrapped/regtested this on i686, compiled Gerald's application
and verified that it does not change performance/compile speed and built
Pooma/LyX with some reductions of code sizes and similar speedups.

I intent to commit the patch tomorrow unless there are complains.

Honza

2004-01-19  Jan Hubicka  <jh@suse.cz>
	* cgraph.c (cgraph_remove_node): Fix removal from linked list.
	* cgraphunit.c (cgraph_finalize_compilation_unit): Clear next_needed
	list.
	(cgraph_remove_unreachable_nodes): New function
	(cgraph_decide_inlining_of_small_function): Fix pasto.
	(cgraph_decide_inlining_incrementally): Fix pasto.
	(cgrpah_decide_inlining): Likewise; remove unreachable nodes.
Index: cgraph.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cgraph.c,v
retrieving revision 1.41
diff -c -3 -p -r1.41 cgraph.c
*** cgraph.c	14 Jan 2004 22:54:49 -0000	1.41
--- cgraph.c	18 Jan 2004 22:04:59 -0000
*************** cgraph_remove_node (struct cgraph_node *
*** 231,237 ****
    if (node->previous)
      node->previous->next = node->next;
    else
!     cgraph_nodes = node;
    if (node->next)
      node->next->previous = node->previous;
    DECL_SAVED_TREE (node->decl) = NULL;
--- 231,237 ----
    if (node->previous)
      node->previous->next = node->next;
    else
!     cgraph_nodes = node->next;
    if (node->next)
      node->next->previous = node->previous;
    DECL_SAVED_TREE (node->decl) = NULL;
Index: cgraphunit.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cgraphunit.c,v
retrieving revision 1.46
diff -c -3 -p -r1.46 cgraphunit.c
*** cgraphunit.c	14 Jan 2004 22:54:50 -0000	1.46
--- cgraphunit.c	18 Jan 2004 22:05:00 -0000
*************** cgraph_finalize_compilation_unit (void)
*** 436,441 ****
--- 436,443 ----
  	  if (cgraph_dump_file)
  	    fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
  	}
+       else
+ 	node->next_needed = NULL;
      }
    if (cgraph_dump_file)
      {
*************** cgraph_inlined_callees (struct cgraph_no
*** 792,797 ****
--- 794,898 ----
    return nfound;
  }
  
+ /* Perform reachability analysis and reclaim all unreachable nodes.
+    This function also remove unneeded bodies of extern inline functions
+    and thus needs to be done only after inlining decisions has been made.  */
+ static bool
+ cgraph_remove_unreachable_nodes (void)
+ {
+   struct cgraph_node *first = (void *) 1;
+   struct cgraph_node *node;
+   bool changed = false;
+   int insns = 0;
+ 
+   if (cgraph_dump_file)
+     fprintf (cgraph_dump_file, "\nReclaiming functions:");
+ #ifdef ENABLE_CHECKING
+   for (node = cgraph_nodes; node; node = node->next)
+     if (node->aux)
+       abort ();
+ #endif
+   for (node = cgraph_nodes; node; node = node->next)
+     if (node->needed && (!DECL_EXTERNAL (node->decl) || !node->analyzed))
+       {
+ 	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 != (void *) 1)
+     {
+       struct cgraph_edge *e;
+       node = first;
+       first = first->aux;
+ 
+       for (e = node->callees; e; e = e->next_callee)
+ 	if (!e->callee->aux
+ 	    && node->analyzed
+ 	    && (!e->inline_failed || !e->callee->analyzed
+ 		|| !DECL_EXTERNAL (e->callee->decl)))
+ 	  {
+ 	    e->callee->aux = first;
+ 	    first = e->callee;
+ 	  }
+     }
+ 
+   /* Remove unreachable nodes.  Extern inline functions need special care;
+      Unreachable extern inline functions shall be removed.
+      Reachable extern inline functions we never inlined shall get their bodies
+      elliminated
+      Reachable extern inline functions we sometimes inlined will be turned into
+      unanalyzed nodes so they look like for true extern functions to the rest
+      of code.  */
+   for (node = cgraph_nodes; node; node = node->next)
+     {
+       if (!node->aux)
+ 	{
+ 	  int local_insns;
+ 	  tree decl = node->decl;
+ 
+ 	  if (DECL_SAVED_INSNS (decl))
+ 	    local_insns = node->local.self_insns;
+ 	  else
+ 	    local_insns = 0;
+ 	  if (cgraph_dump_file)
+ 	    fprintf (cgraph_dump_file, " %s", cgraph_node_name (node));
+ 	  if (!node->analyzed || !DECL_EXTERNAL (node->decl))
+ 	    cgraph_remove_node (node);
+ 	  else
+ 	    {
+ 	      struct cgraph_edge *e;
+ 
+ 	      for (e = node->callers; e; e = e->next_caller)
+ 		if (e->caller->aux)
+ 		  break;
+ 	      if (e || node->needed)
+ 		{
+ 		  DECL_SAVED_TREE (node->decl) = NULL_TREE;
+ 		  while (node->callees)
+ 		    cgraph_remove_edge (node, node->callees->callee);
+ 		  node->analyzed = false;
+ 		}
+ 	      else
+ 		cgraph_remove_node (node);
+ 	    }
+ 	  if (!DECL_SAVED_TREE (decl))
+ 	    insns += local_insns;
+ 	  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);
+   return changed;
+ }
+ 
+ 
  /* Estimate size of the function after inlining WHAT into TO.  */
  
  static int
*************** cgraph_decide_inlining_of_small_function
*** 1055,1061 ****
  						ninlined, &e->inline_failed))
  	      {
  		for (i = 0; i < ninlined; i++)
! 		  inlined[i]->output = 0, node->aux = 0;
  		if (cgraph_dump_file)
  		  fprintf (cgraph_dump_file, " Not inlining into %s.\n",
  			   cgraph_node_name (e->caller));
--- 1156,1162 ----
  						ninlined, &e->inline_failed))
  	      {
  		for (i = 0; i < ninlined; i++)
! 		  inlined[i]->output = 0, inlined[i]->aux = 0;
  		if (cgraph_dump_file)
  		  fprintf (cgraph_dump_file, " Not inlining into %s.\n",
  			   cgraph_node_name (e->caller));
*************** cgraph_decide_inlining_of_small_function
*** 1071,1087 ****
  	       the keys.  */
  	    for (i = 0; i < ninlined; i++)
  	      {
! 		inlined[i]->output = 0, node->aux = 0;
  		if (heap_node[inlined[i]->uid])
  		  fibheap_replace_key (heap, heap_node[inlined[i]->uid],
  				       cgraph_estimate_growth (inlined[i]));
  	      }
! 	if (cgraph_dump_file)
! 	  fprintf (cgraph_dump_file, 
! 		   " Inlined into %s which now has %i insns.\n",
! 		   cgraph_node_name (e->caller),
! 		   e->caller->global.insns);
! 
  	  }
  
        /* Similarly all functions called by the function we just inlined
--- 1172,1187 ----
  	       the keys.  */
  	    for (i = 0; i < ninlined; i++)
  	      {
! 		inlined[i]->output = 0, inlined[i]->aux = 0;
  		if (heap_node[inlined[i]->uid])
  		  fibheap_replace_key (heap, heap_node[inlined[i]->uid],
  				       cgraph_estimate_growth (inlined[i]));
  	      }
! 	    if (cgraph_dump_file)
! 	      fprintf (cgraph_dump_file, 
! 		       " Inlined into %s which now has %i insns.\n",
! 		       cgraph_node_name (e->caller),
! 		       e->caller->global.insns);
  	  }
  
        /* Similarly all functions called by the function we just inlined
*************** cgraph_decide_inlining_of_small_function
*** 1101,1107 ****
  	      fibheap_replace_key (heap, heap_node[e->callee->uid],
  				   cgraph_estimate_growth (e->callee));
  
! 	  inlined_callees[i]->output = 0, node->aux = 0;
  	}
        if (cgraph_dump_file)
  	fprintf (cgraph_dump_file, 
--- 1201,1208 ----
  	      fibheap_replace_key (heap, heap_node[e->callee->uid],
  				   cgraph_estimate_growth (e->callee));
  
! 	  inlined_callees[i]->output = 0;
! 	  inlined_callees[i]->aux = 0;
  	}
        if (cgraph_dump_file)
  	fprintf (cgraph_dump_file, 
*************** cgraph_decide_inlining (void)
*** 1150,1155 ****
--- 1251,1261 ----
  
    if (cgraph_dump_file)
      fprintf (cgraph_dump_file, "\nInlining always_inline functions:\n");
+ #ifdef ENABLE_CHECKING
+   for (node = cgraph_nodes; node; node = node->next)
+     if (node->aux || node->output)
+       abort ();
+ #endif
  
    /* In the first pass mark all always_inline edges.  Do this with a priority
       so none of our later choices will make this impossible.  */
*************** cgraph_decide_inlining (void)
*** 1185,1191 ****
  	  cgraph_mark_inline (node, e->callee, inlined, ninlined,
  			      inlined_callees, ninlined_callees);
  	  for (y = 0; y < ninlined_callees; y++)
! 	    inlined_callees[y]->output = 0, node->aux = 0;
  	  if (cgraph_dump_file)
  	    fprintf (cgraph_dump_file, 
  		     " Inlined into %s which now has %i insns.\n",
--- 1291,1297 ----
  	  cgraph_mark_inline (node, e->callee, inlined, ninlined,
  			      inlined_callees, ninlined_callees);
  	  for (y = 0; y < ninlined_callees; y++)
! 	    inlined_callees[y]->output = 0, inlined_callees[y]->aux = 0;
  	  if (cgraph_dump_file)
  	    fprintf (cgraph_dump_file, 
  		     " Inlined into %s which now has %i insns.\n",
*************** cgraph_decide_inlining (void)
*** 1197,1208 ****
  		 " Inlined %i times for a net change of %+i insns.\n",
  		 node->global.cloned_times, overall_insns - old_insns);
        for (y = 0; y < ninlined; y++)
! 	inlined[y]->output = 0, node->aux = 0;
      }
  
    if (!flag_really_no_inline)
      {
        cgraph_decide_inlining_of_small_functions (inlined, inlined_callees);
  
        if (cgraph_dump_file)
  	fprintf (cgraph_dump_file, "\nDeciding on functions called once:\n");
--- 1303,1324 ----
  		 " Inlined %i times for a net change of %+i insns.\n",
  		 node->global.cloned_times, overall_insns - old_insns);
        for (y = 0; y < ninlined; y++)
! 	inlined[y]->output = 0, inlined[y]->aux = 0;
      }
+ #ifdef ENABLE_CHECKING
+   for (node = cgraph_nodes; node; node = node->next)
+     if (node->aux || node->output)
+       abort ();
+ #endif
  
    if (!flag_really_no_inline)
      {
        cgraph_decide_inlining_of_small_functions (inlined, inlined_callees);
+ #ifdef ENABLE_CHECKING
+       for (node = cgraph_nodes; node; node = node->next)
+ 	if (node->aux || node->output)
+ 	  abort ();
+ #endif
  
        if (cgraph_dump_file)
  	fprintf (cgraph_dump_file, "\nDeciding on functions called once:\n");
*************** cgraph_decide_inlining (void)
*** 1251,1257 ****
  					  ninlined, inlined_callees,
  					  ninlined_callees);
  		      for (y = 0; y < ninlined_callees; y++)
! 			inlined_callees[y]->output = 0, node->aux = 0;
  		      if (cgraph_dump_file)
  			fprintf (cgraph_dump_file,
  				 " Inlined into %s which now has %i insns"
--- 1367,1373 ----
  					  ninlined, inlined_callees,
  					  ninlined_callees);
  		      for (y = 0; y < ninlined_callees; y++)
! 			inlined_callees[y]->output = 0, inlined_callees[y]->aux = 0;
  		      if (cgraph_dump_file)
  			fprintf (cgraph_dump_file,
  				 " Inlined into %s which now has %i insns"
*************** cgraph_decide_inlining (void)
*** 1267,1277 ****
  				 " Inline limit reached, not inlined.\n");
  		    }
  		  for (y = 0; y < ninlined; y++)
! 		    inlined[y]->output = 0, node->aux = 0;
  		}
  	    }
  	}
      }
  
    if (cgraph_dump_file)
      fprintf (cgraph_dump_file,
--- 1383,1394 ----
  				 " Inline limit reached, not inlined.\n");
  		    }
  		  for (y = 0; y < ninlined; y++)
! 		    inlined[y]->output = 0, inlined[y]->aux = 0;
  		}
  	    }
  	}
      }
+   cgraph_remove_unreachable_nodes ();
  
    if (cgraph_dump_file)
      fprintf (cgraph_dump_file,
*************** cgraph_decide_inlining_incrementally (st
*** 1317,1323 ****
  	cgraph_mark_inline (node, e->callee, inlined, ninlined,
  			    inlined_callees, ninlined_callees);
  	for (y = 0; y < ninlined_callees; y++)
! 	  inlined_callees[y]->output = 0, node->aux = 0;
        }
  
    if (!flag_really_no_inline)
--- 1434,1440 ----
  	cgraph_mark_inline (node, e->callee, inlined, ninlined,
  			    inlined_callees, ninlined_callees);
  	for (y = 0; y < ninlined_callees; y++)
! 	  inlined_callees[y]->output = 0, inlined_callees[y]->aux = 0;
        }
  
    if (!flag_really_no_inline)
*************** cgraph_decide_inlining_incrementally (st
*** 1342,1354 ****
  	    cgraph_mark_inline (node, e->callee, inlined, ninlined,
  				inlined_callees, ninlined_callees);
  	    for (y = 0; y < ninlined_callees; y++)
! 	      inlined_callees[y]->output = 0, node->aux = 0;
  	  }
      }
  
    /* Clear the flags set by cgraph_inlined_into.  */
    for (y = 0; y < ninlined; y++)
!     inlined[y]->output = 0, node->aux = 0;
  
    free (inlined);
    free (inlined_callees);
--- 1459,1471 ----
  	    cgraph_mark_inline (node, e->callee, inlined, ninlined,
  				inlined_callees, ninlined_callees);
  	    for (y = 0; y < ninlined_callees; y++)
! 	      inlined_callees[y]->output = 0, inlined_callees[y]->aux = 0;
  	  }
      }
  
    /* Clear the flags set by cgraph_inlined_into.  */
    for (y = 0; y < ninlined; y++)
!     inlined[y]->output = 0, inlined[y]->aux = 0;
  
    free (inlined);
    free (inlined_callees);


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