static void cgraph_reset_node (struct cgraph_node *node) { /* If node->output is set, then we have already begun whole-unit analysis. This is *not* testing for whether we've already emitted the function. That case can be sort-of legitimately seen with real function redefinition errors. I would argue that the front end should never present us with such a case, but don't enforce that for now. */ gcc_assert (!node->output); /* Reset our data structures so we can analyze the function again. */ memset (&node->local, 0, sizeof (node->local)); memset (&node->global, 0, sizeof (node->global)); memset (&node->rtl, 0, sizeof (node->rtl)); node->analyzed = false; node->local.redefined_extern_inline = true; node->local.finalized = false; cgraph_node_remove_callees (node); /* We may need to re-queue the node for assembling in case we already proceeded it and ignored as not needed or got a re-declaration in IMA mode. */ if (node->reachable) { struct cgraph_node *n; for (n = cgraph_nodes_queue; n; n = n->next_needed) if (n == node) break; if (!n) node->reachable = 0; } }
/* Return SSA names that are unused to GGC memory. This is used to keep footprint of compiler during interprocedural optimization. As a side effect the SSA_NAME_VERSION number reuse is reduced so this function should not be used too often. */ static unsigned int release_dead_ssa_names (void) { tree t, next; int n = 0; referenced_var_iterator rvi; /* Current defs point to various dead SSA names that in turn points to dead statements so bunch of dead memory is held from releasing. */ FOR_EACH_REFERENCED_VAR (t, rvi) set_current_def (t, NULL); /* Now release the freelist. */ for (t = FREE_SSANAMES (cfun); t; t = next) { next = TREE_CHAIN (t); /* Dangling pointers might make GGC to still see dead SSA names, so it is important to unlink the list and avoid GGC from seeing all subsequent SSA names. In longer run we want to have all dangling pointers here removed (since they usually go through dead statements that consume considerable amounts of memory). */ TREE_CHAIN (t) = NULL_TREE; n++; } FREE_SSANAMES (cfun) = NULL; /* Cgraph edges has been invalidated and point to dead statement. We need to remove them now and will rebuild it before next IPA pass. */ cgraph_node_remove_callees (cgraph_node (current_function_decl)); if (dump_file) fprintf (dump_file, "Released %i names, %.2f%%\n", n, n * 100.0 / num_ssa_names); return 0; }
static unsigned int remove_cgraph_callee_edges (void) { struct cgraph_node *node = cgraph_get_node (current_function_decl); cgraph_node_remove_callees (node); ipa_remove_all_references (&node->ref_list); return 0; }
unsigned int rebuild_cgraph_edges (void) { basic_block bb; struct cgraph_node *node = cgraph_get_node (current_function_decl); gimple_stmt_iterator gsi; cgraph_node_remove_callees (node); ipa_remove_all_references (&node->ref_list); node->count = ENTRY_BLOCK_PTR->count; FOR_EACH_BB (bb) { for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) { gimple stmt = gsi_stmt (gsi); tree decl; if (is_gimple_call (stmt)) { int freq = compute_call_stmt_bb_frequency (current_function_decl, bb); decl = gimple_call_fndecl (stmt); if (decl) cgraph_create_edge (node, cgraph_get_create_node (decl), stmt, bb->count, freq); else cgraph_create_indirect_edge (node, stmt, gimple_call_flags (stmt), bb->count, freq); } walk_stmt_load_store_addr_ops (stmt, node, mark_load, mark_store, mark_address); } for (gsi = gsi_start (phi_nodes (bb)); !gsi_end_p (gsi); gsi_next (&gsi)) walk_stmt_load_store_addr_ops (gsi_stmt (gsi), node, mark_load, mark_store, mark_address); } record_eh_tables (node, cfun); gcc_assert (!node->global.inlined_to); return 0; }
static unsigned int remove_cgraph_callee_edges (void) { cgraph_node_remove_callees (cgraph_get_node (current_function_decl)); return 0; }
bool cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file) { struct cgraph_node *first = (struct cgraph_node *) (void *) 1; struct cgraph_node *node, *next; bool changed = false; int insns = 0; #ifdef ENABLE_CHECKING verify_cgraph (); #endif if (file) fprintf (file, "\nReclaiming functions:"); #ifdef ENABLE_CHECKING for (node = cgraph_nodes; node; node = node->next) gcc_assert (!node->aux); #endif for (node = cgraph_nodes; node; node = node->next) if (node->needed && !node->global.inlined_to && ((!DECL_EXTERNAL (node->decl)) || !node->analyzed || before_inlining_p)) { node->aux = first; first = node; } else gcc_assert (!node->aux); /* Perform reachability analysis. As a special case do not consider extern inline functions not inlined as live because we won't output them at all. */ while (first != (void *) 1) { struct cgraph_edge *e; node = first; first = (struct cgraph_node *) first->aux; for (e = node->callees; e; e = e->next_callee) if (!e->callee->aux && node->analyzed && (!e->inline_failed || !e->callee->analyzed || (!DECL_EXTERNAL (e->callee->decl)) || before_inlining_p)) { e->callee->aux = first; first = e->callee; } } /* Remove unreachable nodes. Extern inline functions need special care; Unreachable extern inline functions shall be removed. Reachable extern inline functions we never inlined shall get their bodies eliminated. Reachable extern inline functions we sometimes inlined will be turned into unanalyzed nodes so they look like for true extern functions to the rest of code. Body of such functions is released via remove_node once the inline clones are eliminated. */ for (node = cgraph_nodes; node; node = next) { next = node->next; if (!node->aux) { int local_insns; tree decl = node->decl; node->global.inlined_to = NULL; if (DECL_STRUCT_FUNCTION (decl)) local_insns = node->local.self_insns; else local_insns = 0; if (file) fprintf (file, " %s", cgraph_node_name (node)); if (!node->analyzed || !DECL_EXTERNAL (node->decl) || before_inlining_p) cgraph_remove_node (node); else { struct cgraph_edge *e; for (e = node->callers; e; e = e->next_caller) if (e->caller->aux) break; if (e || node->needed) { struct cgraph_node *clone; for (clone = node->next_clone; clone; clone = clone->next_clone) if (clone->aux) break; if (!clone) { cgraph_release_function_body (node); node->analyzed = false; } cgraph_node_remove_callees (node); node->analyzed = false; node->local.inlinable = false; } else cgraph_remove_node (node); } if (!DECL_SAVED_TREE (decl)) insns += local_insns; changed = true; } } for (node = cgraph_nodes; node; node = node->next) node->aux = NULL; if (file) fprintf (file, "\nReclaimed %i insns", insns); #ifdef ENABLE_CHECKING verify_cgraph (); #endif return changed; }