aboutsummaryrefslogtreecommitdiff
path: root/gcc/ipa-inline.c
diff options
context:
space:
mode:
authorJan Hubicka <jh@suse.cz>2012-11-05 15:00:46 +0100
committerJan Hubicka <hubicka@gcc.gnu.org>2012-11-05 14:00:46 +0000
commitd59171daa764fc59764a7538e48460ffcdae3f9b (patch)
tree75c6f6529140bc6332176723a9911440e6cf9481 /gcc/ipa-inline.c
parent0450d718804aac79ea618dcdfc74bfbda0a7e66e (diff)
downloadgcc-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.c170
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;