diff options
author | Jan Hubicka <jh@suse.cz> | 2004-01-04 15:39:13 +0100 |
---|---|---|
committer | Jan Hubicka <hubicka@gcc.gnu.org> | 2004-01-04 14:39:13 +0000 |
commit | dc0bfe6a357714f761a6b4326dc7a3cb03c79d8c (patch) | |
tree | b64167702ac199d1ec0b2c92b512d1cd185a82b7 /gcc/cgraphunit.c | |
parent | e42870dffe41cff30755a74cbe162be96f742442 (diff) | |
download | gcc-dc0bfe6a357714f761a6b4326dc7a3cb03c79d8c.zip gcc-dc0bfe6a357714f761a6b4326dc7a3cb03c79d8c.tar.gz gcc-dc0bfe6a357714f761a6b4326dc7a3cb03c79d8c.tar.bz2 |
Makefile.in (cgraph.o, [...]): Add intl.h dependency.
* Makefile.in (cgraph.o, cgraphunit.o): Add intl.h dependency.
* cgraph.c (create_edge, dump_cgraph): Update to use inline_failed
* cgraph.h (cgraph_edge): Replace inline_call by inline_failed
(cgraph_inline_p): Add extra argument reason.
* cgraphunit.c: Minor formating fixes.
cgraph_first_inlined_callee): New functions.
(record_call_1): Record builtins too.
(cgraph_analyze_function): Update inline_failed messages.
(cgraph_mark_functions_to_output, cgraph_expand_function, cgraph_inlined_into,
cgraph_inlined_callees, cgraph_estimate_growth): Update to use inline_failed.
(cgraph_check_inline_limits): Likewise; Add argument reason.
(cgraph_set_inline_failed): New static function.
(cgraph_decide_inlining_of_small_function, cgraph_decide_inlining): Set
reasons.
(cgraph_inline_p): Add new argument reason.
* tree-inline.c (expand_call_inline): Update warning.
From-SVN: r75391
Diffstat (limited to 'gcc/cgraphunit.c')
-rw-r--r-- | gcc/cgraphunit.c | 171 |
1 files changed, 119 insertions, 52 deletions
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index 932c418..4b4aef0 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -38,6 +38,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "params.h" #include "fibheap.h" #include "c-common.h" +#include "intl.h" #define INSNS_PER_CALL 10 @@ -257,8 +258,6 @@ record_call_1 (tree *tp, int *walk_subtrees, void *data) tree decl = get_callee_fndecl (*tp); if (decl && TREE_CODE (decl) == FUNCTION_DECL) { - if (DECL_BUILT_IN (decl)) - return NULL; cgraph_record_call (data, decl); /* When we see a function call, we don't want to look at the @@ -311,6 +310,7 @@ static void cgraph_analyze_function (struct cgraph_node *node) { tree decl = node->decl; + struct cgraph_edge *e; current_function_decl = decl; @@ -325,6 +325,10 @@ cgraph_analyze_function (struct cgraph_node *node) if (node->local.inlinable) node->local.disregard_inline_limits = (*lang_hooks.tree_inlining.disregard_inline_limits) (decl); + for (e = node->callers; e; e = e->next_caller) + if (e->inline_failed) + e->inline_failed = (!node->local.inlinable ? N_("function not inlinable") + : N_("function not considered for inlining")); if (flag_really_no_inline && !node->local.disregard_inline_limits) node->local.inlinable = 0; /* Inlining characteristics are maintained by the cgraph_mark_inline. */ @@ -442,11 +446,12 @@ cgraph_mark_functions_to_output (void) { tree decl = node->decl; struct cgraph_edge *e; + if (node->output) abort (); for (e = node->callers; e; e = e->next_caller) - if (!e->inline_call) + if (e->inline_failed) break; /* We need to output all local functions that are used and not @@ -476,7 +481,7 @@ cgraph_optimize_function (struct cgraph_node *node) struct cgraph_edge *e; for (e = node->callees; e; e = e->next_callee) - if (e->inline_call || warn_inline) + if (!e->inline_failed || warn_inline) break; if (e) optimize_inline_calls (decl); @@ -512,6 +517,7 @@ cgraph_expand_function (struct cgraph_node *node) /* Fill array order with all nodes with output flag set in the reverse topological order. */ + static int cgraph_postorder (struct cgraph_node **order) { @@ -594,7 +600,7 @@ cgraph_inlined_into (struct cgraph_node *node, struct cgraph_node **array) /* Fast path: since we traverse in mostly topological order, we will likely find no edges. */ for (e = node->callers; e; e = e->next_caller) - if (e->inline_call) + if (!e->inline_failed) break; if (!e) @@ -626,8 +632,9 @@ cgraph_inlined_into (struct cgraph_node *node, struct cgraph_node **array) SET_INLINED_TIMES (caller, INLINED_TIMES (caller) + 1); for (e1 = caller->callers; e1; e1 = e1->next_caller) - if (e1->inline_call) + if (!e1->inline_failed) break; + if (e1) stack[sp++] = e1; else @@ -635,7 +642,7 @@ cgraph_inlined_into (struct cgraph_node *node, struct cgraph_node **array) while (true) { for (e1 = e->next_caller; e1; e1 = e1->next_caller) - if (e1->inline_call) + if (!e1->inline_failed) break; if (e1) @@ -692,7 +699,7 @@ cgraph_inlined_callees (struct cgraph_node *node, struct cgraph_node **array) /* Fast path: since we traverse in mostly topological order, we will likely find no edges. */ for (e = node->callees; e; e = e->next_callee) - if (e->inline_call) + if (!e->inline_failed) break; if (!e) @@ -724,7 +731,7 @@ cgraph_inlined_callees (struct cgraph_node *node, struct cgraph_node **array) SET_INLINED_TIMES (callee, INLINED_TIMES (callee) + 1); for (e1 = callee->callees; e1; e1 = e1->next_callee) - if (e1->inline_call) + if (!e1->inline_failed) break; if (e1) stack[sp++] = e1; @@ -733,7 +740,7 @@ cgraph_inlined_callees (struct cgraph_node *node, struct cgraph_node **array) while (true) { for (e1 = e->next_callee; e1; e1 = e1->next_callee) - if (e1->inline_call) + if (!e1->inline_failed) break; if (e1) @@ -791,7 +798,7 @@ cgraph_estimate_growth (struct cgraph_node *node) struct cgraph_edge *e; for (e = node->callers; e; e = e->next_caller) - if (!e->inline_call) + if (e->inline_failed) { growth += ((cgraph_estimate_size_after_inlining (1, e->caller, node) - @@ -833,13 +840,13 @@ cgraph_mark_inline (struct cgraph_node *to, struct cgraph_node *what, { if (e->caller == to) { - if (e->inline_call) - abort (); - e->inline_call = true; + if (!e->inline_failed) + continue; + e->inline_failed = NULL; times++; clones += e->caller->global.cloned_times; } - else if (!e->inline_call) + else if (e->inline_failed) called = true; } if (!times) @@ -884,7 +891,8 @@ cgraph_mark_inline (struct cgraph_node *to, struct cgraph_node *what, static bool cgraph_check_inline_limits (struct cgraph_node *to, struct cgraph_node *what, - struct cgraph_node **inlined, int ninlined) + struct cgraph_node **inlined, int ninlined, + const char **reason) { int i; int times = 0; @@ -908,7 +916,10 @@ cgraph_check_inline_limits (struct cgraph_node *to, struct cgraph_node *what, newsize = cgraph_estimate_size_after_inlining (times, to, what); if (newsize > PARAM_VALUE (PARAM_LARGE_FUNCTION_INSNS) && newsize > limit) - return false; + { + *reason = N_("--param large-function-growth limit reached"); + return false; + } for (i = 0; i < ninlined; i++) { newsize = @@ -918,7 +929,10 @@ cgraph_check_inline_limits (struct cgraph_node *to, struct cgraph_node *what, && newsize > inlined[i]->local.self_insns * (100 + PARAM_VALUE (PARAM_LARGE_FUNCTION_GROWTH)) / 100) - return false; + { + *reason = N_("--param large-function-growth limit reached while inlining the caller"); + return false; + } } return true; } @@ -936,6 +950,20 @@ cgraph_default_inline_p (struct cgraph_node *n) return n->global.insns < MAX_INLINE_INSNS_AUTO; } +/* Set inline_failed for all callers of given function to REASON. */ + +static void +cgraph_set_inline_failed (struct cgraph_node *node, const char *reason) +{ + struct cgraph_edge *e; + + if (cgraph_dump_file) + fprintf (cgraph_dump_file, "Inlining failed: %s\n", reason); + for (e = node->callers; e; e = e->next_caller) + if (e->inline_failed) + e->inline_failed = reason; +} + /* We use greedy algorithm for inlining of small functions: All inline candidates are put into prioritized heap based on estimated growth of the overall number of instructions and then update the estimates. @@ -960,25 +988,23 @@ cgraph_decide_inlining_of_small_functions (struct cgraph_node **inlined, for (node = cgraph_nodes; node; node = node->next) { - struct cgraph_edge *e; - if (!node->local.inlinable || !node->callers - || !cgraph_default_inline_p (node)) + || node->local.disregard_inline_limits) continue; - /* Rule out always_inline functions we dealt with earlier. */ - for (e = node->callers; e; e = e->next_caller) - if (e->inline_call) - break; - if (e) - continue; + if (!cgraph_default_inline_p (node)) + { + cgraph_set_inline_failed (node, + N_("--param max-inline-insns-single limit reached")); + continue; + } heap_node[node->uid] = fibheap_insert (heap, cgraph_estimate_growth (node), node); } if (cgraph_dump_file) fprintf (cgraph_dump_file, "\nDeciding on smaller functions:\n"); - while ((node = fibheap_extract_min (heap)) && overall_insns <= max_insns) + while (overall_insns <= max_insns && (node = fibheap_extract_min (heap))) { struct cgraph_edge *e; int old_insns = overall_insns; @@ -992,18 +1018,27 @@ cgraph_decide_inlining_of_small_functions (struct cgraph_node **inlined, cgraph_estimate_growth (node)); if (!cgraph_default_inline_p (node)) { - if (cgraph_dump_file) - fprintf (cgraph_dump_file, " Function too large.\n"); + cgraph_set_inline_failed (node, + N_("--param max-inline-insns-single limit reached after inlining into the callee")); continue; } ninlined_callees = cgraph_inlined_callees (node, inlined_callees); for (e = node->callers; e; e = e->next_caller) - if (!e->inline_call && e->caller != node) + if (e->inline_failed) { + /* Marking recursive function inlinine has sane semantic and + thus we should not warn on it. */ + if (e->caller == node) + { + e->inline_failed = ""; + continue; + } ninlined = cgraph_inlined_into (e->caller, inlined); + if (e->callee->output) + e->inline_failed = ""; if (e->callee->output || !cgraph_check_inline_limits (e->caller, node, inlined, - ninlined)) + ninlined, &e->inline_failed)) { for (i = 0; i < ninlined; i++) inlined[i]->output = 0, node->aux = 0; @@ -1039,7 +1074,7 @@ cgraph_decide_inlining_of_small_functions (struct cgraph_node **inlined, are now called more times; update keys. */ for (e = node->callees; e; e = e->next_callee) - if (!e->inline_call && heap_node[e->callee->uid]) + if (e->inline_failed && heap_node[e->callee->uid]) fibheap_replace_key (heap, heap_node[e->callee->uid], cgraph_estimate_growth (e->callee)); @@ -1048,7 +1083,7 @@ cgraph_decide_inlining_of_small_functions (struct cgraph_node **inlined, struct cgraph_edge *e; for (e = inlined_callees[i]->callees; e; e = e->next_callee) - if (!e->inline_call && heap_node[e->callee->uid]) + if (e->inline_failed && heap_node[e->callee->uid]) fibheap_replace_key (heap, heap_node[e->callee->uid], cgraph_estimate_growth (e->callee)); @@ -1059,8 +1094,9 @@ cgraph_decide_inlining_of_small_functions (struct cgraph_node **inlined, " Inlined %i times for a net change of %+i insns.\n", node->global.cloned_times, overall_insns - old_insns); } - if (cgraph_dump_file && !fibheap_empty (heap)) - fprintf (cgraph_dump_file, "\nReached the inline-unit-growth limit.\n"); + while ((node = fibheap_extract_min (heap)) != NULL) + if (!node->local.disregard_inline_limits) + cgraph_set_inline_failed (node, N_("--param inline-unit-growth limit reached")); fibheap_delete (heap); free (heap_node); } @@ -1122,10 +1158,14 @@ cgraph_decide_inlining (void) for (; e; e = e->next_callee) { old_insns = overall_insns; - if (e->inline_call || !e->callee->local.disregard_inline_limits) - continue; - if (e->callee->output || e->callee == node) - continue; + if (!e->inline_failed || !e->callee->local.inlinable + || !e->callee->local.disregard_inline_limits) + continue; + if (e->callee->output || e->callee == node) + { + e->inline_failed = N_("recursive inlining"); + continue; + } ninlined_callees = cgraph_inlined_callees (e->callee, inlined_callees); cgraph_mark_inline (node, e->callee, inlined, ninlined, @@ -1160,7 +1200,7 @@ cgraph_decide_inlining (void) node = order[i]; if (node->callers && !node->callers->next_caller && !node->needed - && node->local.inlinable && !node->callers->inline_call + && node->local.inlinable && node->callers->inline_failed && !DECL_EXTERNAL (node->decl) && !DECL_COMDAT (node->decl)) { bool ok = true; @@ -1168,12 +1208,13 @@ cgraph_decide_inlining (void) /* Verify that we won't duplicate the caller. */ for (node1 = node->callers->caller; - node1->callers && node1->callers->inline_call + node1->callers && node1->callers->inline_failed && ok; node1 = node1->callers->caller) if (node1->callers->next_caller || node1->needed) ok = false; if (ok) { + const char *dummy_reason; if (cgraph_dump_file) fprintf (cgraph_dump_file, "\nConsidering %s %i insns.\n" @@ -1184,8 +1225,11 @@ cgraph_decide_inlining (void) ninlined = cgraph_inlined_into (node->callers->caller, inlined); old_insns = overall_insns; + + /* Inlining functions once would never cause inlining warnings. */ if (cgraph_check_inline_limits - (node->callers->caller, node, inlined, ninlined)) + (node->callers->caller, node, inlined, ninlined, + &dummy_reason)) { ninlined_callees = cgraph_inlined_callees (node, inlined_callees); @@ -1245,9 +1289,16 @@ cgraph_decide_inlining_incrementally (struct cgraph_node *node) /* First of all look for always inline functions. */ for (e = node->callees; e; e = e->next_callee) - if (e->callee->local.disregard_inline_limits && !e->callee->output - && e->callee != node && !e->inline_call) + if (e->callee->local.disregard_inline_limits && e->inline_failed + /* ??? It is possible that renaming variable removed the function body + in duplicate_decls. See gcc.c-torture/compile/20011119-2.c */ + && DECL_SAVED_TREE (e->callee->decl)) { + if (e->callee->output || e->callee == node) + { + e->inline_failed = N_("recursive inlining"); + continue; + } ninlined_callees = cgraph_inlined_callees (e->callee, inlined_callees); cgraph_mark_inline (node, e->callee, inlined, ninlined, inlined_callees, ninlined_callees); @@ -1259,12 +1310,19 @@ cgraph_decide_inlining_incrementally (struct cgraph_node *node) { /* Now do the automatic inlining. */ for (e = node->callees; e; e = e->next_callee) - if (e->callee->local.inlinable && !e->callee->output - && e->callee != node && !e->inline_call + if (e->callee->local.inlinable && e->inline_failed && cgraph_default_inline_p (e->callee) && cgraph_check_inline_limits (node, e->callee, inlined, - ninlined)) + ninlined, &e->inline_failed) + && DECL_SAVED_TREE (e->callee->decl)) { + /* Marking recursive function inlinine has sane semantic and thus + we should not warn on it. */ + if (e->callee->output || e->callee == node) + { + e->inline_failed = ""; + continue; + } ninlined_callees = cgraph_inlined_callees (e->callee, inlined_callees); cgraph_mark_inline (node, e->callee, inlined, ninlined, @@ -1283,10 +1341,12 @@ cgraph_decide_inlining_incrementally (struct cgraph_node *node) } -/* Return true when CALLER_DECL should be inlined into CALLEE_DECL. */ +/* Return true when CALLER_DECL should be inlined into CALLEE_DECL. + When returned false and reason is non-NULL, set it to the reason + why the call was not inlined. */ bool -cgraph_inline_p (tree caller_decl, tree callee_decl) +cgraph_inline_p (tree caller_decl, tree callee_decl, const char **reason) { struct cgraph_node *caller = cgraph_node (caller_decl); struct cgraph_node *callee = cgraph_node (callee_decl); @@ -1294,10 +1354,16 @@ cgraph_inline_p (tree caller_decl, tree callee_decl) for (e = caller->callees; e; e = e->next_callee) if (e->callee == callee) - return e->inline_call; + { + if (e->inline_failed && reason) + *reason = e->inline_failed; + return !e->inline_failed; + } /* We do not record builtins in the callgraph. Perhaps it would make more sense to do so and then prune out those not overwritten by explicit function body. */ + if (reason) + *reason = "originally indirect function calls never inlined"; return false; } /* Expand all functions that must be output. @@ -1340,7 +1406,8 @@ cgraph_expand_all_functions (void) /* Mark all local functions. A local function is one whose calls can occur only in the - current compilation unit, so we change its calling convention. + current compilation unit and all it's calls are explicit, + so we can change its calling convention. We simply mark all static functions whose address is not taken as local. */ |