Commit be330ed4 by Jan Hubicka Committed by Jan Hubicka

cgraph.h (cgraph_only_called_directly_or_aliased_p): Rename from ...

	* cgraph.h (cgraph_only_called_directly_or_aliased_p): Rename from ...
	(cgraph_only_called_directly_p): ... this one; bring offline.
	(resolution_used_from_other_file_p, cgraph_used_from_object_file_p,
	varpool_used_from_object_file_p): Drop names from the declaratoin.
	(cgraph_for_node_thunks_and_aliases, cgraph_for_node_and_aliases,
	collect_callers_of_node): New.
	(cgraph_function_node, cgraph_function_or_thunk_node): New functions.
	(cgraph_edge_recursive_p): Use cgraph_function_node.
	* cgraph.c (cgraph_add_thunk): Check that thunk is not already alias.
	(cgraph_node_cannot_be_local_p_1): Break out from ...
	(cgraph_node_can_be_local_p): ... here; walk aliases.
	(cgraph_for_node_thunks_and_aliases): New function.
	(cgraph_for_node_and_aliases): New function.
	(cgraph_make_node_local_1): Break out from ...
	(cgraph_make_node_local) ... here; use cgraph_for_node_thunks_and_aliases.
	(cgraph_set_nothrow_flag_1): Break out from ...
	(cgraph_set_nothrow_flag) ... here; use cgraph_for_node_thunks_and_aliases.
	(cgraph_set_const_flag_1): Break out from ...
	(cgraph_set_const_flag) ... here; use cgraph_for_node_thunks_and_aliases.
	(cgraph_set_pure_flag_1): Break out from ...
	(cgraph_set_pure_flag) ... here; use cgraph_for_node_thunks_and_aliases.
	(cgraph_propagate_frequency_1): Break out from ...
	(cgraph_propagate_frequency) ... here; use cgraph_for_node_thunks_and_aliases.
	(cgraph_used_from_object_file_p): Do not care about aliases.
	(cgraph_not_only_called_directly_p_1, cgraph_only_called_directly_p): New functions.
	(collect_callers_of_node_1, collect_callers_of_node): New functions.

