static struct cgraph_edge *create_edge (struct cgraph_node *,
struct cgraph_node *);
-static void cgraph_remove_edge (struct cgraph_node *, struct cgraph_node *);
static hashval_t hash_node (const void *);
static int eq_node (const void *, const void *);
slot = (struct cgraph_node **)
htab_find_slot_with_hash (cgraph_hash, DECL_ASSEMBLER_NAME (decl),
IDENTIFIER_HASH_VALUE
- (DECL_ASSEMBLER_NAME (decl)), 1);
+ (DECL_ASSEMBLER_NAME (decl)), INSERT);
if (*slot)
return *slot;
node = ggc_alloc_cleared (sizeof (*node));
slot = (struct cgraph_node **)
htab_find_slot_with_hash (cgraph_hash, id,
- IDENTIFIER_HASH_VALUE (id), 0);
+ IDENTIFIER_HASH_VALUE (id), NO_INSERT);
if (!slot)
return NULL;
return *slot;
as we probably ought to, so we must preserve inline_call flags to
be the same in all copies of the same edge. */
if (cgraph_global_info_ready)
- for (edge2 = caller->callees; edge2; edge2 = edge2->next_caller)
+ for (edge2 = caller->callees; edge2; edge2 = edge2->next_callee)
if (edge2->callee == callee)
{
edge->inline_call = edge2->inline_call;
/* Remove the edge from CALLER to CALLEE in the cgraph. */
-static void
+void
cgraph_remove_edge (struct cgraph_node *caller, struct cgraph_node *callee)
{
struct cgraph_edge **edge, **edge2;
void
cgraph_remove_node (struct cgraph_node *node)
{
+ void **slot;
while (node->callers)
cgraph_remove_edge (node->callers->caller, node);
while (node->callees)
if (node->next)
node->next->previous = node->previous;
DECL_SAVED_TREE (node->decl) = NULL;
+ slot =
+ htab_find_slot_with_hash (cgraph_hash, DECL_ASSEMBLER_NAME (node->decl),
+ IDENTIFIER_HASH_VALUE (DECL_ASSEMBLER_NAME
+ (node->decl)), NO_INSERT);
+ htab_clear_slot (cgraph_hash, slot);
/* Do not free the structure itself so the walk over chain can continue. */
}
-/* Notify finalize_compilation_unit that given node is reachable
- or needed. */
+/* Notify finalize_compilation_unit that given node is reachable. */
+
void
-cgraph_mark_needed_node (struct cgraph_node *node, int needed)
+cgraph_mark_reachable_node (struct cgraph_node *node)
{
- if (needed)
- {
- node->needed = 1;
- }
- if (!node->reachable)
+ if (!node->reachable && node->local.finalized)
{
+ notice_global_symbol (node->decl);
node->reachable = 1;
- if (DECL_SAVED_TREE (node->decl))
+
+ node->next_needed = cgraph_nodes_queue;
+ cgraph_nodes_queue = node;
+
+ /* At the moment frontend automatically emits all nested functions. */
+ if (node->nested)
{
- node->next_needed = cgraph_nodes_queue;
- cgraph_nodes_queue = node;
- }
+ struct cgraph_node *node2;
+
+ for (node2 = node->nested; node2; node2 = node2->next_nested)
+ if (!node2->reachable)
+ cgraph_mark_reachable_node (node2);
+ }
}
}
+/* Likewise indicate that a node is needed, i.e. reachable via some
+ external means. */
+
+void
+cgraph_mark_needed_node (struct cgraph_node *node)
+{
+ node->needed = 1;
+ cgraph_mark_reachable_node (node);
+}
/* Record call from CALLER to CALLEE */
{
struct cgraph_node *node;
- fprintf (f, "\nCallgraph:\n\n");
+ fprintf (f, "callgraph:\n\n");
for (node = cgraph_nodes; node; node = node->next)
{
struct cgraph_edge *edge;
- fprintf (f, "%s", cgraph_node_name (node));
+ fprintf (f, "%s:", cgraph_node_name (node));
if (node->local.self_insns)
fprintf (f, " %i insns", node->local.self_insns);
+ if (node->global.insns && node->global.insns != node->local.self_insns)
+ fprintf (f, " (%i after inlining)", node->global.insns);
if (node->origin)
fprintf (f, " nested in: %s", cgraph_node_name (node->origin));
if (node->needed)
if (DECL_SAVED_TREE (node->decl))
fprintf (f, " tree");
- if (node->local.disgread_inline_limits)
+ if (node->local.local)
+ fprintf (f, " local");
+ if (node->local.disregard_inline_limits)
fprintf (f, " always_inline");
else if (node->local.inlinable)
fprintf (f, " inlinable");
- if (node->global.insns && node->global.insns != node->local.self_insns)
- fprintf (f, " %i insns after inlining", node->global.insns);
if (node->global.cloned_times > 1)
fprintf (f, " cloned %ix", node->global.cloned_times);
- if (node->global.calls)
- fprintf (f, " %i calls", node->global.calls);
- fprintf (f, "\n called by :");
+ fprintf (f, "\n called by: ");
for (edge = node->callers; edge; edge = edge->next_caller)
{
fprintf (f, "%s ", cgraph_node_name (edge->caller));
slot = (struct cgraph_varpool_node **)
htab_find_slot_with_hash (cgraph_varpool_hash, DECL_ASSEMBLER_NAME (decl),
IDENTIFIER_HASH_VALUE (DECL_ASSEMBLER_NAME (decl)),
- 1);
+ INSERT);
if (*slot)
return *slot;
node = ggc_alloc_cleared (sizeof (*node));
slot = (struct cgraph_varpool_node **)
htab_find_slot_with_hash (cgraph_varpool_hash, id,
- IDENTIFIER_HASH_VALUE (id), 0);
+ IDENTIFIER_HASH_VALUE (id), NO_INSERT);
if (!slot)
return NULL;
return *slot;
{
node->next_needed = cgraph_varpool_nodes_queue;
cgraph_varpool_nodes_queue = node;
+ notice_global_symbol (node->decl);
}
node->needed = 1;
}
cgraph_varpool_finalize_decl (tree decl)
{
struct cgraph_varpool_node *node = cgraph_varpool_node (decl);
-
- if (node->needed && !node->finalized)
+
+ /* The first declaration of a variable that comes through this function
+ decides whether it is global (in C, has external linkage)
+ or local (in C, has internal linkage). So do nothing more
+ if this function has already run. */
+ if (node->finalized)
+ return;
+ if (node->needed)
{
node->next_needed = cgraph_varpool_nodes_queue;
cgraph_varpool_nodes_queue = node;
+ notice_global_symbol (decl);
}
node->finalized = true;