This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[3.4/mainline] Backport cgrapunit fix for extern inline funcitons
- From: Jan Hubicka <jh at suse dot cz>
- To: gcc-patches at gcc dot gnu dot org
- Date: Mon, 19 Jan 2004 02:48:23 +0100
- Subject: [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);