mirror of git://gcc.gnu.org/git/gcc.git
cgraph.c (cgraph_turn_edge_to_speculative): Return newly introduced edge; fix typo in sanity check.
* cgraph.c (cgraph_turn_edge_to_speculative): Return newly introduced edge; fix typo in sanity check. (cgraph_resolve_speculation): Export; improve diagnostic. (cgraph_redirect_edge_call_stmt_to_callee): Better diagnostic; cancel speculation at type mismatch. * cgraph.h (cgraph_turn_edge_to_speculative): Update. (cgraph_resolve_speculation): Declare. (symtab_can_be_discarded): New function. * value-prof.c (gimple_ic_transform): Remove actual transform code. * ipa-inline-transform.c (speculation_removed): New global var. (clone_inlined_nodes): See if speculation can be removed. (inline_call): If speculations was removed, we growths may not match. * ipa-inline.c (can_inline_edge_p): Add DISREGARD_LIMITS parameter. (speculation_useful_p): New function. (resolve_noninline_speculation): New function. (inline_small_functions): Resolve useless speculations. * ipa-inline.h (speculation_useful_p): Declare * ipa.c (can_replace_by_local_alias): Simplify. (ipa_profile): Produce speculative calls in non-lto, too; add simple cost model; produce local aliases. From-SVN: r201683
This commit is contained in:
parent
537e035c48
commit
09ce36608d
|
|
@ -1,3 +1,26 @@
|
||||||
|
2013-08-13 Jan Hubicka <jh@suse.cz>
|
||||||
|
|
||||||
|
* cgraph.c (cgraph_turn_edge_to_speculative): Return newly
|
||||||
|
introduced edge; fix typo in sanity check.
|
||||||
|
(cgraph_resolve_speculation): Export; improve diagnostic.
|
||||||
|
(cgraph_redirect_edge_call_stmt_to_callee): Better diagnostic; cancel
|
||||||
|
speculation at type mismatch.
|
||||||
|
* cgraph.h (cgraph_turn_edge_to_speculative): Update.
|
||||||
|
(cgraph_resolve_speculation): Declare.
|
||||||
|
(symtab_can_be_discarded): New function.
|
||||||
|
* value-prof.c (gimple_ic_transform): Remove actual transform code.
|
||||||
|
* ipa-inline-transform.c (speculation_removed): New global var.
|
||||||
|
(clone_inlined_nodes): See if speculation can be removed.
|
||||||
|
(inline_call): If speculations was removed, we growths may not match.
|
||||||
|
* ipa-inline.c (can_inline_edge_p): Add DISREGARD_LIMITS parameter.
|
||||||
|
(speculation_useful_p): New function.
|
||||||
|
(resolve_noninline_speculation): New function.
|
||||||
|
(inline_small_functions): Resolve useless speculations.
|
||||||
|
* ipa-inline.h (speculation_useful_p): Declare
|
||||||
|
* ipa.c (can_replace_by_local_alias): Simplify.
|
||||||
|
(ipa_profile): Produce speculative calls in non-lto, too;
|
||||||
|
add simple cost model; produce local aliases.
|
||||||
|
|
||||||
2013-08-13 David Malcolm <dmalcolm@redhat.com>
|
2013-08-13 David Malcolm <dmalcolm@redhat.com>
|
||||||
|
|
||||||
* config/i386/t-i386 (i386.o): Rename stray PIPELINE_H to
|
* config/i386/t-i386 (i386.o): Rename stray PIPELINE_H to
|
||||||
|
|
|
||||||
48
gcc/cgraph.c
48
gcc/cgraph.c
|
|
@ -1040,9 +1040,11 @@ cgraph_set_edge_callee (struct cgraph_edge *e, struct cgraph_node *n)
|
||||||
|
|
||||||
At this time the function just creates the direct call,
|
At this time the function just creates the direct call,
|
||||||
the referencd representing the if conditional and attaches
|
the referencd representing the if conditional and attaches
|
||||||
them all to the orginal indirect call statement. */
|
them all to the orginal indirect call statement.
|
||||||
|
|
||||||
void
|
Return direct edge created. */
|
||||||
|
|
||||||
|
struct cgraph_edge *
|
||||||
cgraph_turn_edge_to_speculative (struct cgraph_edge *e,
|
cgraph_turn_edge_to_speculative (struct cgraph_edge *e,
|
||||||
struct cgraph_node *n2,
|
struct cgraph_node *n2,
|
||||||
gcov_type direct_count,
|
gcov_type direct_count,
|
||||||
|
|
@ -1073,6 +1075,7 @@ cgraph_turn_edge_to_speculative (struct cgraph_edge *e,
|
||||||
IPA_REF_ADDR, e->call_stmt);
|
IPA_REF_ADDR, e->call_stmt);
|
||||||
ref->lto_stmt_uid = e->lto_stmt_uid;
|
ref->lto_stmt_uid = e->lto_stmt_uid;
|
||||||
ref->speculative = e->speculative;
|
ref->speculative = e->speculative;
|
||||||
|
return e2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Speculative call consist of three components:
|
/* Speculative call consist of three components:
|
||||||
|
|
@ -1107,7 +1110,7 @@ cgraph_speculative_call_info (struct cgraph_edge *e,
|
||||||
if (e2->call_stmt)
|
if (e2->call_stmt)
|
||||||
{
|
{
|
||||||
e = cgraph_edge (e->caller, e2->call_stmt);
|
e = cgraph_edge (e->caller, e2->call_stmt);
|
||||||
gcc_assert (!e->speculative && !e->indirect_unknown_callee);
|
gcc_assert (e->speculative && !e->indirect_unknown_callee);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
for (e = e->caller->callees;
|
for (e = e->caller->callees;
|
||||||
|
|
@ -1147,7 +1150,7 @@ cgraph_redirect_edge_callee (struct cgraph_edge *e, struct cgraph_node *n)
|
||||||
Remove the speculative call sequence and return edge representing the call.
|
Remove the speculative call sequence and return edge representing the call.
|
||||||
It is up to caller to redirect the call as appropriate. */
|
It is up to caller to redirect the call as appropriate. */
|
||||||
|
|
||||||
static struct cgraph_edge *
|
struct cgraph_edge *
|
||||||
cgraph_resolve_speculation (struct cgraph_edge *edge, tree callee_decl)
|
cgraph_resolve_speculation (struct cgraph_edge *edge, tree callee_decl)
|
||||||
{
|
{
|
||||||
struct cgraph_edge *e2;
|
struct cgraph_edge *e2;
|
||||||
|
|
@ -1159,12 +1162,21 @@ cgraph_resolve_speculation (struct cgraph_edge *edge, tree callee_decl)
|
||||||
{
|
{
|
||||||
if (dump_file)
|
if (dump_file)
|
||||||
{
|
{
|
||||||
fprintf (dump_file, "Speculative indirect call %s/%i => %s/%i has "
|
if (callee_decl)
|
||||||
"turned out to have contradicitng known target ",
|
{
|
||||||
xstrdup (cgraph_node_name (edge->caller)), edge->caller->symbol.order,
|
fprintf (dump_file, "Speculative indirect call %s/%i => %s/%i has "
|
||||||
xstrdup (cgraph_node_name (e2->callee)), e2->callee->symbol.order);
|
"turned out to have contradicting known target ",
|
||||||
print_generic_expr (dump_file, callee_decl, 0);
|
xstrdup (cgraph_node_name (edge->caller)), edge->caller->symbol.order,
|
||||||
fprintf (dump_file, "\n");
|
xstrdup (cgraph_node_name (e2->callee)), e2->callee->symbol.order);
|
||||||
|
print_generic_expr (dump_file, callee_decl, 0);
|
||||||
|
fprintf (dump_file, "\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf (dump_file, "Removing speculative call %s/%i => %s/%i\n",
|
||||||
|
xstrdup (cgraph_node_name (edge->caller)), edge->caller->symbol.order,
|
||||||
|
xstrdup (cgraph_node_name (e2->callee)), e2->callee->symbol.order);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -1264,12 +1276,24 @@ cgraph_redirect_edge_call_stmt_to_callee (struct cgraph_edge *e)
|
||||||
cgraph_speculative_call_info (e, e, e2, ref);
|
cgraph_speculative_call_info (e, e, e2, ref);
|
||||||
if (gimple_call_fndecl (e->call_stmt))
|
if (gimple_call_fndecl (e->call_stmt))
|
||||||
e = cgraph_resolve_speculation (e, gimple_call_fndecl (e->call_stmt));
|
e = cgraph_resolve_speculation (e, gimple_call_fndecl (e->call_stmt));
|
||||||
|
if (!gimple_check_call_matching_types (e->call_stmt, e->callee->symbol.decl,
|
||||||
|
true))
|
||||||
|
{
|
||||||
|
e = cgraph_resolve_speculation (e, NULL);
|
||||||
|
if (dump_file)
|
||||||
|
fprintf (dump_file, "Not expanding speculative call of %s/%i -> %s/%i\n"
|
||||||
|
"Type mismatch.\n",
|
||||||
|
xstrdup (cgraph_node_name (e->caller)), e->caller->symbol.order,
|
||||||
|
xstrdup (cgraph_node_name (e->callee)), e->callee->symbol.order);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (dump_file)
|
if (dump_file)
|
||||||
fprintf (dump_file, "Expanding speculative call of %s/%i -> %s/%i\n",
|
fprintf (dump_file, "Expanding speculative call of %s/%i -> %s/%i count:"
|
||||||
|
HOST_WIDEST_INT_PRINT_DEC"\n",
|
||||||
xstrdup (cgraph_node_name (e->caller)), e->caller->symbol.order,
|
xstrdup (cgraph_node_name (e->caller)), e->caller->symbol.order,
|
||||||
xstrdup (cgraph_node_name (e->callee)), e->callee->symbol.order);
|
xstrdup (cgraph_node_name (e->callee)), e->callee->symbol.order,
|
||||||
|
(HOST_WIDEST_INT)e->count);
|
||||||
gcc_assert (e2->speculative);
|
gcc_assert (e2->speculative);
|
||||||
push_cfun (DECL_STRUCT_FUNCTION (e->caller->symbol.decl));
|
push_cfun (DECL_STRUCT_FUNCTION (e->caller->symbol.decl));
|
||||||
new_stmt = gimple_ic (e->call_stmt, cgraph (ref->referred),
|
new_stmt = gimple_ic (e->call_stmt, cgraph (ref->referred),
|
||||||
|
|
|
||||||
15
gcc/cgraph.h
15
gcc/cgraph.h
|
|
@ -726,7 +726,7 @@ bool cgraph_propagate_frequency (struct cgraph_node *node);
|
||||||
struct cgraph_node * cgraph_function_node (struct cgraph_node *,
|
struct cgraph_node * cgraph_function_node (struct cgraph_node *,
|
||||||
enum availability *avail = NULL);
|
enum availability *avail = NULL);
|
||||||
bool cgraph_get_body (struct cgraph_node *node);
|
bool cgraph_get_body (struct cgraph_node *node);
|
||||||
void
|
struct cgraph_edge *
|
||||||
cgraph_turn_edge_to_speculative (struct cgraph_edge *,
|
cgraph_turn_edge_to_speculative (struct cgraph_edge *,
|
||||||
struct cgraph_node *,
|
struct cgraph_node *,
|
||||||
gcov_type, int);
|
gcov_type, int);
|
||||||
|
|
@ -783,6 +783,7 @@ struct cgraph_node *cgraph_function_versioning (struct cgraph_node *,
|
||||||
basic_block, const char *);
|
basic_block, const char *);
|
||||||
void tree_function_versioning (tree, tree, vec<ipa_replace_map_p, va_gc> *,
|
void tree_function_versioning (tree, tree, vec<ipa_replace_map_p, va_gc> *,
|
||||||
bool, bitmap, bool, bitmap, basic_block);
|
bool, bitmap, bool, bitmap, basic_block);
|
||||||
|
struct cgraph_edge *cgraph_resolve_speculation (struct cgraph_edge *, tree);
|
||||||
|
|
||||||
/* In cgraphbuild.c */
|
/* In cgraphbuild.c */
|
||||||
unsigned int rebuild_cgraph_edges (void);
|
unsigned int rebuild_cgraph_edges (void);
|
||||||
|
|
@ -1398,4 +1399,16 @@ symtab_real_symbol_p (symtab_node node)
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return true if NODE can be discarded by linker from the binary. */
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
symtab_can_be_discarded (symtab_node node)
|
||||||
|
{
|
||||||
|
return (DECL_EXTERNAL (node->symbol.decl)
|
||||||
|
|| (DECL_ONE_ONLY (node->symbol.decl)
|
||||||
|
&& node->symbol.resolution != LDPR_PREVAILING_DEF
|
||||||
|
&& node->symbol.resolution != LDPR_PREVAILING_DEF_IRONLY
|
||||||
|
&& node->symbol.resolution != LDPR_PREVAILING_DEF_IRONLY_EXP));
|
||||||
|
}
|
||||||
#endif /* GCC_CGRAPH_H */
|
#endif /* GCC_CGRAPH_H */
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ along with GCC; see the file COPYING3. If not see
|
||||||
|
|
||||||
int ncalls_inlined;
|
int ncalls_inlined;
|
||||||
int nfunctions_inlined;
|
int nfunctions_inlined;
|
||||||
|
bool speculation_removed;
|
||||||
|
|
||||||
/* Scale frequency of NODE edges by FREQ_SCALE. */
|
/* Scale frequency of NODE edges by FREQ_SCALE. */
|
||||||
|
|
||||||
|
|
@ -134,6 +135,7 @@ clone_inlined_nodes (struct cgraph_edge *e, bool duplicate,
|
||||||
bool update_original, int *overall_size)
|
bool update_original, int *overall_size)
|
||||||
{
|
{
|
||||||
struct cgraph_node *inlining_into;
|
struct cgraph_node *inlining_into;
|
||||||
|
struct cgraph_edge *next;
|
||||||
|
|
||||||
if (e->caller->global.inlined_to)
|
if (e->caller->global.inlined_to)
|
||||||
inlining_into = e->caller->global.inlined_to;
|
inlining_into = e->caller->global.inlined_to;
|
||||||
|
|
@ -186,9 +188,17 @@ clone_inlined_nodes (struct cgraph_edge *e, bool duplicate,
|
||||||
e->callee->global.inlined_to = inlining_into;
|
e->callee->global.inlined_to = inlining_into;
|
||||||
|
|
||||||
/* Recursively clone all bodies. */
|
/* Recursively clone all bodies. */
|
||||||
for (e = e->callee->callees; e; e = e->next_callee)
|
for (e = e->callee->callees; e; e = next)
|
||||||
if (!e->inline_failed)
|
{
|
||||||
clone_inlined_nodes (e, duplicate, update_original, overall_size);
|
next = e->next_callee;
|
||||||
|
if (!e->inline_failed)
|
||||||
|
clone_inlined_nodes (e, duplicate, update_original, overall_size);
|
||||||
|
if (e->speculative && !speculation_useful_p (e, true))
|
||||||
|
{
|
||||||
|
cgraph_resolve_speculation (e, NULL);
|
||||||
|
speculation_removed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -218,6 +228,7 @@ inline_call (struct cgraph_edge *e, bool update_original,
|
||||||
bool predicated = inline_edge_summary (e)->predicate != NULL;
|
bool predicated = inline_edge_summary (e)->predicate != NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
speculation_removed = false;
|
||||||
/* Don't inline inlined edges. */
|
/* Don't inline inlined edges. */
|
||||||
gcc_assert (e->inline_failed);
|
gcc_assert (e->inline_failed);
|
||||||
/* Don't even think of inlining inline clone. */
|
/* Don't even think of inlining inline clone. */
|
||||||
|
|
@ -267,6 +278,7 @@ inline_call (struct cgraph_edge *e, bool update_original,
|
||||||
error due to INLINE_SIZE_SCALE roudoff errors. */
|
error due to INLINE_SIZE_SCALE roudoff errors. */
|
||||||
gcc_assert (!update_overall_summary || !overall_size || new_edges_found
|
gcc_assert (!update_overall_summary || !overall_size || new_edges_found
|
||||||
|| abs (estimated_growth - (new_size - old_size)) <= 1
|
|| abs (estimated_growth - (new_size - old_size)) <= 1
|
||||||
|
|| speculation_removed
|
||||||
/* FIXME: a hack. Edges with false predicate are accounted
|
/* FIXME: a hack. Edges with false predicate are accounted
|
||||||
wrong, we should remove them from callgraph. */
|
wrong, we should remove them from callgraph. */
|
||||||
|| predicated);
|
|| predicated);
|
||||||
|
|
|
||||||
255
gcc/ipa-inline.c
255
gcc/ipa-inline.c
|
|
@ -229,10 +229,13 @@ report_inline_failed_reason (struct cgraph_edge *e)
|
||||||
We check whether inlining is possible at all and whether
|
We check whether inlining is possible at all and whether
|
||||||
caller growth limits allow doing so.
|
caller growth limits allow doing so.
|
||||||
|
|
||||||
if REPORT is true, output reason to the dump file. */
|
if REPORT is true, output reason to the dump file.
|
||||||
|
|
||||||
|
if DISREGARD_LIMITES is true, ignore size limits.*/
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
can_inline_edge_p (struct cgraph_edge *e, bool report)
|
can_inline_edge_p (struct cgraph_edge *e, bool report,
|
||||||
|
bool disregard_limits = false)
|
||||||
{
|
{
|
||||||
bool inlinable = true;
|
bool inlinable = true;
|
||||||
enum availability avail;
|
enum availability avail;
|
||||||
|
|
@ -309,6 +312,7 @@ can_inline_edge_p (struct cgraph_edge *e, bool report)
|
||||||
}
|
}
|
||||||
/* Check if caller growth allows the inlining. */
|
/* Check if caller growth allows the inlining. */
|
||||||
else if (!DECL_DISREGARD_INLINE_LIMITS (callee->symbol.decl)
|
else if (!DECL_DISREGARD_INLINE_LIMITS (callee->symbol.decl)
|
||||||
|
&& !disregard_limits
|
||||||
&& !lookup_attribute ("flatten",
|
&& !lookup_attribute ("flatten",
|
||||||
DECL_ATTRIBUTES
|
DECL_ATTRIBUTES
|
||||||
(e->caller->global.inlined_to
|
(e->caller->global.inlined_to
|
||||||
|
|
@ -1400,6 +1404,79 @@ heap_edge_removal_hook (struct cgraph_edge *e, void *data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return true if speculation of edge E seems useful.
|
||||||
|
If ANTICIPATE_INLINING is true, be conservative and hope that E
|
||||||
|
may get inlined. */
|
||||||
|
|
||||||
|
bool
|
||||||
|
speculation_useful_p (struct cgraph_edge *e, bool anticipate_inlining)
|
||||||
|
{
|
||||||
|
enum availability avail;
|
||||||
|
struct cgraph_node *target = cgraph_function_or_thunk_node (e->callee, &avail);
|
||||||
|
struct cgraph_edge *direct, *indirect;
|
||||||
|
struct ipa_ref *ref;
|
||||||
|
|
||||||
|
gcc_assert (e->speculative && !e->indirect_unknown_callee);
|
||||||
|
|
||||||
|
if (!cgraph_maybe_hot_edge_p (e))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* See if IP optimizations found something potentially useful about the
|
||||||
|
function. For now we look only for CONST/PURE flags. Almost everything
|
||||||
|
else we propagate is useless. */
|
||||||
|
if (avail >= AVAIL_AVAILABLE)
|
||||||
|
{
|
||||||
|
int ecf_flags = flags_from_decl_or_type (target->symbol.decl);
|
||||||
|
if (ecf_flags & ECF_CONST)
|
||||||
|
{
|
||||||
|
cgraph_speculative_call_info (e, direct, indirect, ref);
|
||||||
|
if (!(indirect->indirect_info->ecf_flags & ECF_CONST))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (ecf_flags & ECF_PURE)
|
||||||
|
{
|
||||||
|
cgraph_speculative_call_info (e, direct, indirect, ref);
|
||||||
|
if (!(indirect->indirect_info->ecf_flags & ECF_PURE))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* If we did not managed to inline the function nor redirect
|
||||||
|
to an ipa-cp clone (that are seen by having local flag set),
|
||||||
|
it is probably pointless to inline it unless hardware is missing
|
||||||
|
indirect call predictor. */
|
||||||
|
if (!anticipate_inlining && e->inline_failed && !target->local.local)
|
||||||
|
return false;
|
||||||
|
/* For overwritable targets there is not much to do. */
|
||||||
|
if (e->inline_failed && !can_inline_edge_p (e, false, true))
|
||||||
|
return false;
|
||||||
|
/* OK, speculation seems interesting. */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We know that EDGE is not going to be inlined.
|
||||||
|
See if we can remove speculation. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
resolve_noninline_speculation (fibheap_t edge_heap, struct cgraph_edge *edge)
|
||||||
|
{
|
||||||
|
if (edge->speculative && !speculation_useful_p (edge, false))
|
||||||
|
{
|
||||||
|
struct cgraph_node *node = edge->caller;
|
||||||
|
struct cgraph_node *where = node->global.inlined_to
|
||||||
|
? node->global.inlined_to : node;
|
||||||
|
bitmap updated_nodes = BITMAP_ALLOC (NULL);
|
||||||
|
|
||||||
|
cgraph_resolve_speculation (edge, NULL);
|
||||||
|
reset_node_growth_cache (where);
|
||||||
|
reset_edge_caches (where);
|
||||||
|
inline_update_overall_summary (where);
|
||||||
|
update_caller_keys (edge_heap, where,
|
||||||
|
updated_nodes, NULL);
|
||||||
|
reset_node_growth_cache (where);
|
||||||
|
BITMAP_FREE (updated_nodes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* We use greedy algorithm for inlining of small functions:
|
/* We use greedy algorithm for inlining of small functions:
|
||||||
All inline candidates are put into prioritized heap ordered in
|
All inline candidates are put into prioritized heap ordered in
|
||||||
increasing badness.
|
increasing badness.
|
||||||
|
|
@ -1478,14 +1555,19 @@ inline_small_functions (void)
|
||||||
/* Populate the heeap with all edges we might inline. */
|
/* Populate the heeap with all edges we might inline. */
|
||||||
|
|
||||||
FOR_EACH_DEFINED_FUNCTION (node)
|
FOR_EACH_DEFINED_FUNCTION (node)
|
||||||
if (!node->global.inlined_to)
|
{
|
||||||
{
|
bool update = false;
|
||||||
if (dump_file)
|
struct cgraph_edge *next;
|
||||||
fprintf (dump_file, "Enqueueing calls of %s/%i.\n",
|
|
||||||
cgraph_node_name (node), node->symbol.order);
|
|
||||||
|
|
||||||
for (edge = node->callers; edge; edge = edge->next_caller)
|
if (dump_file)
|
||||||
|
fprintf (dump_file, "Enqueueing calls in %s/%i.\n",
|
||||||
|
cgraph_node_name (node), node->symbol.order);
|
||||||
|
|
||||||
|
for (edge = node->callees; edge; edge = next)
|
||||||
|
{
|
||||||
|
next = edge->next_callee;
|
||||||
if (edge->inline_failed
|
if (edge->inline_failed
|
||||||
|
&& !edge->aux
|
||||||
&& can_inline_edge_p (edge, true)
|
&& can_inline_edge_p (edge, true)
|
||||||
&& want_inline_small_function_p (edge, true)
|
&& want_inline_small_function_p (edge, true)
|
||||||
&& edge->inline_failed)
|
&& edge->inline_failed)
|
||||||
|
|
@ -1493,7 +1575,24 @@ inline_small_functions (void)
|
||||||
gcc_assert (!edge->aux);
|
gcc_assert (!edge->aux);
|
||||||
update_edge_key (edge_heap, edge);
|
update_edge_key (edge_heap, edge);
|
||||||
}
|
}
|
||||||
}
|
if (edge->speculative && !speculation_useful_p (edge, edge->aux != NULL))
|
||||||
|
{
|
||||||
|
cgraph_resolve_speculation (edge, NULL);
|
||||||
|
update = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (update)
|
||||||
|
{
|
||||||
|
struct cgraph_node *where = node->global.inlined_to
|
||||||
|
? node->global.inlined_to : node;
|
||||||
|
inline_update_overall_summary (where);
|
||||||
|
reset_node_growth_cache (where);
|
||||||
|
reset_edge_caches (where);
|
||||||
|
update_caller_keys (edge_heap, where,
|
||||||
|
updated_nodes, NULL);
|
||||||
|
bitmap_clear (updated_nodes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
gcc_assert (in_lto_p
|
gcc_assert (in_lto_p
|
||||||
|| !max_count
|
|| !max_count
|
||||||
|
|
@ -1534,7 +1633,10 @@ inline_small_functions (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!can_inline_edge_p (edge, true))
|
if (!can_inline_edge_p (edge, true))
|
||||||
continue;
|
{
|
||||||
|
resolve_noninline_speculation (edge_heap, edge);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
callee = cgraph_function_or_thunk_node (edge->callee, NULL);
|
callee = cgraph_function_or_thunk_node (edge->callee, NULL);
|
||||||
growth = estimate_edge_growth (edge);
|
growth = estimate_edge_growth (edge);
|
||||||
|
|
@ -1568,11 +1670,15 @@ inline_small_functions (void)
|
||||||
{
|
{
|
||||||
edge->inline_failed = CIF_INLINE_UNIT_GROWTH_LIMIT;
|
edge->inline_failed = CIF_INLINE_UNIT_GROWTH_LIMIT;
|
||||||
report_inline_failed_reason (edge);
|
report_inline_failed_reason (edge);
|
||||||
|
resolve_noninline_speculation (edge_heap, edge);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!want_inline_small_function_p (edge, true))
|
if (!want_inline_small_function_p (edge, true))
|
||||||
continue;
|
{
|
||||||
|
resolve_noninline_speculation (edge_heap, edge);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* Heuristics for inlining small functions works poorly for
|
/* Heuristics for inlining small functions works poorly for
|
||||||
recursive calls where we do efect similar to loop unrolling.
|
recursive calls where we do efect similar to loop unrolling.
|
||||||
|
|
@ -1588,6 +1694,7 @@ inline_small_functions (void)
|
||||||
? &new_indirect_edges : NULL))
|
? &new_indirect_edges : NULL))
|
||||||
{
|
{
|
||||||
edge->inline_failed = CIF_RECURSIVE_INLINING;
|
edge->inline_failed = CIF_RECURSIVE_INLINING;
|
||||||
|
resolve_noninline_speculation (edge_heap, edge);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
reset_edge_caches (where);
|
reset_edge_caches (where);
|
||||||
|
|
@ -1596,6 +1703,7 @@ inline_small_functions (void)
|
||||||
if (flag_indirect_inlining)
|
if (flag_indirect_inlining)
|
||||||
add_new_edges_to_heap (edge_heap, new_indirect_edges);
|
add_new_edges_to_heap (edge_heap, new_indirect_edges);
|
||||||
update_callee_keys (edge_heap, where, updated_nodes);
|
update_callee_keys (edge_heap, where, updated_nodes);
|
||||||
|
bitmap_clear (updated_nodes);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -1621,6 +1729,7 @@ inline_small_functions (void)
|
||||||
edge->inline_failed
|
edge->inline_failed
|
||||||
= (DECL_DISREGARD_INLINE_LIMITS (edge->callee->symbol.decl)
|
= (DECL_DISREGARD_INLINE_LIMITS (edge->callee->symbol.decl)
|
||||||
? CIF_RECURSIVE_INLINING : CIF_UNSPECIFIED);
|
? CIF_RECURSIVE_INLINING : CIF_UNSPECIFIED);
|
||||||
|
resolve_noninline_speculation (edge_heap, edge);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (depth && dump_file)
|
else if (depth && dump_file)
|
||||||
|
|
@ -1773,6 +1882,7 @@ ipa_inline (void)
|
||||||
struct cgraph_node **order =
|
struct cgraph_node **order =
|
||||||
XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
|
XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
|
||||||
int i;
|
int i;
|
||||||
|
int cold;
|
||||||
|
|
||||||
if (in_lto_p && optimize)
|
if (in_lto_p && optimize)
|
||||||
ipa_update_after_lto_read ();
|
ipa_update_after_lto_read ();
|
||||||
|
|
@ -1820,66 +1930,83 @@ ipa_inline (void)
|
||||||
code size will shrink because the out-of-line copy is eliminated.
|
code size will shrink because the out-of-line copy is eliminated.
|
||||||
We do this regardless on the callee size as long as function growth limits
|
We do this regardless on the callee size as long as function growth limits
|
||||||
are met. */
|
are met. */
|
||||||
if (flag_inline_functions_called_once)
|
if (dump_file)
|
||||||
|
fprintf (dump_file,
|
||||||
|
"\nDeciding on functions to be inlined into all callers and removing useless speculations:\n");
|
||||||
|
|
||||||
|
/* Inlining one function called once has good chance of preventing
|
||||||
|
inlining other function into the same callee. Ideally we should
|
||||||
|
work in priority order, but probably inlining hot functions first
|
||||||
|
is good cut without the extra pain of maintaining the queue.
|
||||||
|
|
||||||
|
??? this is not really fitting the bill perfectly: inlining function
|
||||||
|
into callee often leads to better optimization of callee due to
|
||||||
|
increased context for optimization.
|
||||||
|
For example if main() function calls a function that outputs help
|
||||||
|
and then function that does the main optmization, we should inline
|
||||||
|
the second with priority even if both calls are cold by themselves.
|
||||||
|
|
||||||
|
We probably want to implement new predicate replacing our use of
|
||||||
|
maybe_hot_edge interpreted as maybe_hot_edge || callee is known
|
||||||
|
to be hot. */
|
||||||
|
for (cold = 0; cold <= 1; cold ++)
|
||||||
{
|
{
|
||||||
int cold;
|
FOR_EACH_DEFINED_FUNCTION (node)
|
||||||
if (dump_file)
|
|
||||||
fprintf (dump_file,
|
|
||||||
"\nDeciding on functions to be inlined into all callers:\n");
|
|
||||||
|
|
||||||
/* Inlining one function called once has good chance of preventing
|
|
||||||
inlining other function into the same callee. Ideally we should
|
|
||||||
work in priority order, but probably inlining hot functions first
|
|
||||||
is good cut without the extra pain of maintaining the queue.
|
|
||||||
|
|
||||||
??? this is not really fitting the bill perfectly: inlining function
|
|
||||||
into callee often leads to better optimization of callee due to
|
|
||||||
increased context for optimization.
|
|
||||||
For example if main() function calls a function that outputs help
|
|
||||||
and then function that does the main optmization, we should inline
|
|
||||||
the second with priority even if both calls are cold by themselves.
|
|
||||||
|
|
||||||
We probably want to implement new predicate replacing our use of
|
|
||||||
maybe_hot_edge interpreted as maybe_hot_edge || callee is known
|
|
||||||
to be hot. */
|
|
||||||
for (cold = 0; cold <= 1; cold ++)
|
|
||||||
{
|
{
|
||||||
FOR_EACH_DEFINED_FUNCTION (node)
|
struct cgraph_edge *edge, *next;
|
||||||
|
bool update=false;
|
||||||
|
|
||||||
|
for (edge = node->callees; edge; edge = next)
|
||||||
{
|
{
|
||||||
if (want_inline_function_to_all_callers_p (node, cold))
|
next = edge->next_callee;
|
||||||
|
if (edge->speculative && !speculation_useful_p (edge, false))
|
||||||
{
|
{
|
||||||
int num_calls = 0;
|
cgraph_resolve_speculation (edge, NULL);
|
||||||
struct cgraph_edge *e;
|
update = true;
|
||||||
for (e = node->callers; e; e = e->next_caller)
|
}
|
||||||
num_calls++;
|
}
|
||||||
while (node->callers && !node->global.inlined_to)
|
if (update)
|
||||||
|
{
|
||||||
|
struct cgraph_node *where = node->global.inlined_to
|
||||||
|
? node->global.inlined_to : node;
|
||||||
|
reset_node_growth_cache (where);
|
||||||
|
reset_edge_caches (where);
|
||||||
|
inline_update_overall_summary (where);
|
||||||
|
}
|
||||||
|
if (flag_inline_functions_called_once
|
||||||
|
&& want_inline_function_to_all_callers_p (node, cold))
|
||||||
|
{
|
||||||
|
int num_calls = 0;
|
||||||
|
struct cgraph_edge *e;
|
||||||
|
for (e = node->callers; e; e = e->next_caller)
|
||||||
|
num_calls++;
|
||||||
|
while (node->callers && !node->global.inlined_to)
|
||||||
|
{
|
||||||
|
struct cgraph_node *caller = node->callers->caller;
|
||||||
|
|
||||||
|
if (dump_file)
|
||||||
{
|
{
|
||||||
struct cgraph_node *caller = node->callers->caller;
|
fprintf (dump_file,
|
||||||
|
"\nInlining %s size %i.\n",
|
||||||
|
cgraph_node_name (node),
|
||||||
|
inline_summary (node)->size);
|
||||||
|
fprintf (dump_file,
|
||||||
|
" Called once from %s %i insns.\n",
|
||||||
|
cgraph_node_name (node->callers->caller),
|
||||||
|
inline_summary (node->callers->caller)->size);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline_call (node->callers, true, NULL, NULL, true);
|
||||||
|
if (dump_file)
|
||||||
|
fprintf (dump_file,
|
||||||
|
" Inlined into %s which now has %i size\n",
|
||||||
|
cgraph_node_name (caller),
|
||||||
|
inline_summary (caller)->size);
|
||||||
|
if (!num_calls--)
|
||||||
|
{
|
||||||
if (dump_file)
|
if (dump_file)
|
||||||
{
|
fprintf (dump_file, "New calls found; giving up.\n");
|
||||||
fprintf (dump_file,
|
break;
|
||||||
"\nInlining %s size %i.\n",
|
|
||||||
cgraph_node_name (node),
|
|
||||||
inline_summary (node)->size);
|
|
||||||
fprintf (dump_file,
|
|
||||||
" Called once from %s %i insns.\n",
|
|
||||||
cgraph_node_name (node->callers->caller),
|
|
||||||
inline_summary (node->callers->caller)->size);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline_call (node->callers, true, NULL, NULL, true);
|
|
||||||
if (dump_file)
|
|
||||||
fprintf (dump_file,
|
|
||||||
" Inlined into %s which now has %i size\n",
|
|
||||||
cgraph_node_name (caller),
|
|
||||||
inline_summary (caller)->size);
|
|
||||||
if (!num_calls--)
|
|
||||||
{
|
|
||||||
if (dump_file)
|
|
||||||
fprintf (dump_file, "New calls found; giving up.\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -226,6 +226,7 @@ inline_hints do_estimate_edge_hints (struct cgraph_edge *edge);
|
||||||
void initialize_growth_caches (void);
|
void initialize_growth_caches (void);
|
||||||
void free_growth_caches (void);
|
void free_growth_caches (void);
|
||||||
void compute_inline_parameters (struct cgraph_node *, bool);
|
void compute_inline_parameters (struct cgraph_node *, bool);
|
||||||
|
bool speculation_useful_p (struct cgraph_edge *e, bool anticipate_inlining);
|
||||||
|
|
||||||
/* In ipa-inline-transform.c */
|
/* In ipa-inline-transform.c */
|
||||||
bool inline_call (struct cgraph_edge *, bool, vec<cgraph_edge_p> *, int *, bool);
|
bool inline_call (struct cgraph_edge *, bool, vec<cgraph_edge_p> *, int *, bool);
|
||||||
|
|
|
||||||
156
gcc/ipa.c
156
gcc/ipa.c
|
|
@ -768,11 +768,7 @@ bool
|
||||||
can_replace_by_local_alias (symtab_node node)
|
can_replace_by_local_alias (symtab_node node)
|
||||||
{
|
{
|
||||||
return (symtab_node_availability (node) > AVAIL_OVERWRITABLE
|
return (symtab_node_availability (node) > AVAIL_OVERWRITABLE
|
||||||
&& !DECL_EXTERNAL (node->symbol.decl)
|
&& !symtab_can_be_discarded (node));
|
||||||
&& (!DECL_ONE_ONLY (node->symbol.decl)
|
|
||||||
|| node->symbol.resolution == LDPR_PREVAILING_DEF
|
|
||||||
|| node->symbol.resolution == LDPR_PREVAILING_DEF_IRONLY
|
|
||||||
|| node->symbol.resolution == LDPR_PREVAILING_DEF_IRONLY_EXP));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mark visibility of all functions.
|
/* Mark visibility of all functions.
|
||||||
|
|
@ -1407,53 +1403,9 @@ ipa_profile (void)
|
||||||
bool something_changed = false;
|
bool something_changed = false;
|
||||||
int i;
|
int i;
|
||||||
gcov_type overall_time = 0, cutoff = 0, cumulated = 0, overall_size = 0;
|
gcov_type overall_time = 0, cutoff = 0, cumulated = 0, overall_size = 0;
|
||||||
|
struct cgraph_node *n,*n2;
|
||||||
/* Produce speculative calls: we saved common traget from porfiling into
|
int nindirect = 0, ncommon = 0, nunknown = 0, nuseless = 0, nconverted = 0;
|
||||||
e->common_target_id. Now, at link time, we can look up corresponding
|
bool node_map_initialized = false;
|
||||||
function node and produce speculative call. */
|
|
||||||
if (in_lto_p)
|
|
||||||
{
|
|
||||||
struct cgraph_edge *e;
|
|
||||||
struct cgraph_node *n,*n2;
|
|
||||||
|
|
||||||
init_node_map (false);
|
|
||||||
FOR_EACH_DEFINED_FUNCTION (n)
|
|
||||||
{
|
|
||||||
bool update = false;
|
|
||||||
|
|
||||||
for (e = n->indirect_calls; e; e = e->next_callee)
|
|
||||||
if (e->indirect_info->common_target_id)
|
|
||||||
{
|
|
||||||
n2 = find_func_by_profile_id (e->indirect_info->common_target_id);
|
|
||||||
if (n2)
|
|
||||||
{
|
|
||||||
if (dump_file)
|
|
||||||
{
|
|
||||||
fprintf (dump_file, "Indirect call -> direct call from"
|
|
||||||
" other module %s/%i => %s/%i, prob %3.2f\n",
|
|
||||||
xstrdup (cgraph_node_name (n)), n->symbol.order,
|
|
||||||
xstrdup (cgraph_node_name (n2)), n2->symbol.order,
|
|
||||||
e->indirect_info->common_target_probability
|
|
||||||
/ (float)REG_BR_PROB_BASE);
|
|
||||||
}
|
|
||||||
cgraph_turn_edge_to_speculative
|
|
||||||
(e, n2,
|
|
||||||
apply_scale (e->count,
|
|
||||||
e->indirect_info->common_target_probability),
|
|
||||||
apply_scale (e->frequency,
|
|
||||||
e->indirect_info->common_target_probability));
|
|
||||||
update = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if (dump_file)
|
|
||||||
fprintf (dump_file, "Function with profile-id %i not found.\n",
|
|
||||||
e->indirect_info->common_target_id);
|
|
||||||
}
|
|
||||||
if (update)
|
|
||||||
inline_update_overall_summary (n);
|
|
||||||
}
|
|
||||||
del_node_map ();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dump_file)
|
if (dump_file)
|
||||||
dump_histogram (dump_file, histogram);
|
dump_histogram (dump_file, histogram);
|
||||||
|
|
@ -1523,6 +1475,106 @@ ipa_profile (void)
|
||||||
histogram.release();
|
histogram.release();
|
||||||
free_alloc_pool (histogram_pool);
|
free_alloc_pool (histogram_pool);
|
||||||
|
|
||||||
|
/* Produce speculative calls: we saved common traget from porfiling into
|
||||||
|
e->common_target_id. Now, at link time, we can look up corresponding
|
||||||
|
function node and produce speculative call. */
|
||||||
|
|
||||||
|
FOR_EACH_DEFINED_FUNCTION (n)
|
||||||
|
{
|
||||||
|
bool update = false;
|
||||||
|
|
||||||
|
for (e = n->indirect_calls; e; e = e->next_callee)
|
||||||
|
{
|
||||||
|
if (n->count)
|
||||||
|
nindirect++;
|
||||||
|
if (e->indirect_info->common_target_id)
|
||||||
|
{
|
||||||
|
if (!node_map_initialized)
|
||||||
|
init_node_map (false);
|
||||||
|
node_map_initialized = true;
|
||||||
|
ncommon++;
|
||||||
|
n2 = find_func_by_profile_id (e->indirect_info->common_target_id);
|
||||||
|
if (n2)
|
||||||
|
{
|
||||||
|
if (dump_file)
|
||||||
|
{
|
||||||
|
fprintf (dump_file, "Indirect call -> direct call from"
|
||||||
|
" other module %s/%i => %s/%i, prob %3.2f\n",
|
||||||
|
xstrdup (cgraph_node_name (n)), n->symbol.order,
|
||||||
|
xstrdup (cgraph_node_name (n2)), n2->symbol.order,
|
||||||
|
e->indirect_info->common_target_probability
|
||||||
|
/ (float)REG_BR_PROB_BASE);
|
||||||
|
}
|
||||||
|
if (e->indirect_info->common_target_probability
|
||||||
|
< REG_BR_PROB_BASE / 2)
|
||||||
|
{
|
||||||
|
nuseless++;
|
||||||
|
if (dump_file)
|
||||||
|
fprintf (dump_file,
|
||||||
|
"Not speculating: probability is too low.\n");
|
||||||
|
}
|
||||||
|
else if (!cgraph_maybe_hot_edge_p (e))
|
||||||
|
{
|
||||||
|
nuseless++;
|
||||||
|
if (dump_file)
|
||||||
|
fprintf (dump_file,
|
||||||
|
"Not speculating: call is cold.\n");
|
||||||
|
}
|
||||||
|
else if (cgraph_function_body_availability (n2)
|
||||||
|
<= AVAIL_OVERWRITABLE
|
||||||
|
&& symtab_can_be_discarded ((symtab_node) n2))
|
||||||
|
{
|
||||||
|
nuseless++;
|
||||||
|
if (dump_file)
|
||||||
|
fprintf (dump_file,
|
||||||
|
"Not speculating: target is overwritable "
|
||||||
|
"and can be discarded.\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Target may be overwritable, but profile says that
|
||||||
|
control flow goes to this particular implementation
|
||||||
|
of N2. Speculate on the local alias to allow inlining.
|
||||||
|
*/
|
||||||
|
if (!symtab_can_be_discarded ((symtab_node) n2))
|
||||||
|
n2 = cgraph (symtab_nonoverwritable_alias ((symtab_node)n2));
|
||||||
|
nconverted++;
|
||||||
|
cgraph_turn_edge_to_speculative
|
||||||
|
(e, n2,
|
||||||
|
apply_scale (e->count,
|
||||||
|
e->indirect_info->common_target_probability),
|
||||||
|
apply_scale (e->frequency,
|
||||||
|
e->indirect_info->common_target_probability));
|
||||||
|
update = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (dump_file)
|
||||||
|
fprintf (dump_file, "Function with profile-id %i not found.\n",
|
||||||
|
e->indirect_info->common_target_id);
|
||||||
|
nunknown++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (update)
|
||||||
|
inline_update_overall_summary (n);
|
||||||
|
}
|
||||||
|
if (node_map_initialized)
|
||||||
|
del_node_map ();
|
||||||
|
if (dump_file && nindirect)
|
||||||
|
fprintf (dump_file,
|
||||||
|
"%i indirect calls trained.\n"
|
||||||
|
"%i (%3.2f%%) have common target.\n"
|
||||||
|
"%i (%3.2f%%) targets was not found.\n"
|
||||||
|
"%i (%3.2f%%) speculations seems useless.\n"
|
||||||
|
"%i (%3.2f%%) speculations produced.\n",
|
||||||
|
nindirect,
|
||||||
|
ncommon, ncommon * 100.0 / nindirect,
|
||||||
|
nunknown, nunknown * 100.0 / nindirect,
|
||||||
|
nuseless, nuseless * 100.0 / nindirect,
|
||||||
|
nconverted, nconverted * 100.0 / nindirect);
|
||||||
|
|
||||||
order_pos = ipa_reverse_postorder (order);
|
order_pos = ipa_reverse_postorder (order);
|
||||||
for (i = order_pos - 1; i >= 0; i--)
|
for (i = order_pos - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1431,8 +1431,6 @@ gimple_ic_transform (gimple_stmt_iterator *gsi)
|
||||||
gimple stmt = gsi_stmt (*gsi);
|
gimple stmt = gsi_stmt (*gsi);
|
||||||
histogram_value histogram;
|
histogram_value histogram;
|
||||||
gcov_type val, count, all, bb_all;
|
gcov_type val, count, all, bb_all;
|
||||||
gcov_type prob;
|
|
||||||
gimple modify;
|
|
||||||
struct cgraph_node *direct_call;
|
struct cgraph_node *direct_call;
|
||||||
|
|
||||||
if (gimple_code (stmt) != GIMPLE_CALL)
|
if (gimple_code (stmt) != GIMPLE_CALL)
|
||||||
|
|
@ -1452,12 +1450,6 @@ gimple_ic_transform (gimple_stmt_iterator *gsi)
|
||||||
count = histogram->hvalue.counters [1];
|
count = histogram->hvalue.counters [1];
|
||||||
all = histogram->hvalue.counters [2];
|
all = histogram->hvalue.counters [2];
|
||||||
|
|
||||||
if (4 * count <= 3 * all)
|
|
||||||
{
|
|
||||||
gimple_remove_histogram_value (cfun, stmt, histogram);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bb_all = gimple_bb (stmt)->count;
|
bb_all = gimple_bb (stmt)->count;
|
||||||
/* The order of CHECK_COUNTER calls is important -
|
/* The order of CHECK_COUNTER calls is important -
|
||||||
since check_counter can correct the third parameter
|
since check_counter can correct the third parameter
|
||||||
|
|
@ -1469,10 +1461,9 @@ gimple_ic_transform (gimple_stmt_iterator *gsi)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (all > 0)
|
if (4 * count <= 3 * all)
|
||||||
prob = GCOV_COMPUTE_SCALE (count, all);
|
return false;
|
||||||
else
|
|
||||||
prob = 0;
|
|
||||||
direct_call = find_func_by_profile_id ((int)val);
|
direct_call = find_func_by_profile_id ((int)val);
|
||||||
|
|
||||||
if (direct_call == NULL)
|
if (direct_call == NULL)
|
||||||
|
|
@ -1488,12 +1479,21 @@ gimple_ic_transform (gimple_stmt_iterator *gsi)
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
gimple_remove_histogram_value (cfun, stmt, histogram);
|
|
||||||
|
|
||||||
if (!check_ic_target (stmt, direct_call))
|
if (!check_ic_target (stmt, direct_call))
|
||||||
return false;
|
{
|
||||||
|
if (dump_file)
|
||||||
modify = gimple_ic (stmt, direct_call, prob, count, all);
|
{
|
||||||
|
fprintf (dump_file, "Indirect call -> direct call ");
|
||||||
|
print_generic_expr (dump_file, gimple_call_fn (stmt), TDF_SLIM);
|
||||||
|
fprintf (dump_file, "=> ");
|
||||||
|
print_generic_expr (dump_file, direct_call->symbol.decl, TDF_SLIM);
|
||||||
|
fprintf (dump_file, " transformation skipped because of type mismatch");
|
||||||
|
print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
|
||||||
|
}
|
||||||
|
gimple_remove_histogram_value (cfun, stmt, histogram);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (dump_file)
|
if (dump_file)
|
||||||
{
|
{
|
||||||
|
|
@ -1501,10 +1501,8 @@ gimple_ic_transform (gimple_stmt_iterator *gsi)
|
||||||
print_generic_expr (dump_file, gimple_call_fn (stmt), TDF_SLIM);
|
print_generic_expr (dump_file, gimple_call_fn (stmt), TDF_SLIM);
|
||||||
fprintf (dump_file, "=> ");
|
fprintf (dump_file, "=> ");
|
||||||
print_generic_expr (dump_file, direct_call->symbol.decl, TDF_SLIM);
|
print_generic_expr (dump_file, direct_call->symbol.decl, TDF_SLIM);
|
||||||
fprintf (dump_file, " transformation on insn ");
|
fprintf (dump_file, " transformation on insn postponned to ipa-profile");
|
||||||
print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
|
print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
|
||||||
fprintf (dump_file, " to ");
|
|
||||||
print_gimple_stmt (dump_file, modify, 0, TDF_SLIM);
|
|
||||||
fprintf (dump_file, "hist->count "HOST_WIDEST_INT_PRINT_DEC
|
fprintf (dump_file, "hist->count "HOST_WIDEST_INT_PRINT_DEC
|
||||||
" hist->all "HOST_WIDEST_INT_PRINT_DEC"\n", count, all);
|
" hist->all "HOST_WIDEST_INT_PRINT_DEC"\n", count, all);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue