+2008-07-12 Jan Hubicka <jh@suse.cz>
+
+ * cgraph.c (assembler_name_hash): New static var.
+ (hash_node_by_assembler_name, eq_assembler_name): New.
+ (cgraph_node_for_asm): Use hashtable.
+ (cgraph_remove_node): Maintain hashtable.
+ (change_decl_assembler_name): Sanity check that names are not changing
+ after aliasing was processed.
+ * cgraph.h (varpoon_node): Add next GGC marker.
+ * tree.c (decl_assembler_name_equal): Constify.
+ (decl_assembler_name_hash): New.
+ * tree.h (decl_assembler_name_equal): Constify.
+ (decl_assembler_name_hash): Update.
+
2008-07-12 David Daney <ddaney@avtrex.com>
* config/mips/driver-native.c (host_detect_local_cpu): Handle
/* Hash table used to convert declarations into nodes. */
static GTY((param_is (struct cgraph_node))) htab_t cgraph_hash;
+/* Hash table used to convert assembler names into nodes. */
+static GTY((param_is (struct cgraph_node))) htab_t assembler_name_hash;
/* The linked list of cgraph nodes. */
struct cgraph_node *cgraph_nodes;
node->origin->nested = node;
node->master_clone = node;
}
+
+ /* This code can go away once flag_unit_at_a_mode is removed. */
+ if (assembler_name_hash)
+ {
+ tree name = DECL_ASSEMBLER_NAME (node->decl);
+ slot = ((struct cgraph_node **)
+ htab_find_slot_with_hash (assembler_name_hash, name,
+ decl_assembler_name_hash (name),
+ INSERT));
+ if (!*slot)
+ *slot = node;
+ }
return node;
}
*slot = node;
}
+/* Returns a hash code for P. */
+
+static hashval_t
+hash_node_by_assembler_name (const void *p)
+{
+ const struct cgraph_node *n = (const struct cgraph_node *) p;
+ return (hashval_t) decl_assembler_name_hash (DECL_ASSEMBLER_NAME (n->decl));
+}
+
+/* Returns nonzero if P1 and P2 are equal. */
+
+static int
+eq_assembler_name (const void *p1, const void *p2)
+{
+ const struct cgraph_node *n1 = (const struct cgraph_node *) p1;
+ const_tree name = (const_tree)p2;
+ return (decl_assembler_name_equal (n1->decl, name));
+}
/* Return the cgraph node that has ASMNAME for its DECL_ASSEMBLER_NAME.
Return NULL if there's no such node. */
cgraph_node_for_asm (tree asmname)
{
struct cgraph_node *node;
+ void **slot;
- for (node = cgraph_nodes; node ; node = node->next)
- if (decl_assembler_name_equal (node->decl, asmname))
- return node;
+ if (!assembler_name_hash)
+ {
+ assembler_name_hash =
+ htab_create_ggc (10, hash_node_by_assembler_name, eq_assembler_name,
+ NULL);
+ for (node = cgraph_nodes; node; node = node->next)
+ if (!node->global.inlined_to)
+ {
+ tree name = DECL_ASSEMBLER_NAME (node->decl);
+ slot = htab_find_slot_with_hash (assembler_name_hash, name,
+ decl_assembler_name_hash (name),
+ INSERT);
+ /* We can have multiple declarations with same assembler name. For C++
+ it is __builtin_strlen and strlen, for instance. Do we need to
+ record them all? Original implementation marked just first one
+ so lets hope for the best. */
+ if (*slot)
+ continue;
+ *slot = node;
+ }
+ }
+
+ slot = htab_find_slot_with_hash (assembler_name_hash, asmname,
+ decl_assembler_name_hash (asmname),
+ NO_INSERT);
+ if (slot)
+ return (struct cgraph_node *) *slot;
return NULL;
}
cgraph_call_node_removal_hooks (node);
cgraph_node_remove_callers (node);
cgraph_node_remove_callees (node);
+
/* Incremental inlining access removed nodes stored in the postorder list.
*/
node->needed = node->reachable = false;
&& (TREE_ASM_WRITTEN (n->decl) || DECL_EXTERNAL (n->decl))))
kill_body = true;
}
+ if (assembler_name_hash)
+ {
+ tree name = DECL_ASSEMBLER_NAME (node->decl);
+ slot = htab_find_slot_with_hash (assembler_name_hash, name,
+ decl_assembler_name_hash (name),
+ NO_INSERT);
+ /* Inline clones are not hashed. */
+ if (slot && *slot == node)
+ htab_clear_slot (assembler_name_hash, slot);
+ }
if (kill_body && flag_unit_at_a_time)
cgraph_release_function_body (node);
void
change_decl_assembler_name (tree decl, tree name)
{
+ gcc_assert (!assembler_name_hash);
if (!DECL_ASSEMBLER_NAME_SET_P (decl))
{
SET_DECL_ASSEMBLER_NAME (decl, name);
/* Compare ASMNAME with the DECL_ASSEMBLER_NAME of DECL. */
bool
-decl_assembler_name_equal (tree decl, tree asmname)
+decl_assembler_name_equal (tree decl, const_tree asmname)
{
tree decl_asmname = DECL_ASSEMBLER_NAME (decl);
return false;
}
+/* Hash asmnames ignoring the user specified marks. */
+
+hashval_t
+decl_assembler_name_hash (const_tree asmname)
+{
+ if (IDENTIFIER_POINTER (asmname)[0] == '*')
+ {
+ const char *decl_str = IDENTIFIER_POINTER (asmname) + 1;
+ size_t ulp_len = strlen (user_label_prefix);
+
+ if (ulp_len == 0)
+ ;
+ else if (strncmp (decl_str, user_label_prefix, ulp_len) == 0)
+ decl_str += ulp_len;
+
+ return htab_hash_string (decl_str);
+ }
+
+ return htab_hash_string (IDENTIFIER_POINTER (asmname));
+}
+
/* Compute the number of bytes occupied by a tree with code CODE.
This function cannot be used for nodes that have variable sizes,
including TREE_VEC, PHI_NODE, STRING_CST, and CALL_EXPR. */