static void searchc (struct searchc_env* env, struct cgraph_node *v, bool (*ignore_edge) (struct cgraph_edge *)) { struct cgraph_edge *edge; struct ipa_dfs_info *v_info = (struct ipa_dfs_info *) v->aux; /* mark node as old */ v_info->new_node = false; splay_tree_remove (env->nodes_marked_new, v->uid); v_info->dfn_number = env->count; v_info->low_link = env->count; env->count++; env->stack[(env->stack_size)++] = v; v_info->on_stack = true; for (edge = v->callees; edge; edge = edge->next_callee) { struct ipa_dfs_info * w_info; enum availability avail; struct cgraph_node *w = cgraph_function_or_thunk_node (edge->callee, &avail); if (!w || (ignore_edge && ignore_edge (edge))) continue; if (w->aux && (avail > AVAIL_OVERWRITABLE || (env->allow_overwritable && avail == AVAIL_OVERWRITABLE))) { w_info = (struct ipa_dfs_info *) w->aux; if (w_info->new_node) { searchc (env, w, ignore_edge); v_info->low_link = (v_info->low_link < w_info->low_link) ? v_info->low_link : w_info->low_link; } else if ((w_info->dfn_number < v_info->dfn_number) && (w_info->on_stack)) v_info->low_link = (w_info->dfn_number < v_info->low_link) ? w_info->dfn_number : v_info->low_link; } } if (v_info->low_link == v_info->dfn_number) { struct cgraph_node *last = NULL; struct cgraph_node *x; struct ipa_dfs_info *x_info; do { x = env->stack[--(env->stack_size)]; x_info = (struct ipa_dfs_info *) x->aux; x_info->on_stack = false; x_info->scc_no = v_info->dfn_number; if (env->reduce) { x_info->next_cycle = last; last = x; } else env->result[env->order_pos++] = x; } while (v != x); if (env->reduce) env->result[env->order_pos++] = v; } }
bool inline_call (struct cgraph_edge *e, bool update_original, vec<cgraph_edge_p> *new_edges, int *overall_size, bool update_overall_summary) { 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 /* 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->symbol.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); alias = next_alias; } else break; } } clone_inlined_nodes (e, true, update_original, overall_size); 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; #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 /* 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->symbol.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; }
/* Mark edge E as inlined and update callgraph accordingly. UPDATE_ORIGINAL specify whether profile of original function should be updated. If any new indirect edges are discovered in the process, add them to NEW_EDGES, unless it is NULL. Return true iff any new callgraph edges were discovered as a result of inlining. */ bool inline_call (struct cgraph_edge *e, bool update_original, VEC (cgraph_edge_p, heap) **new_edges, int *overall_size) { 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); /* 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->symbol.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. */