aboutsummaryrefslogtreecommitdiff
path: root/gcc/cgraph.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cgraph.c')
-rw-r--r--gcc/cgraph.c164
1 files changed, 105 insertions, 59 deletions
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index 7bc065b79d3..43238e58ecd 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -48,6 +48,9 @@ struct cgraph_node *cgraph_nodes_queue;
/* Number of nodes in existence. */
int cgraph_n_nodes;
+/* Maximal uid used in cgraph nodes. */
+int cgraph_max_uid;
+
/* Set when whole unit has been analyzed so we can access global info. */
bool cgraph_global_info_ready = false;
@@ -63,17 +66,16 @@ int cgraph_varpool_n_nodes;
/* The linked list of cgraph varpool nodes. */
static GTY(()) struct cgraph_varpool_node *cgraph_varpool_nodes;
-static struct cgraph_edge *create_edge PARAMS ((struct cgraph_node *,
- struct cgraph_node *));
-static void cgraph_remove_edge PARAMS ((struct cgraph_node *, struct cgraph_node *));
-static hashval_t hash_node PARAMS ((const void *));
-static int eq_node PARAMS ((const void *, const void *));
+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 *);
/* Returns a hash code for P. */
static hashval_t
-hash_node (p)
- const void *p;
+hash_node (const void *p)
{
return ((hashval_t)
IDENTIFIER_HASH_VALUE (DECL_ASSEMBLER_NAME
@@ -83,9 +85,7 @@ hash_node (p)
/* Returns nonzero if P1 and P2 are equal. */
static int
-eq_node (p1, p2)
- const void *p1;
- const void *p2;
+eq_node (const void *p1, const void *p2)
{
return ((DECL_ASSEMBLER_NAME (((struct cgraph_node *) p1)->decl)) ==
(tree) p2);
@@ -93,8 +93,7 @@ eq_node (p1, p2)
/* Return cgraph node assigned to DECL. Create new one when needed. */
struct cgraph_node *
-cgraph_node (decl)
- tree decl;
+cgraph_node (tree decl)
{
struct cgraph_node *node;
struct cgraph_node **slot;
@@ -114,6 +113,7 @@ cgraph_node (decl)
node = ggc_alloc_cleared (sizeof (*node));
node->decl = decl;
node->next = cgraph_nodes;
+ node->uid = cgraph_max_uid++;
if (cgraph_nodes)
cgraph_nodes->previous = node;
node->previous = NULL;
@@ -131,8 +131,7 @@ cgraph_node (decl)
/* Try to find existing function for identifier ID. */
struct cgraph_node *
-cgraph_node_for_identifier (id)
- tree id;
+cgraph_node_for_identifier (tree id)
{
struct cgraph_node **slot;
@@ -144,7 +143,7 @@ cgraph_node_for_identifier (id)
slot = (struct cgraph_node **)
htab_find_slot_with_hash (cgraph_hash, id,
- IDENTIFIER_HASH_VALUE (id), 0);
+ IDENTIFIER_HASH_VALUE (id), 0);
if (!slot)
return NULL;
return *slot;
@@ -153,10 +152,22 @@ cgraph_node_for_identifier (id)
/* Create edge from CALLER to CALLEE in the cgraph. */
static struct cgraph_edge *
-create_edge (caller, callee)
- struct cgraph_node *caller, *callee;
+create_edge (struct cgraph_node *caller, struct cgraph_node *callee)
{
struct cgraph_edge *edge = ggc_alloc (sizeof (struct cgraph_edge));
+ struct cgraph_edge *edge2;
+
+ edge->inline_call = false;
+ /* At the moment we don't associate calls with specific CALL_EXPRs
+ 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_callee)
+ if (edge2->callee == callee)
+ {
+ edge->inline_call = edge2->inline_call;
+ break;
+ }
edge->caller = caller;
edge->callee = callee;
@@ -170,8 +181,7 @@ create_edge (caller, callee)
/* Remove the edge from CALLER to CALLEE in the cgraph. */
static void
-cgraph_remove_edge (caller, callee)
- struct cgraph_node *caller, *callee;
+cgraph_remove_edge (struct cgraph_node *caller, struct cgraph_node *callee)
{
struct cgraph_edge **edge, **edge2;
@@ -192,9 +202,9 @@ cgraph_remove_edge (caller, callee)
/* Remove the node from cgraph. */
void
-cgraph_remove_node (node)
- struct cgraph_node *node;
+cgraph_remove_node (struct cgraph_node *node)
{
+ void **slot;
while (node->callers)
cgraph_remove_edge (node->callers->caller, node);
while (node->callees)
@@ -216,44 +226,59 @@ cgraph_remove_node (node)
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)), 1);
+ 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 (node, needed)
- 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_edge *
-cgraph_record_call (caller, callee)
- tree caller, callee;
+cgraph_record_call (tree caller, tree callee)
{
return create_edge (cgraph_node (caller), cgraph_node (callee));
}
void
-cgraph_remove_call (caller, callee)
- tree caller, callee;
+cgraph_remove_call (tree caller, tree callee)
{
cgraph_remove_edge (cgraph_node (caller), cgraph_node (callee));
}
@@ -261,8 +286,7 @@ cgraph_remove_call (caller, callee)
/* Return true when CALLER_DECL calls CALLEE_DECL. */
bool
-cgraph_calls_p (caller_decl, callee_decl)
- tree caller_decl, callee_decl;
+cgraph_calls_p (tree caller_decl, tree callee_decl)
{
struct cgraph_node *caller = cgraph_node (caller_decl);
struct cgraph_node *callee = cgraph_node (callee_decl);
@@ -277,8 +301,7 @@ cgraph_calls_p (caller_decl, callee_decl)
/* Return local info for the compiled function. */
struct cgraph_local_info *
-cgraph_local_info (decl)
- tree decl;
+cgraph_local_info (tree decl)
{
struct cgraph_node *node;
if (TREE_CODE (decl) != FUNCTION_DECL)
@@ -290,8 +313,7 @@ cgraph_local_info (decl)
/* Return local info for the compiled function. */
struct cgraph_global_info *
-cgraph_global_info (decl)
- tree decl;
+cgraph_global_info (tree decl)
{
struct cgraph_node *node;
if (TREE_CODE (decl) != FUNCTION_DECL || !cgraph_global_info_ready)
@@ -303,8 +325,7 @@ cgraph_global_info (decl)
/* Return local info for the compiled function. */
struct cgraph_rtl_info *
-cgraph_rtl_info (decl)
- tree decl;
+cgraph_rtl_info (tree decl)
{
struct cgraph_node *node;
if (TREE_CODE (decl) != FUNCTION_DECL)
@@ -318,8 +339,7 @@ cgraph_rtl_info (decl)
/* Return name of the node used in debug output. */
const char *
-cgraph_node_name (node)
- struct cgraph_node *node;
+cgraph_node_name (struct cgraph_node *node)
{
return (*lang_hooks.decl_printable_name) (node->decl, 2);
}
@@ -327,8 +347,7 @@ cgraph_node_name (node)
/* Dump the callgraph. */
void
-dump_cgraph (f)
- FILE *f;
+dump_cgraph (FILE *f)
{
struct cgraph_node *node;
@@ -337,6 +356,8 @@ dump_cgraph (f)
{
struct cgraph_edge *edge;
fprintf (f, "%s", cgraph_node_name (node));
+ if (node->local.self_insns)
+ fprintf (f, " %i insns", node->local.self_insns);
if (node->origin)
fprintf (f, " nested in: %s", cgraph_node_name (node->origin));
if (node->needed)
@@ -346,13 +367,30 @@ dump_cgraph (f)
if (DECL_SAVED_TREE (node->decl))
fprintf (f, " tree");
- fprintf (f, "\n called by :");
+ 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);
+
+ fprintf (f, "\n called by: ");
for (edge = node->callers; edge; edge = edge->next_caller)
- fprintf (f, "%s ", cgraph_node_name (edge->caller));
+ {
+ fprintf (f, "%s ", cgraph_node_name (edge->caller));
+ if (edge->inline_call)
+ fprintf(f, "(inlined) ");
+ }
fprintf (f, "\n calls: ");
for (edge = node->callees; edge; edge = edge->next_callee)
- fprintf (f, "%s ", cgraph_node_name (edge->callee));
+ {
+ fprintf (f, "%s ", cgraph_node_name (edge->callee));
+ if (edge->inline_call)
+ fprintf(f, "(inlined) ");
+ }
fprintf (f, "\n");
}
}
@@ -360,7 +398,7 @@ dump_cgraph (f)
/* Returns a hash code for P. */
static hashval_t
-cgraph_varpool_hash_node (const PTR p)
+cgraph_varpool_hash_node (const void *p)
{
return ((hashval_t)
IDENTIFIER_HASH_VALUE (DECL_ASSEMBLER_NAME
@@ -370,7 +408,7 @@ cgraph_varpool_hash_node (const PTR p)
/* Returns nonzero if P1 and P2 are equal. */
static int
-eq_cgraph_varpool_node (const PTR p1, const PTR p2)
+eq_cgraph_varpool_node (const void *p1, const void *p2)
{
return ((DECL_ASSEMBLER_NAME (((struct cgraph_varpool_node *) p1)->decl)) ==
(tree) p2);
@@ -434,6 +472,7 @@ cgraph_varpool_mark_needed_node (struct cgraph_varpool_node *node)
{
node->next_needed = cgraph_varpool_nodes_queue;
cgraph_varpool_nodes_queue = node;
+ notice_global_symbol (node->decl);
}
node->needed = 1;
}
@@ -442,11 +481,18 @@ void
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;
@@ -464,7 +510,7 @@ cgraph_varpool_finalize_decl (tree decl)
}
bool
-cgraph_varpool_assemble_pending_decls ()
+cgraph_varpool_assemble_pending_decls (void)
{
bool changed = false;