aboutsummaryrefslogtreecommitdiff
path: root/gcc/cgraph.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cgraph.c')
-rw-r--r--gcc/cgraph.c211
1 files changed, 200 insertions, 11 deletions
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index fd77f663bba..ffc33123028 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -24,7 +24,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
-#include "tree-inline.h"
#include "langhooks.h"
#include "hashtab.h"
#include "toplev.h"
@@ -34,13 +33,14 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "target.h"
#include "cgraph.h"
#include "varray.h"
+#include "output.h"
/* The known declarations must not get garbage collected. Callgraph
datastructures should not get saved via PCH code since this would
make it difficult to extend into intra-module optimizer later. So
we store only the references into the array to prevent gabrage
collector from deleting live data. */
-static GTY(()) varray_type known_fns;
+static GTY(()) varray_type known_decls;
/* Hash table used to convert declarations into nodes. */
static htab_t cgraph_hash = 0;
@@ -48,23 +48,35 @@ static htab_t cgraph_hash = 0;
/* The linked list of cgraph nodes. */
struct cgraph_node *cgraph_nodes;
+/* Queue of cgraph nodes scheduled to be lowered. */
+struct cgraph_node *cgraph_nodes_queue;
+
/* Number of nodes in existence. */
int cgraph_n_nodes;
/* Set when whole unit has been analyzed so we can access global info. */
bool cgraph_global_info_ready = false;
+/* Hash table used to convert declarations into nodes. */
+static htab_t cgraph_varpool_hash = 0;
+
+/* Queue of cgraph nodes scheduled to be lowered and output. */
+struct cgraph_varpool_node *cgraph_varpool_nodes_queue;
+
+/* Number of nodes in existence. */
+int cgraph_varpool_n_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 PTR));
-static int eq_node PARAMS ((const PTR, const PTR));
+static hashval_t hash_node PARAMS ((const void *));
+static int eq_node PARAMS ((const void *, const void *));
/* Returns a hash code for P. */
static hashval_t
hash_node (p)
- const PTR p;
+ const void *p;
{
return (hashval_t)
htab_hash_pointer (DECL_ASSEMBLER_NAME
@@ -75,11 +87,11 @@ hash_node (p)
static int
eq_node (p1, p2)
- const PTR p1;
- const PTR p2;
+ const void *p1;
+ const void *p2;
{
return ((DECL_ASSEMBLER_NAME (((struct cgraph_node *) p1)->decl)) ==
- DECL_ASSEMBLER_NAME ((tree) p2));
+ (tree) p2);
}
/* Return cgraph node assigned to DECL. Create new one when needed. */
@@ -96,11 +108,13 @@ cgraph_node (decl)
if (!cgraph_hash)
{
cgraph_hash = htab_create (10, hash_node, eq_node, NULL);
- VARRAY_TREE_INIT (known_fns, 32, "known_fns");
+ if (!known_decls)
+ VARRAY_TREE_INIT (known_decls, 32, "known_decls");
}
slot =
- (struct cgraph_node **) htab_find_slot_with_hash (cgraph_hash, decl,
+ (struct cgraph_node **) htab_find_slot_with_hash (cgraph_hash,
+ DECL_ASSEMBLER_NAME (decl),
htab_hash_pointer
(DECL_ASSEMBLER_NAME
(decl)), 1);
@@ -121,10 +135,31 @@ cgraph_node (decl)
node->next_nested = node->origin->nested;
node->origin->nested = node;
}
- VARRAY_PUSH_TREE (known_fns, decl);
+ VARRAY_PUSH_TREE (known_decls, decl);
return node;
}
+/* Try to find existing function for identifier ID. */
+struct cgraph_node *
+cgraph_node_for_identifier (id)
+ tree id;
+{
+ struct cgraph_node **slot;
+
+ if (TREE_CODE (id) != IDENTIFIER_NODE)
+ abort ();
+
+ if (!cgraph_hash)
+ return NULL;
+
+ slot =
+ (struct cgraph_node **) htab_find_slot_with_hash (cgraph_hash, id,
+ htab_hash_pointer (id), 0);
+ if (!slot)
+ return NULL;
+ return *slot;
+}
+
/* Create edge from CALLER to CALLEE in the cgraph. */
static struct cgraph_edge *
@@ -194,6 +229,28 @@ cgraph_remove_node (node)
/* Do not free the structure itself so the walk over chain can continue. */
}
+/* Notify finalize_compilation_unit that given node is reachable
+ or needed. */
+void
+cgraph_mark_needed_node (node, needed)
+ struct cgraph_node *node;
+ int needed;
+{
+ if (needed)
+ {
+ node->needed = 1;
+ }
+ if (!node->reachable)
+ {
+ node->reachable = 1;
+ if (DECL_SAVED_TREE (node->decl))
+ {
+ node->aux = cgraph_nodes_queue;
+ cgraph_nodes_queue = node;
+ }
+ }
+}
+
/* Record call from CALLER to CALLEE */
@@ -306,4 +363,136 @@ dump_cgraph (f)
}
}
+/* Returns a hash code for P. */
+
+static hashval_t
+cgraph_varpool_hash_node (const PTR p)
+{
+ return (hashval_t)
+ htab_hash_pointer (DECL_ASSEMBLER_NAME
+ (((struct cgraph_varpool_node *) p)->decl));
+}
+
+/* Returns non-zero if P1 and P2 are equal. */
+
+static int
+eq_cgraph_varpool_node (const PTR p1, const PTR p2)
+{
+ return ((DECL_ASSEMBLER_NAME (((struct cgraph_varpool_node *) p1)->decl)) ==
+ (tree) p2);
+}
+
+/* Return cgraph_varpool node assigned to DECL. Create new one when needed. */
+struct cgraph_varpool_node *
+cgraph_varpool_node (tree decl)
+{
+ struct cgraph_varpool_node *node;
+ struct cgraph_varpool_node **slot;
+
+ if (!DECL_P (decl) || TREE_CODE (decl) == FUNCTION_DECL)
+ abort ();
+
+ if (!cgraph_varpool_hash)
+ {
+ cgraph_varpool_hash = htab_create (10, cgraph_varpool_hash_node, eq_cgraph_varpool_node, NULL);
+ if (!known_decls)
+ VARRAY_TREE_INIT (known_decls, 32, "known_decls");
+ }
+
+ slot =
+ (struct cgraph_varpool_node **) htab_find_slot_with_hash (cgraph_varpool_hash,
+ DECL_ASSEMBLER_NAME (decl),
+ htab_hash_pointer
+ (DECL_ASSEMBLER_NAME
+ (decl)), 1);
+ if (*slot)
+ return *slot;
+ node = xcalloc (sizeof (*node), 1);
+ node->decl = decl;
+ cgraph_varpool_n_nodes++;
+ *slot = node;
+ VARRAY_PUSH_TREE (known_decls, decl);
+ return node;
+}
+
+/* Try to find existing function for identifier ID. */
+struct cgraph_varpool_node *
+cgraph_varpool_node_for_identifier (tree id)
+{
+ struct cgraph_varpool_node **slot;
+
+ if (TREE_CODE (id) != IDENTIFIER_NODE)
+ abort ();
+
+ if (!cgraph_varpool_hash)
+ return NULL;
+
+ slot =
+ (struct cgraph_varpool_node **) htab_find_slot_with_hash (cgraph_varpool_hash, id,
+ htab_hash_pointer (id), 0);
+ if (!slot)
+ return NULL;
+ return *slot;
+}
+
+/* Notify finalize_compilation_unit that given node is reachable
+ or needed. */
+void
+cgraph_varpool_mark_needed_node (struct cgraph_varpool_node *node)
+{
+ if (!node->needed && node->finalized)
+ {
+ node->aux = cgraph_varpool_nodes_queue;
+ cgraph_varpool_nodes_queue = node;
+ }
+ node->needed = 1;
+}
+
+void
+cgraph_varpool_finalize_decl (tree decl)
+{
+ struct cgraph_varpool_node *node = cgraph_varpool_node (decl);
+
+ if (node->needed && !node->finalized)
+ {
+ node->aux = cgraph_varpool_nodes_queue;
+ cgraph_varpool_nodes_queue = node;
+ }
+ node->finalized = true;
+
+ if (/* Externally visible variables must be output. The exception are
+ COMDAT functions that must be output only when they are needed. */
+ (TREE_PUBLIC (decl) && !DECL_COMDAT (decl))
+ /* Function whose name is output to the assembler file must be produced.
+ It is possible to assemble the name later after finalizing the function
+ and the fact is noticed in assemble_name then. */
+ || (DECL_ASSEMBLER_NAME_SET_P (decl)
+ && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))))
+ {
+ cgraph_varpool_mark_needed_node (node);
+ }
+}
+
+bool
+cgraph_varpool_assemble_pending_decls ()
+{
+ bool changed = false;
+
+ while (cgraph_varpool_nodes_queue)
+ {
+ tree decl = cgraph_varpool_nodes_queue->decl;
+ struct cgraph_varpool_node *node = cgraph_varpool_nodes_queue;
+
+ cgraph_varpool_nodes_queue = cgraph_varpool_nodes_queue->aux;
+ if (!TREE_ASM_WRITTEN (decl))
+ {
+ assemble_variable (decl, 0, 1, 0);
+ changed = true;
+ }
+ node->aux = NULL;
+ }
+ return changed;
+}
+
+
#include "gt-cgraph.h"