summaryrefslogtreecommitdiff
path: root/gcc/ipa-inline-analysis.c
diff options
context:
space:
mode:
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2012-08-19 05:55:20 +0000
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2012-08-19 05:55:20 +0000
commiteb7c606e1e1222b20023e10832593ae0e5478c8d (patch)
tree032d8e752b8a993f1aa19d59d320266d25238378 /gcc/ipa-inline-analysis.c
parentf260f060e739be598c8ff906ff61b6fdffe64571 (diff)
downloadgcc-eb7c606e1e1222b20023e10832593ae0e5478c8d.tar.gz
PR lto/45375
* ipa-inline.c (want_inline_small_function_p): Bypass inline limits for hinted functions. (edge_badness): Dump hints; decrease badness for hinted funcitons. * ipa-inline.h (enum inline_hints_vals): New enum. (inline_hints): New type. (edge_growth_cache_entry): Add hints. (dump_inline_summary): Update. (dump_inline_hints): Declare. (do_estimate_edge_hints): Declare. (estimate_edge_hints): New inline function. (reset_edge_growth_cache): Update. * predict.c (cgraph_maybe_hot_edge_p): Do not ice on indirect edges. * ipa-inline-analysis.c (dump_inline_hints): New function. (estimate_edge_devirt_benefit): Return true when function should be hinted. (estimate_calls_size_and_time): New hints argument; set it when devritualization happens. (estimate_node_size_and_time): New hints argument. (do_estimate_edge_time): Cache hints. (do_estimate_edge_growth): Update. (do_estimate_edge_hints): New function git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@190509 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/ipa-inline-analysis.c')
-rw-r--r--gcc/ipa-inline-analysis.c125
1 files changed, 83 insertions, 42 deletions
diff --git a/gcc/ipa-inline-analysis.c b/gcc/ipa-inline-analysis.c
index 9f96ca8a3ba..c30e81a88f1 100644
--- a/gcc/ipa-inline-analysis.c
+++ b/gcc/ipa-inline-analysis.c
@@ -615,6 +615,22 @@ dump_predicate (FILE *f, conditions conds, struct predicate *pred)
}
+/* Dump inline hints. */
+void
+dump_inline_hints (FILE *f, inline_hints hints)
+{
+ if (!hints)
+ return;
+ fprintf (f, "inline hints:");
+ if (hints & INLINE_HINT_indirect_call)
+ {
+ hints &= ~INLINE_HINT_indirect_call;
+ fprintf (f, " indirect_call");
+ }
+ gcc_assert (!hints);
+}
+
+
/* Record SIZE and TIME under condition PRED into the inline summary. */
static void
@@ -2302,7 +2318,7 @@ estimate_edge_size_and_time (struct cgraph_edge *e, int *size, int *time,
/* Estimate benefit devirtualizing indirect edge IE, provided KNOWN_VALS and
KNOWN_BINFOS. */
-static void
+static bool
estimate_edge_devirt_benefit (struct cgraph_edge *ie,
int *size, int *time, int prob,
VEC (tree, heap) *known_vals,
@@ -2311,14 +2327,16 @@ estimate_edge_devirt_benefit (struct cgraph_edge *ie,
{
tree target;
int time_diff, size_diff;
+ struct cgraph_node *callee;
+ struct inline_summary *isummary;
if (!known_vals && !known_binfos)
- return;
+ return false;
target = ipa_get_indirect_edge_target (ie, known_vals, known_binfos,
known_aggs);
if (!target)
- return;
+ return false;
/* Account for difference in cost between indirect and direct calls. */
size_diff = ((eni_size_weights.indirect_call_cost - eni_size_weights.call_cost)
@@ -2328,40 +2346,11 @@ estimate_edge_devirt_benefit (struct cgraph_edge *ie,
* INLINE_TIME_SCALE * prob / REG_BR_PROB_BASE);
*time -= time_diff;
- /* TODO: This code is trying to benefit indirect calls that will be inlined later.
- The logic however do not belong into local size/time estimates and can not be
- done here, or the accounting of changes will get wrong and we result with
- negative function body sizes. We need to introduce infrastructure for independent
- benefits to the inliner. */
-#if 0
- struct cgraph_node *callee;
- struct inline_summary *isummary;
- int edge_size, edge_time, time_diff, size_diff;
-
callee = cgraph_get_node (target);
if (!callee || !callee->analyzed)
- return;
+ return false;
isummary = inline_summary (callee);
- if (!isummary->inlinable)
- return;
-
- estimate_edge_size_and_time (ie, &edge_size, &edge_time, prob);
-
- /* Count benefit only from functions that definitely will be inlined
- if additional context from NODE's caller were available.
-
- We just account overall size change by inlining. TODO:
- we really need to add sort of benefit metrics for these kind of
- cases. */
- if (edge_size - size_diff >= isummary->size * INLINE_SIZE_SCALE)
- {
- /* Subtract size and time that we added for edge IE. */
- *size -= edge_size - size_diff;
-
- /* Account inlined call. */
- *size += isummary->size * INLINE_SIZE_SCALE;
- }
-#endif
+ return isummary->inlinable;
}
@@ -2371,6 +2360,7 @@ estimate_edge_devirt_benefit (struct cgraph_edge *ie,
static void
estimate_calls_size_and_time (struct cgraph_node *node, int *size, int *time,
+ inline_hints *hints,
clause_t possible_truths,
VEC (tree, heap) *known_vals,
VEC (tree, heap) *known_binfos,
@@ -2389,7 +2379,7 @@ estimate_calls_size_and_time (struct cgraph_node *node, int *size, int *time,
estimate_edge_size_and_time (e, size, time, REG_BR_PROB_BASE);
}
else
- estimate_calls_size_and_time (e->callee, size, time,
+ estimate_calls_size_and_time (e->callee, size, time, hints,
possible_truths,
known_vals, known_binfos, known_aggs);
}
@@ -2400,8 +2390,11 @@ estimate_calls_size_and_time (struct cgraph_node *node, int *size, int *time,
if (!es->predicate || evaluate_predicate (es->predicate, possible_truths))
{
estimate_edge_size_and_time (e, size, time, REG_BR_PROB_BASE);
- estimate_edge_devirt_benefit (e, size, time, REG_BR_PROB_BASE,
- known_vals, known_binfos, known_aggs);
+ if (estimate_edge_devirt_benefit (e, size, time, REG_BR_PROB_BASE,
+ known_vals, known_binfos, known_aggs)
+ && hints
+ && cgraph_maybe_hot_edge_p (e))
+ *hints |= INLINE_HINT_indirect_call;
}
}
}
@@ -2418,12 +2411,14 @@ estimate_node_size_and_time (struct cgraph_node *node,
VEC (tree, heap) *known_binfos,
VEC (ipa_agg_jump_function_p, heap) *known_aggs,
int *ret_size, int *ret_time,
+ inline_hints *ret_hints,
VEC (inline_param_summary_t, heap)
*inline_param_summary)
{
struct inline_summary *info = inline_summary (node);
size_time_entry *e;
int size = 0, time = 0;
+ inline_hints hints = 0;
int i;
if (dump_file
@@ -2467,7 +2462,7 @@ estimate_node_size_and_time (struct cgraph_node *node,
if (time > MAX_TIME * INLINE_TIME_SCALE)
time = MAX_TIME * INLINE_TIME_SCALE;
- estimate_calls_size_and_time (node, &size, &time, possible_truths,
+ estimate_calls_size_and_time (node, &size, &time, &hints, possible_truths,
known_vals, known_binfos, known_aggs);
time = (time + INLINE_TIME_SCALE / 2) / INLINE_TIME_SCALE;
size = (size + INLINE_SIZE_SCALE / 2) / INLINE_SIZE_SCALE;
@@ -2480,6 +2475,8 @@ estimate_node_size_and_time (struct cgraph_node *node,
*ret_time = time;
if (ret_size)
*ret_size = size;
+ if (ret_hints)
+ *ret_hints = hints;
return;
}
@@ -2499,7 +2496,7 @@ estimate_ipcp_clone_size_and_time (struct cgraph_node *node,
clause = evaluate_conditions_for_known_args (node, false, known_vals, NULL);
estimate_node_size_and_time (node, clause, known_vals, known_binfos, NULL,
- ret_size, ret_time,
+ ret_size, ret_time, NULL,
NULL);
}
@@ -2871,7 +2868,7 @@ inline_update_overall_summary (struct cgraph_node *node)
info->time = 0;
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 (node, &info->size, &info->time,
+ estimate_calls_size_and_time (node, &info->size, &info->time, NULL,
~(clause_t)(1 << predicate_false_condition),
NULL, NULL, NULL);
info->time = (info->time + INLINE_TIME_SCALE / 2) / INLINE_TIME_SCALE;
@@ -2890,6 +2887,7 @@ do_estimate_edge_time (struct cgraph_edge *edge)
{
int time;
int size;
+ inline_hints hints;
gcov_type ret;
struct cgraph_node *callee;
clause_t clause;
@@ -2905,7 +2903,7 @@ do_estimate_edge_time (struct cgraph_edge *edge)
&clause, &known_vals, &known_binfos,
&known_aggs);
estimate_node_size_and_time (callee, clause, known_vals, known_binfos,
- known_aggs, &size, &time, es->param);
+ known_aggs, &size, &time, &hints, es->param);
VEC_free (tree, heap, known_vals);
VEC_free (tree, heap, known_binfos);
VEC_free (ipa_agg_jump_function_p, heap, known_aggs);
@@ -2929,6 +2927,8 @@ do_estimate_edge_time (struct cgraph_edge *edge)
gcc_checking_assert (es->call_stmt_size);
VEC_index (edge_growth_cache_entry, edge_growth_cache, edge->uid).size
= ret_size + (ret_size >= 0);
+ VEC_index (edge_growth_cache_entry, edge_growth_cache, edge->uid).hints
+ = hints + 1;
}
return ret;
}
@@ -2967,7 +2967,7 @@ do_estimate_edge_growth (struct cgraph_edge *edge)
&clause, &known_vals, &known_binfos,
&known_aggs);
estimate_node_size_and_time (callee, clause, known_vals, known_binfos,
- known_aggs, &size, NULL, NULL);
+ known_aggs, &size, NULL, NULL, NULL);
VEC_free (tree, heap, known_vals);
VEC_free (tree, heap, known_binfos);
VEC_free (ipa_agg_jump_function_p, heap, known_aggs);
@@ -2976,6 +2976,47 @@ do_estimate_edge_growth (struct cgraph_edge *edge)
}
+/* Estimate the growth of the caller when inlining EDGE.
+ Only to be called via estimate_edge_size. */
+
+inline_hints
+do_estimate_edge_hints (struct cgraph_edge *edge)
+{
+ inline_hints hints;
+ struct cgraph_node *callee;
+ clause_t clause;
+ VEC (tree, heap) *known_vals;
+ VEC (tree, heap) *known_binfos;
+ VEC (ipa_agg_jump_function_p, heap) *known_aggs;
+
+ /* When we do caching, use do_estimate_edge_time to populate the entry. */
+
+ if (edge_growth_cache)
+ {
+ do_estimate_edge_time (edge);
+ hints = VEC_index (edge_growth_cache_entry,
+ edge_growth_cache,
+ edge->uid).hints;
+ gcc_checking_assert (hints);
+ return hints - 1;
+ }
+
+ callee = cgraph_function_or_thunk_node (edge->callee, NULL);
+
+ /* Early inliner runs without caching, go ahead and do the dirty work. */
+ gcc_checking_assert (edge->inline_failed);
+ evaluate_properties_for_edge (edge, true,
+ &clause, &known_vals, &known_binfos,
+ &known_aggs);
+ estimate_node_size_and_time (callee, clause, known_vals, known_binfos,
+ known_aggs, NULL, NULL, &hints, NULL);
+ VEC_free (tree, heap, known_vals);
+ VEC_free (tree, heap, known_binfos);
+ VEC_free (ipa_agg_jump_function_p, heap, known_aggs);
+ return hints;
+}
+
+
/* Estimate self time of the function NODE after inlining EDGE. */
int