diff options
author | Jan Hubicka <jh@suse.cz> | 2012-11-05 15:00:46 +0100 |
---|---|---|
committer | Jan Hubicka <hubicka@gcc.gnu.org> | 2012-11-05 14:00:46 +0000 |
commit | d59171daa764fc59764a7538e48460ffcdae3f9b (patch) | |
tree | 75c6f6529140bc6332176723a9911440e6cf9481 /gcc/ipa-inline.c | |
parent | 0450d718804aac79ea618dcdfc74bfbda0a7e66e (diff) | |
download | gcc-d59171daa764fc59764a7538e48460ffcdae3f9b.zip gcc-d59171daa764fc59764a7538e48460ffcdae3f9b.tar.gz gcc-d59171daa764fc59764a7538e48460ffcdae3f9b.tar.bz2 |
ipa-inline.c (compute_uninlined_call_time, [...]): New functions.
* ipa-inline.c (compute_uninlined_call_time,
compute_inlined_call_time): New functions.
(RELATIVE_TIME_BENEFIT_RANGE): New macro.
(relative_time_benefit): Rewrite.
(edge_badness): Rewrite path with guessed profile and estimated profile.
* ipa-inline.h (INLINE_HINT_declared_inline, INLINE_HINT_cross_module):
New hints.
(struct inline_summary): Add GROWTH filed.
* ipa-inline-analysis.c (dump_inline_hints): Update.
(reset_inline_summary): Update.
(dump_inline_summary): Update.
(will_be_nonconstant_predicate): Cleanup to use gimple_store_p and
gimple_assign_load_p predicates.
(estimate_node_size_and_time): Drop INLINE_HINT_declared_inline hint.
(simple_edge_hints): New function.
(do_estimate_edge_time): Return time of invocation of callee rather
than the time scaled by edge frequency; update hints code.
(do_estimate_edge_hints): Update.
(do_estimate_growth): Cleanup.
From-SVN: r193161
Diffstat (limited to 'gcc/ipa-inline.c')
-rw-r--r-- | gcc/ipa-inline.c | 170 |
1 files changed, 100 insertions, 70 deletions
diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c index 2bca2c5..b6a69cb 100644 --- a/gcc/ipa-inline.c +++ b/gcc/ipa-inline.c @@ -456,6 +456,42 @@ want_early_inline_function_p (struct cgraph_edge *e) return want_inline; } +/* Compute time of the edge->caller + edge->callee execution when inlining + does not happen. */ + +inline int +compute_uninlined_call_time (struct inline_summary *callee_info, + struct cgraph_edge *edge) +{ + int uninlined_call_time = + RDIV ((gcov_type)callee_info->time * MAX (edge->frequency, 1), + CGRAPH_FREQ_BASE); + int caller_time = inline_summary (edge->caller->global.inlined_to + ? edge->caller->global.inlined_to + : edge->caller)->time; + return uninlined_call_time + caller_time; +} + +/* Same as compute_uinlined_call_time but compute time when inlining + does happen. */ + +inline gcov_type +compute_inlined_call_time (struct cgraph_edge *edge, + int edge_time) +{ + int caller_time = inline_summary (edge->caller->global.inlined_to + ? edge->caller->global.inlined_to + : edge->caller)->time; + int time = caller_time + RDIV ((edge_time - inline_edge_summary (edge)->call_stmt_time) + * MAX (edge->frequency, 1), + CGRAPH_FREQ_BASE); + /* Possible one roundoff error, but watch for overflows. */ + gcc_checking_assert (time >= INT_MIN / 2); + if (time < 0) + time = 0; + return time; +} + /* Return true if we are interested in inlining small function. When REPORT is true, report reason to dump file. */ @@ -724,31 +760,41 @@ want_inline_function_to_all_callers_p (struct cgraph_node *node, bool cold) return true; } +#define RELATIVE_TIME_BENEFIT_RANGE (INT_MAX / 64) /* Return relative time improvement for inlining EDGE in range - 1...2^9. */ + 1...RELATIVE_TIME_BENEFIT_RANGE */ static inline int relative_time_benefit (struct inline_summary *callee_info, struct cgraph_edge *edge, - int time_growth) + int edge_time) { int relbenefit; - gcov_type uninlined_call_time; + int uninlined_call_time = compute_uninlined_call_time (callee_info, edge); + int inlined_call_time = compute_inlined_call_time (edge, edge_time); + + /* Inlining into extern inline function is not a win. */ + if (DECL_EXTERNAL (edge->caller->global.inlined_to + ? edge->caller->global.inlined_to->symbol.decl + : edge->caller->symbol.decl)) + return 1; + + /* Watch overflows. */ + gcc_checking_assert (uninlined_call_time >= 0); + gcc_checking_assert (inlined_call_time >= 0); + gcc_checking_assert (uninlined_call_time >= inlined_call_time); - uninlined_call_time = - ((gcov_type) - (callee_info->time - + inline_edge_summary (edge)->call_stmt_time) * edge->frequency - + CGRAPH_FREQ_BASE / 2) / CGRAPH_FREQ_BASE; /* Compute relative time benefit, i.e. how much the call becomes faster. ??? perhaps computing how much the caller+calle together become faster would lead to more realistic results. */ if (!uninlined_call_time) uninlined_call_time = 1; relbenefit = - (uninlined_call_time - time_growth) * 256 / (uninlined_call_time); - relbenefit = MIN (relbenefit, 512); + RDIV (((gcov_type)uninlined_call_time - inlined_call_time) * RELATIVE_TIME_BENEFIT_RANGE, + uninlined_call_time); + relbenefit = MIN (relbenefit, RELATIVE_TIME_BENEFIT_RANGE); + gcc_checking_assert (relbenefit >= 0); relbenefit = MAX (relbenefit, 1); return relbenefit; } @@ -764,7 +810,7 @@ static int edge_badness (struct cgraph_edge *edge, bool dump) { gcov_type badness; - int growth, time_growth; + int growth, edge_time; struct cgraph_node *callee = cgraph_function_or_thunk_node (edge->callee, NULL); struct inline_summary *callee_info = inline_summary (callee); @@ -774,17 +820,20 @@ edge_badness (struct cgraph_edge *edge, bool dump) return INT_MIN; growth = estimate_edge_growth (edge); - time_growth = estimate_edge_time (edge); + edge_time = estimate_edge_time (edge); hints = estimate_edge_hints (edge); + gcc_checking_assert (edge_time >= 0); + gcc_checking_assert (edge_time <= callee_info->time); + gcc_checking_assert (growth <= callee_info->size); if (dump) { fprintf (dump_file, " Badness calculation for %s -> %s\n", xstrdup (cgraph_node_name (edge->caller)), xstrdup (cgraph_node_name (callee))); - fprintf (dump_file, " size growth %i, time growth %i ", + fprintf (dump_file, " size growth %i, time %i ", growth, - time_growth); + edge_time); dump_inline_hints (dump_file, hints); fprintf (dump_file, "\n"); } @@ -802,7 +851,7 @@ edge_badness (struct cgraph_edge *edge, bool dump) relative_edge_count * relative_time_benefit goodness = ------------------------------------------- - edge_growth + growth_f_caller badness = -goodness The fraction is upside down, because on edge counts and time beneits @@ -810,11 +859,11 @@ edge_badness (struct cgraph_edge *edge, bool dump) else if (max_count) { - int relbenefit = relative_time_benefit (callee_info, edge, time_growth); + int relbenefit = relative_time_benefit (callee_info, edge, edge_time); badness = ((int) - ((double) edge->count * INT_MIN / 2 / max_count / 512) * - relative_time_benefit (callee_info, edge, time_growth)) / growth; + ((double) edge->count * INT_MIN / 2 / max_count / RELATIVE_TIME_BENEFIT_RANGE) * + relbenefit) / growth; /* Be sure that insanity of the profile won't lead to increasing counts in the scalling and thus to overflow in the computation above. */ @@ -826,73 +875,53 @@ edge_badness (struct cgraph_edge *edge, bool dump) " * Relative benefit %f\n", (int) badness, (double) badness / INT_MIN, (double) edge->count / max_count, - relbenefit * 100 / 256.0); + relbenefit * 100.0 / RELATIVE_TIME_BENEFIT_RANGE); } } /* When function local profile is available. Compute badness as: - - growth_of_callee - badness = -------------------------------------- + growth_for-all - relative_time_benefit * edge_frequency + relative_time_benefit + goodness = --------------------------------- + growth_of_caller * overall_growth + badness = - goodness + + compensated by the inline hints. */ else if (flag_guess_branch_prob) { - int div = edge->frequency * (1<<10) / CGRAPH_FREQ_MAX; - - div = MAX (div, 1); - gcc_checking_assert (edge->frequency <= CGRAPH_FREQ_MAX); - div *= relative_time_benefit (callee_info, edge, time_growth); - - /* frequency is normalized in range 1...2^10. - relbenefit in range 1...2^9 - DIV should be in range 1....2^19. */ - gcc_checking_assert (div >= 1 && div <= (1<<19)); - - /* Result must be integer in range 0...INT_MAX. - Set the base of fixed point calculation so we don't lose much of - precision for small bandesses (those are interesting) yet we don't - overflow for growths that are still in interesting range. - - Fixed point arithmetic with point at 6th bit. */ - badness = ((gcov_type)growth) * (1<<(19+6)); - badness = (badness + div / 2) / div; - - /* Overall growth of inlining all calls of function matters: we want to - inline so offline copy of function is no longer needed. - - Additionally functions that can be fully inlined without much of - effort are better inline candidates than functions that can be fully - inlined only after noticeable overall unit growths. The latter - are better in a sense compressing of code size by factoring out common - code into separate function shared by multiple code paths. - - We might mix the valud into the fraction by taking into account - relative growth of the unit, but for now just add the number - into resulting fraction. */ - if (badness > INT_MAX / 8) - { - badness = INT_MAX / 8; - if (dump) - fprintf (dump_file, "Badness overflow\n"); - } - if (hints & (INLINE_HINT_indirect_call - | INLINE_HINT_loop_iterations - | INLINE_HINT_loop_stride)) - badness /= 8; + badness = (relative_time_benefit (callee_info, edge, edge_time) + * (INT_MIN / 16 / RELATIVE_TIME_BENEFIT_RANGE)); + badness /= (growth * MAX (1, callee_info->growth)); + gcc_checking_assert (badness <=0 && badness >= INT_MIN / 16); + if ((hints & (INLINE_HINT_indirect_call + | INLINE_HINT_loop_iterations + | INLINE_HINT_loop_stride)) + || callee_info->growth <= 0) + badness *= 8; if (hints & (INLINE_HINT_same_scc)) - badness *= 4; - if (hints & (INLINE_HINT_in_scc)) - badness *= 2; + badness /= 16; + else if (hints & (INLINE_HINT_in_scc)) + badness /= 8; + else if (hints & (INLINE_HINT_cross_module)) + badness /= 2; + gcc_checking_assert (badness <= 0 && badness >= INT_MIN / 2); + if ((hints & INLINE_HINT_declared_inline) && badness >= INT_MIN / 32) + badness *= 16; if (dump) { fprintf (dump_file, " %i: guessed profile. frequency %f," - " benefit %f%%, divisor %i\n", + " benefit %f%%, time w/o inlining %i, time w inlining %i" + " overall growth %i (current) %i (original)\n", (int) badness, (double)edge->frequency / CGRAPH_FREQ_BASE, - relative_time_benefit (callee_info, edge, time_growth) * 100 / 256.0, div); + relative_time_benefit (callee_info, edge, edge_time) * 100.0 + / RELATIVE_TIME_BENEFIT_RANGE, + compute_uninlined_call_time (callee_info, edge), + (int)compute_inlined_call_time (edge, edge_time), + estimate_growth (callee), + callee_info->growth); } } /* When function local profile is not available or it does not give @@ -1371,6 +1400,7 @@ inline_small_functions (void) if (!DECL_EXTERNAL (node->symbol.decl)) initial_size += info->size; + info->growth = estimate_growth (node); if (dfs && dfs->next_cycle) { struct cgraph_node *n2; |