From 1e83bd7003e03160b7d71fb959111e89b53446ab Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Sat, 23 Nov 2019 13:13:23 +0000 Subject: [PATCH] Convert inliner to new param infrastructure /bin/sh: :q: command not found This patch adds opt_for_fn for all cross module params used by inliner so they can be modified at function granuality. With inlining almost always there are three functions to consider (callee and caller of the inlined edge and the outer function caller is inlined to). I always use the outer function params since that is how local parameters behave. I hope it is kind of what is also expected in most case: it is better to inline agressively into -O3 compiled code rather than inline agressively -O3 functions into their callers. New params infrastructure is nice. One drawback is that is very hard to search for individual param uses since they all occupy global namespace. With C++ world we had chance to do something like params.param_flag_name or params::param_flag_name instead... Bootstrapped/regtested x86_64-linux, comitted. * cif-code.def (MAX_INLINE_INSNS_SINGLE_O2_LIMIT): Remove. * doc/invoke.texi (max-inline-insns-single-O2, inline-heuristics-hint-percent-O2, inline-min-speedup-O2, early-inlining-insns-O2): Remove documentation. * ipa-fnsummary.c (analyze_function_body, compute_fn_summary): Use opt_for_fn when accessing parameters. * ipa-inline.c (caller_growth_limits, can_inline_edge_p, inline_insns_auto, can_inline_edge_by_limits_p, want_early_inline_function_p, big_speedup_p, want_inline_small_function_p, want_inline_self_recursive_call_p, recursive_inlining, compute_max_insns, inline_small_functions): Likewise. * opts.c (default_options): Add -O3 defaults for OPT__param_early_inlining_insns_, OPT__param_inline_heuristics_hint_percent_, OPT__param_inline_min_speedup_, OPT__param_max_inline_insns_single_. * params.opt (-param=early-inlining-insns-O2=, -param=inline-heuristics-hint-percent-O2=, -param=inline-min-speedup-O2=, -param=max-inline-insns-single-O2= -param=early-inlining-insns=, -param=inline-heuristics-hint-percent=, -param=inline-min-speedup=, -param=inline-unit-growth=, -param=large-function-growth=, -param=large-stack-frame=, -param=large-stack-frame-growth=, -param=large-unit-insns=, -param=max-inline-insns-recursive=, -param=max-inline-insns-recursive-auto=, -param=max-inline-insns-single=, -param=max-inline-insns-size=, -param=max-inline-insns-small=, -param=max-inline-recursive-depth=, -param=max-inline-recursive-depth-auto=, -param=min-inline-recursive-probability=, -param=partial-inlining-entry-probability=, -param=uninlined-function-insns=, -param=uninlined-function-time=, -param=uninlined-thunk-insns=, -param=uninlined-thunk-time=): Add Optimization. * g++.dg/tree-ssa/pr53844.C: Drop -O2 from param name. * g++.dg/tree-ssa/pr61034.C: Likewise. * g++.dg/tree-ssa/pr8781.C: Likewise. * g++.dg/warn/Wstringop-truncation-1.C: Likewise. * gcc.dg/ipa/pr63416.c: Likewise. * gcc.dg/tree-ssa/ssa-thread-12.c: Likewise. * gcc.dg/vect/pr66142.c: Likewise. * gcc.dg/winline-3.c: Likewise. * gcc.target/powerpc/pr72804.c: Likewise. From-SVN: r278645 --- gcc/ipa-inline.c | 96 +++++++++++++++++++++++------------------------- 1 file changed, 45 insertions(+), 51 deletions(-) diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c index 4dd4de157f1..08612e79eb0 100644 --- a/gcc/ipa-inline.c +++ b/gcc/ipa-inline.c @@ -178,13 +178,13 @@ caller_growth_limits (struct cgraph_edge *e) if (limit < what_size_info->self_size) limit = what_size_info->self_size; - limit += limit * param_large_function_growth / 100; + limit += limit * opt_for_fn (to->decl, param_large_function_growth) / 100; /* 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 = estimate_size_after_inlining (to, e); if (newsize >= ipa_size_summaries->get (what)->size - && newsize > param_large_function_insns + && newsize > opt_for_fn (to->decl, param_large_function_insns) && newsize > limit) { e->inline_failed = CIF_LARGE_FUNCTION_GROWTH_LIMIT; @@ -200,7 +200,8 @@ caller_growth_limits (struct cgraph_edge *e) on every invocation of the caller (i.e. its call statement dominates exit block). We do not track this information, yet. */ stack_size_limit += ((gcov_type)stack_size_limit - * param_stack_frame_growth / 100); + * opt_for_fn (to->decl, param_stack_frame_growth) + / 100); inlined_stack = (ipa_get_stack_frame_offset (to) + outer_info->estimated_self_stack_size @@ -213,7 +214,7 @@ caller_growth_limits (struct cgraph_edge *e) This bit overoptimistically assume that we are good at stack packing. */ && inlined_stack > ipa_fn_summaries->get (to)->estimated_stack_size - && inlined_stack > param_large_stack_frame) + && inlined_stack > opt_for_fn (to->decl, param_large_stack_frame)) { e->inline_failed = CIF_LARGE_STACK_FRAME_GROWTH_LIMIT; return false; @@ -395,20 +396,10 @@ can_inline_edge_p (struct cgraph_edge *e, bool report, static int inline_insns_single (cgraph_node *n, bool hint) { - if (opt_for_fn (n->decl, optimize) >= 3) - { - if (hint) - return param_max_inline_insns_single - * param_inline_heuristics_hint_percent / 100; - return param_max_inline_insns_single; - } - else - { - if (hint) - return param_max_inline_insns_single_o2 - * param_inline_heuristics_hint_percent_o2 / 100; - return param_max_inline_insns_single_o2; - } + if (hint) + return opt_for_fn (n->decl, param_max_inline_insns_single) + * opt_for_fn (n->decl, param_inline_heuristics_hint_percent) / 100; + return opt_for_fn (n->decl, param_max_inline_insns_single); } /* Return inlining_insns_auto limit for function N. If HINT is true @@ -419,7 +410,8 @@ inline_insns_auto (cgraph_node *n, bool hint) { int max_inline_insns_auto = opt_for_fn (n->decl, param_max_inline_insns_auto); if (hint) - return max_inline_insns_auto * param_inline_heuristics_hint_percent / 100; + return max_inline_insns_auto + * opt_for_fn (n->decl, param_inline_heuristics_hint_percent) / 100; return max_inline_insns_auto; } @@ -563,7 +555,7 @@ can_inline_edge_by_limits_p (struct cgraph_edge *e, bool report, > opt_for_fn (caller->decl, optimize_size)) { int growth = estimate_edge_growth (e); - if (growth > param_max_inline_insns_size + if (growth > opt_for_fn (caller->decl, param_max_inline_insns_size) && (!DECL_DECLARED_INLINE_P (callee->decl) && growth >= MAX (inline_insns_single (caller, false), inline_insns_auto (caller, false)))) @@ -675,9 +667,7 @@ want_early_inline_function_p (struct cgraph_edge *e) /* First take care of very large functions. */ int min_growth = estimate_min_edge_growth (e), growth = 0; int n; - int early_inlining_insns = opt_for_fn (e->caller->decl, optimize) >= 3 - ? param_early_inlining_insns - : param_early_inlining_insns_o2; + int early_inlining_insns = param_early_inlining_insns; if (min_growth > early_inlining_insns) { @@ -824,9 +814,7 @@ big_speedup_p (struct cgraph_edge *e) cgraph_node *caller = (e->caller->inlined_to ? e->caller->inlined_to : e->caller); - int limit = opt_for_fn (caller->decl, optimize) >= 3 - ? param_inline_min_speedup - : param_inline_min_speedup_o2; + int limit = opt_for_fn (caller->decl, param_inline_min_speedup); if ((time - inlined_time) * 100 > time * limit) return true; @@ -841,6 +829,8 @@ want_inline_small_function_p (struct cgraph_edge *e, bool report) { bool want_inline = true; struct cgraph_node *callee = e->callee->ultimate_alias_target (); + cgraph_node *to = (e->caller->inlined_to + ? e->caller->inlined_to : e->caller); /* Allow this function to be called before can_inline_edge_p, since it's usually cheaper. */ @@ -876,9 +866,7 @@ want_inline_small_function_p (struct cgraph_edge *e, bool report) ? CIF_MAX_INLINE_INSNS_SINGLE_LIMIT : CIF_MAX_INLINE_INSNS_AUTO_LIMIT); else - e->inline_failed = (DECL_DECLARED_INLINE_P (callee->decl) - ? CIF_MAX_INLINE_INSNS_SINGLE_O2_LIMIT - : CIF_MAX_INLINE_INSNS_AUTO_LIMIT); + e->inline_failed = CIF_MAX_INLINE_INSNS_AUTO_LIMIT; want_inline = false; } else @@ -890,7 +878,8 @@ want_inline_small_function_p (struct cgraph_edge *e, bool report) | INLINE_HINT_loop_iterations | INLINE_HINT_loop_stride)); - if (growth <= param_max_inline_insns_size) + if (growth <= opt_for_fn (to->decl, + param_max_inline_insns_size)) ; /* Apply param_max_inline_insns_single limit. Do not do so when hints suggests that inlining given function is very profitable. @@ -902,15 +891,13 @@ want_inline_small_function_p (struct cgraph_edge *e, bool report) || growth >= inline_insns_single (e->caller, true) || !big_speedup_p (e))) { - if (opt_for_fn (e->caller->decl, optimize) >= 3) - e->inline_failed = CIF_MAX_INLINE_INSNS_SINGLE_LIMIT; - else - e->inline_failed = CIF_MAX_INLINE_INSNS_SINGLE_O2_LIMIT; + e->inline_failed = CIF_MAX_INLINE_INSNS_SINGLE_LIMIT; want_inline = false; } else if (!DECL_DECLARED_INLINE_P (callee->decl) && !opt_for_fn (e->caller->decl, flag_inline_functions) - && growth >= param_max_inline_insns_small) + && growth >= opt_for_fn (to->decl, + param_max_inline_insns_small)) { /* growth_positive_p is expensive, always test it last. */ if (growth >= inline_insns_single (e->caller, false) @@ -951,7 +938,7 @@ want_inline_small_function_p (struct cgraph_edge *e, bool report) } /* EDGE is self recursive edge. - We hand two cases - when function A is inlining into itself + We handle two cases - when function A is inlining into itself or when function A is being inlined into another inliner copy of function A within function B. @@ -970,10 +957,12 @@ want_inline_self_recursive_call_p (struct cgraph_edge *edge, char const *reason = NULL; bool want_inline = true; sreal caller_freq = 1; - int max_depth = param_max_inline_recursive_depth_auto; + int max_depth = opt_for_fn (outer_node->decl, + param_max_inline_recursive_depth_auto); if (DECL_DECLARED_INLINE_P (edge->caller->decl)) - max_depth = param_max_inline_recursive_depth; + max_depth = opt_for_fn (outer_node->decl, + param_max_inline_recursive_depth); if (!edge->maybe_hot_p ()) { @@ -1035,7 +1024,8 @@ want_inline_self_recursive_call_p (struct cgraph_edge *edge, { if (edge->sreal_frequency () * 100 <= caller_freq - * param_min_inline_recursive_probability) + * opt_for_fn (outer_node->decl, + param_min_inline_recursive_probability)) { reason = "frequency of recursive call is too small"; want_inline = false; @@ -1241,7 +1231,9 @@ edge_badness (struct cgraph_edge *edge, bool dump) /* ... or when early optimizers decided to split and edge frequency still indicates splitting is a win ... */ || (callee->split_part && !caller->split_part - && freq * 100 < param_partial_inlining_entry_probability + && freq * 100 + < opt_for_fn (caller->decl, + param_partial_inlining_entry_probability) /* ... and do not overwrite user specified hints. */ && (!DECL_DECLARED_INLINE_P (edge->callee->decl) || DECL_DECLARED_INLINE_P (caller->decl))))) @@ -1599,7 +1591,10 @@ static bool recursive_inlining (struct cgraph_edge *edge, vec *new_edges) { - int limit = param_max_inline_insns_recursive_auto; + cgraph_node *to = (edge->caller->inlined_to + ? edge->caller->inlined_to : edge->caller); + int limit = opt_for_fn (to->decl, + param_max_inline_insns_recursive_auto); edge_heap_t heap (sreal::min ()); struct cgraph_node *node; struct cgraph_edge *e; @@ -1612,7 +1607,7 @@ recursive_inlining (struct cgraph_edge *edge, node = node->inlined_to; if (DECL_DECLARED_INLINE_P (node->decl)) - limit = param_max_inline_insns_recursive; + limit = opt_for_fn (to->decl, param_max_inline_insns_recursive); /* Make sure that function is small enough to be considered for inlining. */ if (estimate_size_after_inlining (node, edge) >= limit) @@ -1735,14 +1730,14 @@ recursive_inlining (struct cgraph_edge *edge, allow the unit to grow. */ static int -compute_max_insns (int insns) +compute_max_insns (cgraph_node *node, int insns) { int max_insns = insns; - if (max_insns < param_large_unit_insns) - max_insns = param_large_unit_insns; + if (max_insns < opt_for_fn (node->decl, param_large_unit_insns)) + max_insns = opt_for_fn (node->decl, param_large_unit_insns); return ((int64_t) max_insns - * (100 + param_inline_unit_growth) / 100); + * (100 + opt_for_fn (node->decl, param_inline_unit_growth)) / 100); } @@ -1906,7 +1901,7 @@ inline_small_functions (void) struct cgraph_edge *edge; edge_heap_t edge_heap (sreal::min ()); auto_bitmap updated_nodes; - int min_size, max_size; + int min_size; auto_vec new_indirect_edges; int initial_size = 0; struct cgraph_node **order = XCNEWVEC (cgraph_node *, symtab->cgraph_count); @@ -1973,7 +1968,6 @@ inline_small_functions (void) initial_size); overall_size = initial_size; - max_size = compute_max_insns (overall_size); min_size = overall_size; /* Populate the heap with all edges we might inline. */ @@ -2141,7 +2135,9 @@ inline_small_functions (void) edge_badness (edge, true); } - if (overall_size + growth > max_size + where = edge->caller; + + if (overall_size + growth > compute_max_insns (where, min_size) && !DECL_DISREGARD_INLINE_LIMITS (callee->decl)) { edge->inline_failed = CIF_INLINE_UNIT_GROWTH_LIMIT; @@ -2164,7 +2160,6 @@ inline_small_functions (void) specific inliner. */ if (edge->recursive_p ()) { - where = edge->caller; if (where->inlined_to) where = where->inlined_to; if (!recursive_inlining (edge, @@ -2278,7 +2273,6 @@ inline_small_functions (void) if (min_size > overall_size) { min_size = overall_size; - max_size = compute_max_insns (min_size); if (dump_file) fprintf (dump_file, "New minimal size reached: %i\n", min_size); -- 2.30.2