static void varpool_remove_unreferenced_decls (void) { varpool_node *next, *node; varpool_node *first = (varpool_node *)(void *)1; int i; struct ipa_ref *ref; struct pointer_set_t *referenced = pointer_set_create (); if (seen_error ()) return; if (cgraph_dump_file) fprintf (cgraph_dump_file, "Trivially needed variables:"); FOR_EACH_DEFINED_VARIABLE (node) { if (node->analyzed && (!varpool_can_remove_if_no_refs (node) /* We just expanded all function bodies. See if any of them needed the variable. */ || DECL_RTL_SET_P (node->decl))) { enqueue_node (node, &first); if (cgraph_dump_file) fprintf (cgraph_dump_file, " %s", node->asm_name ()); } } while (first != (varpool_node *)(void *)1) { node = first; first = (varpool_node *)first->aux; if (node->same_comdat_group) { symtab_node *next; for (next = node->same_comdat_group; next != node; next = next->same_comdat_group) { varpool_node *vnext = dyn_cast <varpool_node *> (next); if (vnext && vnext->analyzed && !symtab_comdat_local_p (next)) enqueue_node (vnext, &first); } } for (i = 0; ipa_ref_list_reference_iterate (&node->ref_list, i, ref); i++) { varpool_node *vnode = dyn_cast <varpool_node *> (ref->referred); if (vnode && !vnode->in_other_partition && (!DECL_EXTERNAL (ref->referred->decl) || vnode->alias) && vnode->analyzed) enqueue_node (vnode, &first); else pointer_set_insert (referenced, node); } } if (cgraph_dump_file) fprintf (cgraph_dump_file, "\nRemoving variables:"); for (node = varpool_first_defined_variable (); node; node = next) { next = varpool_next_defined_variable (node); if (!node->aux) { if (cgraph_dump_file) fprintf (cgraph_dump_file, " %s", node->asm_name ()); if (pointer_set_contains (referenced, node)) varpool_remove_initializer (node); else varpool_remove_node (node); } } pointer_set_destroy (referenced); if (cgraph_dump_file) fprintf (cgraph_dump_file, "\n"); }
bool inline_call (struct cgraph_edge *e, bool update_original, vec<cgraph_edge_p> *new_edges, int *overall_size, bool update_overall_summary, bool *callee_removed) { int old_size = 0, new_size = 0; struct cgraph_node *to = NULL; struct cgraph_edge *curr = e; struct cgraph_node *callee = cgraph_function_or_thunk_node (e->callee, NULL); bool new_edges_found = false; #ifdef ENABLE_CHECKING int estimated_growth = estimate_edge_growth (e); bool predicated = inline_edge_summary (e)->predicate != NULL; #endif speculation_removed = false; /* Don't inline inlined edges. */ gcc_assert (e->inline_failed); /* Don't even think of inlining inline clone. */ gcc_assert (!callee->global.inlined_to); e->inline_failed = CIF_OK; DECL_POSSIBLY_INLINED (callee->decl) = true; to = e->caller; if (to->global.inlined_to) to = to->global.inlined_to; /* If aliases are involved, redirect edge to the actual destination and possibly remove the aliases. */ if (e->callee != callee) { struct cgraph_node *alias = e->callee, *next_alias; cgraph_redirect_edge_callee (e, callee); while (alias && alias != callee) { if (!alias->callers && can_remove_node_now_p (alias, e)) { next_alias = cgraph_alias_target (alias); cgraph_remove_node (alias); if (callee_removed) *callee_removed = true; alias = next_alias; } else break; } } clone_inlined_nodes (e, true, update_original, overall_size, e->frequency); gcc_assert (curr->callee->global.inlined_to == to); old_size = inline_summary (to)->size; inline_merge_summary (e); if (optimize) new_edges_found = ipa_propagate_indirect_call_infos (curr, new_edges); if (update_overall_summary) inline_update_overall_summary (to); new_size = inline_summary (to)->size; if (callee->calls_comdat_local) to->calls_comdat_local = true; else if (to->calls_comdat_local && symtab_comdat_local_p (callee)) { struct cgraph_edge *se = to->callees; for (; se; se = se->next_callee) if (se->inline_failed && symtab_comdat_local_p (se->callee)) break; if (se == NULL) to->calls_comdat_local = false; } #ifdef ENABLE_CHECKING /* Verify that estimated growth match real growth. Allow off-by-one error due to INLINE_SIZE_SCALE roudoff errors. */ gcc_assert (!update_overall_summary || !overall_size || new_edges_found || abs (estimated_growth - (new_size - old_size)) <= 1 || speculation_removed /* FIXME: a hack. Edges with false predicate are accounted wrong, we should remove them from callgraph. */ || predicated); #endif /* Account the change of overall unit size; external functions will be removed and are thus not accounted. */ if (overall_size && !DECL_EXTERNAL (to->decl)) *overall_size += new_size - old_size; ncalls_inlined++; /* This must happen after inline_merge_summary that rely on jump functions of callee to not be updated. */ return new_edges_found; }
DEBUG_FUNCTION bool verify_symtab_base (symtab_node *node) { bool error_found = false; symtab_node *hashed_node; if (is_a <cgraph_node> (node)) { if (TREE_CODE (node->decl) != FUNCTION_DECL) { error ("function symbol is not function"); error_found = true; } } else if (is_a <varpool_node> (node)) { if (TREE_CODE (node->decl) != VAR_DECL) { error ("variable symbol is not variable"); error_found = true; } } else { error ("node has unknown type"); error_found = true; } if (cgraph_state != CGRAPH_LTO_STREAMING) { hashed_node = symtab_get_node (node->decl); if (!hashed_node) { error ("node not found in symtab decl hashtable"); error_found = true; } if (hashed_node != node && (!is_a <cgraph_node> (node) || !dyn_cast <cgraph_node> (node)->clone_of || dyn_cast <cgraph_node> (node)->clone_of->decl != node->decl)) { error ("node differs from symtab decl hashtable"); error_found = true; } } if (assembler_name_hash) { hashed_node = symtab_node_for_asm (DECL_ASSEMBLER_NAME (node->decl)); if (hashed_node && hashed_node->previous_sharing_asm_name) { error ("assembler name hash list corrupted"); error_found = true; } while (hashed_node) { if (hashed_node == node) break; hashed_node = hashed_node->next_sharing_asm_name; } if (!hashed_node && !(is_a <varpool_node> (node) || DECL_HARD_REGISTER (node->decl))) { error ("node not found in symtab assembler name hash"); error_found = true; } } if (node->previous_sharing_asm_name && node->previous_sharing_asm_name->next_sharing_asm_name != node) { error ("double linked list of assembler names corrupted"); error_found = true; } if (node->analyzed && !node->definition) { error ("node is analyzed byt it is not a definition"); error_found = true; } if (node->cpp_implicit_alias && !node->alias) { error ("node is alias but not implicit alias"); error_found = true; } if (node->alias && !node->definition && !node->weakref) { error ("node is alias but not definition"); error_found = true; } if (node->weakref && !node->alias) { error ("node is weakref but not an alias"); error_found = true; } if (node->same_comdat_group) { symtab_node *n = node->same_comdat_group; if (!DECL_ONE_ONLY (n->decl)) { error ("non-DECL_ONE_ONLY node in a same_comdat_group list"); error_found = true; } if (n->type != node->type) { error ("mixing different types of symbol in same comdat groups is not supported"); error_found = true; } if (n == node) { error ("node is alone in a comdat group"); error_found = true; } do { if (!n->same_comdat_group) { error ("same_comdat_group is not a circular list"); error_found = true; break; } n = n->same_comdat_group; } while (n != node); if (symtab_comdat_local_p (node)) { struct ipa_ref_list *refs = &node->ref_list; struct ipa_ref *ref; for (int i = 0; ipa_ref_list_referring_iterate (refs, i, ref); ++i) { if (!symtab_in_same_comdat_p (ref->referring, node)) { error ("comdat-local symbol referred to by %s outside its " "comdat", identifier_to_locale (ref->referring->name())); error_found = true; } } } } return error_found; }