Hi, this patch moves cgraph/varpool hashes into symbol table hashes, so the symbol table is actually almost a symbol table ;) Work done.
Bootstrapped/regtested x86_64-linux. Will commit it after bit of more testing - the assembler name handling is slipperly wrt aliases. Honza * cgraph.c (cgraph_hash, assembler_name_hash): Remove. (hash_node, eq_node): Remove. (cgraph_create_node): Do not handle hashtable. (cgraph_get_node): Remove. (cgraph_insert_node_to_hashtable): Remove. (hash_node_by_assembler_name): Remove. (eq_assembler_name): Remove. (cgraph_node_for_asm): Rewrite. (cgraph_find_replacement_node): Break out from ... (cgraph_remove_node): ... here; do not maintain hashtables. (change_decl_assembler_name): Remove. (cgraph_clone_node): Do not maintain hashtables. * cgraph.h (const_symtab_node): New typedef. (cgraph_insert_node_to_hashtable): Remove. (symtab_get_node, symtab_node_for_asm, symtab_insert_node_to_hashtable): Declare. (cgraph_find_replacement_node): Declare. (cgraph_get_node, varpool_get_node): Turn into inlines. (cgraph, varpool): Work sanely on NULL pointers. (FOR_EACH_SYMBOL): New walker. * ipa-inline-transform.c (save_inline_function_body): Use symtab_insert_node_to_hashtable. * symtab.c: Include ggc.h and diagnostics.h (symtab_hash, assembler_name_hash): New static vars; (hash_node, eq_node, hash_node_by_assembler_name, eq_assembler_name): New. (symtab_register_node): Update hashtables. (symtab_insert_node_to_hashtable): New. (symtab_unregister_node): Update hashtables. (symtab_get_node): New. (symtab_node_for_asm): New. (change_decl_assembler_name): New. * Makefile.in (symtab.o): Needs GTY. * varpool.c (varpool_hash): Remove. (hash_varpool_node, eq_varpool_node, varpool_get_node): Remove. (varpool_node): Rewrite using varpool_get_node. (varpool_remove_node): DO not maintain hashtables. (varpool_node_for_asm); Rewrite. Index: cgraph.c =================================================================== *** cgraph.c (revision 186496) --- cgraph.c (working copy) *************** static void cgraph_node_remove_callers ( *** 119,129 **** static inline void cgraph_edge_remove_caller (struct cgraph_edge *e); static inline void cgraph_edge_remove_callee (struct cgraph_edge *e); - /* Hash table used to convert declarations into nodes. */ - static GTY((param_is (union symtab_node_def))) htab_t cgraph_hash; - /* Hash table used to convert assembler names into nodes. */ - static GTY((param_is (union symtab_node_def))) htab_t assembler_name_hash; - /* Queue of cgraph nodes scheduled to be lowered. */ symtab_node x_cgraph_nodes_queue; #define cgraph_nodes_queue ((struct cgraph_node *)x_cgraph_nodes_queue) --- 119,124 ---- *************** cgraph_call_node_duplication_hooks (stru *** 419,444 **** } } - /* Returns a hash code for P. */ - - static hashval_t - hash_node (const void *p) - { - const struct cgraph_node *n = (const struct cgraph_node *) p; - return (hashval_t) DECL_UID (n->symbol.decl); - } - - - /* Returns nonzero if P1 and P2 are equal. */ - - static int - eq_node (const void *p1, const void *p2) - { - const struct cgraph_node *n1 = (const struct cgraph_node *) p1; - const struct cgraph_node *n2 = (const struct cgraph_node *) p2; - return DECL_UID (n1->symbol.decl) == DECL_UID (n2->symbol.decl); - } - /* Allocate new callgraph node. */ static inline struct cgraph_node * --- 414,419 ---- *************** cgraph_create_node_1 (void) *** 479,520 **** struct cgraph_node * cgraph_create_node (tree decl) { ! struct cgraph_node key, *node, **slot; ! gcc_assert (TREE_CODE (decl) == FUNCTION_DECL); - if (!cgraph_hash) - cgraph_hash = htab_create_ggc (10, hash_node, eq_node, NULL); - - key.symbol.decl = decl; - slot = (struct cgraph_node **) htab_find_slot (cgraph_hash, &key, INSERT); - gcc_assert (!*slot); - - node = cgraph_create_node_1 (); node->symbol.decl = decl; ! symtab_register_node ((symtab_node)node); ! *slot = node; if (DECL_CONTEXT (decl) && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL) { node->origin = cgraph_get_create_node (DECL_CONTEXT (decl)); node->next_nested = node->origin->nested; node->origin->nested = node; } - if (assembler_name_hash) - { - void **aslot; - tree name = DECL_ASSEMBLER_NAME (decl); - - aslot = 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 (*aslot == NULL) - *aslot = node; - } return node; } --- 454,471 ---- struct cgraph_node * cgraph_create_node (tree decl) { ! struct cgraph_node *node = cgraph_create_node_1 (); gcc_assert (TREE_CODE (decl) == FUNCTION_DECL); node->symbol.decl = decl; ! symtab_register_node ((symtab_node) node); ! if (DECL_CONTEXT (decl) && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL) { node->origin = cgraph_get_create_node (DECL_CONTEXT (decl)); node->next_nested = node->origin->nested; node->origin->nested = node; } return node; } *************** cgraph_add_thunk (struct cgraph_node *de *** 629,728 **** return node; } - /* Returns the cgraph node assigned to DECL or NULL if no cgraph node - is assigned. */ - - struct cgraph_node * - cgraph_get_node (const_tree decl) - { - struct cgraph_node key, *node = NULL, **slot; - - gcc_assert (TREE_CODE (decl) == FUNCTION_DECL); - - if (!cgraph_hash) - return NULL; - - key.symbol.decl = CONST_CAST2 (tree, const_tree, decl); - - slot = (struct cgraph_node **) htab_find_slot (cgraph_hash, &key, - NO_INSERT); - - if (slot && *slot) - node = *slot; - return node; - } - - /* Insert already constructed node into hashtable. */ - - void - cgraph_insert_node_to_hashtable (struct cgraph_node *node) - { - struct cgraph_node **slot; - - slot = (struct cgraph_node **) htab_find_slot (cgraph_hash, node, INSERT); - - gcc_assert (!*slot); - *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->symbol.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->symbol.decl, name)); - } - /* Return the cgraph node that has ASMNAME for its DECL_ASSEMBLER_NAME. Return NULL if there's no such node. */ struct cgraph_node * cgraph_node_for_asm (tree asmname) { ! struct cgraph_node *node; ! void **slot; ! if (!assembler_name_hash) ! { ! assembler_name_hash = ! htab_create_ggc (10, hash_node_by_assembler_name, eq_assembler_name, ! NULL); ! FOR_EACH_FUNCTION (node) ! if (!node->global.inlined_to) ! { ! tree name = DECL_ASSEMBLER_NAME (node->symbol.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) ! *slot = node; ! } ! } ! ! slot = htab_find_slot_with_hash (assembler_name_hash, asmname, ! decl_assembler_name_hash (asmname), ! NO_INSERT); ! ! if (slot) ! { ! node = (struct cgraph_node *) *slot; ! return node; ! } return NULL; } --- 580,595 ---- return node; } /* Return the cgraph node that has ASMNAME for its DECL_ASSEMBLER_NAME. Return NULL if there's no such node. */ struct cgraph_node * cgraph_node_for_asm (tree asmname) { ! symtab_node node = symtab_node_for_asm (asmname); ! if (node && symtab_function_p (node)) ! return cgraph (node); return NULL; } *************** cgraph_release_function_body (struct cgr *** 1392,1404 **** DECL_INITIAL (node->symbol.decl) = error_mark_node; } /* Remove the node from cgraph. */ void cgraph_remove_node (struct cgraph_node *node) { - void **slot; - bool kill_body = false; struct cgraph_node *n; int uid = node->uid; --- 1259,1354 ---- DECL_INITIAL (node->symbol.decl) = error_mark_node; } + /* NODE is being removed from symbol table; see if its entry can be replaced by + other inline clone. */ + struct cgraph_node * + cgraph_find_replacement_node (struct cgraph_node *node) + { + struct cgraph_node *next_inline_clone, *replacement; + + for (next_inline_clone = node->clones; + next_inline_clone + && next_inline_clone->symbol.decl != node->symbol.decl; + next_inline_clone = next_inline_clone->next_sibling_clone) + ; + + /* If there is inline clone of the node being removed, we need + to put it into the position of removed node and reorganize all + other clones to be based on it. */ + if (next_inline_clone) + { + struct cgraph_node *n; + struct cgraph_node *new_clones; + + replacement = next_inline_clone; + + /* Unlink inline clone from the list of clones of removed node. */ + if (next_inline_clone->next_sibling_clone) + next_inline_clone->next_sibling_clone->prev_sibling_clone + = next_inline_clone->prev_sibling_clone; + if (next_inline_clone->prev_sibling_clone) + { + gcc_assert (node->clones != next_inline_clone); + next_inline_clone->prev_sibling_clone->next_sibling_clone + = next_inline_clone->next_sibling_clone; + } + else + { + gcc_assert (node->clones == next_inline_clone); + node->clones = next_inline_clone->next_sibling_clone; + } + + new_clones = node->clones; + node->clones = NULL; + + /* Copy clone info. */ + next_inline_clone->clone = node->clone; + + /* Now place it into clone tree at same level at NODE. */ + next_inline_clone->clone_of = node->clone_of; + next_inline_clone->prev_sibling_clone = NULL; + next_inline_clone->next_sibling_clone = NULL; + if (node->clone_of) + { + if (node->clone_of->clones) + node->clone_of->clones->prev_sibling_clone = next_inline_clone; + next_inline_clone->next_sibling_clone = node->clone_of->clones; + node->clone_of->clones = next_inline_clone; + } + + /* Merge the clone list. */ + if (new_clones) + { + if (!next_inline_clone->clones) + next_inline_clone->clones = new_clones; + else + { + n = next_inline_clone->clones; + while (n->next_sibling_clone) + n = n->next_sibling_clone; + n->next_sibling_clone = new_clones; + new_clones->prev_sibling_clone = n; + } + } + + /* Update clone_of pointers. */ + n = new_clones; + while (n) + { + n->clone_of = next_inline_clone; + n = n->next_sibling_clone; + } + return replacement; + } + else + return NULL; + } + /* Remove the node from cgraph. */ void cgraph_remove_node (struct cgraph_node *node) { struct cgraph_node *n; int uid = node->uid; *************** cgraph_remove_node (struct cgraph_node * *** 1423,1513 **** *node2 = node->next_nested; } symtab_unregister_node ((symtab_node)node); - slot = htab_find_slot (cgraph_hash, node, NO_INSERT); - if (*slot == node) - { - struct cgraph_node *next_inline_clone; - - for (next_inline_clone = node->clones; - next_inline_clone - && next_inline_clone->symbol.decl != node->symbol.decl; - next_inline_clone = next_inline_clone->next_sibling_clone) - ; - - /* If there is inline clone of the node being removed, we need - to put it into the position of removed node and reorganize all - other clones to be based on it. */ - if (next_inline_clone) - { - struct cgraph_node *n; - struct cgraph_node *new_clones; - - *slot = next_inline_clone; - - /* Unlink inline clone from the list of clones of removed node. */ - if (next_inline_clone->next_sibling_clone) - next_inline_clone->next_sibling_clone->prev_sibling_clone - = next_inline_clone->prev_sibling_clone; - if (next_inline_clone->prev_sibling_clone) - { - gcc_assert (node->clones != next_inline_clone); - next_inline_clone->prev_sibling_clone->next_sibling_clone - = next_inline_clone->next_sibling_clone; - } - else - { - gcc_assert (node->clones == next_inline_clone); - node->clones = next_inline_clone->next_sibling_clone; - } - - new_clones = node->clones; - node->clones = NULL; - - /* Copy clone info. */ - next_inline_clone->clone = node->clone; - - /* Now place it into clone tree at same level at NODE. */ - next_inline_clone->clone_of = node->clone_of; - next_inline_clone->prev_sibling_clone = NULL; - next_inline_clone->next_sibling_clone = NULL; - if (node->clone_of) - { - if (node->clone_of->clones) - node->clone_of->clones->prev_sibling_clone = next_inline_clone; - next_inline_clone->next_sibling_clone = node->clone_of->clones; - node->clone_of->clones = next_inline_clone; - } - - /* Merge the clone list. */ - if (new_clones) - { - if (!next_inline_clone->clones) - next_inline_clone->clones = new_clones; - else - { - n = next_inline_clone->clones; - while (n->next_sibling_clone) - n = n->next_sibling_clone; - n->next_sibling_clone = new_clones; - new_clones->prev_sibling_clone = n; - } - } - - /* Update clone_of pointers. */ - n = new_clones; - while (n) - { - n->clone_of = next_inline_clone; - n = n->next_sibling_clone; - } - } - else - { - htab_clear_slot (cgraph_hash, slot); - kill_body = true; - } - - } if (node->prev_sibling_clone) node->prev_sibling_clone->next_sibling_clone = node->next_sibling_clone; else if (node->clone_of) --- 1373,1378 ---- *************** cgraph_remove_node (struct cgraph_node * *** 1549,1577 **** itself is kept in the cgraph even after it is compiled. Check whether we are done with this body and reclaim it proactively if this is the case. */ ! if (!kill_body && *slot) ! { ! struct cgraph_node *n = (struct cgraph_node *) *slot; ! if (!n->clones && !n->clone_of && !n->global.inlined_to && (cgraph_global_info_ready && (TREE_ASM_WRITTEN (n->symbol.decl) || DECL_EXTERNAL (n->symbol.decl) ! || n->symbol.in_other_partition))) ! kill_body = true; ! } ! if (assembler_name_hash) ! { ! tree name = DECL_ASSEMBLER_NAME (node->symbol.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) cgraph_release_function_body (node); node->symbol.decl = NULL; if (node->call_site_hash) { --- 1414,1428 ---- itself is kept in the cgraph even after it is compiled. Check whether we are done with this body and reclaim it proactively if this is the case. */ ! n = cgraph_get_node (node->symbol.decl); ! if (!n ! || (!n->clones && !n->clone_of && !n->global.inlined_to && (cgraph_global_info_ready && (TREE_ASM_WRITTEN (n->symbol.decl) || DECL_EXTERNAL (n->symbol.decl) ! || n->symbol.in_other_partition)))) cgraph_release_function_body (node); + node->symbol.decl = NULL; if (node->call_site_hash) { *************** debug_cgraph (void) *** 1939,1989 **** dump_cgraph (stderr); } - - /* Set the DECL_ASSEMBLER_NAME and update cgraph hashtables. */ - - void - change_decl_assembler_name (tree decl, tree name) - { - struct cgraph_node *node; - void **slot; - if (!DECL_ASSEMBLER_NAME_SET_P (decl)) - SET_DECL_ASSEMBLER_NAME (decl, name); - else - { - if (name == DECL_ASSEMBLER_NAME (decl)) - return; - - if (assembler_name_hash - && TREE_CODE (decl) == FUNCTION_DECL - && (node = cgraph_get_node (decl)) != NULL) - { - tree old_name = DECL_ASSEMBLER_NAME (decl); - slot = htab_find_slot_with_hash (assembler_name_hash, old_name, - decl_assembler_name_hash (old_name), - NO_INSERT); - /* Inline clones are not hashed. */ - if (slot && *slot == node) - htab_clear_slot (assembler_name_hash, slot); - } - if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)) - && DECL_RTL_SET_P (decl)) - warning (0, "%D renamed after being referenced in assembly", decl); - - SET_DECL_ASSEMBLER_NAME (decl, name); - } - if (assembler_name_hash - && TREE_CODE (decl) == FUNCTION_DECL - && (node = cgraph_get_node (decl)) != NULL) - { - slot = htab_find_slot_with_hash (assembler_name_hash, name, - decl_assembler_name_hash (name), - INSERT); - gcc_assert (!*slot); - *slot = node; - } - } - /* Add a top-level asm statement to the list. */ struct cgraph_asm_node * --- 1790,1795 ---- *************** cgraph_clone_node (struct cgraph_node *n *** 2154,2178 **** n->clones = new_node; new_node->clone_of = n; - if (n->symbol.decl != decl) - { - struct cgraph_node **slot; - slot = (struct cgraph_node **) htab_find_slot (cgraph_hash, new_node, INSERT); - gcc_assert (!*slot); - *slot = new_node; - if (assembler_name_hash) - { - void **aslot; - tree name = DECL_ASSEMBLER_NAME (decl); - - aslot = htab_find_slot_with_hash (assembler_name_hash, name, - decl_assembler_name_hash (name), - INSERT); - gcc_assert (!*aslot); - *aslot = new_node; - } - } - if (call_duplication_hook) cgraph_call_node_duplication_hooks (n, new_node); return new_node; --- 1960,1965 ---- Index: cgraph.h =================================================================== *** cgraph.h (revision 186496) --- cgraph.h (working copy) *************** enum symtab_type *** 40,45 **** --- 40,46 ---- union symtab_node_def; typedef union symtab_node_def *symtab_node; + typedef const union symtab_node_def *const_symtab_node; /* Base of all entries in the symbol table. The symtab_node is inherited by cgraph and varpol nodes. */ *************** extern bool same_body_aliases_done; *** 499,513 **** void symtab_register_node (symtab_node); void symtab_unregister_node (symtab_node); void symtab_remove_node (symtab_node); /* In cgraph.c */ void dump_cgraph (FILE *); void debug_cgraph (void); void dump_cgraph_node (FILE *, struct cgraph_node *); void debug_cgraph_node (struct cgraph_node *); - void cgraph_insert_node_to_hashtable (struct cgraph_node *node); void cgraph_remove_edge (struct cgraph_edge *); void cgraph_remove_node (struct cgraph_node *); void cgraph_add_to_same_comdat_group (struct cgraph_node *, struct cgraph_node *); bool cgraph_remove_node_and_inline_clones (struct cgraph_node *, struct cgraph_node *); void cgraph_release_function_body (struct cgraph_node *); --- 500,517 ---- void symtab_register_node (symtab_node); void symtab_unregister_node (symtab_node); void symtab_remove_node (symtab_node); + symtab_node symtab_get_node (const_tree); + symtab_node symtab_node_for_asm (const_tree asmname); + void symtab_insert_node_to_hashtable (symtab_node); /* In cgraph.c */ void dump_cgraph (FILE *); void debug_cgraph (void); void dump_cgraph_node (FILE *, struct cgraph_node *); void debug_cgraph_node (struct cgraph_node *); void cgraph_remove_edge (struct cgraph_edge *); void cgraph_remove_node (struct cgraph_node *); + struct cgraph_node *cgraph_find_replacement_node (struct cgraph_node *); void cgraph_add_to_same_comdat_group (struct cgraph_node *, struct cgraph_node *); bool cgraph_remove_node_and_inline_clones (struct cgraph_node *, struct cgraph_node *); void cgraph_release_function_body (struct cgraph_node *); *************** struct cgraph_edge *cgraph_create_edge ( *** 518,524 **** struct cgraph_edge *cgraph_create_indirect_edge (struct cgraph_node *, gimple, int, gcov_type, int); struct cgraph_indirect_call_info *cgraph_allocate_init_indirect_info (void); - struct cgraph_node * cgraph_get_node (const_tree); struct cgraph_node * cgraph_create_node (tree); struct cgraph_node * cgraph_get_create_node (tree); struct cgraph_node * cgraph_same_body_alias (struct cgraph_node *, tree, tree); --- 522,527 ---- *************** void cgraph_make_node_local (struct cgra *** 697,703 **** bool cgraph_node_can_be_local_p (struct cgraph_node *); - struct varpool_node * varpool_get_node (const_tree decl); void varpool_remove_node (struct varpool_node *node); void varpool_finalize_named_section_flags (struct varpool_node *node); bool varpool_assemble_pending_decls (void); --- 700,705 ---- *************** static inline struct cgraph_node * *** 734,740 **** cgraph (symtab_node node) { gcc_checking_assert (!node || node->symbol.type == SYMTAB_FUNCTION); ! return &node->x_function; } /* Return varpool node for given symbol and check it is a variable. */ --- 736,742 ---- cgraph (symtab_node node) { gcc_checking_assert (!node || node->symbol.type == SYMTAB_FUNCTION); ! return (struct cgraph_node *)node; } /* Return varpool node for given symbol and check it is a variable. */ *************** static inline struct varpool_node * *** 742,750 **** varpool (symtab_node node) { gcc_checking_assert (!node || node->symbol.type == SYMTAB_VARIABLE); ! return &node->x_variable; } /* Return first reachable static variable with initializer. */ static inline struct varpool_node * --- 744,771 ---- varpool (symtab_node node) { gcc_checking_assert (!node || node->symbol.type == SYMTAB_VARIABLE); ! return (struct varpool_node *)node; } + /* Return callgraph node for given symbol and check it is a function. */ + static inline struct cgraph_node * + cgraph_get_node (const_tree decl) + { + gcc_checking_assert (TREE_CODE (decl) == FUNCTION_DECL); + return cgraph (symtab_get_node (decl)); + } + + /* Return varpool node for given symbol and check it is a function. */ + static inline struct varpool_node * + varpool_get_node (const_tree decl) + { + gcc_checking_assert (TREE_CODE (decl) == VAR_DECL); + return varpool (symtab_get_node (decl)); + } + + /* Walk all symbols. */ + #define FOR_EACH_SYMBOL(node) \ + for ((node) = symtab_nodes; (node); (node) = (node)->symbol.next) /* Return first reachable static variable with initializer. */ static inline struct varpool_node * Index: ipa-inline-transform.c =================================================================== *** ipa-inline-transform.c (revision 186491) --- ipa-inline-transform.c (working copy) *************** save_inline_function_body (struct cgraph *** 278,284 **** /* first_clone will be turned into real function. */ first_clone = node->clones; first_clone->symbol.decl = copy_node (node->symbol.decl); ! cgraph_insert_node_to_hashtable (first_clone); gcc_assert (first_clone == cgraph_get_node (first_clone->symbol.decl)); /* Now reshape the clone tree, so all other clones descends from --- 278,284 ---- /* first_clone will be turned into real function. */ first_clone = node->clones; first_clone->symbol.decl = copy_node (node->symbol.decl); ! symtab_insert_node_to_hashtable ((symtab_node) first_clone); gcc_assert (first_clone == cgraph_get_node (first_clone->symbol.decl)); /* Now reshape the clone tree, so all other clones descends from Index: symtab.c =================================================================== *** symtab.c (revision 186496) --- symtab.c (working copy) *************** along with GCC; see the file COPYING3. *** 25,31 **** --- 25,38 ---- #include "tree.h" #include "tree-inline.h" #include "hashtab.h" + #include "ggc.h" #include "cgraph.h" + #include "diagnostic.h" + + /* Hash table used to convert declarations into nodes. */ + static GTY((param_is (union symtab_node_def))) htab_t symtab_hash; + /* Hash table used to convert assembler names into nodes. */ + static GTY((param_is (union symtab_node_def))) htab_t assembler_name_hash; /* Linked list of symbol table nodes. */ symtab_node symtab_nodes; *************** symtab_node symtab_nodes; *** 35,65 **** --- 42,166 ---- them, to support -fno-toplevel-reorder. */ int symtab_order; + /* Returns a hash code for P. */ + + static hashval_t + hash_node (const void *p) + { + const_symtab_node n = (const_symtab_node ) p; + return (hashval_t) DECL_UID (n->symbol.decl); + } + + + /* Returns nonzero if P1 and P2 are equal. */ + + static int + eq_node (const void *p1, const void *p2) + { + const_symtab_node n1 = (const_symtab_node) p1; + const_symtab_node n2 = (const_symtab_node) p2; + return DECL_UID (n1->symbol.decl) == DECL_UID (n2->symbol.decl); + } + + /* Returns a hash code for P. */ + + static hashval_t + hash_node_by_assembler_name (const void *p) + { + const_symtab_node n = (const_symtab_node) p; + return (hashval_t) decl_assembler_name_hash (DECL_ASSEMBLER_NAME (n->symbol.decl)); + } + + /* Returns nonzero if P1 and P2 are equal. */ + + static int + eq_assembler_name (const void *p1, const void *p2) + { + const_symtab_node n1 = (const_symtab_node) p1; + const_tree name = (const_tree)p2; + return (decl_assembler_name_equal (n1->symbol.decl, name)); + } + + /* Add node into symbol table. This function is not used directly, but via cgraph/varpool node creation routines. */ void symtab_register_node (symtab_node node) { + struct symtab_node_base key; + symtab_node *slot; + node->symbol.next = symtab_nodes; node->symbol.previous = NULL; if (symtab_nodes) symtab_nodes->symbol.previous = node; symtab_nodes = node; + if (!symtab_hash) + symtab_hash = htab_create_ggc (10, hash_node, eq_node, NULL); + key.decl = node->symbol.decl; + slot = (symtab_node *) htab_find_slot (symtab_hash, &key, INSERT); + if (*slot == NULL) + *slot = node; + + if (assembler_name_hash) + { + void **aslot; + tree name = DECL_ASSEMBLER_NAME (node->symbol.decl); + + aslot = 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 (*aslot == NULL) + *aslot = node; + } + node->symbol.order = symtab_order++; ipa_empty_ref_list (&node->symbol.ref_list); } + /* Make NODE to be the one symtab hash is pointing to. Used when reshaping tree + of inline clones. */ + void + symtab_insert_node_to_hashtable (symtab_node node) + { + struct symtab_node_base key; + symtab_node *slot; + + if (!symtab_hash) + symtab_hash = htab_create_ggc (10, hash_node, eq_node, NULL); + key.decl = node->symbol.decl; + slot = (symtab_node *) htab_find_slot (symtab_hash, &key, INSERT); + *slot = node; + + if (assembler_name_hash) + { + void **aslot; + tree name = DECL_ASSEMBLER_NAME (node->symbol.decl); + + aslot = htab_find_slot_with_hash (assembler_name_hash, name, + decl_assembler_name_hash (name), + INSERT); + *aslot = node; + } + } + /* Remove node from symbol table. This function is not used directly, but via cgraph/varpool node removal routines. */ void symtab_unregister_node (symtab_node node) { + void **slot; ipa_remove_all_references (&node->symbol.ref_list); ipa_remove_all_refering (&node->symbol.ref_list); + symtab_node replacement_node = NULL; if (node->symbol.same_comdat_group) { *************** symtab_unregister_node (symtab_node node *** 83,88 **** --- 184,243 ---- node->symbol.next->symbol.previous = node->symbol.previous; node->symbol.next = NULL; node->symbol.previous = NULL; + + slot = htab_find_slot (symtab_hash, node, NO_INSERT); + if (*slot == node) + { + if (symtab_function_p (node)) + replacement_node = (symtab_node)cgraph_find_replacement_node (cgraph (node)); + if (!replacement_node) + htab_clear_slot (symtab_hash, slot); + else + *slot = replacement_node; + } + + if (assembler_name_hash) + { + tree name = DECL_ASSEMBLER_NAME (node->symbol.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) + { + if (!replacement_node) + htab_clear_slot (assembler_name_hash, slot); + else + *slot = replacement_node; + } + } + } + + /* Return symbol table node associated with DECL, if any, + and NULL otherwise. */ + + symtab_node + symtab_get_node (const_tree decl) + { + symtab_node *slot; + struct symtab_node_base key; + + gcc_checking_assert (TREE_CODE (decl) == FUNCTION_DECL + || (TREE_CODE (decl) == VAR_DECL + && (TREE_STATIC (decl) || DECL_EXTERNAL (decl) + || in_lto_p))); + + if (!symtab_hash) + return NULL; + + key.decl = CONST_CAST2 (tree, const_tree, decl); + + slot = (symtab_node *) htab_find_slot (symtab_hash, &key, + NO_INSERT); + + if (slot) + return *slot; + return NULL; } /* Remove symtab NODE from the symbol table. */ *************** symtab_remove_node (symtab_node node) *** 95,97 **** --- 250,341 ---- else if (symtab_variable_p (node)) varpool_remove_node (varpool (node)); } + + /* Return the cgraph node that has ASMNAME for its DECL_ASSEMBLER_NAME. + Return NULL if there's no such node. */ + + symtab_node + symtab_node_for_asm (const_tree asmname) + { + symtab_node node; + void **slot; + + if (!assembler_name_hash) + { + assembler_name_hash = + htab_create_ggc (10, hash_node_by_assembler_name, eq_assembler_name, + NULL); + FOR_EACH_SYMBOL (node) + if (!symtab_function_p (node) || !cgraph (node)->global.inlined_to) + { + tree name = DECL_ASSEMBLER_NAME (node->symbol.decl); + slot = htab_find_slot_with_hash (assembler_name_hash, name, + decl_assembler_name_hash (name), + INSERT); + gcc_checking_assert (node == symtab_get_node (node->symbol.decl)); + /* 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) + *slot = node; + } + } + + slot = htab_find_slot_with_hash (assembler_name_hash, asmname, + decl_assembler_name_hash (asmname), + NO_INSERT); + + if (slot) + { + node = (symtab_node) *slot; + return node; + } + return NULL; + } + + /* Set the DECL_ASSEMBLER_NAME and update symtab hashtables. */ + + void + change_decl_assembler_name (tree decl, tree name) + { + symtab_node node; + void **slot; + if (!DECL_ASSEMBLER_NAME_SET_P (decl)) + SET_DECL_ASSEMBLER_NAME (decl, name); + else + { + if (name == DECL_ASSEMBLER_NAME (decl)) + return; + + if (assembler_name_hash + && TREE_CODE (decl) == FUNCTION_DECL + && (node = symtab_get_node (decl)) != NULL) + { + tree old_name = DECL_ASSEMBLER_NAME (decl); + slot = htab_find_slot_with_hash (assembler_name_hash, old_name, + decl_assembler_name_hash (old_name), + NO_INSERT); + /* Inline clones are not hashed. */ + if (slot && *slot == node) + htab_clear_slot (assembler_name_hash, slot); + } + if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)) + && DECL_RTL_SET_P (decl)) + warning (0, "%D renamed after being referenced in assembly", decl); + + SET_DECL_ASSEMBLER_NAME (decl, name); + } + if (assembler_name_hash + && TREE_CODE (decl) == FUNCTION_DECL + && (node = symtab_get_node (decl)) != NULL) + { + slot = htab_find_slot_with_hash (assembler_name_hash, name, + decl_assembler_name_hash (name), + INSERT); + gcc_checking_assert (!*slot); + *slot = node; + } + } + + #include "gt-symtab.h" Index: Makefile.in =================================================================== *** Makefile.in (revision 186496) --- Makefile.in (working copy) *************** simplify-rtx.o : simplify-rtx.c $(CONFIG *** 2912,2918 **** $(TREE_H) $(TARGET_H) symtab.o : symtab.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ langhooks.h toplev.h $(DIAGNOSTIC_CORE_H) $(FLAGS_H) $(GGC_H) $(TARGET_H) $(CGRAPH_H) \ ! $(HASHTAB_H) cgraph.o : cgraph.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ langhooks.h toplev.h $(DIAGNOSTIC_CORE_H) $(FLAGS_H) $(GGC_H) $(TARGET_H) $(CGRAPH_H) \ gt-cgraph.h output.h intl.h $(BASIC_BLOCK_H) debug.h $(HASHTAB_H) \ --- 2912,2918 ---- $(TREE_H) $(TARGET_H) symtab.o : symtab.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ langhooks.h toplev.h $(DIAGNOSTIC_CORE_H) $(FLAGS_H) $(GGC_H) $(TARGET_H) $(CGRAPH_H) \ ! $(HASHTAB_H) gt-symtab.h cgraph.o : cgraph.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ langhooks.h toplev.h $(DIAGNOSTIC_CORE_H) $(FLAGS_H) $(GGC_H) $(TARGET_H) $(CGRAPH_H) \ gt-cgraph.h output.h intl.h $(BASIC_BLOCK_H) debug.h $(HASHTAB_H) \ *************** GTFILES = $(CPP_ID_DATA_H) $(srcdir)/inp *** 3690,3696 **** $(srcdir)/fixed-value.h \ $(srcdir)/output.h $(srcdir)/cfgloop.h \ $(srcdir)/cselib.h $(srcdir)/basic-block.h $(srcdir)/ipa-ref.h $(srcdir)/cgraph.h \ ! $(srcdir)/reload.h $(srcdir)/caller-save.c \ $(srcdir)/alias.c $(srcdir)/bitmap.c $(srcdir)/cselib.c $(srcdir)/cgraph.c \ $(srcdir)/ipa-prop.c $(srcdir)/ipa-cp.c $(srcdir)/matrix-reorg.c \ $(srcdir)/dbxout.c \ --- 3690,3696 ---- $(srcdir)/fixed-value.h \ $(srcdir)/output.h $(srcdir)/cfgloop.h \ $(srcdir)/cselib.h $(srcdir)/basic-block.h $(srcdir)/ipa-ref.h $(srcdir)/cgraph.h \ ! $(srcdir)/reload.h $(srcdir)/caller-save.c $(srcdir)/symtab.c \ $(srcdir)/alias.c $(srcdir)/bitmap.c $(srcdir)/cselib.c $(srcdir)/cgraph.c \ $(srcdir)/ipa-prop.c $(srcdir)/ipa-cp.c $(srcdir)/matrix-reorg.c \ $(srcdir)/dbxout.c \ Index: varpool.c =================================================================== *** varpool.c (revision 186496) --- varpool.c (working copy) *************** along with GCC; see the file COPYING3. *** 48,56 **** All variables supposed to be output into final file needs to be explicitly marked by frontend via VARPOOL_FINALIZE_DECL function. */ - /* Hash table used to convert declarations into nodes. */ - static GTY((param_is (union symtab_node_def))) htab_t varpool_hash; - /* Queue of cgraph nodes scheduled to be lowered and output. The queue is maintained via mark_needed_node, linked via node->next_needed pointer. --- 48,53 ---- *************** varpool_node_name (struct varpool_node * *** 84,149 **** return lang_hooks.decl_printable_name (node->symbol.decl, 2); } - /* Returns a hash code for P. */ - static hashval_t - hash_varpool_node (const void *p) - { - const struct varpool_node *n = (const struct varpool_node *) p; - return (hashval_t) DECL_UID (n->symbol.decl); - } - - /* Returns nonzero if P1 and P2 are equal. */ - static int - eq_varpool_node (const void *p1, const void *p2) - { - const struct varpool_node *n1 = - (const struct varpool_node *) p1; - const struct varpool_node *n2 = - (const struct varpool_node *) p2; - return DECL_UID (n1->symbol.decl) == DECL_UID (n2->symbol.decl); - } - - /* Return varpool node assigned to DECL without creating new one. */ - struct varpool_node * - varpool_get_node (const_tree decl) - { - struct varpool_node key, **slot; - - gcc_assert (TREE_CODE (decl) == VAR_DECL - && (TREE_STATIC (decl) || DECL_EXTERNAL (decl))); - - if (!varpool_hash) - return NULL; - key.symbol.decl = CONST_CAST2 (tree, const_tree, decl); - slot = (struct varpool_node **) - htab_find_slot (varpool_hash, &key, NO_INSERT); - if (!slot) - return NULL; - return *slot; - } - /* Return varpool node assigned to DECL. Create new one when needed. */ struct varpool_node * varpool_node (tree decl) { ! struct varpool_node key, *node, **slot; ! gcc_assert (TREE_CODE (decl) == VAR_DECL && (TREE_STATIC (decl) || DECL_EXTERNAL (decl) || in_lto_p)); - if (!varpool_hash) - varpool_hash = htab_create_ggc (10, hash_varpool_node, - eq_varpool_node, NULL); - key.symbol.decl = decl; - slot = (struct varpool_node **) - htab_find_slot (varpool_hash, &key, INSERT); - if (*slot) - return *slot; node = ggc_alloc_cleared_varpool_node (); node->symbol.type = SYMTAB_VARIABLE; node->symbol.decl = decl; symtab_register_node ((symtab_node)node); - *slot = node; return node; } --- 81,100 ---- return lang_hooks.decl_printable_name (node->symbol.decl, 2); } /* Return varpool node assigned to DECL. Create new one when needed. */ struct varpool_node * varpool_node (tree decl) { ! struct varpool_node *node = varpool_get_node (decl); gcc_assert (TREE_CODE (decl) == VAR_DECL && (TREE_STATIC (decl) || DECL_EXTERNAL (decl) || in_lto_p)); + if (node) + return node; node = ggc_alloc_cleared_varpool_node (); node->symbol.type = SYMTAB_VARIABLE; node->symbol.decl = decl; symtab_register_node ((symtab_node)node); return node; } *************** varpool_node (tree decl) *** 151,160 **** void varpool_remove_node (struct varpool_node *node) { - void **slot; - slot = htab_find_slot (varpool_hash, node, NO_INSERT); - gcc_assert (*slot == node); - htab_clear_slot (varpool_hash, slot); gcc_assert (!varpool_assembled_nodes_queue); symtab_unregister_node ((symtab_node)node); if (varpool_first_unanalyzed_node == node) --- 102,107 ---- *************** debug_varpool (void) *** 238,249 **** struct varpool_node * varpool_node_for_asm (tree asmname) { ! struct varpool_node *node; ! ! FOR_EACH_VARIABLE (node) ! if (decl_assembler_name_equal (node->symbol.decl, asmname)) ! return node; ! return NULL; } --- 185,193 ---- struct varpool_node * varpool_node_for_asm (tree asmname) { ! symtab_node node = symtab_node_for_asm (asmname); ! if (node && symtab_variable_p (node)) ! return varpool (node); return NULL; }