From 49d9c9d283caf5918add61e5f6b35c9cd437e8b6 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Sat, 9 Nov 2019 18:52:56 +0100 Subject: [PATCH] ipa-inline-analysis.c (do_estimate_growth_1): Add support for capping the growth cumulated. * ipa-inline-analysis.c (do_estimate_growth_1): Add support for capping the growth cumulated. (offline_size): Break out from ... (estimate_growth): ... here. (check_callers): Add N, OFFLINE and MIN_SIZE and KNOWN_EDGE parameters. (growth_likely_positive): Turn to ... (growth_positive_p): Re-implement. * ipa-inline.h (growth_likely_positive): Remove. (growth_positive_p): Declare. * ipa-inline.c (want_inline_small_function_p): Use growth_positive_p. (want_inline_function_to_all_callers_p): Likewise. From-SVN: r278007 --- gcc/ChangeLog | 16 ++++ gcc/ipa-inline-analysis.c | 163 ++++++++++++++++++++++++-------------- gcc/ipa-inline.c | 12 +-- gcc/ipa-inline.h | 2 +- 4 files changed, 126 insertions(+), 67 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e2bef8bc2a0..1a1c68c3d8a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,19 @@ +2019-11-09 Jan Hubicka + + * ipa-inline-analysis.c (do_estimate_growth_1): Add support for + capping the growth cumulated. + (offline_size): Break out from ... + (estimate_growth): ... here. + (check_callers): Add N, OFFLINE and MIN_SIZE and KNOWN_EDGE + parameters. + (growth_likely_positive): Turn to ... + (growth_positive_p): Re-implement. + * ipa-inline.h (growth_likely_positive): Remove. + (growth_positive_p): Declare. + * ipa-inline.c (want_inline_small_function_p): Use + growth_positive_p. + (want_inline_function_to_all_callers_p): Likewise. + 2019-11-09 Jan Hubicka * ipa-fnsummary.c (ipa_call_context::estimate_size_and_time): Fix diff --git a/gcc/ipa-inline-analysis.c b/gcc/ipa-inline-analysis.c index ea1fae484ff..9839cae43a3 100644 --- a/gcc/ipa-inline-analysis.c +++ b/gcc/ipa-inline-analysis.c @@ -387,6 +387,7 @@ struct growth_data bool self_recursive; bool uninlinable; int growth; + int cap; }; @@ -406,29 +407,57 @@ do_estimate_growth_1 (struct cgraph_node *node, void *data) || !opt_for_fn (e->caller->decl, optimize)) { d->uninlinable = true; + if (d->cap < INT_MAX) + return true; continue; } if (e->recursive_p ()) { d->self_recursive = true; + if (d->cap < INT_MAX) + return true; continue; } d->growth += estimate_edge_growth (e); + if (d->growth > d->cap) + return true; } return false; } +/* Return estimated savings for eliminating offline copy of NODE by inlining + it everywhere. */ + +static int +offline_size (struct cgraph_node *node, ipa_size_summary *info) +{ + if (!DECL_EXTERNAL (node->decl)) + { + if (node->will_be_removed_from_program_if_no_direct_calls_p ()) + return info->size; + /* COMDAT functions are very often not shared across multiple units + since they come from various template instantiations. + Take this into account. */ + else if (DECL_COMDAT (node->decl) + && node->can_remove_if_no_direct_calls_p ()) + return (info->size + * (100 - PARAM_VALUE (PARAM_COMDAT_SHARING_PROBABILITY)) + + 50) / 100; + } + return 0; +} /* Estimate the growth caused by inlining NODE into all callees. */ int estimate_growth (struct cgraph_node *node) { - struct growth_data d = { node, false, false, 0 }; - class ipa_size_summary *info = ipa_size_summaries->get (node); + struct growth_data d = { node, false, false, 0, INT_MAX }; + ipa_size_summary *info = ipa_size_summaries->get (node); - node->call_for_symbol_and_aliases (do_estimate_growth_1, &d, true); + if (node->call_for_symbol_and_aliases (do_estimate_growth_1, &d, true)) + return 1; /* For self recursive functions the growth estimation really should be infinity. We don't want to return very large values because the growth @@ -436,21 +465,8 @@ estimate_growth (struct cgraph_node *node) return zero or negative growths. */ if (d.self_recursive) d.growth = d.growth < info->size ? info->size : d.growth; - else if (DECL_EXTERNAL (node->decl) || d.uninlinable) - ; - else - { - if (node->will_be_removed_from_program_if_no_direct_calls_p ()) - d.growth -= info->size; - /* COMDAT functions are very often not shared across multiple units - since they come from various template instantiations. - Take this into account. */ - else if (DECL_COMDAT (node->decl) - && node->can_remove_if_no_direct_calls_p ()) - d.growth -= (info->size - * (100 - PARAM_VALUE (PARAM_COMDAT_SHARING_PROBABILITY)) - + 50) / 100; - } + else if (!d.uninlinable) + d.growth -= offline_size (node, info); return d.growth; } @@ -458,7 +474,8 @@ estimate_growth (struct cgraph_node *node) /* Verify if there are fewer than MAX_CALLERS. */ static bool -check_callers (cgraph_node *node, int *max_callers) +check_callers (cgraph_node *node, int *growth, int *n, int offline, + int min_size, struct cgraph_edge *known_edge) { ipa_ref *ref; @@ -467,70 +484,96 @@ check_callers (cgraph_node *node, int *max_callers) for (cgraph_edge *e = node->callers; e; e = e->next_caller) { - (*max_callers)--; - if (!*max_callers - || cgraph_inline_failed_type (e->inline_failed) == CIF_FINAL_ERROR) + edge_growth_cache_entry *entry; + + if (e == known_edge) + continue; + if (cgraph_inline_failed_type (e->inline_failed) == CIF_FINAL_ERROR) + return true; + if (edge_growth_cache != NULL + && (entry = edge_growth_cache->get (e)) != NULL + && entry->size != 0) + *growth += entry->size - (entry->size > 0); + else + { + class ipa_call_summary *es = ipa_call_summaries->get (e); + if (!es) + return true; + *growth += min_size - es->call_stmt_size; + if (--(*n) < 0) + return false; + } + if (*growth > offline) return true; } - FOR_EACH_ALIAS (node, ref) - if (check_callers (dyn_cast (ref->referring), max_callers)) - return true; + if (*n > 0) + FOR_EACH_ALIAS (node, ref) + if (check_callers (dyn_cast (ref->referring), growth, n, + offline, min_size, known_edge)) + return true; return false; } -/* Make cheap estimation if growth of NODE is likely positive knowing - EDGE_GROWTH of one particular edge. - We assume that most of other edges will have similar growth - and skip computation if there are too many callers. */ +/* Decide if growth of NODE is positive. This is cheaper than calculating + actual growth. If edge growth of KNOWN_EDGE is known + it is passed by EDGE_GROWTH. */ bool -growth_likely_positive (struct cgraph_node *node, - int edge_growth) +growth_positive_p (struct cgraph_node *node, + struct cgraph_edge * known_edge, int edge_growth) { - int max_callers; struct cgraph_edge *e; - gcc_checking_assert (edge_growth > 0); + + ipa_size_summary *s = ipa_size_summaries->get (node); /* First quickly check if NODE is removable at all. */ - if (DECL_EXTERNAL (node->decl)) - return true; - if (!node->can_remove_if_no_direct_calls_and_refs_p () - || node->address_taken) + int offline = offline_size (node, s); + if (offline <= 0 && known_edge && edge_growth > 0) return true; - max_callers = ipa_size_summaries->get (node)->size * 4 / edge_growth + 2; + int min_size = ipa_fn_summaries->get (node)->min_size; + int n = 10; + int min_growth = known_edge ? edge_growth : 0; for (e = node->callers; e; e = e->next_caller) { - max_callers--; - if (!max_callers - || cgraph_inline_failed_type (e->inline_failed) == CIF_FINAL_ERROR) + edge_growth_cache_entry *entry; + + if (cgraph_inline_failed_type (e->inline_failed) == CIF_FINAL_ERROR) + return true; + if (e == known_edge) + continue; + if (edge_growth_cache != NULL + && (entry = edge_growth_cache->get (e)) != NULL + && entry->size != 0) + min_growth += entry->size - (entry->size > 0); + else + { + class ipa_call_summary *es = ipa_call_summaries->get (e); + if (!es) + return true; + min_growth += min_size - es->call_stmt_size; + if (--n <= 0) + break; + } + if (min_growth > offline) return true; } ipa_ref *ref; - FOR_EACH_ALIAS (node, ref) - if (check_callers (dyn_cast (ref->referring), &max_callers)) - return true; - - /* Unlike for functions called once, we play unsafe with - COMDATs. We can allow that since we know functions - in consideration are small (and thus risk is small) and - moreover grow estimates already accounts that COMDAT - functions may or may not disappear when eliminated from - current unit. With good probability making aggressive - choice in all units is going to make overall program - smaller. */ - if (DECL_COMDAT (node->decl)) - { - if (!node->can_remove_if_no_direct_calls_p ()) + if (n > 0) + FOR_EACH_ALIAS (node, ref) + if (check_callers (dyn_cast (ref->referring), + &min_growth, &n, offline, min_size, known_edge)) return true; - } - else if (!node->will_be_removed_from_program_if_no_direct_calls_p ()) - return true; - return estimate_growth (node) > 0; + struct growth_data d = { node, false, false, 0, offline }; + if (node->call_for_symbol_and_aliases (do_estimate_growth_1, &d, true)) + return true; + if (d.self_recursive || d.uninlinable) + return true; + return (d.growth > offline); } diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c index 9f47239bc03..83764f6100a 100644 --- a/gcc/ipa-inline.c +++ b/gcc/ipa-inline.c @@ -883,9 +883,9 @@ want_inline_small_function_p (struct cgraph_edge *e, bool report) && !opt_for_fn (e->caller->decl, flag_inline_functions) && growth >= PARAM_VALUE (PARAM_MAX_INLINE_INSNS_SMALL)) { - /* growth_likely_positive is expensive, always test it last. */ + /* growth_positive_p is expensive, always test it last. */ if (growth >= inline_insns_single (e->caller, false) - || growth_likely_positive (callee, growth)) + || growth_positive_p (callee, e, growth)) { e->inline_failed = CIF_NOT_DECLARED_INLINED; want_inline = false; @@ -899,9 +899,9 @@ want_inline_small_function_p (struct cgraph_edge *e, bool report) || growth >= inline_insns_auto (e->caller, true) || !big_speedup_p (e))) { - /* growth_likely_positive is expensive, always test it last. */ + /* growth_positive_p is expensive, always test it last. */ if (growth >= inline_insns_single (e->caller, false) - || growth_likely_positive (callee, growth)) + || growth_positive_p (callee, e, growth)) { if (opt_for_fn (e->caller->decl, optimize) >= 3) e->inline_failed = CIF_MAX_INLINE_INSNS_AUTO_LIMIT; @@ -913,7 +913,7 @@ want_inline_small_function_p (struct cgraph_edge *e, bool report) /* If call is cold, do not inline when function body would grow. */ else if (!e->maybe_hot_p () && (growth >= inline_insns_single (e->caller, false) - || growth_likely_positive (callee, growth))) + || growth_positive_p (callee, e, growth))) { e->inline_failed = CIF_UNLIKELY_CALL; want_inline = false; @@ -1075,7 +1075,7 @@ want_inline_function_to_all_callers_p (struct cgraph_node *node, bool cold) if (!node->call_for_symbol_and_aliases (has_caller_p, NULL, true)) return false; /* Inlining into all callers would increase size? */ - if (estimate_growth (node) > 0) + if (growth_positive_p (node, NULL, INT_MIN) > 0) return false; /* All inlines must be possible. */ if (node->call_for_symbol_and_aliases (check_callers, &has_hot_call, diff --git a/gcc/ipa-inline.h b/gcc/ipa-inline.h index 33205a0e6db..f650b0e83fa 100644 --- a/gcc/ipa-inline.h +++ b/gcc/ipa-inline.h @@ -44,7 +44,7 @@ extern fast_call_summary *edge_growth_cache; /* In ipa-inline-analysis.c */ int estimate_size_after_inlining (struct cgraph_node *, struct cgraph_edge *); int estimate_growth (struct cgraph_node *); -bool growth_likely_positive (struct cgraph_node *, int); +bool growth_positive_p (struct cgraph_node *, struct cgraph_edge *, int); int do_estimate_edge_size (struct cgraph_edge *edge); sreal do_estimate_edge_time (struct cgraph_edge *edge); ipa_hints do_estimate_edge_hints (struct cgraph_edge *edge); -- 2.30.2