#include "gimple.h"
#include "tree-dump.h"
#include "tree-flow.h"
+#include "value-prof.h"
static void cgraph_node_remove_callers (struct cgraph_node *node);
static inline void cgraph_edge_remove_caller (struct cgraph_edge *e);
/* List of hooks triggered when an function is inserted. */
struct cgraph_node_hook_list *first_cgraph_function_insertion_hook;
+/* Head of a linked list of unused (freed) call graph nodes.
+ Do not GTY((delete)) this list so UIDs gets reliably recycled. */
+static GTY(()) struct cgraph_node *free_nodes;
+/* Head of a linked list of unused (freed) call graph edges.
+ Do not GTY((delete)) this list so UIDs gets reliably recycled. */
+static GTY(()) struct cgraph_edge *free_edges;
+
+/* Macros to access the next item in the list of free cgraph nodes and
+ edges. */
+#define NEXT_FREE_NODE(NODE) (NODE)->next
+#define NEXT_FREE_EDGE(EDGE) (EDGE)->prev_caller
/* Register HOOK to be called with DATA on each removed edge. */
struct cgraph_edge_hook_list *
while (*ptr != entry)
ptr = &(*ptr)->next;
*ptr = entry->next;
+ free (entry);
}
/* Call all edge removal hooks. */
while (*ptr != entry)
ptr = &(*ptr)->next;
*ptr = entry->next;
+ free (entry);
}
/* Call all node removal hooks. */
while (*ptr != entry)
ptr = &(*ptr)->next;
*ptr = entry->next;
+ free (entry);
}
/* Call all node removal hooks. */
while (*ptr != entry)
ptr = &(*ptr)->next;
*ptr = entry->next;
+ free (entry);
}
/* Call all edge duplication hooks. */
while (*ptr != entry)
ptr = &(*ptr)->next;
*ptr = entry->next;
+ free (entry);
}
/* Call all node duplication hooks. */
{
struct cgraph_node *node;
- node = GGC_CNEW (struct cgraph_node);
+ if (free_nodes)
+ {
+ node = free_nodes;
+ free_nodes = NEXT_FREE_NODE (node);
+ }
+ else
+ {
+ node = GGC_CNEW (struct cgraph_node);
+ node->uid = cgraph_max_uid++;
+ }
+
node->next = cgraph_nodes;
- node->uid = cgraph_max_uid++;
node->pid = -1;
node->order = cgraph_order++;
if (cgraph_nodes)
cgraph_create_edge (struct cgraph_node *caller, struct cgraph_node *callee,
gimple call_stmt, gcov_type count, int freq, int nest)
{
- struct cgraph_edge *edge = GGC_NEW (struct cgraph_edge);
+ struct cgraph_edge *edge;
#ifdef ENABLE_CHECKING
/* This is rather pricely check possibly trigerring construction of call stmt
gcc_assert (is_gimple_call (call_stmt));
+ if (free_edges)
+ {
+ edge = free_edges;
+ free_edges = NEXT_FREE_EDGE (edge);
+ }
+ else
+ {
+ edge = GGC_NEW (struct cgraph_edge);
+ edge->uid = cgraph_edge_max_uid++;
+ }
+
if (!callee->analyzed)
edge->inline_failed = N_("function body not available");
else if (callee->local.redefined_extern_inline)
gcc_assert (freq <= CGRAPH_FREQ_MAX);
edge->loop_nest = nest;
edge->indirect_call = 0;
- edge->uid = cgraph_edge_max_uid++;
if (caller->call_site_hash)
{
void **slot;
htab_hash_pointer (e->call_stmt));
}
+/* Put the edge onto the free list. */
+
+static void
+cgraph_free_edge (struct cgraph_edge *e)
+{
+ int uid = e->uid;
+
+ /* Clear out the edge so we do not dangle pointers. */
+ memset (e, 0, sizeof (*e));
+ e->uid = uid;
+ NEXT_FREE_EDGE (e) = free_edges;
+ free_edges = e;
+}
+
/* Remove the edge E in the cgraph. */
void
cgraph_remove_edge (struct cgraph_edge *e)
{
+ /* Call all edge removal hooks. */
cgraph_call_edge_removal_hooks (e);
+
/* Remove from callers list of the callee. */
cgraph_edge_remove_callee (e);
/* Remove from callees list of the callers. */
cgraph_edge_remove_caller (e);
+
+ /* Put the edge onto the free list. */
+ cgraph_free_edge (e);
}
/* Redirect callee of E to N. The function does not update underlying
void
cgraph_node_remove_callees (struct cgraph_node *node)
{
- struct cgraph_edge *e;
+ struct cgraph_edge *e, *f;
/* It is sufficient to remove the edges from the lists of callers of
the callees. The callee list of the node can be zapped with one
assignment. */
- for (e = node->callees; e; e = e->next_callee)
+ for (e = node->callees; e; e = f)
{
+ f = e->next_callee;
cgraph_call_edge_removal_hooks (e);
cgraph_edge_remove_callee (e);
+ cgraph_free_edge (e);
}
node->callees = NULL;
if (node->call_site_hash)
static void
cgraph_node_remove_callers (struct cgraph_node *node)
{
- struct cgraph_edge *e;
+ struct cgraph_edge *e, *f;
/* It is sufficient to remove the edges from the lists of callees of
the callers. The caller list of the node can be zapped with one
assignment. */
- for (e = node->callers; e; e = e->next_caller)
+ for (e = node->callers; e; e = f)
{
+ f = e->next_caller;
cgraph_call_edge_removal_hooks (e);
cgraph_edge_remove_caller (e);
+ cgraph_free_edge (e);
}
node->callers = NULL;
}
gcc_assert (dom_computed[1] == DOM_NONE);
clear_edges ();
}
+ if (cfun->value_histograms)
+ free_histograms ();
+ gcc_assert (!current_loops);
pop_cfun();
gimple_set_body (node->decl, NULL);
VEC_free (ipa_opt_pass, heap,
DECL_STRUCT_FUNCTION (node->decl) = NULL;
}
DECL_SAVED_TREE (node->decl) = NULL;
- DECL_INITIAL (node->decl) = error_mark_node;
+ /* If the node is abstract and needed, then do not clear DECL_INITIAL
+ of its associated function function declaration because it's
+ needed to emit debug info later. */
+ if (!node->abstract_and_needed)
+ DECL_INITIAL (node->decl) = error_mark_node;
}
/* Remove the node from cgraph. */
void **slot;
bool kill_body = false;
struct cgraph_node *n;
+ int uid = node->uid;
cgraph_call_node_removal_hooks (node);
cgraph_node_remove_callers (node);
node->call_site_hash = NULL;
}
cgraph_n_nodes--;
- /* Do not free the structure itself so the walk over chain can continue. */
+
+ /* Clear out the node to NULL all pointers and add the node to the free
+ list. */
+ memset (node, 0, sizeof(*node));
+ node->uid = uid;
+ NEXT_FREE_NODE (node) = free_nodes;
+ free_nodes = node;
}
/* Notify finalize_compilation_unit that given node is reachable. */
avail = AVAIL_NOT_AVAILABLE;
else if (node->local.local)
avail = AVAIL_LOCAL;
- else if (node->local.externally_visible)
+ else if (!node->local.externally_visible)
avail = AVAIL_AVAILABLE;
/* If the function can be overwritten, return OVERWRITABLE. Take