aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJan Hubicka <jh@suse.cz>2012-08-19 07:55:20 +0200
committerJan Hubicka <hubicka@gcc.gnu.org>2012-08-19 05:55:20 +0000
commit37678631a8a4464bc16c8d02dfaa4086f6038cb1 (patch)
tree032d8e752b8a993f1aa19d59d320266d25238378 /gcc
parentecfdae6f116a6c154d57a4fced789d6f1b396c07 (diff)
downloadgcc-37678631a8a4464bc16c8d02dfaa4086f6038cb1.zip
gcc-37678631a8a4464bc16c8d02dfaa4086f6038cb1.tar.gz
gcc-37678631a8a4464bc16c8d02dfaa4086f6038cb1.tar.bz2
re PR lto/45375 ([meta-bug] Issues with building Mozilla (i.e. Firefox) with LTO)
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 From-SVN: r190509
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog25
-rw-r--r--gcc/ipa-inline-analysis.c125
-rw-r--r--gcc/ipa-inline.c22
-rw-r--r--gcc/ipa-inline.h30
-rw-r--r--gcc/predict.c6
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.dg/ipa/iinline-1.c3
7 files changed, 165 insertions, 50 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 1f313e9..6dabed6 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,28 @@
+2012-08-18 Jan Hubicka <jh@suse.cz>
+
+ 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
+
2012-08-18 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
PR middle-end/53823
diff --git a/gcc/ipa-inline-analysis.c b/gcc/ipa-inline-analysis.c
index 9f96ca8..c30e81a 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
diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index 5215049..55d9a52 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -472,11 +472,15 @@ want_inline_small_function_p (struct cgraph_edge *e, bool report)
else
{
int growth = estimate_edge_growth (e);
+ inline_hints hints = estimate_edge_hints (e);
if (growth <= 0)
;
+ /* Apply MAX_INLINE_INSNS_SINGLE limit. Do not do so when
+ hints suggests that inlining given function is very profitable. */
else if (DECL_DECLARED_INLINE_P (callee->symbol.decl)
- && growth >= MAX_INLINE_INSNS_SINGLE)
+ && growth >= MAX_INLINE_INSNS_SINGLE
+ && !(hints & INLINE_HINT_indirect_call))
{
e->inline_failed = CIF_MAX_INLINE_INSNS_SINGLE_LIMIT;
want_inline = false;
@@ -523,8 +527,14 @@ want_inline_small_function_p (struct cgraph_edge *e, bool report)
e->inline_failed = CIF_NOT_DECLARED_INLINED;
want_inline = false;
}
+ /* Apply MAX_INLINE_INSNS_AUTO limit for functions not declared inline
+ Upgrade it to MAX_INLINE_INSNS_SINGLE when hints suggests that
+ inlining given function is very profitable. */
else if (!DECL_DECLARED_INLINE_P (callee->symbol.decl)
- && growth >= MAX_INLINE_INSNS_AUTO)
+ && growth >= ((hints & INLINE_HINT_indirect_call)
+ ? MAX (MAX_INLINE_INSNS_AUTO,
+ MAX_INLINE_INSNS_SINGLE)
+ : MAX_INLINE_INSNS_AUTO))
{
e->inline_failed = CIF_MAX_INLINE_INSNS_AUTO_LIMIT;
want_inline = false;
@@ -743,21 +753,25 @@ edge_badness (struct cgraph_edge *edge, bool dump)
struct cgraph_node *callee = cgraph_function_or_thunk_node (edge->callee,
NULL);
struct inline_summary *callee_info = inline_summary (callee);
+ inline_hints hints;
if (DECL_DISREGARD_INLINE_LIMITS (callee->symbol.decl))
return INT_MIN;
growth = estimate_edge_growth (edge);
time_growth = estimate_edge_time (edge);
+ hints = estimate_edge_hints (edge);
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\n",
+ fprintf (dump_file, " size growth %i, time growth %i ",
growth,
time_growth);
+ dump_inline_hints (dump_file, hints);
+ fprintf (dump_file, "\n");
}
/* Always prefer inlining saving code size. */
@@ -849,6 +863,8 @@ edge_badness (struct cgraph_edge *edge, bool dump)
if (dump)
fprintf (dump_file, "Badness overflow\n");
}
+ if (hints & INLINE_HINT_indirect_call)
+ badness /= 8;
if (dump)
{
fprintf (dump_file,
diff --git a/gcc/ipa-inline.h b/gcc/ipa-inline.h
index d6909af..fca99e6 100644
--- a/gcc/ipa-inline.h
+++ b/gcc/ipa-inline.h
@@ -42,6 +42,13 @@ typedef struct GTY(()) condition
unsigned by_ref : 1;
} condition;
+/* Inline hints are reasons why inline heuristics should preffer inlining given function.
+ They are represtented as bitmap of the following values. */
+enum inline_hints_vals {
+ INLINE_HINT_indirect_call = 1
+};
+typedef int inline_hints;
+
DEF_VEC_O (condition);
DEF_VEC_ALLOC_O (condition, gc);
@@ -158,6 +165,7 @@ extern VEC(inline_edge_summary_t,heap) *inline_edge_summary_vec;
typedef struct edge_growth_cache_entry
{
int time, size;
+ inline_hints hints;
} edge_growth_cache_entry;
DEF_VEC_O(edge_growth_cache_entry);
DEF_VEC_ALLOC_O(edge_growth_cache_entry,heap);
@@ -168,7 +176,8 @@ extern VEC(edge_growth_cache_entry,heap) *edge_growth_cache;
/* In ipa-inline-analysis.c */
void debug_inline_summary (struct cgraph_node *);
void dump_inline_summaries (FILE *f);
-void dump_inline_summary (FILE * f, struct cgraph_node *node);
+void dump_inline_summary (FILE *f, struct cgraph_node *node);
+void dump_inline_hints (FILE *f, inline_hints);
void inline_generate_summary (void);
void inline_read_summary (void);
void inline_write_summary (void);
@@ -185,6 +194,7 @@ void inline_merge_summary (struct cgraph_edge *edge);
void inline_update_overall_summary (struct cgraph_node *node);
int do_estimate_edge_growth (struct cgraph_edge *edge);
int do_estimate_edge_time (struct cgraph_edge *edge);
+inline_hints do_estimate_edge_hints (struct cgraph_edge *edge);
void initialize_growth_caches (void);
void free_growth_caches (void);
void compute_inline_parameters (struct cgraph_node *, bool);
@@ -257,6 +267,22 @@ estimate_edge_time (struct cgraph_edge *edge)
}
+/* Return estimated callee runtime increase after inlning
+ EDGE. */
+
+static inline inline_hints
+estimate_edge_hints (struct cgraph_edge *edge)
+{
+ inline_hints ret;
+ if ((int)VEC_length (edge_growth_cache_entry, edge_growth_cache) <= edge->uid
+ || !(ret = VEC_index (edge_growth_cache_entry,
+ edge_growth_cache,
+ edge->uid).hints))
+ return do_estimate_edge_time (edge);
+ return ret - 1;
+}
+
+
/* Reset cached value for NODE. */
static inline void
@@ -273,7 +299,7 @@ reset_edge_growth_cache (struct cgraph_edge *edge)
{
if ((int)VEC_length (edge_growth_cache_entry, edge_growth_cache) > edge->uid)
{
- struct edge_growth_cache_entry zero = {0, 0};
+ struct edge_growth_cache_entry zero = {0, 0, 0};
VEC_replace (edge_growth_cache_entry, edge_growth_cache, edge->uid, zero);
}
}
diff --git a/gcc/predict.c b/gcc/predict.c
index c884d38..e1a064d 100644
--- a/gcc/predict.c
+++ b/gcc/predict.c
@@ -165,10 +165,12 @@ cgraph_maybe_hot_edge_p (struct cgraph_edge *edge)
<= profile_info->sum_max / PARAM_VALUE (HOT_BB_COUNT_FRACTION)))
return false;
if (edge->caller->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED
- || edge->callee->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED)
+ || (edge->callee
+ && edge->callee->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED))
return false;
if (edge->caller->frequency > NODE_FREQUENCY_UNLIKELY_EXECUTED
- && edge->callee->frequency <= NODE_FREQUENCY_EXECUTED_ONCE)
+ && (edge->callee
+ && edge->callee->frequency <= NODE_FREQUENCY_EXECUTED_ONCE))
return false;
if (optimize_size)
return false;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index e8a48c9..378e778 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2012-08-18 Jan Hubicka <jh@suse.cz>
+
+ * gcc.dg/ipa/iinline-1.c: Update testcase to test inline hints.
+
2012-08-18 Mikael Morin <mikael@gcc.gnu.org>
PR fortran/39290
diff --git a/gcc/testsuite/gcc.dg/ipa/iinline-1.c b/gcc/testsuite/gcc.dg/ipa/iinline-1.c
index 617c484..860b3e5 100644
--- a/gcc/testsuite/gcc.dg/ipa/iinline-1.c
+++ b/gcc/testsuite/gcc.dg/ipa/iinline-1.c
@@ -1,7 +1,7 @@
/* Verify that simple indirect calls are inlined even without early
inlining.. */
/* { dg-do compile } */
-/* { dg-options "-O3 -c -fdump-ipa-inline -fno-early-inlining" } */
+/* { dg-options "-O3 -c -fdump-ipa-inline-details -fno-early-inlining -fno-ipa-cp" } */
extern void non_existent(int);
@@ -22,5 +22,6 @@ int test (void)
return 0;
}
+/* { dg-final { scan-ipa-dump "indirect_call" "inline" } } */
/* { dg-final { scan-ipa-dump "hooray\[^\\n\]*inline copy in test" "inline" } } */
/* { dg-final { cleanup-ipa-dump "inline" } } */