diff options
Diffstat (limited to 'gcc/cgraphunit.c')
-rw-r--r-- | gcc/cgraphunit.c | 149 |
1 files changed, 133 insertions, 16 deletions
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index 27e4d8d..a883ebf 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -436,6 +436,8 @@ cgraph_finalize_compilation_unit (void) if (cgraph_dump_file) fprintf (cgraph_dump_file, " %s", cgraph_node_name (node)); } + else + node->next_needed = NULL; } if (cgraph_dump_file) { @@ -792,6 +794,105 @@ cgraph_inlined_callees (struct cgraph_node *node, struct cgraph_node **array) 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 @@ -1055,7 +1156,7 @@ cgraph_decide_inlining_of_small_functions (struct cgraph_node **inlined, ninlined, &e->inline_failed)) { for (i = 0; i < ninlined; i++) - inlined[i]->output = 0, node->aux = 0; + 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)); @@ -1071,17 +1172,16 @@ cgraph_decide_inlining_of_small_functions (struct cgraph_node **inlined, the keys. */ for (i = 0; i < ninlined; i++) { - inlined[i]->output = 0, node->aux = 0; + 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); - + 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 @@ -1101,7 +1201,8 @@ cgraph_decide_inlining_of_small_functions (struct cgraph_node **inlined, fibheap_replace_key (heap, heap_node[e->callee->uid], cgraph_estimate_growth (e->callee)); - inlined_callees[i]->output = 0, node->aux = 0; + inlined_callees[i]->output = 0; + inlined_callees[i]->aux = 0; } if (cgraph_dump_file) fprintf (cgraph_dump_file, @@ -1150,6 +1251,11 @@ cgraph_decide_inlining (void) 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. */ @@ -1185,7 +1291,7 @@ cgraph_decide_inlining (void) 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; + 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", @@ -1197,12 +1303,22 @@ cgraph_decide_inlining (void) " 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; + 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"); @@ -1251,7 +1367,7 @@ cgraph_decide_inlining (void) ninlined, inlined_callees, ninlined_callees); for (y = 0; y < ninlined_callees; y++) - inlined_callees[y]->output = 0, node->aux = 0; + 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" @@ -1267,11 +1383,12 @@ cgraph_decide_inlining (void) " Inline limit reached, not inlined.\n"); } for (y = 0; y < ninlined; y++) - inlined[y]->output = 0, node->aux = 0; + inlined[y]->output = 0, inlined[y]->aux = 0; } } } } + cgraph_remove_unreachable_nodes (); if (cgraph_dump_file) fprintf (cgraph_dump_file, @@ -1317,7 +1434,7 @@ cgraph_decide_inlining_incrementally (struct cgraph_node *node) 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; + inlined_callees[y]->output = 0, inlined_callees[y]->aux = 0; } if (!flag_really_no_inline) @@ -1342,13 +1459,13 @@ cgraph_decide_inlining_incrementally (struct cgraph_node *node) 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; + 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, node->aux = 0; + inlined[y]->output = 0, inlined[y]->aux = 0; free (inlined); free (inlined_callees); |