aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Guenther <rguenther@suse.de>2011-04-06 08:51:23 +0000
committerRichard Biener <rguenth@gcc.gnu.org>2011-04-06 08:51:23 +0000
commitd7d1d041aedeeb19cc16c718ec517aaeac81c10e (patch)
tree2e899a35ae492409cf1aea6ceba40b33bc2febab
parent2feb95f7d8c340e425d977a660d7b6d4c3282792 (diff)
downloadgcc-d7d1d041aedeeb19cc16c718ec517aaeac81c10e.zip
gcc-d7d1d041aedeeb19cc16c718ec517aaeac81c10e.tar.gz
gcc-d7d1d041aedeeb19cc16c718ec517aaeac81c10e.tar.bz2
re PR middle-end/47663 (Very simple wrapper not inlined)
2011-04-06 Richard Guenther <rguenther@suse.de> PR tree-optimization/47663 * cgraph.h (struct cgraph_edge): Add call_stmt_size and call_stmt_time fields. (cgraph_edge_inlinable_p): Declare. (cgraph_edge_recursive_p): New inline function. * cgraph.c (cgraph_create_edge_1): Initialize call_stmt_size. (cgraph_clone_edge): Copy it. * ipa-inline.c (cgraph_estimate_edge_time): New function. Account for call stmt time. (cgraph_estimate_time_after_inlining): Take edge argument. (cgraph_estimate_edge_growth): Account call stmt size. (cgraph_estimate_size_after_inlining): Take edge argument. (cgraph_mark_inline_edge): Adjust. (cgraph_check_inline_limits): Likewise. (cgraph_recursive_inlining_p): Remove. (cgraph_edge_badness): Use cgraph_edge_recursive_p. (cgraph_decide_recursive_inlining): Take edge argument and adjust. (cgraph_decide_inlining_of_small_functions): Do not avoid diags for recursive inlining here. (cgraph_flatten): Adjust. (cgraph_decide_inlining_incrementally): Likewise. (estimate_function_body_sizes): Remove call cost handling. (compute_inline_parameters): Initialize caller edge call costs. (cgraph_estimate_edge_growth): New function. (cgraph_estimate_growth): Use it. (cgraph_edge_badness): Likewise. (cgraph_check_inline_limits): Take an edge argument. (cgraph_decide_inlining_of_small_functions): Adjust. (cgraph_decide_inlining): Likewise. * tree-inline.c (estimate_num_insns): Only account for call return value if it is used. (expand_call_inline): Avoid diagnostics on recursive inline functions here. * lto-cgraph.c (lto_output_edge): Output edge call costs. (input_edge): Input edge call costs. * gcc.dg/tree-ssa/inline-8.c: New testcase. From-SVN: r172023
-rw-r--r--gcc/ChangeLog39
-rw-r--r--gcc/cgraph.c4
-rw-r--r--gcc/cgraph.h15
-rw-r--r--gcc/ipa-inline.c263
-rw-r--r--gcc/lto-cgraph.c7
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/inline-8.c31
-rw-r--r--gcc/tree-inline.c5
8 files changed, 232 insertions, 137 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index b72dbd0..7b473e8 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,42 @@
+2011-04-06 Richard Guenther <rguenther@suse.de>
+
+ PR tree-optimization/47663
+ * cgraph.h (struct cgraph_edge): Add call_stmt_size and
+ call_stmt_time fields.
+ (cgraph_edge_inlinable_p): Declare.
+ (cgraph_edge_recursive_p): New inline function.
+ * cgraph.c (cgraph_create_edge_1): Initialize call_stmt_size.
+ (cgraph_clone_edge): Copy it.
+ * ipa-inline.c (cgraph_estimate_edge_time): New function.
+ Account for call stmt time.
+ (cgraph_estimate_time_after_inlining): Take edge argument.
+ (cgraph_estimate_edge_growth): Account call stmt size.
+ (cgraph_estimate_size_after_inlining): Take edge argument.
+ (cgraph_mark_inline_edge): Adjust.
+ (cgraph_check_inline_limits): Likewise.
+ (cgraph_recursive_inlining_p): Remove.
+ (cgraph_edge_badness): Use cgraph_edge_recursive_p.
+ (cgraph_decide_recursive_inlining): Take edge argument and
+ adjust.
+ (cgraph_decide_inlining_of_small_functions): Do not avoid
+ diags for recursive inlining here.
+ (cgraph_flatten): Adjust.
+ (cgraph_decide_inlining_incrementally): Likewise.
+ (estimate_function_body_sizes): Remove call cost handling.
+ (compute_inline_parameters): Initialize caller edge call costs.
+ (cgraph_estimate_edge_growth): New function.
+ (cgraph_estimate_growth): Use it.
+ (cgraph_edge_badness): Likewise.
+ (cgraph_check_inline_limits): Take an edge argument.
+ (cgraph_decide_inlining_of_small_functions): Adjust.
+ (cgraph_decide_inlining): Likewise.
+ * tree-inline.c (estimate_num_insns): Only account for call
+ return value if it is used.
+ (expand_call_inline): Avoid diagnostics on recursive inline
+ functions here.
+ * lto-cgraph.c (lto_output_edge): Output edge call costs.
+ (input_edge): Input edge call costs.
+
2011-04-06 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
* config/alpha/osf5.h (MAX_OFILE_ALIGNMENT): Define.
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index 3cf75f2..a6217e9 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -1032,6 +1032,8 @@ cgraph_create_edge_1 (struct cgraph_node *caller, struct cgraph_node *callee,
edge->loop_nest = nest;
edge->call_stmt = call_stmt;
+ edge->call_stmt_size = 0;
+ edge->call_stmt_time = 0;
push_cfun (DECL_STRUCT_FUNCTION (caller->decl));
edge->can_throw_external
= call_stmt ? stmt_can_throw_external (call_stmt) : false;
@@ -2141,6 +2143,8 @@ cgraph_clone_edge (struct cgraph_edge *e, struct cgraph_node *n,
}
}
+ new_edge->call_stmt_size = e->call_stmt_size;
+ new_edge->call_stmt_time = e->call_stmt_time;
new_edge->inline_failed = e->inline_failed;
new_edge->indirect_inlining_edge = e->indirect_inlining_edge;
new_edge->lto_stmt_uid = stmt_uid;
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index e774c00..1d3a87b 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -431,6 +431,9 @@ struct GTY((chain_next ("%h.next_caller"), chain_prev ("%h.prev_caller"))) cgrap
int frequency;
/* Unique id of the edge. */
int uid;
+ /* Estimated size and time of the call statement. */
+ int call_stmt_size;
+ int call_stmt_time;
/* Depth of loop nest, 1 means no loop nest. */
unsigned short int loop_nest;
/* Whether this edge was made direct by indirect inlining. */
@@ -771,6 +774,7 @@ varpool_next_static_initializer (struct varpool_node *node)
/* In ipa-inline.c */
void cgraph_clone_inlined_nodes (struct cgraph_edge *, bool, bool);
void compute_inline_parameters (struct cgraph_node *);
+cgraph_inline_failed_t cgraph_edge_inlinable_p (struct cgraph_edge *);
/* Create a new static variable of type TYPE. */
@@ -958,6 +962,17 @@ varpool_all_refs_explicit_p (struct varpool_node *vnode)
/* Constant pool accessor function. */
htab_t constant_pool_htab (void);
+/* Return true when the edge E represents a direct recursion. */
+static inline bool
+cgraph_edge_recursive_p (struct cgraph_edge *e)
+{
+ if (e->caller->global.inlined_to)
+ return e->caller->global.inlined_to->decl == e->callee->decl;
+ else
+ return e->caller->decl == e->callee->decl;
+}
+
+
/* FIXME: inappropriate dependency of cgraph on IPA. */
#include "ipa-ref-inline.h"
diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index 77ab17e..af92393 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -164,16 +164,31 @@ inline_summary (struct cgraph_node *node)
return &node->local.inline_summary;
}
-/* Estimate self time of the function after inlining WHAT into TO. */
+/* Estimate the time cost for the caller when inlining EDGE. */
+
+static inline int
+cgraph_estimate_edge_time (struct cgraph_edge *edge)
+{
+ int call_stmt_time;
+ /* ??? We throw away cgraph edges all the time so the information
+ we store in edges doesn't persist for early inlining. Ugh. */
+ if (!edge->call_stmt)
+ call_stmt_time = edge->call_stmt_time;
+ else
+ call_stmt_time = estimate_num_insns (edge->call_stmt, &eni_time_weights);
+ return (((gcov_type)edge->callee->global.time
+ - inline_summary (edge->callee)->time_inlining_benefit
+ - call_stmt_time) * edge->frequency
+ + CGRAPH_FREQ_BASE / 2) / CGRAPH_FREQ_BASE;
+}
+
+/* Estimate self time of the function NODE after inlining EDGE. */
static int
-cgraph_estimate_time_after_inlining (int frequency, struct cgraph_node *to,
- struct cgraph_node *what)
+cgraph_estimate_time_after_inlining (struct cgraph_node *node,
+ struct cgraph_edge *edge)
{
- gcov_type time = (((gcov_type)what->global.time
- - inline_summary (what)->time_inlining_benefit)
- * frequency + CGRAPH_FREQ_BASE / 2) / CGRAPH_FREQ_BASE
- + to->global.time;
+ gcov_type time = node->global.time + cgraph_estimate_edge_time (edge);
if (time < 0)
time = 0;
if (time > MAX_TIME)
@@ -181,14 +196,31 @@ cgraph_estimate_time_after_inlining (int frequency, struct cgraph_node *to,
return time;
}
-/* Estimate self size of the function after inlining WHAT into TO. */
+/* Estimate the growth of the caller when inlining EDGE. */
static inline int
-cgraph_estimate_size_after_inlining (struct cgraph_node *to,
- struct cgraph_node *what)
+cgraph_estimate_edge_growth (struct cgraph_edge *edge)
{
- int size = ((what->global.size - inline_summary (what)->size_inlining_benefit)
- + to->global.size);
+ int call_stmt_size;
+ /* ??? We throw away cgraph edges all the time so the information
+ we store in edges doesn't persist for early inlining. Ugh. */
+ if (!edge->call_stmt)
+ call_stmt_size = edge->call_stmt_size;
+ else
+ call_stmt_size = estimate_num_insns (edge->call_stmt, &eni_size_weights);
+ return (edge->callee->global.size
+ - inline_summary (edge->callee)->size_inlining_benefit
+ - call_stmt_size);
+}
+
+/* Estimate the size of NODE after inlining EDGE which should be an
+ edge to either NODE or a call inlined into NODE. */
+
+static inline int
+cgraph_estimate_size_after_inlining (struct cgraph_node *node,
+ struct cgraph_edge *edge)
+{
+ int size = node->global.size + cgraph_estimate_edge_growth (edge);
gcc_assert (size >= 0);
return size;
}
@@ -301,9 +333,8 @@ cgraph_mark_inline_edge (struct cgraph_edge *e, bool update_original,
VEC (cgraph_edge_p, heap) **new_edges)
{
int old_size = 0, new_size = 0;
- struct cgraph_node *to = NULL, *what;
+ struct cgraph_node *to = NULL;
struct cgraph_edge *curr = e;
- int freq;
/* Don't inline inlined edges. */
gcc_assert (e->inline_failed);
@@ -315,19 +346,16 @@ cgraph_mark_inline_edge (struct cgraph_edge *e, bool update_original,
cgraph_clone_inlined_nodes (e, true, update_original);
- what = e->callee;
-
- freq = e->frequency;
/* Now update size of caller and all functions caller is inlined into. */
for (;e && !e->inline_failed; e = e->caller->callers)
{
to = e->caller;
old_size = e->caller->global.size;
- new_size = cgraph_estimate_size_after_inlining (to, what);
+ new_size = cgraph_estimate_size_after_inlining (to, e);
to->global.size = new_size;
- to->global.time = cgraph_estimate_time_after_inlining (freq, to, what);
+ to->global.time = cgraph_estimate_time_after_inlining (to, e);
}
- gcc_assert (what->global.inlined_to == to);
+ gcc_assert (curr->callee->global.inlined_to == to);
if (new_size > old_size)
overall_size += new_size - old_size;
ncalls_inlined++;
@@ -357,8 +385,7 @@ cgraph_estimate_growth (struct cgraph_node *node)
if (e->caller == node)
self_recursive = true;
if (e->inline_failed)
- growth += (cgraph_estimate_size_after_inlining (e->caller, node)
- - e->caller->global.size);
+ growth += cgraph_estimate_edge_growth (e);
}
/* ??? Wrong for non-trivially self recursive functions or cases where
@@ -379,17 +406,17 @@ cgraph_estimate_growth (struct cgraph_node *node)
return growth;
}
-/* Return false when inlining WHAT into TO is not good idea
- as it would cause too large growth of function bodies.
- When ONE_ONLY is true, assume that only one call site is going
- to be inlined, otherwise figure out how many call sites in
- TO calls WHAT and verify that all can be inlined.
- */
+/* Return false when inlining edge E is not good idea
+ as it would cause too large growth of the callers function body
+ or stack frame size. *REASON if non-NULL is updated if the
+ inlining is not a good idea. */
static bool
-cgraph_check_inline_limits (struct cgraph_node *to, struct cgraph_node *what,
+cgraph_check_inline_limits (struct cgraph_edge *e,
cgraph_inline_failed_t *reason)
{
+ struct cgraph_node *to = e->caller;
+ struct cgraph_node *what = e->callee;
int newsize;
int limit;
HOST_WIDE_INT stack_size_limit, inlined_stack;
@@ -408,7 +435,7 @@ cgraph_check_inline_limits (struct cgraph_node *to, struct cgraph_node *what,
/* Check the size after inlining against the function limits. But allow
the function to shrink if it went over the limits by forced inlining. */
- newsize = cgraph_estimate_size_after_inlining (to, what);
+ newsize = cgraph_estimate_size_after_inlining (to, e);
if (newsize >= to->global.size
&& newsize > PARAM_VALUE (PARAM_LARGE_FUNCTION_INSNS)
&& newsize > limit)
@@ -487,28 +514,6 @@ cgraph_default_inline_p (struct cgraph_node *n, cgraph_inline_failed_t *reason)
return true;
}
-/* Return true when inlining WHAT would create recursive inlining.
- We call recursive inlining all cases where same function appears more than
- once in the single recursion nest path in the inline graph. */
-
-static inline bool
-cgraph_recursive_inlining_p (struct cgraph_node *to,
- struct cgraph_node *what,
- cgraph_inline_failed_t *reason)
-{
- bool recursive;
- if (to->global.inlined_to)
- recursive = what->decl == to->global.inlined_to->decl;
- else
- recursive = what->decl == to->decl;
- /* Marking recursive function inline has sane semantic and thus we should
- not warn on it. */
- if (recursive && reason)
- *reason = (what->local.disregard_inline_limits
- ? CIF_RECURSIVE_INLINING : CIF_UNSPECIFIED);
- return recursive;
-}
-
/* A cost model driving the inlining heuristics in a way so the edges with
smallest badness are inlined first. After each inlining is performed
the costs of all caller edges of nodes affected are recomputed so the
@@ -524,9 +529,7 @@ cgraph_edge_badness (struct cgraph_edge *edge, bool dump)
if (edge->callee->local.disregard_inline_limits)
return INT_MIN;
- growth =
- (cgraph_estimate_size_after_inlining (edge->caller, edge->callee)
- - edge->caller->global.size);
+ growth = cgraph_estimate_edge_growth (edge);
if (dump)
{
@@ -536,9 +539,11 @@ cgraph_edge_badness (struct cgraph_edge *edge, bool dump)
fprintf (dump_file, " growth %i, time %i-%i, size %i-%i\n",
growth,
edge->callee->global.time,
- inline_summary (edge->callee)->time_inlining_benefit,
+ inline_summary (edge->callee)->time_inlining_benefit
+ + edge->call_stmt_time,
edge->callee->global.size,
- inline_summary (edge->callee)->size_inlining_benefit);
+ inline_summary (edge->callee)->size_inlining_benefit
+ + edge->call_stmt_size);
}
/* Always prefer inlining saving code size. */
@@ -557,7 +562,8 @@ cgraph_edge_badness (struct cgraph_edge *edge, bool dump)
badness =
((int)
((double) edge->count * INT_MIN / max_count / (max_benefit + 1)) *
- (inline_summary (edge->callee)->time_inlining_benefit + 1)) / growth;
+ (inline_summary (edge->callee)->time_inlining_benefit
+ + edge->call_stmt_time + 1)) / growth;
if (dump)
{
fprintf (dump_file,
@@ -566,7 +572,8 @@ cgraph_edge_badness (struct cgraph_edge *edge, bool dump)
(int) badness, (double) badness / INT_MIN,
(double) edge->count / max_count,
(double) (inline_summary (edge->callee)->
- time_inlining_benefit + 1) / (max_benefit + 1));
+ time_inlining_benefit
+ + edge->call_stmt_time + 1) / (max_benefit + 1));
}
}
@@ -586,8 +593,9 @@ cgraph_edge_badness (struct cgraph_edge *edge, bool dump)
int growth_for_all;
badness = growth * 10000;
benefitperc =
- 100 * inline_summary (edge->callee)->time_inlining_benefit
- / (edge->callee->global.time + 1) +1;
+ 100 * (inline_summary (edge->callee)->time_inlining_benefit
+ + edge->call_stmt_time)
+ / (edge->callee->global.time + 1) + 1;
benefitperc = MIN (benefitperc, 100);
div *= benefitperc;
@@ -636,7 +644,7 @@ cgraph_edge_badness (struct cgraph_edge *edge, bool dump)
gcc_assert (badness >= INT_MIN);
gcc_assert (badness <= INT_MAX - 1);
/* Make recursive inlining happen always after other inlining is done. */
- if (cgraph_recursive_inlining_p (edge->caller, edge->callee, NULL))
+ if (cgraph_edge_recursive_p (edge))
return badness + 1;
else
return badness;
@@ -822,18 +830,23 @@ lookup_recursive_calls (struct cgraph_node *node, struct cgraph_node *where,
is NULL. */
static bool
-cgraph_decide_recursive_inlining (struct cgraph_node *node,
+cgraph_decide_recursive_inlining (struct cgraph_edge *edge,
VEC (cgraph_edge_p, heap) **new_edges)
{
int limit = PARAM_VALUE (PARAM_MAX_INLINE_INSNS_RECURSIVE_AUTO);
int max_depth = PARAM_VALUE (PARAM_MAX_INLINE_RECURSIVE_DEPTH_AUTO);
int probability = PARAM_VALUE (PARAM_MIN_INLINE_RECURSIVE_PROBABILITY);
fibheap_t heap;
+ struct cgraph_node *node;
struct cgraph_edge *e;
struct cgraph_node *master_clone, *next;
int depth = 0;
int n = 0;
+ node = edge->caller;
+ if (node->global.inlined_to)
+ node = node->global.inlined_to;
+
/* It does not make sense to recursively inline always-inline functions
as we are going to sorry() on the remaining calls anyway. */
if (node->local.disregard_inline_limits
@@ -852,7 +865,7 @@ cgraph_decide_recursive_inlining (struct cgraph_node *node,
/* Make sure that function is small enough to be considered for inlining. */
if (!max_depth
- || cgraph_estimate_size_after_inlining (node, node) >= limit)
+ || cgraph_estimate_size_after_inlining (node, edge) >= limit)
return false;
heap = fibheap_new ();
lookup_recursive_calls (node, node, heap);
@@ -876,14 +889,15 @@ cgraph_decide_recursive_inlining (struct cgraph_node *node,
cgraph_clone_inlined_nodes (e, true, false);
/* Do the inlining and update list of recursive call during process. */
- while (!fibheap_empty (heap)
- && (cgraph_estimate_size_after_inlining (node, master_clone)
- <= limit))
+ while (!fibheap_empty (heap))
{
struct cgraph_edge *curr
= (struct cgraph_edge *) fibheap_extract_min (heap);
struct cgraph_node *cnode;
+ if (cgraph_estimate_size_after_inlining (node, curr) > limit)
+ break;
+
depth = 1;
for (cnode = curr->caller;
cnode->global.inlined_to; cnode = cnode->callers->caller)
@@ -1083,10 +1097,7 @@ cgraph_decide_inlining_of_small_functions (void)
}
callee = edge->callee;
-
- growth = (cgraph_estimate_size_after_inlining (edge->caller, edge->callee)
- - edge->caller->global.size);
-
+ growth = cgraph_estimate_edge_growth (edge);
if (dump_file)
{
fprintf (dump_file,
@@ -1155,25 +1166,17 @@ cgraph_decide_inlining_of_small_functions (void)
not_good = CIF_OPTIMIZING_FOR_SIZE;
if (not_good && growth > 0 && cgraph_estimate_growth (edge->callee) > 0)
{
- if (!cgraph_recursive_inlining_p (edge->caller, edge->callee,
- &edge->inline_failed))
- {
- edge->inline_failed = not_good;
- if (dump_file)
- fprintf (dump_file, " inline_failed:%s.\n",
- cgraph_inline_failed_string (edge->inline_failed));
- }
+ edge->inline_failed = not_good;
+ if (dump_file)
+ fprintf (dump_file, " inline_failed:%s.\n",
+ cgraph_inline_failed_string (edge->inline_failed));
continue;
}
if (!cgraph_default_inline_p (edge->callee, &edge->inline_failed))
{
- if (!cgraph_recursive_inlining_p (edge->caller, edge->callee,
- &edge->inline_failed))
- {
- if (dump_file)
- fprintf (dump_file, " inline_failed:%s.\n",
- cgraph_inline_failed_string (edge->inline_failed));
- }
+ if (dump_file)
+ fprintf (dump_file, " inline_failed:%s.\n",
+ cgraph_inline_failed_string (edge->inline_failed));
continue;
}
if (!tree_can_inline_p (edge)
@@ -1184,16 +1187,18 @@ cgraph_decide_inlining_of_small_functions (void)
cgraph_inline_failed_string (edge->inline_failed));
continue;
}
- if (cgraph_recursive_inlining_p (edge->caller, edge->callee,
- &edge->inline_failed))
+ if (cgraph_edge_recursive_p (edge))
{
where = edge->caller;
if (where->global.inlined_to)
where = where->global.inlined_to;
- if (!cgraph_decide_recursive_inlining (where,
+ if (!cgraph_decide_recursive_inlining (edge,
flag_indirect_inlining
? &new_indirect_edges : NULL))
- continue;
+ {
+ edge->inline_failed = CIF_RECURSIVE_INLINING;
+ continue;
+ }
if (flag_indirect_inlining)
add_new_edges_to_heap (heap, new_indirect_edges);
update_all_callee_keys (heap, where, updated_nodes);
@@ -1201,8 +1206,7 @@ cgraph_decide_inlining_of_small_functions (void)
else
{
struct cgraph_node *callee;
- if (!cgraph_check_inline_limits (edge->caller, edge->callee,
- &edge->inline_failed))
+ if (!cgraph_check_inline_limits (edge, &edge->inline_failed))
{
if (dump_file)
fprintf (dump_file, " Not inlining into %s:%s.\n",
@@ -1295,9 +1299,7 @@ cgraph_decide_inlining_of_small_functions (void)
if (dump_flags & TDF_DETAILS)
cgraph_edge_badness (edge, true);
}
- if (!edge->callee->local.disregard_inline_limits && edge->inline_failed
- && !cgraph_recursive_inlining_p (edge->caller, edge->callee,
- &edge->inline_failed))
+ if (!edge->callee->local.disregard_inline_limits && edge->inline_failed)
edge->inline_failed = CIF_INLINE_UNIT_GROWTH_LIMIT;
}
@@ -1359,7 +1361,7 @@ cgraph_flatten (struct cgraph_node *node)
continue;
}
- if (cgraph_recursive_inlining_p (node, e->callee, &e->inline_failed))
+ if (cgraph_edge_recursive_p (e))
{
if (dump_file)
fprintf (dump_file, "Not inlining: recursive call.\n");
@@ -1431,10 +1433,14 @@ cgraph_decide_inlining (void)
if (!DECL_EXTERNAL (node->decl))
initial_size += node->global.size;
for (e = node->callees; e; e = e->next_callee)
- if (max_count < e->count)
- max_count = e->count;
- if (max_benefit < inline_summary (node)->time_inlining_benefit)
- max_benefit = inline_summary (node)->time_inlining_benefit;
+ {
+ int benefit = (inline_summary (node)->time_inlining_benefit
+ + e->call_stmt_time);
+ if (max_count < e->count)
+ max_count = e->count;
+ if (max_benefit < benefit)
+ max_benefit = benefit;
+ }
}
gcc_assert (in_lto_p
|| !max_count
@@ -1516,8 +1522,7 @@ cgraph_decide_inlining (void)
node->callers->caller->global.size);
}
- if (cgraph_check_inline_limits (node->callers->caller, node,
- &reason))
+ if (cgraph_check_inline_limits (node->callers, &reason))
{
struct cgraph_node *caller = node->callers->caller;
cgraph_mark_inline_edge (node->callers, true, NULL);
@@ -1602,7 +1607,7 @@ cgraph_decide_inlining_incrementally (struct cgraph_node *node,
fprintf (dump_file,
"Considering to always inline inline candidate %s.\n",
cgraph_node_name (e->callee));
- if (cgraph_recursive_inlining_p (node, e->callee, &e->inline_failed))
+ if (cgraph_edge_recursive_p (e))
{
if (dump_file)
fprintf (dump_file, "Not inlining: recursive call.\n");
@@ -1656,7 +1661,7 @@ cgraph_decide_inlining_incrementally (struct cgraph_node *node,
if (dump_file)
fprintf (dump_file, "Considering inline candidate %s.\n",
cgraph_node_name (e->callee));
- if (cgraph_recursive_inlining_p (node, e->callee, &e->inline_failed))
+ if (cgraph_edge_recursive_p (e))
{
if (dump_file)
fprintf (dump_file, "Not inlining: recursive call.\n");
@@ -1681,16 +1686,13 @@ cgraph_decide_inlining_incrementally (struct cgraph_node *node,
if (((mode == INLINE_SIZE || mode == INLINE_SIZE_NORECURSIVE)
|| (!flag_inline_functions
&& !DECL_DECLARED_INLINE_P (e->callee->decl)))
- && (cgraph_estimate_size_after_inlining (e->caller, e->callee)
- > e->caller->global.size + allowed_growth)
+ && cgraph_estimate_edge_growth (e) > allowed_growth
&& cgraph_estimate_growth (e->callee) > allowed_growth)
{
if (dump_file)
fprintf (dump_file,
"Not inlining: code size would grow by %i.\n",
- cgraph_estimate_size_after_inlining (e->caller,
- e->callee)
- - e->caller->global.size);
+ cgraph_estimate_edge_growth (e));
continue;
}
if (e->call_stmt_cannot_inline_p
@@ -1708,7 +1710,7 @@ cgraph_decide_inlining_incrementally (struct cgraph_node *node,
"Not inlining: Function body no longer available.\n");
continue;
}
- if (!cgraph_check_inline_limits (node, e->callee, &e->inline_failed))
+ if (!cgraph_check_inline_limits (e, &e->inline_failed))
{
if (dump_file)
fprintf (dump_file, "Not inlining: %s.\n",
@@ -1901,9 +1903,7 @@ estimate_function_body_sizes (struct cgraph_node *node)
basic_block bb;
gimple_stmt_iterator bsi;
struct function *my_function = DECL_STRUCT_FUNCTION (node->decl);
- tree arg;
int freq;
- tree funtype = TREE_TYPE (node->decl);
if (dump_file)
fprintf (dump_file, "Analyzing function body size: %s\n",
@@ -1944,35 +1944,16 @@ estimate_function_body_sizes (struct cgraph_node *node)
time_inlining_benefit = ((time_inlining_benefit + CGRAPH_FREQ_BASE)
/ (CGRAPH_FREQ_BASE * 2));
size_inlining_benefit = (size_inlining_benefit + 1) / 2;
- if (dump_file)
- fprintf (dump_file, "Overall function body time: %i-%i size: %i-%i\n",
- (int)time, (int)time_inlining_benefit,
- size, size_inlining_benefit);
- time_inlining_benefit += eni_time_weights.call_cost;
- size_inlining_benefit += eni_size_weights.call_cost;
- if (!VOID_TYPE_P (TREE_TYPE (funtype)))
- {
- int cost = estimate_move_cost (TREE_TYPE (funtype));
- time_inlining_benefit += cost;
- size_inlining_benefit += cost;
- }
- for (arg = DECL_ARGUMENTS (node->decl); arg; arg = DECL_CHAIN (arg))
- if (!VOID_TYPE_P (TREE_TYPE (arg)))
- {
- int cost = estimate_move_cost (TREE_TYPE (arg));
- time_inlining_benefit += cost;
- size_inlining_benefit += cost;
- }
if (time_inlining_benefit > MAX_TIME)
time_inlining_benefit = MAX_TIME;
if (time > MAX_TIME)
time = MAX_TIME;
- inline_summary (node)->self_time = time;
- inline_summary (node)->self_size = size;
if (dump_file)
- fprintf (dump_file, "With function call overhead time: %i-%i size: %i-%i\n",
+ fprintf (dump_file, "Overall function body time: %i-%i size: %i-%i\n",
(int)time, (int)time_inlining_benefit,
size, size_inlining_benefit);
+ inline_summary (node)->self_time = time;
+ inline_summary (node)->self_size = size;
inline_summary (node)->time_inlining_benefit = time_inlining_benefit;
inline_summary (node)->size_inlining_benefit = size_inlining_benefit;
}
@@ -1982,6 +1963,7 @@ void
compute_inline_parameters (struct cgraph_node *node)
{
HOST_WIDE_INT self_stack_size;
+ struct cgraph_edge *e;
gcc_assert (!node->global.inlined_to);
@@ -2001,8 +1983,6 @@ compute_inline_parameters (struct cgraph_node *node)
node->local.can_change_signature = true;
else
{
- struct cgraph_edge *e;
-
/* Functions calling builtin_apply can not change signature. */
for (e = node->callees; e; e = e->next_callee)
if (DECL_BUILT_IN (e->callee->decl)
@@ -2012,6 +1992,17 @@ compute_inline_parameters (struct cgraph_node *node)
node->local.can_change_signature = !e;
}
estimate_function_body_sizes (node);
+ /* Compute size of call statements. We have to do this for callers here,
+ those sizes need to be present for edges _to_ us as early as
+ we are finished with early opts. */
+ for (e = node->callers; e; e = e->next_caller)
+ if (e->call_stmt)
+ {
+ e->call_stmt_size
+ = estimate_num_insns (e->call_stmt, &eni_size_weights);
+ e->call_stmt_time
+ = estimate_num_insns (e->call_stmt, &eni_time_weights);
+ }
/* Inlining characteristics are maintained by the cgraph_mark_inline. */
node->global.time = inline_summary (node)->self_time;
node->global.size = inline_summary (node)->self_size;
diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c
index 8838947..f8de894 100644
--- a/gcc/lto-cgraph.c
+++ b/gcc/lto-cgraph.c
@@ -285,6 +285,8 @@ lto_output_edge (struct lto_simple_output_block *ob, struct cgraph_edge *edge,
bp_pack_value (&bp, uid, HOST_BITS_PER_INT);
bp_pack_value (&bp, edge->inline_failed, HOST_BITS_PER_INT);
bp_pack_value (&bp, edge->frequency, HOST_BITS_PER_INT);
+ bp_pack_value (&bp, edge->call_stmt_size, HOST_BITS_PER_INT);
+ bp_pack_value (&bp, edge->call_stmt_time, HOST_BITS_PER_INT);
bp_pack_value (&bp, edge->loop_nest, 30);
bp_pack_value (&bp, edge->indirect_inlining_edge, 1);
bp_pack_value (&bp, edge->call_stmt_cannot_inline_p, 1);
@@ -1215,6 +1217,7 @@ input_edge (struct lto_input_block *ib, VEC(cgraph_node_ptr, heap) *nodes,
cgraph_inline_failed_t inline_failed;
struct bitpack_d bp;
int ecf_flags = 0;
+ int call_stmt_time, call_stmt_size;
caller = VEC_index (cgraph_node_ptr, nodes, lto_input_sleb128 (ib));
if (caller == NULL || caller->decl == NULL_TREE)
@@ -1236,6 +1239,8 @@ input_edge (struct lto_input_block *ib, VEC(cgraph_node_ptr, heap) *nodes,
inline_failed = (cgraph_inline_failed_t) bp_unpack_value (&bp,
HOST_BITS_PER_INT);
freq = (int) bp_unpack_value (&bp, HOST_BITS_PER_INT);
+ call_stmt_size = (int) bp_unpack_value (&bp, HOST_BITS_PER_INT);
+ call_stmt_time = (int) bp_unpack_value (&bp, HOST_BITS_PER_INT);
nest = (unsigned) bp_unpack_value (&bp, 30);
if (indirect)
@@ -1248,6 +1253,8 @@ input_edge (struct lto_input_block *ib, VEC(cgraph_node_ptr, heap) *nodes,
edge->inline_failed = inline_failed;
edge->call_stmt_cannot_inline_p = bp_unpack_value (&bp, 1);
edge->can_throw_external = bp_unpack_value (&bp, 1);
+ edge->call_stmt_size = call_stmt_size;
+ edge->call_stmt_time = call_stmt_time;
if (indirect)
{
if (bp_unpack_value (&bp, 1))
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 47b393d..c7e70b2 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2011-04-06 Richard Guenther <rguenther@suse.de>
+
+ PR tree-optimization/47663
+ * gcc.dg/tree-ssa/inline-8.c: New testcase.
+
2011-04-05 Eric Botcazou <ebotcazou@adacore.com>
* gcc.dg/torture/pr47917.c: Add -D_XOPEN_SOURCE=500 to dg-options for
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/inline-8.c b/gcc/testsuite/gcc.dg/tree-ssa/inline-8.c
new file mode 100644
index 0000000..3215473
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/inline-8.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-O -finline-small-functions --param early-inlining-insns=0 -fdump-tree-einline" } */
+
+int foo0();
+void bar0() { foo0(); }
+void foobar0() { bar0(); }
+
+void foo1();
+void bar1() { foo1(); }
+void foobar1() { bar1(); }
+
+#if 0
+int foo2();
+int bar2() { return foo2(); }
+/* The size estimate fails to see that inlining the call statement in bar2
+ will make its lhs dead. */
+void foobar2() { bar2(); }
+#endif
+
+int foo3();
+int bar3() { return foo3(); }
+int foobar3() { return bar3(); }
+
+int bar4() { return 0; }
+void foobar4() { bar4(); }
+
+int bar5() { return 0; }
+int foobar5() { return bar5(); }
+
+/* { dg-final { scan-tree-dump-times "Inlining" 5 "einline" } } */
+/* { dg-final { cleanup-tree-dump "einline" } } */
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index 4cf2a12..a6dac2d 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -3514,7 +3514,8 @@ estimate_num_insns (gimple stmt, eni_weights *weights)
if (decl)
funtype = TREE_TYPE (decl);
- if (!VOID_TYPE_P (TREE_TYPE (funtype)))
+ if (!VOID_TYPE_P (TREE_TYPE (funtype))
+ && gimple_call_lhs (stmt))
cost += estimate_move_cost (TREE_TYPE (funtype));
if (funtype)
@@ -3812,6 +3813,8 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
&& !DECL_IN_SYSTEM_HEADER (fn)
&& reason != CIF_UNSPECIFIED
&& !lookup_attribute ("noinline", DECL_ATTRIBUTES (fn))
+ /* Do not warn about not inlined recursive calls. */
+ && !cgraph_edge_recursive_p (cg_edge)
/* Avoid warnings during early inline pass. */
&& cgraph_global_info_ready)
{