From-SVN: r174871
parent 2ea91d6b
2011-06-09 Jan Hubicka <jh@suse.cz>
* cgraph.h (cgraph_only_called_directly_or_aliased_p): Rename from ...
(cgraph_only_called_directly_p): ... this one; bring offline.
(resolution_used_from_other_file_p, cgraph_used_from_object_file_p,
varpool_used_from_object_file_p): Drop names from the declaratoin.
(cgraph_for_node_thunks_and_aliases, cgraph_for_node_and_aliases,
collect_callers_of_node): New.
(cgraph_function_node, cgraph_function_or_thunk_node): New functions.
(cgraph_edge_recursive_p): Use cgraph_function_node.
* cgraph.c (cgraph_add_thunk): Check that thunk is not already alias.
(cgraph_node_cannot_be_local_p_1): Break out from ...
(cgraph_node_can_be_local_p): ... here; walk aliases.
(cgraph_for_node_thunks_and_aliases): New function.
(cgraph_for_node_and_aliases): New function.
(cgraph_make_node_local_1): Break out from ...
(cgraph_make_node_local) ... here; use cgraph_for_node_thunks_and_aliases.
(cgraph_set_nothrow_flag_1): Break out from ...
(cgraph_set_nothrow_flag) ... here; use cgraph_for_node_thunks_and_aliases.
(cgraph_set_const_flag_1): Break out from ...
(cgraph_set_const_flag) ... here; use cgraph_for_node_thunks_and_aliases.
(cgraph_set_pure_flag_1): Break out from ...
(cgraph_set_pure_flag) ... here; use cgraph_for_node_thunks_and_aliases.
(cgraph_propagate_frequency_1): Break out from ...
(cgraph_propagate_frequency) ... here; use cgraph_for_node_thunks_and_aliases.
(cgraph_used_from_object_file_p): Do not care about aliases.
(cgraph_not_only_called_directly_p_1, cgraph_only_called_directly_p): New functions.
(collect_callers_of_node_1, collect_callers_of_node): New functions.
2011-06-10 Hans-Peter Nilsson <hp@axis.com> 2011-06-10 Hans-Peter Nilsson <hp@axis.com>
PR rtl-optimization/49154 PR rtl-optimization/49154
......
...@@ -608,7 +608,8 @@ cgraph_add_thunk (struct cgraph_node *decl_node ATTRIBUTE_UNUSED, ...@@ -608,7 +608,8 @@ cgraph_add_thunk (struct cgraph_node *decl_node ATTRIBUTE_UNUSED,
if (node) if (node)
{ {
gcc_assert (node->local.finalized); gcc_assert (node->local.finalized);
gcc_assert (!node->same_body); gcc_assert (!node->alias);
gcc_assert (!node->thunk.thunk_p);
cgraph_remove_node (node); cgraph_remove_node (node);
} }
...@@ -2508,6 +2509,16 @@ cgraph_add_new_function (tree fndecl, bool lowered) ...@@ -2508,6 +2509,16 @@ cgraph_add_new_function (tree fndecl, bool lowered)
DECL_FUNCTION_PERSONALITY (fndecl) = lang_hooks.eh_personality (); DECL_FUNCTION_PERSONALITY (fndecl) = lang_hooks.eh_personality ();
} }
/* Worker for cgraph_node_can_be_local_p. */
static bool
cgraph_node_cannot_be_local_p_1 (struct cgraph_node *node,
void *data ATTRIBUTE_UNUSED)
{
return !(!node->needed
&& ((DECL_COMDAT (node->decl) && !node->same_comdat_group)
|| !node->local.externally_visible));
}
/* Return true if NODE can be made local for API change. /* Return true if NODE can be made local for API change.
Extern inline functions and C++ COMDAT functions can be made local Extern inline functions and C++ COMDAT functions can be made local
at the expense of possible code size growth if function is used in multiple at the expense of possible code size growth if function is used in multiple
...@@ -2515,9 +2526,10 @@ cgraph_add_new_function (tree fndecl, bool lowered) ...@@ -2515,9 +2526,10 @@ cgraph_add_new_function (tree fndecl, bool lowered)
bool bool
cgraph_node_can_be_local_p (struct cgraph_node *node) cgraph_node_can_be_local_p (struct cgraph_node *node)
{ {
return (!node->needed && !node->address_taken return (!node->address_taken
&& ((DECL_COMDAT (node->decl) && !node->same_comdat_group) && !cgraph_for_node_and_aliases (node,
|| !node->local.externally_visible)); cgraph_node_cannot_be_local_p_1,
NULL, true));
} }
/* Make DECL local. FIXME: We shouldn't need to mess with rtl this early, /* Make DECL local. FIXME: We shouldn't need to mess with rtl this early,
...@@ -2591,119 +2603,191 @@ cgraph_make_decl_local (tree decl) ...@@ -2591,119 +2603,191 @@ cgraph_make_decl_local (tree decl)
SYMBOL_REF_WEAK (symbol) = DECL_WEAK (decl); SYMBOL_REF_WEAK (symbol) = DECL_WEAK (decl);
} }
/* Bring NODE local. */ /* Call calback on NODE, thunks and aliases asociated to NODE.
void When INCLUDE_OVERWRITABLE is false, overwritable aliases and thunks are
cgraph_make_node_local (struct cgraph_node *node) skipped. */
bool
cgraph_for_node_thunks_and_aliases (struct cgraph_node *node,
bool (*callback) (struct cgraph_node *, void *),
void *data,
bool include_overwritable)
{ {
gcc_assert (cgraph_node_can_be_local_p (node)); struct cgraph_edge *e;
if (DECL_COMDAT (node->decl) || DECL_EXTERNAL (node->decl))
{
struct cgraph_node *alias; struct cgraph_node *alias;
cgraph_make_decl_local (node->decl);
if (callback (node, data))
return true;
for (alias = node->same_body; alias; alias = alias->next) for (alias = node->same_body; alias; alias = alias->next)
cgraph_make_decl_local (alias->decl); if (callback (alias, data))
return true;
for (e = node->callers; e; e = e->next_caller)
if (e->caller->thunk.thunk_p
&& (include_overwritable
|| cgraph_function_body_availability (e->caller) > AVAIL_OVERWRITABLE))
cgraph_for_node_thunks_and_aliases (e->caller, callback, data, include_overwritable);
return false;
}
/* Call calback on NODE and aliases asociated to NODE.
When INCLUDE_OVERWRITABLE is false, overwritable aliases and thunks are
skipped. */
bool
cgraph_for_node_and_aliases (struct cgraph_node *node,
bool (*callback) (struct cgraph_node *, void *),
void *data,
bool include_overwritable ATTRIBUTE_UNUSED)
{
struct cgraph_node *alias;
if (callback (node, data))
return true;
for (alias = node->same_body; alias; alias = alias->next)
if (callback (alias, data))
return true;
return false;
}
/* Worker to bring NODE local. */
static bool
cgraph_make_node_local_1 (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
{
gcc_checking_assert (cgraph_node_can_be_local_p (node));
if (DECL_COMDAT (node->decl) || DECL_EXTERNAL (node->decl))
{
cgraph_make_decl_local (node->decl);
node->local.externally_visible = false; node->local.externally_visible = false;
node->local.local = true; node->local.local = true;
node->resolution = LDPR_PREVAILING_DEF_IRONLY; node->resolution = LDPR_PREVAILING_DEF_IRONLY;
gcc_assert (cgraph_function_body_availability (node) == AVAIL_LOCAL); gcc_assert (cgraph_function_body_availability (node) == AVAIL_LOCAL);
} }
return false;
}
/* Bring NODE local. */
void
cgraph_make_node_local (struct cgraph_node *node)
{
cgraph_for_node_thunks_and_aliases (node, cgraph_make_node_local_1,
NULL, true);
} }
/* Set TREE_NOTHROW on NODE's decl and on same_body aliases of NODE /* Worker to set nothrow flag. */
static bool
cgraph_set_nothrow_flag_1 (struct cgraph_node *node, void *data)
{
TREE_NOTHROW (node->decl) = data != NULL;
return false;
}
/* Set TREE_NOTHROW on NODE's decl and on aliases of NODE
if any to NOTHROW. */ if any to NOTHROW. */
void void
cgraph_set_nothrow_flag (struct cgraph_node *node, bool nothrow) cgraph_set_nothrow_flag (struct cgraph_node *node, bool nothrow)
{ {
struct cgraph_node *alias; cgraph_for_node_thunks_and_aliases (node, cgraph_set_nothrow_flag_1,
TREE_NOTHROW (node->decl) = nothrow; (void *)(size_t)nothrow, false);
for (alias = node->same_body; alias; alias = alias->next)
TREE_NOTHROW (alias->decl) = nothrow;
} }
/* Set TREE_READONLY on NODE's decl and on same_body aliases of NODE /* Worker to set const flag. */
if any to READONLY. */
void static bool
cgraph_set_const_flag (struct cgraph_node *node, bool readonly, bool looping) cgraph_set_const_flag_1 (struct cgraph_node *node, void *data)
{ {
struct cgraph_node *alias;
/* Static constructors and destructors without a side effect can be /* Static constructors and destructors without a side effect can be
optimized out. */ optimized out. */
if (!looping && readonly) if (data && !((size_t)data & 2))
{ {
if (DECL_STATIC_CONSTRUCTOR (node->decl)) if (DECL_STATIC_CONSTRUCTOR (node->decl))
DECL_STATIC_CONSTRUCTOR (node->decl) = 0; DECL_STATIC_CONSTRUCTOR (node->decl) = 0;
if (DECL_STATIC_DESTRUCTOR (node->decl)) if (DECL_STATIC_DESTRUCTOR (node->decl))
DECL_STATIC_DESTRUCTOR (node->decl) = 0; DECL_STATIC_DESTRUCTOR (node->decl) = 0;
} }
TREE_READONLY (node->decl) = readonly; TREE_READONLY (node->decl) = data != NULL;
DECL_LOOPING_CONST_OR_PURE_P (node->decl) = looping; DECL_LOOPING_CONST_OR_PURE_P (node->decl) = ((size_t)data & 2) != 0;
for (alias = node->same_body; alias; alias = alias->next) return false;
{
TREE_READONLY (alias->decl) = readonly;
DECL_LOOPING_CONST_OR_PURE_P (alias->decl) = looping;
}
} }
/* Set DECL_PURE_P on NODE's decl and on same_body aliases of NODE /* Set TREE_READONLY on NODE's decl and on aliases of NODE
if any to PURE. */ if any to READONLY. */
void void
cgraph_set_pure_flag (struct cgraph_node *node, bool pure, bool looping) cgraph_set_const_flag (struct cgraph_node *node, bool readonly, bool looping)
{ {
struct cgraph_node *alias; cgraph_for_node_thunks_and_aliases (node, cgraph_set_const_flag_1,
/* Static constructors and destructors without a side effect can be (void *)(size_t)(readonly + (int)looping * 2),
false);
}
/* Worker to set pure flag. */
static bool
cgraph_set_pure_flag_1 (struct cgraph_node *node, void *data)
{
/* Static pureructors and destructors without a side effect can be
optimized out. */ optimized out. */
if (!looping && pure) if (data && !((size_t)data & 2))
{ {
if (DECL_STATIC_CONSTRUCTOR (node->decl)) if (DECL_STATIC_CONSTRUCTOR (node->decl))
DECL_STATIC_CONSTRUCTOR (node->decl) = 0; DECL_STATIC_CONSTRUCTOR (node->decl) = 0;
if (DECL_STATIC_DESTRUCTOR (node->decl)) if (DECL_STATIC_DESTRUCTOR (node->decl))
DECL_STATIC_DESTRUCTOR (node->decl) = 0; DECL_STATIC_DESTRUCTOR (node->decl) = 0;
} }
DECL_PURE_P (node->decl) = pure; DECL_PURE_P (node->decl) = data != NULL;
DECL_LOOPING_CONST_OR_PURE_P (node->decl) = looping; DECL_LOOPING_CONST_OR_PURE_P (node->decl) = ((size_t)data & 2) != 0;
for (alias = node->same_body; alias; alias = alias->next) return false;
{
DECL_PURE_P (alias->decl) = pure;
DECL_LOOPING_CONST_OR_PURE_P (alias->decl) = looping;
}
} }
/* See if the frequency of NODE can be updated based on frequencies of its /* Set DECL_PURE_P on NODE's decl and on aliases of NODE
callers. */ if any to PURE. */
bool
cgraph_propagate_frequency (struct cgraph_node *node) void
cgraph_set_pure_flag (struct cgraph_node *node, bool pure, bool looping)
{ {
bool maybe_unlikely_executed = true, maybe_executed_once = true; cgraph_for_node_thunks_and_aliases (node, cgraph_set_pure_flag_1,
bool only_called_at_startup = true; (void *)(size_t)(pure + (int)looping * 2),
bool only_called_at_exit = true; false);
bool changed = false; }
struct cgraph_edge *edge;
if (!node->local.local) /* Data used by cgraph_propagate_frequency. */
return false;
gcc_assert (node->analyzed); struct cgraph_propagate_frequency_data
if (dump_file && (dump_flags & TDF_DETAILS)) {
fprintf (dump_file, "Processing frequency %s\n", cgraph_node_name (node)); bool maybe_unlikely_executed;
bool maybe_executed_once;
bool only_called_at_startup;
bool only_called_at_exit;
};
/* Worker for cgraph_propagate_frequency_1. */
static bool
cgraph_propagate_frequency_1 (struct cgraph_node *node, void *data)
{
struct cgraph_propagate_frequency_data *d;
struct cgraph_edge *edge;
d = (struct cgraph_propagate_frequency_data *)data;
for (edge = node->callers; for (edge = node->callers;
edge && (maybe_unlikely_executed || maybe_executed_once edge && (d->maybe_unlikely_executed || d->maybe_executed_once
|| only_called_at_startup || only_called_at_exit); || d->only_called_at_startup || d->only_called_at_exit);
edge = edge->next_caller) edge = edge->next_caller)
{ {
if (edge->caller != node) if (edge->caller != node)
{ {
only_called_at_startup &= edge->caller->only_called_at_startup; d->only_called_at_startup &= edge->caller->only_called_at_startup;
/* It makes sense to put main() together with the static constructors. /* It makes sense to put main() together with the static constructors.
It will be executed for sure, but rest of functions called from It will be executed for sure, but rest of functions called from
main are definitely not at startup only. */ main are definitely not at startup only. */
if (MAIN_NAME_P (DECL_NAME (edge->caller->decl))) if (MAIN_NAME_P (DECL_NAME (edge->caller->decl)))
only_called_at_startup = 0; d->only_called_at_startup = 0;
only_called_at_exit &= edge->caller->only_called_at_exit; d->only_called_at_exit &= edge->caller->only_called_at_exit;
} }
if (!edge->frequency) if (!edge->frequency)
continue; continue;
...@@ -2715,10 +2799,10 @@ cgraph_propagate_frequency (struct cgraph_node *node) ...@@ -2715,10 +2799,10 @@ cgraph_propagate_frequency (struct cgraph_node *node)
if (dump_file && (dump_flags & TDF_DETAILS)) if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, " Called by %s that is executed once\n", fprintf (dump_file, " Called by %s that is executed once\n",
cgraph_node_name (edge->caller)); cgraph_node_name (edge->caller));
maybe_unlikely_executed = false; d->maybe_unlikely_executed = false;
if (inline_edge_summary (edge)->loop_depth) if (inline_edge_summary (edge)->loop_depth)
{ {
maybe_executed_once = false; d->maybe_executed_once = false;
if (dump_file && (dump_flags & TDF_DETAILS)) if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, " Called in loop\n"); fprintf (dump_file, " Called in loop\n");
} }
...@@ -2728,12 +2812,31 @@ cgraph_propagate_frequency (struct cgraph_node *node) ...@@ -2728,12 +2812,31 @@ cgraph_propagate_frequency (struct cgraph_node *node)
if (dump_file && (dump_flags & TDF_DETAILS)) if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, " Called by %s that is normal or hot\n", fprintf (dump_file, " Called by %s that is normal or hot\n",
cgraph_node_name (edge->caller)); cgraph_node_name (edge->caller));
maybe_unlikely_executed = false; d->maybe_unlikely_executed = false;
maybe_executed_once = false; d->maybe_executed_once = false;
break; break;
} }
} }
if ((only_called_at_startup && !only_called_at_exit) return edge != NULL;
}
/* See if the frequency of NODE can be updated based on frequencies of its
callers. */
bool
cgraph_propagate_frequency (struct cgraph_node *node)
{
struct cgraph_propagate_frequency_data d = {true, true, true, true};
bool changed = false;
if (!node->local.local)
return false;
gcc_assert (node->analyzed);
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Processing frequency %s\n", cgraph_node_name (node));
cgraph_for_node_and_aliases (node, cgraph_propagate_frequency_1, &d, true);
if ((d.only_called_at_startup && !d.only_called_at_exit)
&& !node->only_called_at_startup) && !node->only_called_at_startup)
{ {
node->only_called_at_startup = true; node->only_called_at_startup = true;
...@@ -2742,7 +2845,7 @@ cgraph_propagate_frequency (struct cgraph_node *node) ...@@ -2742,7 +2845,7 @@ cgraph_propagate_frequency (struct cgraph_node *node)
cgraph_node_name (node)); cgraph_node_name (node));
changed = true; changed = true;
} }
if ((only_called_at_exit && !only_called_at_startup) if ((d.only_called_at_exit && !d.only_called_at_startup)
&& !node->only_called_at_exit) && !node->only_called_at_exit)
{ {
node->only_called_at_exit = true; node->only_called_at_exit = true;
...@@ -2755,7 +2858,7 @@ cgraph_propagate_frequency (struct cgraph_node *node) ...@@ -2755,7 +2858,7 @@ cgraph_propagate_frequency (struct cgraph_node *node)
if (node->frequency == NODE_FREQUENCY_HOT if (node->frequency == NODE_FREQUENCY_HOT
|| node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED) || node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED)
return changed; return changed;
if (maybe_unlikely_executed) if (d.maybe_unlikely_executed)
{ {
node->frequency = NODE_FREQUENCY_UNLIKELY_EXECUTED; node->frequency = NODE_FREQUENCY_UNLIKELY_EXECUTED;
if (dump_file) if (dump_file)
...@@ -2763,7 +2866,7 @@ cgraph_propagate_frequency (struct cgraph_node *node) ...@@ -2763,7 +2866,7 @@ cgraph_propagate_frequency (struct cgraph_node *node)
cgraph_node_name (node)); cgraph_node_name (node));
changed = true; changed = true;
} }
else if (maybe_executed_once && node->frequency != NODE_FREQUENCY_EXECUTED_ONCE) else if (d.maybe_executed_once && node->frequency != NODE_FREQUENCY_EXECUTED_ONCE)
{ {
node->frequency = NODE_FREQUENCY_EXECUTED_ONCE; node->frequency = NODE_FREQUENCY_EXECUTED_ONCE;
if (dump_file) if (dump_file)
...@@ -2877,24 +2980,70 @@ resolution_used_from_other_file_p (enum ld_plugin_symbol_resolution resolution) ...@@ -2877,24 +2980,70 @@ resolution_used_from_other_file_p (enum ld_plugin_symbol_resolution resolution)
|| resolution == LDPR_RESOLVED_DYN); || resolution == LDPR_RESOLVED_DYN);
} }
/* Return true when NODE is known to be used from other (non-LTO) object file. /* Return true when NODE is known to be used from other (non-LTO) object file.
Known only when doing LTO via linker plugin. */ Known only when doing LTO via linker plugin. */
bool bool
cgraph_used_from_object_file_p (struct cgraph_node *node) cgraph_used_from_object_file_p (struct cgraph_node *node)
{ {
struct cgraph_node *alias;
gcc_assert (!node->global.inlined_to); gcc_assert (!node->global.inlined_to);
if (!TREE_PUBLIC (node->decl) || DECL_EXTERNAL (node->decl)) if (!TREE_PUBLIC (node->decl) || DECL_EXTERNAL (node->decl))
return false; return false;
if (resolution_used_from_other_file_p (node->resolution)) if (resolution_used_from_other_file_p (node->resolution))
return true; return true;
for (alias = node->same_body; alias; alias = alias->next)
if (TREE_PUBLIC (alias->decl)
&& resolution_used_from_other_file_p (alias->resolution))
return true;
return false; return false;
} }
/* Worker for cgraph_only_called_directly_p. */
static bool
cgraph_not_only_called_directly_p_1 (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
{
return !cgraph_only_called_directly_or_aliased_p (node);
}
/* Return true when function NODE and all its aliases are only called
directly.
i.e. it is not externally visible, address was not taken and
it is not used in any other non-standard way. */
bool
cgraph_only_called_directly_p (struct cgraph_node *node)
{
gcc_assert (cgraph_function_or_thunk_node (node, NULL) == node);
return !cgraph_for_node_and_aliases (node, cgraph_not_only_called_directly_p_1,
NULL, true);
}
/* Collect all callers of NODE. Worker for collect_callers_of_node. */
static bool
collect_callers_of_node_1 (struct cgraph_node *node, void *data)
{
VEC (cgraph_edge_p, heap) ** redirect_callers = (VEC (cgraph_edge_p, heap) **)data;
struct cgraph_edge *cs;
enum availability avail;
cgraph_function_or_thunk_node (node, &avail);
if (avail > AVAIL_OVERWRITABLE)
for (cs = node->callers; cs != NULL; cs = cs->next_caller)
if (!cs->indirect_inlining_edge)
VEC_safe_push (cgraph_edge_p, heap, *redirect_callers, cs);
return false;
}
/* Collect all callers of NODE and its aliases that are known to lead to NODE
(i.e. are not overwritable). */
VEC (cgraph_edge_p, heap) *
collect_callers_of_node (struct cgraph_node *node)
{
VEC (cgraph_edge_p, heap) * redirect_callers = NULL;
cgraph_for_node_and_aliases (node, collect_callers_of_node_1,
&redirect_callers, false);
return redirect_callers;
}
#include "gt-cgraph.h" #include "gt-cgraph.h"
...@@ -512,6 +512,7 @@ struct cgraph_node * cgraph_clone_node (struct cgraph_node *, tree, gcov_type, ...@@ -512,6 +512,7 @@ struct cgraph_node * cgraph_clone_node (struct cgraph_node *, tree, gcov_type,
void cgraph_redirect_edge_callee (struct cgraph_edge *, struct cgraph_node *); void cgraph_redirect_edge_callee (struct cgraph_edge *, struct cgraph_node *);
void cgraph_make_edge_direct (struct cgraph_edge *, struct cgraph_node *, void cgraph_make_edge_direct (struct cgraph_edge *, struct cgraph_node *,
HOST_WIDE_INT); HOST_WIDE_INT);
bool cgraph_only_called_directly_p (struct cgraph_node *);
struct cgraph_asm_node *cgraph_add_asm_node (tree); struct cgraph_asm_node *cgraph_add_asm_node (tree);
...@@ -537,9 +538,18 @@ bool cgraph_will_be_removed_from_program_if_no_direct_calls ...@@ -537,9 +538,18 @@ 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 resolution_used_from_other_file_p (enum ld_plugin_symbol_resolution resolution); bool resolution_used_from_other_file_p (enum ld_plugin_symbol_resolution);
bool cgraph_used_from_object_file_p (struct cgraph_node *node); bool cgraph_used_from_object_file_p (struct cgraph_node *);
bool varpool_used_from_object_file_p (struct varpool_node *node); bool varpool_used_from_object_file_p (struct varpool_node *);
bool cgraph_for_node_thunks_and_aliases (struct cgraph_node *,
bool (*) (struct cgraph_node *, void *),
void *,
bool);
bool cgraph_for_node_and_aliases (struct cgraph_node *,
bool (*) (struct cgraph_node *, void *),
void *, bool);
VEC (cgraph_edge_p, heap) * collect_callers_of_node (struct cgraph_node *node);
/* In cgraphunit.c */ /* In cgraphunit.c */
extern FILE *cgraph_dump_file; extern FILE *cgraph_dump_file;
...@@ -899,12 +909,12 @@ varpool_node_set_nonempty_p (varpool_node_set set) ...@@ -899,12 +909,12 @@ varpool_node_set_nonempty_p (varpool_node_set set)
return !VEC_empty (varpool_node_ptr, set->nodes); return !VEC_empty (varpool_node_ptr, set->nodes);
} }
/* Return true when function NODE is only called directly. /* Return true when function NODE is only called directly or it has alias.
i.e. it is not externally visible, address was not taken and i.e. it is not externally visible, address was not taken and
it is not used in any other non-standard way. */ it is not used in any other non-standard way. */
static inline bool static inline bool
cgraph_only_called_directly_p (struct cgraph_node *node) cgraph_only_called_directly_or_aliased_p (struct cgraph_node *node)
{ {
gcc_assert (!node->global.inlined_to); gcc_assert (!node->global.inlined_to);
return (!node->needed && !node->address_taken return (!node->needed && !node->address_taken
...@@ -923,7 +933,8 @@ cgraph_can_remove_if_no_direct_calls_p (struct cgraph_node *node) ...@@ -923,7 +933,8 @@ cgraph_can_remove_if_no_direct_calls_p (struct cgraph_node *node)
/* Extern inlines can always go, we will use the external definition. */ /* Extern inlines can always go, we will use the external definition. */
if (DECL_EXTERNAL (node->decl)) if (DECL_EXTERNAL (node->decl))
return true; return true;
return !node->address_taken && cgraph_can_remove_if_no_direct_calls_and_refs_p (node); return (!node->address_taken
&& cgraph_can_remove_if_no_direct_calls_and_refs_p (node));
} }
/* Return true when function NODE can be removed from callgraph /* Return true when function NODE can be removed from callgraph
...@@ -954,17 +965,56 @@ varpool_all_refs_explicit_p (struct varpool_node *vnode) ...@@ -954,17 +965,56 @@ varpool_all_refs_explicit_p (struct varpool_node *vnode)
/* Constant pool accessor function. */ /* Constant pool accessor function. */
htab_t constant_pool_htab (void); htab_t constant_pool_htab (void);
/* FIXME: inappropriate dependency of cgraph on IPA. */
#include "ipa-ref-inline.h"
/* Given NODE, walk the alias chain to return the function NODE is alias of.
Walk through thunk, too.
When AVAILABILITY is non-NULL, get minimal availablity in the chain. */
static inline struct cgraph_node *
cgraph_function_node (struct cgraph_node *node, enum availability *availability)
{
if (availability)
*availability = cgraph_function_body_availability (node);
while (node)
{
if (node->thunk.thunk_p)
node = node->callees->callee;
else
return node;
if (availability)
{
enum availability a;
a = cgraph_function_body_availability (node);
if (a < *availability)
*availability = a;
}
}
return NULL;
}
/* Given NODE, walk the alias chain to return the function NODE is alias of.
Do not walk through thunks.
When AVAILABILITY is non-NULL, get minimal availablity in the chain. */
static inline struct cgraph_node *
cgraph_function_or_thunk_node (struct cgraph_node *node, enum availability *availability)
{
if (availability)
*availability = cgraph_function_body_availability (node);
return node;
return NULL;
}
/* Return true when the edge E represents a direct recursion. */ /* Return true when the edge E represents a direct recursion. */
static inline bool static inline bool
cgraph_edge_recursive_p (struct cgraph_edge *e) cgraph_edge_recursive_p (struct cgraph_edge *e)
{ {
struct cgraph_node *callee = cgraph_function_or_thunk_node (e->callee, NULL);
if (e->caller->global.inlined_to) if (e->caller->global.inlined_to)
return e->caller->global.inlined_to->decl == e->callee->decl; return e->caller->global.inlined_to->decl == callee->decl;
else else
return e->caller->decl == e->callee->decl; return e->caller->decl == callee->decl;
} }
/* FIXME: inappropriate dependency of cgraph on IPA. */
#include "ipa-ref-inline.h"
#endif /* GCC_CGRAPH_H */ #endif /* GCC_CGRAPH_H */
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