Commit 9aa3f5c5 by Jan Hubicka Committed by Jan Hubicka

cgraph.c (cgraph_for_node_thunks_and_aliases, [...]): Fix thinko in recursive walking.

	* cgraph.c (cgraph_for_node_thunks_and_aliases,
	cgraph_for_node_and_aliases): Fix thinko in recursive walking.
	(nonremovable_p): New function.
	(cgraph_can_remove_if_no_direct_calls_p): New function.
	(used_from_object_file_p): New functoin.
	(cgraph_will_be_removed_from_program_if_no_direct_calls): Look for references
	from aliases.
	* cgraph.h (cgraph_can_remove_if_no_direct_calls_p): Bring offline.
	* ipa-inline.c (check_caller_edge): New function.
	(want_inline_function_called_once_p): Use it; accept aliases called once, too.
	* ipa-inline-analysis.c (do_estimate_growth): Remove FIXME.

From-SVN: r174985
parent 30cecf17
2011-06-13 Jan Hubicka <jh@suse.cz>
* cgraph.c (cgraph_for_node_thunks_and_aliases,
cgraph_for_node_and_aliases): Fix thinko in recursive walking.
(nonremovable_p): New function.
(cgraph_can_remove_if_no_direct_calls_p): New function.
(used_from_object_file_p): New functoin.
(cgraph_will_be_removed_from_program_if_no_direct_calls): Look for references
from aliases.
* cgraph.h (cgraph_can_remove_if_no_direct_calls_p): Bring offline.
* ipa-inline.c (check_caller_edge): New function.
(want_inline_function_called_once_p): Use it; accept aliases called once, too.
* ipa-inline-analysis.c (do_estimate_growth): Remove FIXME.
2011-06-13 Ramana Radhakrishnan <ramana.radhakrishnan@linaro.org> 2011-06-13 Ramana Radhakrishnan <ramana.radhakrishnan@linaro.org>
PR target/48454 PR target/48454
......
...@@ -2567,14 +2567,18 @@ cgraph_for_node_thunks_and_aliases (struct cgraph_node *node, ...@@ -2567,14 +2567,18 @@ cgraph_for_node_thunks_and_aliases (struct cgraph_node *node,
if (e->caller->thunk.thunk_p if (e->caller->thunk.thunk_p
&& (include_overwritable && (include_overwritable
|| cgraph_function_body_availability (e->caller))) || cgraph_function_body_availability (e->caller)))
cgraph_for_node_thunks_and_aliases (e->caller, callback, data, include_overwritable); if (cgraph_for_node_thunks_and_aliases (e->caller, callback, data,
include_overwritable))
return true;
for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref); i++) for (i = 0; ipa_ref_list_refering_iterate (&node->ref_list, i, ref); i++)
if (ref->use == IPA_REF_ALIAS) if (ref->use == IPA_REF_ALIAS)
{ {
struct cgraph_node *alias = ipa_ref_refering_node (ref); struct cgraph_node *alias = ipa_ref_refering_node (ref);
if (include_overwritable if (include_overwritable
|| cgraph_function_body_availability (alias) > AVAIL_OVERWRITABLE) || cgraph_function_body_availability (alias) > AVAIL_OVERWRITABLE)
cgraph_for_node_thunks_and_aliases (alias, callback, data, include_overwritable); if (cgraph_for_node_thunks_and_aliases (alias, callback, data,
include_overwritable))
return true;
} }
return false; return false;
} }
...@@ -2600,7 +2604,9 @@ cgraph_for_node_and_aliases (struct cgraph_node *node, ...@@ -2600,7 +2604,9 @@ cgraph_for_node_and_aliases (struct cgraph_node *node,
struct cgraph_node *alias = ipa_ref_refering_node (ref); struct cgraph_node *alias = ipa_ref_refering_node (ref);
if (include_overwritable if (include_overwritable
|| cgraph_function_body_availability (alias) > AVAIL_OVERWRITABLE) || cgraph_function_body_availability (alias) > AVAIL_OVERWRITABLE)
cgraph_for_node_and_aliases (alias, callback, data, include_overwritable); if (cgraph_for_node_and_aliases (alias, callback, data,
include_overwritable))
return true;
} }
return false; return false;
} }
...@@ -2900,6 +2906,36 @@ cgraph_can_remove_if_no_direct_calls_and_refs_p (struct cgraph_node *node) ...@@ -2900,6 +2906,36 @@ cgraph_can_remove_if_no_direct_calls_and_refs_p (struct cgraph_node *node)
return true; return true;
} }
/* Worker for cgraph_can_remove_if_no_direct_calls_p. */
static bool
nonremovable_p (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
{
return !cgraph_can_remove_if_no_direct_calls_and_refs_p (node);
}
/* Return true when function NODE and its aliases can be removed from callgraph
if all direct calls are eliminated. */
bool
cgraph_can_remove_if_no_direct_calls_p (struct cgraph_node *node)
{
/* Extern inlines can always go, we will use the external definition. */
if (DECL_EXTERNAL (node->decl))
return true;
if (node->address_taken)
return false;
return !cgraph_for_node_and_aliases (node, nonremovable_p, NULL, true);
}
/* Worker for cgraph_can_remove_if_no_direct_calls_p. */
static bool
used_from_object_file_p (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
{
return cgraph_used_from_object_file_p (node);
}
/* Return true when function NODE can be expected to be removed /* Return true when function NODE can be expected to be removed
from program when direct calls in this compilation unit are removed. from program when direct calls in this compilation unit are removed.
...@@ -2918,7 +2954,7 @@ bool ...@@ -2918,7 +2954,7 @@ bool
cgraph_will_be_removed_from_program_if_no_direct_calls (struct cgraph_node *node) cgraph_will_be_removed_from_program_if_no_direct_calls (struct cgraph_node *node)
{ {
gcc_assert (!node->global.inlined_to); gcc_assert (!node->global.inlined_to);
if (cgraph_used_from_object_file_p (node)) if (cgraph_for_node_and_aliases (node, used_from_object_file_p, NULL, true))
return false; return false;
if (!in_lto_p && !flag_whole_program) if (!in_lto_p && !flag_whole_program)
return cgraph_only_called_directly_p (node); return cgraph_only_called_directly_p (node);
......
...@@ -535,6 +535,7 @@ bool cgraph_will_be_removed_from_program_if_no_direct_calls ...@@ -535,6 +535,7 @@ bool cgraph_will_be_removed_from_program_if_no_direct_calls
(struct cgraph_node *node); (struct cgraph_node *node);
bool cgraph_can_remove_if_no_direct_calls_and_refs_p bool cgraph_can_remove_if_no_direct_calls_and_refs_p
(struct cgraph_node *node); (struct cgraph_node *node);
bool cgraph_can_remove_if_no_direct_calls_p (struct cgraph_node *node);
bool resolution_used_from_other_file_p (enum ld_plugin_symbol_resolution); bool resolution_used_from_other_file_p (enum ld_plugin_symbol_resolution);
bool cgraph_used_from_object_file_p (struct cgraph_node *); bool cgraph_used_from_object_file_p (struct cgraph_node *);
bool varpool_used_from_object_file_p (struct varpool_node *); bool varpool_used_from_object_file_p (struct varpool_node *);
...@@ -926,20 +927,6 @@ cgraph_only_called_directly_or_aliased_p (struct cgraph_node *node) ...@@ -926,20 +927,6 @@ cgraph_only_called_directly_or_aliased_p (struct cgraph_node *node)
if all direct calls are eliminated. */ if all direct calls are eliminated. */
static inline bool static inline bool
cgraph_can_remove_if_no_direct_calls_p (struct cgraph_node *node)
{
/* Extern inlines can always go, we will use the external definition. */
if (DECL_EXTERNAL (node->decl))
return true;
return (!node->address_taken
&& cgraph_can_remove_if_no_direct_calls_and_refs_p (node)
&& !ipa_ref_has_aliases_p (&node->ref_list));
}
/* Return true when function NODE can be removed from callgraph
if all direct calls are eliminated. */
static inline bool
varpool_can_remove_if_no_refs (struct varpool_node *node) varpool_can_remove_if_no_refs (struct varpool_node *node)
{ {
return (!node->force_output && !node->used_from_other_partition return (!node->force_output && !node->used_from_other_partition
......
...@@ -2229,8 +2229,7 @@ do_estimate_growth (struct cgraph_node *node) ...@@ -2229,8 +2229,7 @@ do_estimate_growth (struct cgraph_node *node)
&& !cgraph_will_be_removed_from_program_if_no_direct_calls (node)) && !cgraph_will_be_removed_from_program_if_no_direct_calls (node))
d.growth -= info->size; d.growth -= info->size;
/* COMDAT functions are very often not shared across multiple units since they /* COMDAT functions are very often not shared across multiple units since they
come from various template instantiations. Take this into account. come from various template instantiations. Take this into account. */
FIXME: allow also COMDATs with COMDAT aliases. */
else if (DECL_COMDAT (node->decl) else if (DECL_COMDAT (node->decl)
&& cgraph_can_remove_if_no_direct_calls_p (node)) && cgraph_can_remove_if_no_direct_calls_p (node))
d.growth -= (info->size d.growth -= (info->size
......
...@@ -643,6 +643,16 @@ want_inline_self_recursive_call_p (struct cgraph_edge *edge, ...@@ -643,6 +643,16 @@ want_inline_self_recursive_call_p (struct cgraph_edge *edge,
return want_inline; return want_inline;
} }
/* Return true when NODE has caller other than EDGE.
Worker for cgraph_for_node_and_aliases. */
static bool
check_caller_edge (struct cgraph_node *node, void *edge)
{
return (node->callers
&& node->callers != edge);
}
/* Decide if NODE is called once inlining it would eliminate need /* Decide if NODE is called once inlining it would eliminate need
for the offline copy of function. */ for the offline copy of function. */
...@@ -650,24 +660,26 @@ want_inline_self_recursive_call_p (struct cgraph_edge *edge, ...@@ -650,24 +660,26 @@ want_inline_self_recursive_call_p (struct cgraph_edge *edge,
static bool static bool
want_inline_function_called_once_p (struct cgraph_node *node) want_inline_function_called_once_p (struct cgraph_node *node)
{ {
if (node->alias) struct cgraph_node *function = cgraph_function_or_thunk_node (node, NULL);
return false;
/* Already inlined? */ /* Already inlined? */
if (node->global.inlined_to) if (function->global.inlined_to)
return false; return false;
/* Zero or more then one callers? */ /* Zero or more then one callers? */
if (!node->callers if (!node->callers
|| node->callers->next_caller) || node->callers->next_caller)
return false; return false;
/* Maybe other aliases has more direct calls. */
if (cgraph_for_node_and_aliases (node, check_caller_edge, node->callers, true))
return false;
/* Recursive call makes no sense to inline. */ /* Recursive call makes no sense to inline. */
if (node->callers->caller == node) if (cgraph_edge_recursive_p (node->callers))
return false; return false;
/* External functions are not really in the unit, so inlining /* External functions are not really in the unit, so inlining
them when called once would just increase the program size. */ them when called once would just increase the program size. */
if (DECL_EXTERNAL (node->decl)) if (DECL_EXTERNAL (function->decl))
return false; return false;
/* Offline body must be optimized out. */ /* Offline body must be optimized out. */
if (!cgraph_will_be_removed_from_program_if_no_direct_calls (node)) if (!cgraph_will_be_removed_from_program_if_no_direct_calls (function))
return false; return false;
if (!can_inline_edge_p (node->callers, true)) if (!can_inline_edge_p (node->callers, true))
return false; return false;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment