aboutsummaryrefslogtreecommitdiff
path: root/gcc/ipa-inline-analysis.c
diff options
context:
space:
mode:
authorJan Hubicka <jh@suse.cz>2011-04-27 00:05:50 +0200
committerJan Hubicka <hubicka@gcc.gnu.org>2011-04-26 22:05:50 +0000
commit898b8927465614b911841f134f37165a613debf5 (patch)
tree9dd85417eff67af5337a8aed679418604daf66df /gcc/ipa-inline-analysis.c
parentffa037724f62366e4e78b496f182d999ea7b75ce (diff)
downloadgcc-898b8927465614b911841f134f37165a613debf5.zip
gcc-898b8927465614b911841f134f37165a613debf5.tar.gz
gcc-898b8927465614b911841f134f37165a613debf5.tar.bz2
cgraphbuild.c (build_cgraph_edges): Update call of cgraph_create_edge and cgraph_create_indirect_edge.
* cgraphbuild.c (build_cgraph_edges): Update call of cgraph_create_edge and cgraph_create_indirect_edge. * cgraph.c (cgraph_create_edge_including_clones, cgraph_create_edge_1, cgraph_allocate_init_indirect_info, cgraph_update_edges_for_call_stmt_node): Do not take nest argument; do not initialize call_stmt_size/time. (dump_cgraph_node): Do not dump nest. (cgraph_clone_edge): Do not take loop_nest argument; do not propagate it; do not clone call_stmt_size/time. (cgraph_clone_node): Likewise. (cgraph_create_virtual_clone): Update. * cgraph.h (struct cgraph_edge): Remove call_stmt_size/call_stmt_time/loop_nest. (cgraph_create_edge, cgraph_create_indirect_edge, cgraph_create_edge_including_clones, cgraph_clone_node): Update prototype. * tree-emutls.c (gen_emutls_addr): Update. * ipa-inline-transform.c (update_noncloned_frequencies): Do not handle loop_nest; handle indirect calls, too. (clone_inlined_nodes): Do not care about updating inline summaries. * cgraphunit.c (cgraph_copy_node_for_versioning): Update. * lto-cgraph.c (lto_output_edge, input_node, input_edge): Do not stream call_stmt_size/call_stmt_time/loop_nest. * ipa-inline.c (edge_badness): Update. (ipa_inline): dump summaries after inlining. * ipa-inline.h (struct inline_edge_summary, inline_edge_summary_t): new. (inline_edge_summary): New function. * ipa-inline-analysis.c (edge_duplication_hook_holder): New holder. (inline_edge_removal_hook): Handle edge summaries. (inline_edge_duplication_hook): New hook. (inline_summary_alloc): Alloc hooks. (initialize_growth_caches): Do not register removal hooks. (free_growth_caches); Do not free removal hook. (dump_inline_edge_summary): New function. (dump_inline_summary): Use it. (estimate_function_body_sizes, estimate_edge_size_and_time): Update. (inline_update_callee_summaries): New function. (inline_merge_summary): Use it. (do_estimate_edge_time, do_estimate_edge_growth): Update. (read_inline_edge_summary): New function. (inline_read_section): Use it. (write_inline_edge_summary): New function. (inline_write_summary): Use it. (inline_free_summary): Free edge new holders. * tree-inline.c (copy_bb): Update. From-SVN: r172989
Diffstat (limited to 'gcc/ipa-inline-analysis.c')
-rw-r--r--gcc/ipa-inline-analysis.c177
1 files changed, 161 insertions, 16 deletions
diff --git a/gcc/ipa-inline-analysis.c b/gcc/ipa-inline-analysis.c
index bedd963..8cf9bc3 100644
--- a/gcc/ipa-inline-analysis.c
+++ b/gcc/ipa-inline-analysis.c
@@ -110,14 +110,20 @@ enum predicate_conditions
static struct cgraph_node_hook_list *function_insertion_hook_holder;
static struct cgraph_node_hook_list *node_removal_hook_holder;
static struct cgraph_2node_hook_list *node_duplication_hook_holder;
+static struct cgraph_2edge_hook_list *edge_duplication_hook_holder;
static struct cgraph_edge_hook_list *edge_removal_hook_holder;
static void inline_node_removal_hook (struct cgraph_node *, void *);
static void inline_node_duplication_hook (struct cgraph_node *,
struct cgraph_node *, void *);
+static void inline_edge_removal_hook (struct cgraph_edge *, void *);
+static void inline_edge_duplication_hook (struct cgraph_edge *,
+ struct cgraph_edge *,
+ void *);
/* VECtor holding inline summaries.
In GGC memory because conditions might point to constant trees. */
VEC(inline_summary_t,gc) *inline_summary_vec;
+VEC(inline_edge_summary_t,heap) *inline_edge_summary_vec;
/* Cached node/edge growths. */
VEC(int,heap) *node_growth_cache;
@@ -512,14 +518,24 @@ inline_summary_alloc (void)
if (!node_removal_hook_holder)
node_removal_hook_holder =
cgraph_add_node_removal_hook (&inline_node_removal_hook, NULL);
+ if (!edge_removal_hook_holder)
+ edge_removal_hook_holder =
+ cgraph_add_edge_removal_hook (&inline_edge_removal_hook, NULL);
if (!node_duplication_hook_holder)
node_duplication_hook_holder =
cgraph_add_node_duplication_hook (&inline_node_duplication_hook, NULL);
+ if (!edge_duplication_hook_holder)
+ edge_duplication_hook_holder =
+ cgraph_add_edge_duplication_hook (&inline_edge_duplication_hook, NULL);
if (VEC_length (inline_summary_t, inline_summary_vec)
<= (unsigned) cgraph_max_uid)
VEC_safe_grow_cleared (inline_summary_t, gc,
inline_summary_vec, cgraph_max_uid + 1);
+ if (VEC_length (inline_edge_summary_t, inline_edge_summary_vec)
+ <= (unsigned) cgraph_edge_max_uid)
+ VEC_safe_grow_cleared (inline_edge_summary_t, heap,
+ inline_edge_summary_vec, cgraph_edge_max_uid + 1);
}
/* Hook that is called by cgraph.c when a node is removed. */
@@ -540,6 +556,7 @@ inline_node_removal_hook (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
memset (info, 0, sizeof (inline_summary_t));
}
+
/* Hook that is called by cgraph.c when a node is duplicated. */
static void
@@ -556,12 +573,29 @@ inline_node_duplication_hook (struct cgraph_node *src, struct cgraph_node *dst,
}
+/* Hook that is called by cgraph.c when a node is duplicated. */
+
+static void
+inline_edge_duplication_hook (struct cgraph_edge *src, struct cgraph_edge *dst,
+ ATTRIBUTE_UNUSED void *data)
+{
+ struct inline_edge_summary *info;
+ inline_summary_alloc ();
+ info = inline_edge_summary (dst);
+ memcpy (info, inline_edge_summary (src),
+ sizeof (struct inline_edge_summary));
+}
+
+
/* Keep edge cache consistent across edge removal. */
static void
inline_edge_removal_hook (struct cgraph_edge *edge, void *data ATTRIBUTE_UNUSED)
{
- reset_edge_growth_cache (edge);
+ if (edge_growth_cache)
+ reset_edge_growth_cache (edge);
+ if (edge->uid < (int)VEC_length (inline_edge_summary_t, inline_edge_summary_vec))
+ memset (inline_edge_summary (edge), 0, sizeof (struct inline_edge_summary));
}
@@ -570,9 +604,6 @@ inline_edge_removal_hook (struct cgraph_edge *edge, void *data ATTRIBUTE_UNUSED)
void
initialize_growth_caches (void)
{
- if (!edge_removal_hook_holder)
- edge_removal_hook_holder =
- cgraph_add_edge_removal_hook (&inline_edge_removal_hook, NULL);
if (cgraph_edge_max_uid)
VEC_safe_grow_cleared (edge_growth_cache_entry, heap, edge_growth_cache,
cgraph_edge_max_uid);
@@ -586,8 +617,6 @@ initialize_growth_caches (void)
void
free_growth_caches (void)
{
- if (edge_removal_hook_holder)
- cgraph_remove_edge_removal_hook (edge_removal_hook_holder);
VEC_free (edge_growth_cache_entry, heap, edge_growth_cache);
edge_growth_cache = 0;
VEC_free (int, heap, node_growth_cache);
@@ -595,6 +624,42 @@ free_growth_caches (void)
}
+/* Dump edge summaries associated to NODE and recursively to all clones.
+ Indent by INDENT. */
+
+static void
+dump_inline_edge_summary (FILE * f, int indent, struct cgraph_node *node)
+{
+ struct cgraph_edge *edge;
+ for (edge = node->callees; edge; edge = edge->next_callee)
+ {
+ struct inline_edge_summary *es = inline_edge_summary (edge);
+ fprintf (f, "%*s%s/%i %s\n%*s loop depth:%2i freq:%4i size:%2i time: %2i\n",
+ indent, "", cgraph_node_name (edge->callee),
+ edge->callee->uid,
+ edge->inline_failed ? "inlined"
+ : cgraph_inline_failed_string (edge->inline_failed),
+ indent, "",
+ es->loop_depth,
+ edge->frequency,
+ es->call_stmt_size,
+ es->call_stmt_time);
+ if (!edge->inline_failed)
+ dump_inline_edge_summary (f, indent+2, edge->callee);
+ }
+ for (edge = node->indirect_calls; edge; edge = edge->next_callee)
+ {
+ struct inline_edge_summary *es = inline_edge_summary (edge);
+ fprintf (f, "%*sindirect call loop depth:%2i freq:%4i size:%2i time: %2i\n",
+ indent, "",
+ es->loop_depth,
+ edge->frequency,
+ es->call_stmt_size,
+ es->call_stmt_time);
+ }
+}
+
+
static void
dump_inline_summary (FILE * f, struct cgraph_node *node)
{
@@ -630,6 +695,8 @@ dump_inline_summary (FILE * f, struct cgraph_node *node)
(double) e->time / INLINE_TIME_SCALE);
dump_predicate (f, s->conds, &e->predicate);
}
+ fprintf (f, " calls:\n");
+ dump_inline_edge_summary (f, 4, node);
fprintf (f, "\n");
}
}
@@ -646,7 +713,7 @@ dump_inline_summaries (FILE *f)
struct cgraph_node *node;
for (node = cgraph_nodes; node; node = node->next)
- if (node->analyzed)
+ if (node->analyzed && !node->global.inlined_to)
dump_inline_summary (f, node);
}
@@ -919,8 +986,11 @@ estimate_function_body_sizes (struct cgraph_node *node, bool early)
if (is_gimple_call (stmt))
{
struct cgraph_edge *edge = cgraph_edge (node, stmt);
- edge->call_stmt_size = this_size;
- edge->call_stmt_time = this_time;
+ struct inline_edge_summary *es = inline_edge_summary (edge);
+
+ es->call_stmt_size = this_size;
+ es->call_stmt_time = this_time;
+ es->loop_depth = bb->loop_depth;
/* Do not inline calls where we cannot triviall work around
mismatches in argument or return types. */
@@ -1076,8 +1146,9 @@ struct gimple_opt_pass pass_inline_parameters =
static void
estimate_edge_size_and_time (struct cgraph_edge *e, int *size, int *time)
{
- *size += e->call_stmt_size * INLINE_SIZE_SCALE;
- *time += (e->call_stmt_time
+ struct inline_edge_summary *es = inline_edge_summary (e);
+ *size += es->call_stmt_size * INLINE_SIZE_SCALE;
+ *time += (es->call_stmt_time
* e->frequency * (INLINE_TIME_SCALE / CGRAPH_FREQ_BASE));
if (*time > MAX_TIME * INLINE_TIME_SCALE)
*time = MAX_TIME * INLINE_TIME_SCALE;
@@ -1222,6 +1293,38 @@ remap_predicate (struct inline_summary *info, struct inline_summary *callee_info
}
+/* Update summary information of inline clones after inlining.
+ Compute peak stack usage. */
+
+static void
+inline_update_callee_summaries (struct cgraph_node *node,
+ int depth)
+{
+ struct cgraph_edge *e;
+ struct inline_summary *callee_info = inline_summary (node);
+ struct inline_summary *caller_info = inline_summary (node->callers->caller);
+ HOST_WIDE_INT peak;
+
+ callee_info->stack_frame_offset
+ = caller_info->stack_frame_offset
+ + caller_info->estimated_self_stack_size;
+ peak = callee_info->stack_frame_offset
+ + callee_info->estimated_self_stack_size;
+ if (inline_summary (node->global.inlined_to)->estimated_stack_size
+ < peak)
+ inline_summary (node->global.inlined_to)->estimated_stack_size = peak;
+ cgraph_propagate_frequency (node);
+ for (e = node->callees; e; e = e->next_callee)
+ {
+ if (!e->inline_failed)
+ inline_update_callee_summaries (e->callee, depth);
+ inline_edge_summary (e)->loop_depth += depth;
+ }
+ for (e = node->indirect_calls; e; e = e->next_callee)
+ inline_edge_summary (e)->loop_depth += depth;
+}
+
+
/* We inlined EDGE. Update summary of the function we inlined into. */
void
@@ -1275,6 +1378,10 @@ inline_merge_summary (struct cgraph_edge *edge)
for (i = 0; VEC_iterate (size_time_entry, info->entry, i, e); i++)
info->size += e->size, info->time += e->time;
estimate_calls_size_and_time (to, &info->size, &info->time);
+
+ inline_update_callee_summaries (edge->callee,
+ inline_edge_summary (edge)->loop_depth);
+
info->time = (info->time + INLINE_TIME_SCALE / 2) / INLINE_TIME_SCALE;
info->size = (info->size + INLINE_SIZE_SCALE / 2) / INLINE_SIZE_SCALE;
}
@@ -1293,11 +1400,12 @@ do_estimate_edge_time (struct cgraph_edge *edge)
int time;
int size;
gcov_type ret;
+ struct inline_edge_summary *es = inline_edge_summary (edge);
gcc_checking_assert (edge->inline_failed);
estimate_callee_size_and_time (edge, true, &size, &time);
- ret = (((gcov_type)time - edge->call_stmt_time) * edge->frequency
+ ret = (((gcov_type)time - es->call_stmt_time) * edge->frequency
+ CGRAPH_FREQ_BASE / 2) / CGRAPH_FREQ_BASE;
if (ret > MAX_TIME)
ret = MAX_TIME;
@@ -1313,8 +1421,8 @@ do_estimate_edge_time (struct cgraph_edge *edge)
VEC_index (edge_growth_cache_entry, edge_growth_cache, edge->uid)->time
= ret + (ret >= 0);
- ret_size = size - edge->call_stmt_size;
- gcc_checking_assert (edge->call_stmt_size);
+ ret_size = size - es->call_stmt_size;
+ gcc_checking_assert (es->call_stmt_size);
VEC_index (edge_growth_cache_entry, edge_growth_cache, edge->uid)->size
= ret_size + (ret_size >= 0);
}
@@ -1345,8 +1453,8 @@ do_estimate_edge_growth (struct cgraph_edge *edge)
/* Early inliner runs without caching, go ahead and do the dirty work. */
gcc_checking_assert (edge->inline_failed);
estimate_callee_size_and_time (edge, true, &size, NULL);
- gcc_checking_assert (edge->call_stmt_size);
- return size - edge->call_stmt_size;
+ gcc_checking_assert (inline_edge_summary (edge)->call_stmt_size);
+ return size - inline_edge_summary (edge)->call_stmt_size;
}
@@ -1494,6 +1602,18 @@ inline_generate_summary (void)
}
+/* Write inline summary for edge E to OB. */
+
+static void
+read_inline_edge_summary (struct lto_input_block *ib, struct cgraph_edge *e)
+{
+ struct inline_edge_summary *es = inline_edge_summary (e);
+ es->call_stmt_size = lto_input_uleb128 (ib);
+ es->call_stmt_time = lto_input_uleb128 (ib);
+ es->loop_depth = lto_input_uleb128 (ib);
+}
+
+
/* Stream in inline summaries from the section. */
static void
@@ -1524,6 +1644,7 @@ inline_read_section (struct lto_file_decl_data *file_data, const char *data,
struct inline_summary *info;
lto_cgraph_encoder_t encoder;
struct bitpack_d bp;
+ struct cgraph_edge *e;
index = lto_input_uleb128 (&ib);
encoder = file_data->cgraph_node_encoder;
@@ -1568,6 +1689,10 @@ inline_read_section (struct lto_file_decl_data *file_data, const char *data,
VEC_safe_push (size_time_entry, gc, info->entry, &e);
}
+ for (e = node->callees; e; e = e->next_callee)
+ read_inline_edge_summary (&ib, e);
+ for (e = node->indirect_calls; e; e = e->next_callee)
+ read_inline_edge_summary (&ib, e);
}
lto_free_section_data (file_data, LTO_section_inline_summary, NULL, data,
@@ -1611,6 +1736,17 @@ inline_read_summary (void)
cgraph_add_function_insertion_hook (&add_new_function, NULL);
}
+/* Write inline summary for edge E to OB. */
+
+static void
+write_inline_edge_summary (struct output_block *ob, struct cgraph_edge *e)
+{
+ struct inline_edge_summary *es = inline_edge_summary (e);
+ lto_output_uleb128_stream (ob->main_stream, es->call_stmt_size);
+ lto_output_uleb128_stream (ob->main_stream, es->call_stmt_time);
+ lto_output_uleb128_stream (ob->main_stream, es->loop_depth);
+}
+
/* Write inline summary for node in SET.
Jump functions are shared among ipa-cp and inliner, so when ipa-cp is
@@ -1638,6 +1774,7 @@ inline_write_summary (cgraph_node_set set,
{
struct inline_summary *info = inline_summary (node);
struct bitpack_d bp;
+ struct cgraph_edge *edge;
int i;
size_time_entry *e;
struct condition *c;
@@ -1684,6 +1821,10 @@ inline_write_summary (cgraph_node_set set,
}
lto_output_uleb128_stream (ob->main_stream, 0);
}
+ for (edge = node->callees; edge; edge = edge->next_callee)
+ write_inline_edge_summary (ob, edge);
+ for (edge = node->indirect_calls; edge; edge = edge->next_callee)
+ write_inline_edge_summary (ob, edge);
}
}
lto_output_1_stream (ob->main_stream, 0);
@@ -1705,9 +1846,13 @@ inline_free_summary (void)
function_insertion_hook_holder = NULL;
if (node_removal_hook_holder)
cgraph_remove_node_removal_hook (node_removal_hook_holder);
+ if (edge_removal_hook_holder)
+ cgraph_remove_edge_removal_hook (edge_removal_hook_holder);
node_removal_hook_holder = NULL;
if (node_duplication_hook_holder)
cgraph_remove_node_duplication_hook (node_duplication_hook_holder);
+ if (edge_duplication_hook_holder)
+ cgraph_remove_edge_duplication_hook (edge_duplication_hook_holder);
node_duplication_hook_holder = NULL;
VEC_free (inline_summary_t, gc, inline_summary_vec);
inline_summary_vec = NULL;