Commit dc0bfe6a by Jan Hubicka Committed by Jan Hubicka

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
parent e42870df
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> 2004-01-03 Nathanael Nerode <neroden@gcc.gnu.org>
* configure.ac: Replace AC_INIT, AC_OUTPUT, AC_CANONICAL_SYSTEM * configure.ac: Replace AC_INIT, AC_OUTPUT, AC_CANONICAL_SYSTEM
......
...@@ -1633,9 +1633,10 @@ simplify-rtx.o : simplify-rtx.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RT ...@@ -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 \ $(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) 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) \ 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) \ 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 \ 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 \ $(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 \ toplev.h $(GGC_H) $(TARGET_H) langhooks.h $(COVERAGE_H) libfuncs.h \
......
...@@ -34,6 +34,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA ...@@ -34,6 +34,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "cgraph.h" #include "cgraph.h"
#include "varray.h" #include "varray.h"
#include "output.h" #include "output.h"
#include "intl.h"
/* Hash table used to convert declarations into nodes. */ /* Hash table used to convert declarations into nodes. */
...@@ -156,7 +157,13 @@ create_edge (struct cgraph_node *caller, struct cgraph_node *callee) ...@@ -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 *edge = ggc_alloc (sizeof (struct cgraph_edge));
struct cgraph_edge *edge2; 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 /* 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 as we probably ought to, so we must preserve inline_call flags to
be the same in all copies of the same edge. */ be the same in all copies of the same edge. */
...@@ -164,7 +171,7 @@ create_edge (struct cgraph_node *caller, struct cgraph_node *callee) ...@@ -164,7 +171,7 @@ create_edge (struct cgraph_node *caller, struct cgraph_node *callee)
for (edge2 = caller->callees; edge2; edge2 = edge2->next_callee) for (edge2 = caller->callees; edge2; edge2 = edge2->next_callee)
if (edge2->callee == callee) if (edge2->callee == callee)
{ {
edge->inline_call = edge2->inline_call; edge->inline_failed = edge2->inline_failed;
break; break;
} }
...@@ -381,7 +388,7 @@ dump_cgraph (FILE *f) ...@@ -381,7 +388,7 @@ dump_cgraph (FILE *f)
for (edge = node->callers; edge; edge = edge->next_caller) for (edge = node->callers; edge; edge = edge->next_caller)
{ {
fprintf (f, "%s ", cgraph_node_name (edge->caller)); fprintf (f, "%s ", cgraph_node_name (edge->caller));
if (edge->inline_call) if (!edge->inline_failed)
fprintf(f, "(inlined) "); fprintf(f, "(inlined) ");
} }
...@@ -389,7 +396,7 @@ dump_cgraph (FILE *f) ...@@ -389,7 +396,7 @@ dump_cgraph (FILE *f)
for (edge = node->callees; edge; edge = edge->next_callee) for (edge = node->callees; edge; edge = edge->next_callee)
{ {
fprintf (f, "%s ", cgraph_node_name (edge->callee)); fprintf (f, "%s ", cgraph_node_name (edge->callee));
if (edge->inline_call) if (!edge->inline_failed)
fprintf(f, "(inlined) "); fprintf(f, "(inlined) ");
} }
fprintf (f, "\n"); fprintf (f, "\n");
......
...@@ -119,7 +119,9 @@ struct cgraph_edge GTY(()) ...@@ -119,7 +119,9 @@ struct cgraph_edge GTY(())
struct cgraph_node *callee; struct cgraph_node *callee;
struct cgraph_edge *next_caller; struct cgraph_edge *next_caller;
struct cgraph_edge *next_callee; 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. /* The cgraph_varpool data structure.
...@@ -181,6 +183,6 @@ void cgraph_create_edges (tree, tree); ...@@ -181,6 +183,6 @@ void cgraph_create_edges (tree, tree);
void cgraph_optimize (void); void cgraph_optimize (void);
void cgraph_mark_needed_node (struct cgraph_node *); void cgraph_mark_needed_node (struct cgraph_node *);
void cgraph_mark_reachable_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 */ #endif /* GCC_CGRAPH_H */
...@@ -38,6 +38,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA ...@@ -38,6 +38,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "params.h" #include "params.h"
#include "fibheap.h" #include "fibheap.h"
#include "c-common.h" #include "c-common.h"
#include "intl.h"
#define INSNS_PER_CALL 10 #define INSNS_PER_CALL 10
...@@ -257,8 +258,6 @@ record_call_1 (tree *tp, int *walk_subtrees, void *data) ...@@ -257,8 +258,6 @@ record_call_1 (tree *tp, int *walk_subtrees, void *data)
tree decl = get_callee_fndecl (*tp); tree decl = get_callee_fndecl (*tp);
if (decl && TREE_CODE (decl) == FUNCTION_DECL) if (decl && TREE_CODE (decl) == FUNCTION_DECL)
{ {
if (DECL_BUILT_IN (decl))
return NULL;
cgraph_record_call (data, decl); cgraph_record_call (data, decl);
/* When we see a function call, we don't want to look at the /* When we see a function call, we don't want to look at the
...@@ -311,6 +310,7 @@ static void ...@@ -311,6 +310,7 @@ static void
cgraph_analyze_function (struct cgraph_node *node) cgraph_analyze_function (struct cgraph_node *node)
{ {
tree decl = node->decl; tree decl = node->decl;
struct cgraph_edge *e;
current_function_decl = decl; current_function_decl = decl;
...@@ -325,6 +325,10 @@ cgraph_analyze_function (struct cgraph_node *node) ...@@ -325,6 +325,10 @@ cgraph_analyze_function (struct cgraph_node *node)
if (node->local.inlinable) if (node->local.inlinable)
node->local.disregard_inline_limits node->local.disregard_inline_limits
= (*lang_hooks.tree_inlining.disregard_inline_limits) (decl); = (*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) if (flag_really_no_inline && !node->local.disregard_inline_limits)
node->local.inlinable = 0; node->local.inlinable = 0;
/* Inlining characteristics are maintained by the cgraph_mark_inline. */ /* Inlining characteristics are maintained by the cgraph_mark_inline. */
...@@ -442,11 +446,12 @@ cgraph_mark_functions_to_output (void) ...@@ -442,11 +446,12 @@ cgraph_mark_functions_to_output (void)
{ {
tree decl = node->decl; tree decl = node->decl;
struct cgraph_edge *e; struct cgraph_edge *e;
if (node->output) if (node->output)
abort (); abort ();
for (e = node->callers; e; e = e->next_caller) for (e = node->callers; e; e = e->next_caller)
if (!e->inline_call) if (e->inline_failed)
break; break;
/* We need to output all local functions that are used and not /* We need to output all local functions that are used and not
...@@ -476,7 +481,7 @@ cgraph_optimize_function (struct cgraph_node *node) ...@@ -476,7 +481,7 @@ cgraph_optimize_function (struct cgraph_node *node)
struct cgraph_edge *e; struct cgraph_edge *e;
for (e = node->callees; e; e = e->next_callee) for (e = node->callees; e; e = e->next_callee)
if (e->inline_call || warn_inline) if (!e->inline_failed || warn_inline)
break; break;
if (e) if (e)
optimize_inline_calls (decl); optimize_inline_calls (decl);
...@@ -512,6 +517,7 @@ cgraph_expand_function (struct cgraph_node *node) ...@@ -512,6 +517,7 @@ cgraph_expand_function (struct cgraph_node *node)
/* Fill array order with all nodes with output flag set in the reverse /* Fill array order with all nodes with output flag set in the reverse
topological order. */ topological order. */
static int static int
cgraph_postorder (struct cgraph_node **order) cgraph_postorder (struct cgraph_node **order)
{ {
...@@ -594,7 +600,7 @@ cgraph_inlined_into (struct cgraph_node *node, struct cgraph_node **array) ...@@ -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 /* Fast path: since we traverse in mostly topological order, we will likely
find no edges. */ find no edges. */
for (e = node->callers; e; e = e->next_caller) for (e = node->callers; e; e = e->next_caller)
if (e->inline_call) if (!e->inline_failed)
break; break;
if (!e) if (!e)
...@@ -626,8 +632,9 @@ cgraph_inlined_into (struct cgraph_node *node, struct cgraph_node **array) ...@@ -626,8 +632,9 @@ cgraph_inlined_into (struct cgraph_node *node, struct cgraph_node **array)
SET_INLINED_TIMES (caller, INLINED_TIMES (caller) + 1); SET_INLINED_TIMES (caller, INLINED_TIMES (caller) + 1);
for (e1 = caller->callers; e1; e1 = e1->next_caller) for (e1 = caller->callers; e1; e1 = e1->next_caller)
if (e1->inline_call) if (!e1->inline_failed)
break; break;
if (e1) if (e1)
stack[sp++] = e1; stack[sp++] = e1;
else else
...@@ -635,7 +642,7 @@ cgraph_inlined_into (struct cgraph_node *node, struct cgraph_node **array) ...@@ -635,7 +642,7 @@ cgraph_inlined_into (struct cgraph_node *node, struct cgraph_node **array)
while (true) while (true)
{ {
for (e1 = e->next_caller; e1; e1 = e1->next_caller) for (e1 = e->next_caller; e1; e1 = e1->next_caller)
if (e1->inline_call) if (!e1->inline_failed)
break; break;
if (e1) if (e1)
...@@ -692,7 +699,7 @@ cgraph_inlined_callees (struct cgraph_node *node, struct cgraph_node **array) ...@@ -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 /* Fast path: since we traverse in mostly topological order, we will likely
find no edges. */ find no edges. */
for (e = node->callees; e; e = e->next_callee) for (e = node->callees; e; e = e->next_callee)
if (e->inline_call) if (!e->inline_failed)
break; break;
if (!e) if (!e)
...@@ -724,7 +731,7 @@ cgraph_inlined_callees (struct cgraph_node *node, struct cgraph_node **array) ...@@ -724,7 +731,7 @@ cgraph_inlined_callees (struct cgraph_node *node, struct cgraph_node **array)
SET_INLINED_TIMES (callee, INLINED_TIMES (callee) + 1); SET_INLINED_TIMES (callee, INLINED_TIMES (callee) + 1);
for (e1 = callee->callees; e1; e1 = e1->next_callee) for (e1 = callee->callees; e1; e1 = e1->next_callee)
if (e1->inline_call) if (!e1->inline_failed)
break; break;
if (e1) if (e1)
stack[sp++] = e1; stack[sp++] = e1;
...@@ -733,7 +740,7 @@ cgraph_inlined_callees (struct cgraph_node *node, struct cgraph_node **array) ...@@ -733,7 +740,7 @@ cgraph_inlined_callees (struct cgraph_node *node, struct cgraph_node **array)
while (true) while (true)
{ {
for (e1 = e->next_callee; e1; e1 = e1->next_callee) for (e1 = e->next_callee; e1; e1 = e1->next_callee)
if (e1->inline_call) if (!e1->inline_failed)
break; break;
if (e1) if (e1)
...@@ -791,7 +798,7 @@ cgraph_estimate_growth (struct cgraph_node *node) ...@@ -791,7 +798,7 @@ cgraph_estimate_growth (struct cgraph_node *node)
struct cgraph_edge *e; struct cgraph_edge *e;
for (e = node->callers; e; e = e->next_caller) 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) 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, ...@@ -833,13 +840,13 @@ cgraph_mark_inline (struct cgraph_node *to, struct cgraph_node *what,
{ {
if (e->caller == to) if (e->caller == to)
{ {
if (e->inline_call) if (!e->inline_failed)
abort (); continue;
e->inline_call = true; e->inline_failed = NULL;
times++; times++;
clones += e->caller->global.cloned_times; clones += e->caller->global.cloned_times;
} }
else if (!e->inline_call) else if (e->inline_failed)
called = true; called = true;
} }
if (!times) if (!times)
...@@ -884,7 +891,8 @@ cgraph_mark_inline (struct cgraph_node *to, struct cgraph_node *what, ...@@ -884,7 +891,8 @@ cgraph_mark_inline (struct cgraph_node *to, struct cgraph_node *what,
static bool static bool
cgraph_check_inline_limits (struct cgraph_node *to, struct cgraph_node *what, 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 i;
int times = 0; int times = 0;
...@@ -908,7 +916,10 @@ cgraph_check_inline_limits (struct cgraph_node *to, struct cgraph_node *what, ...@@ -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); newsize = cgraph_estimate_size_after_inlining (times, to, what);
if (newsize > PARAM_VALUE (PARAM_LARGE_FUNCTION_INSNS) if (newsize > PARAM_VALUE (PARAM_LARGE_FUNCTION_INSNS)
&& newsize > limit) && newsize > limit)
return false; {
*reason = N_("--param large-function-growth limit reached");
return false;
}
for (i = 0; i < ninlined; i++) for (i = 0; i < ninlined; i++)
{ {
newsize = newsize =
...@@ -918,7 +929,10 @@ cgraph_check_inline_limits (struct cgraph_node *to, struct cgraph_node *what, ...@@ -918,7 +929,10 @@ cgraph_check_inline_limits (struct cgraph_node *to, struct cgraph_node *what,
&& newsize > && newsize >
inlined[i]->local.self_insns * inlined[i]->local.self_insns *
(100 + PARAM_VALUE (PARAM_LARGE_FUNCTION_GROWTH)) / 100) (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; return true;
} }
...@@ -936,6 +950,20 @@ cgraph_default_inline_p (struct cgraph_node *n) ...@@ -936,6 +950,20 @@ cgraph_default_inline_p (struct cgraph_node *n)
return n->global.insns < MAX_INLINE_INSNS_AUTO; 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: /* We use greedy algorithm for inlining of small functions:
All inline candidates are put into prioritized heap based on estimated All inline candidates are put into prioritized heap based on estimated
growth of the overall number of instructions and then update the estimates. 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, ...@@ -960,25 +988,23 @@ cgraph_decide_inlining_of_small_functions (struct cgraph_node **inlined,
for (node = cgraph_nodes; node; node = node->next) for (node = cgraph_nodes; node; node = node->next)
{ {
struct cgraph_edge *e;
if (!node->local.inlinable || !node->callers if (!node->local.inlinable || !node->callers
|| !cgraph_default_inline_p (node)) || node->local.disregard_inline_limits)
continue; continue;
/* Rule out always_inline functions we dealt with earlier. */ if (!cgraph_default_inline_p (node))
for (e = node->callers; e; e = e->next_caller) {
if (e->inline_call) cgraph_set_inline_failed (node,
break; N_("--param max-inline-insns-single limit reached"));
if (e) continue;
continue; }
heap_node[node->uid] = heap_node[node->uid] =
fibheap_insert (heap, cgraph_estimate_growth (node), node); fibheap_insert (heap, cgraph_estimate_growth (node), node);
} }
if (cgraph_dump_file) if (cgraph_dump_file)
fprintf (cgraph_dump_file, "\nDeciding on smaller functions:\n"); 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; struct cgraph_edge *e;
int old_insns = overall_insns; int old_insns = overall_insns;
...@@ -992,18 +1018,27 @@ cgraph_decide_inlining_of_small_functions (struct cgraph_node **inlined, ...@@ -992,18 +1018,27 @@ cgraph_decide_inlining_of_small_functions (struct cgraph_node **inlined,
cgraph_estimate_growth (node)); cgraph_estimate_growth (node));
if (!cgraph_default_inline_p (node)) if (!cgraph_default_inline_p (node))
{ {
if (cgraph_dump_file) cgraph_set_inline_failed (node,
fprintf (cgraph_dump_file, " Function too large.\n"); N_("--param max-inline-insns-single limit reached after inlining into the callee"));
continue; continue;
} }
ninlined_callees = cgraph_inlined_callees (node, inlined_callees); ninlined_callees = cgraph_inlined_callees (node, inlined_callees);
for (e = node->callers; e; e = e->next_caller) 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); ninlined = cgraph_inlined_into (e->caller, inlined);
if (e->callee->output)
e->inline_failed = "";
if (e->callee->output if (e->callee->output
|| !cgraph_check_inline_limits (e->caller, node, inlined, || !cgraph_check_inline_limits (e->caller, node, inlined,
ninlined)) ninlined, &e->inline_failed))
{ {
for (i = 0; i < ninlined; i++) for (i = 0; i < ninlined; i++)
inlined[i]->output = 0, node->aux = 0; inlined[i]->output = 0, node->aux = 0;
...@@ -1039,7 +1074,7 @@ cgraph_decide_inlining_of_small_functions (struct cgraph_node **inlined, ...@@ -1039,7 +1074,7 @@ cgraph_decide_inlining_of_small_functions (struct cgraph_node **inlined,
are now called more times; update keys. */ are now called more times; update keys. */
for (e = node->callees; e; e = e->next_callee) 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], fibheap_replace_key (heap, heap_node[e->callee->uid],
cgraph_estimate_growth (e->callee)); cgraph_estimate_growth (e->callee));
...@@ -1048,7 +1083,7 @@ cgraph_decide_inlining_of_small_functions (struct cgraph_node **inlined, ...@@ -1048,7 +1083,7 @@ cgraph_decide_inlining_of_small_functions (struct cgraph_node **inlined,
struct cgraph_edge *e; struct cgraph_edge *e;
for (e = inlined_callees[i]->callees; e; e = e->next_callee) 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], fibheap_replace_key (heap, heap_node[e->callee->uid],
cgraph_estimate_growth (e->callee)); cgraph_estimate_growth (e->callee));
...@@ -1059,8 +1094,9 @@ cgraph_decide_inlining_of_small_functions (struct cgraph_node **inlined, ...@@ -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", " Inlined %i times for a net change of %+i insns.\n",
node->global.cloned_times, overall_insns - old_insns); node->global.cloned_times, overall_insns - old_insns);
} }
if (cgraph_dump_file && !fibheap_empty (heap)) while ((node = fibheap_extract_min (heap)) != NULL)
fprintf (cgraph_dump_file, "\nReached the inline-unit-growth limit.\n"); if (!node->local.disregard_inline_limits)
cgraph_set_inline_failed (node, N_("--param inline-unit-growth limit reached"));
fibheap_delete (heap); fibheap_delete (heap);
free (heap_node); free (heap_node);
} }
...@@ -1122,10 +1158,14 @@ cgraph_decide_inlining (void) ...@@ -1122,10 +1158,14 @@ cgraph_decide_inlining (void)
for (; e; e = e->next_callee) for (; e; e = e->next_callee)
{ {
old_insns = overall_insns; old_insns = overall_insns;
if (e->inline_call || !e->callee->local.disregard_inline_limits) if (!e->inline_failed || !e->callee->local.inlinable
continue; || !e->callee->local.disregard_inline_limits)
if (e->callee->output || e->callee == node) continue;
continue; if (e->callee->output || e->callee == node)
{
e->inline_failed = N_("recursive inlining");
continue;
}
ninlined_callees = ninlined_callees =
cgraph_inlined_callees (e->callee, inlined_callees); cgraph_inlined_callees (e->callee, inlined_callees);
cgraph_mark_inline (node, e->callee, inlined, ninlined, cgraph_mark_inline (node, e->callee, inlined, ninlined,
...@@ -1160,7 +1200,7 @@ cgraph_decide_inlining (void) ...@@ -1160,7 +1200,7 @@ cgraph_decide_inlining (void)
node = order[i]; node = order[i];
if (node->callers && !node->callers->next_caller && !node->needed 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)) && !DECL_EXTERNAL (node->decl) && !DECL_COMDAT (node->decl))
{ {
bool ok = true; bool ok = true;
...@@ -1168,12 +1208,13 @@ cgraph_decide_inlining (void) ...@@ -1168,12 +1208,13 @@ cgraph_decide_inlining (void)
/* Verify that we won't duplicate the caller. */ /* Verify that we won't duplicate the caller. */
for (node1 = node->callers->caller; for (node1 = node->callers->caller;
node1->callers && node1->callers->inline_call node1->callers && node1->callers->inline_failed
&& ok; node1 = node1->callers->caller) && ok; node1 = node1->callers->caller)
if (node1->callers->next_caller || node1->needed) if (node1->callers->next_caller || node1->needed)
ok = false; ok = false;
if (ok) if (ok)
{ {
const char *dummy_reason;
if (cgraph_dump_file) if (cgraph_dump_file)
fprintf (cgraph_dump_file, fprintf (cgraph_dump_file,
"\nConsidering %s %i insns.\n" "\nConsidering %s %i insns.\n"
...@@ -1184,8 +1225,11 @@ cgraph_decide_inlining (void) ...@@ -1184,8 +1225,11 @@ cgraph_decide_inlining (void)
ninlined = cgraph_inlined_into (node->callers->caller, ninlined = cgraph_inlined_into (node->callers->caller,
inlined); inlined);
old_insns = overall_insns; old_insns = overall_insns;
/* Inlining functions once would never cause inlining warnings. */
if (cgraph_check_inline_limits if (cgraph_check_inline_limits
(node->callers->caller, node, inlined, ninlined)) (node->callers->caller, node, inlined, ninlined,
&dummy_reason))
{ {
ninlined_callees = ninlined_callees =
cgraph_inlined_callees (node, inlined_callees); cgraph_inlined_callees (node, inlined_callees);
...@@ -1245,9 +1289,16 @@ cgraph_decide_inlining_incrementally (struct cgraph_node *node) ...@@ -1245,9 +1289,16 @@ cgraph_decide_inlining_incrementally (struct cgraph_node *node)
/* First of all look for always inline functions. */ /* First of all look for always inline functions. */
for (e = node->callees; e; e = e->next_callee) for (e = node->callees; e; e = e->next_callee)
if (e->callee->local.disregard_inline_limits && !e->callee->output if (e->callee->local.disregard_inline_limits && e->inline_failed
&& e->callee != node && !e->inline_call) /* ??? 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); ninlined_callees = cgraph_inlined_callees (e->callee, inlined_callees);
cgraph_mark_inline (node, e->callee, inlined, ninlined, cgraph_mark_inline (node, e->callee, inlined, ninlined,
inlined_callees, ninlined_callees); inlined_callees, ninlined_callees);
...@@ -1259,12 +1310,19 @@ cgraph_decide_inlining_incrementally (struct cgraph_node *node) ...@@ -1259,12 +1310,19 @@ cgraph_decide_inlining_incrementally (struct cgraph_node *node)
{ {
/* Now do the automatic inlining. */ /* Now do the automatic inlining. */
for (e = node->callees; e; e = e->next_callee) for (e = node->callees; e; e = e->next_callee)
if (e->callee->local.inlinable && !e->callee->output if (e->callee->local.inlinable && e->inline_failed
&& e->callee != node && !e->inline_call
&& cgraph_default_inline_p (e->callee) && cgraph_default_inline_p (e->callee)
&& cgraph_check_inline_limits (node, e->callee, inlined, && 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, ninlined_callees = cgraph_inlined_callees (e->callee,
inlined_callees); inlined_callees);
cgraph_mark_inline (node, e->callee, inlined, ninlined, cgraph_mark_inline (node, e->callee, inlined, ninlined,
...@@ -1283,10 +1341,12 @@ cgraph_decide_inlining_incrementally (struct cgraph_node *node) ...@@ -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 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 *caller = cgraph_node (caller_decl);
struct cgraph_node *callee = cgraph_node (callee_decl); struct cgraph_node *callee = cgraph_node (callee_decl);
...@@ -1294,10 +1354,16 @@ cgraph_inline_p (tree caller_decl, tree callee_decl) ...@@ -1294,10 +1354,16 @@ cgraph_inline_p (tree caller_decl, tree callee_decl)
for (e = caller->callees; e; e = e->next_callee) for (e = caller->callees; e; e = e->next_callee)
if (e->callee == 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 /* 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 sense to do so and then prune out those not overwritten by explicit
function body. */ function body. */
if (reason)
*reason = "originally indirect function calls never inlined";
return false; return false;
} }
/* Expand all functions that must be output. /* Expand all functions that must be output.
...@@ -1340,7 +1406,8 @@ cgraph_expand_all_functions (void) ...@@ -1340,7 +1406,8 @@ cgraph_expand_all_functions (void)
/* Mark all local functions. /* Mark all local functions.
A local function is one whose calls can occur only in the 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 We simply mark all static functions whose address is not taken
as local. */ as local. */
......
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> 2004-01-02 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
PR c++/13520 PR c++/13520
......
/* { 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;
}
/* { 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" "" } */
}
/* { 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" "" } */
}
/* { 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)
{
}
/* { 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" } */
}
/* { 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" } */
}
/* { 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" } */
}
...@@ -1247,6 +1247,7 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data) ...@@ -1247,6 +1247,7 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *data)
splay_tree st; splay_tree st;
tree args; tree args;
tree return_slot_addr; tree return_slot_addr;
const char *reason;
/* See what we've got. */ /* See what we've got. */
id = (inline_data *) data; id = (inline_data *) data;
...@@ -1327,12 +1328,13 @@ expand_call_inline (tree *tp, int *walk_subtrees, void *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 /* Don't try to inline functions that are not well-suited to
inlining. */ 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) if (warn_inline && DECL_DECLARED_INLINE_P (fn)
&& !DECL_IN_SYSTEM_HEADER (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"); warning ("called from here");
} }
return NULL_TREE; return NULL_TREE;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment