diff options
-rw-r--r-- | gcc/ChangeLog | 19 | ||||
-rw-r--r-- | gcc/Makefile.in | 5 | ||||
-rw-r--r-- | gcc/cgraph.c | 15 | ||||
-rw-r--r-- | gcc/cgraph.h | 6 | ||||
-rw-r--r-- | gcc/cgraphunit.c | 171 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/winline-1.c | 13 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/winline-2.c | 8 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/winline-3.c | 21 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/winline-4.c | 11 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/winline-5.c | 29 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/winline-6.c | 21 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/winline-7.c | 12 | ||||
-rw-r--r-- | gcc/tree-inline.c | 10 |
14 files changed, 281 insertions, 64 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 555a1e373aa..a1b09c01db3 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,22 @@ +2004-01-04 Jan Hubicka <jh@suse.cz> + + * 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. + 2004-01-03 Nathanael Nerode <neroden@gcc.gnu.org> * configure.ac: Replace AC_INIT, AC_OUTPUT, AC_CANONICAL_SYSTEM diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 13901411156..592acd81ef9 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1633,9 +1633,10 @@ simplify-rtx.o : simplify-rtx.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RT $(REGS_H) hard-reg-set.h flags.h real.h insn-config.h $(RECOG_H) $(EXPR_H) toplev.h \ output.h function.h $(GGC_H) $(OBSTACK_H) $(TM_P_H) $(TREE_H) $(TARGET_H) cgraph.o : cgraph.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - langhooks.h toplev.h flags.h $(GGC_H) $(TARGET_H) cgraph.h gt-cgraph.h output.h + langhooks.h toplev.h flags.h $(GGC_H) $(TARGET_H) cgraph.h gt-cgraph.h \ + output.h intl.h cgraphunit.o : cgraphunit.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ - langhooks.h tree-inline.h toplev.h flags.h $(GGC_H) $(TARGET_H) cgraph.h + langhooks.h tree-inline.h toplev.h flags.h $(GGC_H) $(TARGET_H) cgraph.h intl.h coverage.o : coverage.c gcov-io.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(TM_H) $(RTL_H) $(TREE_H) flags.h output.h $(REGS_H) $(EXPR_H) function.h \ toplev.h $(GGC_H) $(TARGET_H) langhooks.h $(COVERAGE_H) libfuncs.h \ diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 26cbd27100c..73a420e6e7c 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -34,6 +34,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "cgraph.h" #include "varray.h" #include "output.h" +#include "intl.h" /* Hash table used to convert declarations into nodes. */ @@ -156,7 +157,13 @@ create_edge (struct cgraph_node *caller, struct cgraph_node *callee) struct cgraph_edge *edge = ggc_alloc (sizeof (struct cgraph_edge)); struct cgraph_edge *edge2; - edge->inline_call = false; + if (!DECL_SAVED_TREE (callee->decl)) + edge->inline_failed = N_("function body not available"); + else if (callee->local.inlinable) + edge->inline_failed = N_("function not considered for inlining"); + else + edge->inline_failed = N_("function not inlinable"); + /* At the moment we don't associate calls with specific CALL_EXPRs as we probably ought to, so we must preserve inline_call flags to be the same in all copies of the same edge. */ @@ -164,7 +171,7 @@ create_edge (struct cgraph_node *caller, struct cgraph_node *callee) for (edge2 = caller->callees; edge2; edge2 = edge2->next_callee) if (edge2->callee == callee) { - edge->inline_call = edge2->inline_call; + edge->inline_failed = edge2->inline_failed; break; } @@ -381,7 +388,7 @@ dump_cgraph (FILE *f) for (edge = node->callers; edge; edge = edge->next_caller) { fprintf (f, "%s ", cgraph_node_name (edge->caller)); - if (edge->inline_call) + if (!edge->inline_failed) fprintf(f, "(inlined) "); } @@ -389,7 +396,7 @@ dump_cgraph (FILE *f) for (edge = node->callees; edge; edge = edge->next_callee) { fprintf (f, "%s ", cgraph_node_name (edge->callee)); - if (edge->inline_call) + if (!edge->inline_failed) fprintf(f, "(inlined) "); } fprintf (f, "\n"); diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 9540eccd937..5cf31d7afae 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -119,7 +119,9 @@ struct cgraph_edge GTY(()) struct cgraph_node *callee; struct cgraph_edge *next_caller; struct cgraph_edge *next_callee; - bool inline_call; + /* When NULL, inline this call. When non-NULL, points to the explanation + why function was not inlined. */ + const char *inline_failed; }; /* The cgraph_varpool data structure. @@ -181,6 +183,6 @@ void cgraph_create_edges (tree, tree); void cgraph_optimize (void); void cgraph_mark_needed_node (struct cgraph_node *); void cgraph_mark_reachable_node (struct cgraph_node *); -bool cgraph_inline_p (tree, tree); +bool cgraph_inline_p (tree, tree, const char **reason); #endif /* GCC_CGRAPH_H */ diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index 932c418a073..4b4aef046ed 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. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 55b8f033e6b..0b82e5877c8 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2004-01-04 Jan Hubicka <jh@suse.cz> + + * gcc.dg/winline[1-7].c: New tests. + 2004-01-02 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net> PR c++/13520 diff --git a/gcc/testsuite/gcc.dg/winline-1.c b/gcc/testsuite/gcc.dg/winline-1.c new file mode 100644 index 00000000000..ac2ae82427a --- /dev/null +++ b/gcc/testsuite/gcc.dg/winline-1.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-Winline -O2" } */ + +void q(void); +inline int t(void) +{ + int ret; + q(); + ret = t(); /* We define sane semantics for inline keyword on recursive + functions, so do not warn here. */ + q(); + return ret; +} diff --git a/gcc/testsuite/gcc.dg/winline-2.c b/gcc/testsuite/gcc.dg/winline-2.c new file mode 100644 index 00000000000..584c68fddf6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/winline-2.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-options "-Winline -O2" } */ + +inline int q(void); /* { dg-warning "body not available" "" } */ +inline int t(void) +{ + return q(); /* { dg-warning "called from here" "" } */ +} diff --git a/gcc/testsuite/gcc.dg/winline-3.c b/gcc/testsuite/gcc.dg/winline-3.c new file mode 100644 index 00000000000..ce9e08012ca --- /dev/null +++ b/gcc/testsuite/gcc.dg/winline-3.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-Winline -O2 --param max-inline-insns-single=1" } */ + +void big (void); +inline int q(void) +{ /* { dg-warning "max-inline-insns-single" "" } */ + big(); + big(); + big(); + big(); + big(); + big(); + big(); + big(); + big(); + big(); +} +inline int t (void) +{ + return q (); /* { dg-warning "called from here" "" } */ +} diff --git a/gcc/testsuite/gcc.dg/winline-4.c b/gcc/testsuite/gcc.dg/winline-4.c new file mode 100644 index 00000000000..5ce0a02202d --- /dev/null +++ b/gcc/testsuite/gcc.dg/winline-4.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-Winline -O1 -fno-unit-at-a-time" } */ + +inline int q(void); /* { dg-warning "body not available" } */ +inline int t(void) +{ + return q(); /* { dg-warning "called from here" } */ +} +int q(void) +{ +} diff --git a/gcc/testsuite/gcc.dg/winline-5.c b/gcc/testsuite/gcc.dg/winline-5.c new file mode 100644 index 00000000000..20df786a757 --- /dev/null +++ b/gcc/testsuite/gcc.dg/winline-5.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-options "-Winline -O2 --param inline-unit-growth=0" } */ + +void big (void); +inline int q(void) +{ /* { dg-warning "inline-unit-growth" } */ + big(); + big(); + big(); + big(); + big(); + big(); + big(); + big(); + big(); + big(); +} +inline int q1(void) +{ + big(); + big(); + big(); +} +int t (void) +{ + /* We allow one inlining over limit. */ + q1(); + return q (); /* { dg-warning "called from here" } */ +} diff --git a/gcc/testsuite/gcc.dg/winline-6.c b/gcc/testsuite/gcc.dg/winline-6.c new file mode 100644 index 00000000000..7ce7481a3ef --- /dev/null +++ b/gcc/testsuite/gcc.dg/winline-6.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-Winline -O2 --param large-function-growth=0 --param large-function-insns=1" } */ + +void big (void); +inline int q(void) +{ /* { dg-warning "large-function-growth" } */ + big(); + big(); + big(); + big(); + big(); + big(); + big(); + big(); + big(); + big(); +} +inline int t (void) +{ + return q (); /* { dg-warning "called from here" } */ +} diff --git a/gcc/testsuite/gcc.dg/winline-7.c b/gcc/testsuite/gcc.dg/winline-7.c new file mode 100644 index 00000000000..03b951763dc --- /dev/null +++ b/gcc/testsuite/gcc.dg/winline-7.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-Winline -O2" } */ + +void big (void); +inline int q(void) +{ /* { dg-warning "(function not inlinable|alloca)" } */ + return (int)alloca(10); +} +inline int t (void) +{ + return q (); /* { dg-warning "called from here" } */ +} diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index 48b59a41ed5..9d73be287ba 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -1247,6 +1247,7 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data) splay_tree st; tree args; tree return_slot_addr; + const char *reason; /* See what we've got. */ id = (inline_data *) data; @@ -1327,12 +1328,13 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data) /* Don't try to inline functions that are not well-suited to inlining. */ - if (!DECL_SAVED_TREE (fn) || !cgraph_inline_p (id->current_decl, fn)) + if (!cgraph_inline_p (id->current_decl, fn, &reason)) { - if (warn_inline && DECL_INLINE (fn) && DECL_DECLARED_INLINE_P (fn) - && !DECL_IN_SYSTEM_HEADER (fn)) + if (warn_inline && DECL_DECLARED_INLINE_P (fn) + && !DECL_IN_SYSTEM_HEADER (fn) + && strlen (reason)) { - warning ("%Jinlining failed in call to '%F'", fn, fn); + warning ("%Jinlining failed in call to '%F': %s", fn, fn, reason); warning ("called from here"); } return NULL_TREE; |