-/**
- * Append all call nodes of the source environment to the nodes of in the destination
- * environment.
- *
- * @param dst destination environment
- * @param src source environment
- * @param loop_depth the loop depth of the call that is replaced by the src list
- */
-static void append_call_list(inline_irg_env *dst, inline_irg_env *src, int loop_depth)
-{
- call_entry *entry, *nentry;
-
- /* Note that the src list points to Call nodes in the inlined graph, but
- we need Call nodes in our graph. Luckily the inliner leaves this information
- in the link field. */
- list_for_each_entry(call_entry, entry, &src->calls, list) {
- nentry = duplicate_call_entry(entry, (ir_node*)get_irn_link(entry->call), loop_depth);
- list_add_tail(&nentry->list, &dst->calls);
- }
- dst->n_call_nodes += src->n_call_nodes;
- dst->n_nodes += src->n_nodes;
-}
-
-/*
- * Inlines small leave methods at call sites where the called address comes
- * from a Const node that references the entity representing the called
- * method.
- * The size argument is a rough measure for the code size of the method:
- * Methods where the obstack containing the firm graph is smaller than
- * size are inlined.
- */
-void inline_leave_functions(unsigned maxsize, unsigned leavesize,
- unsigned size, int ignore_runtime)
-{
- inline_irg_env *env;
- ir_graph *irg;
- size_t i, n_irgs;
- ir_graph *rem;
- int did_inline;
- wenv_t wenv;
- call_entry *entry, *next;
- const call_entry *centry;
- pmap *copied_graphs;
- pmap_entry *pm_entry;
-
- rem = current_ir_graph;
- obstack_init(&temp_obst);
-
- /* a map for the copied graphs, used to inline recursive calls */
- copied_graphs = pmap_create();
-
- /* extend all irgs by a temporary data structure for inlining. */
- n_irgs = get_irp_n_irgs();
- for (i = 0; i < n_irgs; ++i)
- set_irg_link(get_irp_irg(i), alloc_inline_irg_env());
-
- /* Pre-compute information in temporary data structure. */
- wenv.ignore_runtime = ignore_runtime;
- wenv.ignore_callers = 0;
- for (i = 0; i < n_irgs; ++i) {
- ir_graph *irg = get_irp_irg(i);
-
- assert(get_irg_phase_state(irg) != phase_building);
- free_callee_info(irg);
-
- assure_loopinfo(irg);
- wenv.x = (inline_irg_env*)get_irg_link(irg);
- irg_walk_graph(irg, NULL, collect_calls2, &wenv);
- }
-
- /* -- and now inline. -- */
-
- /* Inline leaves recursively -- we might construct new leaves. */
- do {
- did_inline = 0;
-
- for (i = 0; i < n_irgs; ++i) {
- ir_node *call;
- int phiproj_computed = 0;
-
- current_ir_graph = get_irp_irg(i);
- env = (inline_irg_env*)get_irg_link(current_ir_graph);
-
- ir_reserve_resources(current_ir_graph, IR_RESOURCE_IRN_LINK|IR_RESOURCE_PHI_LIST);
- list_for_each_entry_safe(call_entry, entry, next, &env->calls, list) {
- ir_graph *callee;
- irg_inline_property prop;
-
- if (env->n_nodes > maxsize)
- break;
-
- call = entry->call;
- callee = entry->callee;
-
- prop = get_irg_inline_property(callee);
- if (prop == irg_inline_forbidden) {
- continue;
- }
-
- if (is_leave(callee) && (
- is_smaller(callee, leavesize) || prop >= irg_inline_forced)) {
- if (!phiproj_computed) {
- phiproj_computed = 1;
- collect_phiprojs(current_ir_graph);
- }
- did_inline = inline_method(call, callee);
-
- if (did_inline) {
- inline_irg_env *callee_env = (inline_irg_env*)get_irg_link(callee);
-
- /* call was inlined, Phi/Projs for current graph must be recomputed */
- phiproj_computed = 0;
-
- /* Do some statistics */
- env->got_inline = 1;
- --env->n_call_nodes;
- env->n_nodes += callee_env->n_nodes;
- --callee_env->n_callers;
-
- /* remove this call from the list */
- list_del(&entry->list);
- continue;
- }
- }
- }
- ir_free_resources(current_ir_graph, IR_RESOURCE_IRN_LINK|IR_RESOURCE_PHI_LIST);
- }
- } while (did_inline);
-
- /* inline other small functions. */
- for (i = 0; i < n_irgs; ++i) {
- ir_node *call;
- int phiproj_computed = 0;
-
- current_ir_graph = get_irp_irg(i);
- env = (inline_irg_env*)get_irg_link(current_ir_graph);
-
- ir_reserve_resources(current_ir_graph, IR_RESOURCE_IRN_LINK|IR_RESOURCE_PHI_LIST);
-
- /* note that the list of possible calls is updated during the process */
- list_for_each_entry_safe(call_entry, entry, next, &env->calls, list) {
- irg_inline_property prop;
- ir_graph *callee;
- pmap_entry *e;
-
- call = entry->call;
- callee = entry->callee;
-
- prop = get_irg_inline_property(callee);
- if (prop == irg_inline_forbidden) {
- continue;
- }
-
- e = pmap_find(copied_graphs, callee);
- if (e != NULL) {
- /*
- * Remap callee if we have a copy.
- * FIXME: Should we do this only for recursive Calls ?
- */
- callee = (ir_graph*)e->value;
- }
-
- if (prop >= irg_inline_forced ||
- (is_smaller(callee, size) && env->n_nodes < maxsize) /* small function */) {
- if (current_ir_graph == callee) {
- /*
- * Recursive call: we cannot directly inline because we cannot walk
- * the graph and change it. So we have to make a copy of the graph
- * first.
- */
-
- inline_irg_env *callee_env;
- ir_graph *copy;
-
- ir_free_resources(current_ir_graph, IR_RESOURCE_IRN_LINK|IR_RESOURCE_PHI_LIST);
-
- /*
- * No copy yet, create one.
- * Note that recursive methods are never leaves, so it is sufficient
- * to test this condition here.
- */
- copy = create_irg_copy(callee);
-
- /* create_irg_copy() destroys the Proj links, recompute them */
- phiproj_computed = 0;
-
- ir_reserve_resources(current_ir_graph, IR_RESOURCE_IRN_LINK|IR_RESOURCE_PHI_LIST);
-
- /* allocate new environment */
- callee_env = alloc_inline_irg_env();
- set_irg_link(copy, callee_env);
-
- assure_loopinfo(copy);
- wenv.x = callee_env;
- wenv.ignore_callers = 1;
- irg_walk_graph(copy, NULL, collect_calls2, &wenv);
-
- /*
- * Enter the entity of the original graph. This is needed
- * for inline_method(). However, note that ent->irg still points
- * to callee, NOT to copy.
- */
- set_irg_entity(copy, get_irg_entity(callee));
-
- pmap_insert(copied_graphs, callee, copy);
- callee = copy;
-
- /* we have only one caller: the original graph */
- callee_env->n_callers = 1;
- callee_env->n_callers_orig = 1;
- }
- if (! phiproj_computed) {
- phiproj_computed = 1;
- collect_phiprojs(current_ir_graph);
- }
- did_inline = inline_method(call, callee);
- if (did_inline) {
- inline_irg_env *callee_env = (inline_irg_env *)get_irg_link(callee);
-
- /* call was inlined, Phi/Projs for current graph must be recomputed */
- phiproj_computed = 0;
-
- /* callee was inline. Append its call list. */
- env->got_inline = 1;
- --env->n_call_nodes;
- append_call_list(env, callee_env, entry->loop_depth);
- --callee_env->n_callers;
-
- /* after we have inlined callee, all called methods inside callee
- are now called once more */
- list_for_each_entry(call_entry, centry, &callee_env->calls, list) {
- inline_irg_env *penv = (inline_irg_env*)get_irg_link(centry->callee);
- ++penv->n_callers;
- }
-
- /* remove this call from the list */
- list_del(&entry->list);
- continue;
- }
- }
- }
- ir_free_resources(current_ir_graph, IR_RESOURCE_IRN_LINK|IR_RESOURCE_PHI_LIST);
- }
-
- for (i = 0; i < n_irgs; ++i) {
- irg = get_irp_irg(i);
- env = (inline_irg_env*)get_irg_link(irg);
-
- if (env->got_inline) {
- optimize_graph_df(irg);
- optimize_cf(irg);
- }
- if (env->got_inline || (env->n_callers_orig != env->n_callers)) {
- DB((dbg, LEVEL_1, "Nodes:%3d ->%3d, calls:%3d ->%3d, callers:%3d ->%3d, -- %s\n",
- env->n_nodes_orig, env->n_nodes, env->n_call_nodes_orig, env->n_call_nodes,
- env->n_callers_orig, env->n_callers,
- get_entity_name(get_irg_entity(irg))));
- }
- }
-
- /* kill the copied graphs: we don't need them anymore */
- foreach_pmap(copied_graphs, pm_entry) {
- ir_graph *copy = (ir_graph*)pm_entry->value;
-
- /* reset the entity, otherwise it will be deleted in the next step ... */
- set_irg_entity(copy, NULL);
- free_ir_graph(copy);
- }
- pmap_destroy(copied_graphs);
-
- obstack_free(&temp_obst, NULL);
- current_ir_graph = rem;
-}
-
-typedef struct inline_leave_functions_pass_t {
- ir_prog_pass_t pass;
- unsigned maxsize;
- unsigned leavesize;
- unsigned size;
- int ignore_runtime;
-} inline_leave_functions_pass_t;
-
-/**
- * Wrapper to run inline_leave_functions() as a ir_prog pass.
- */
-static int inline_leave_functions_wrapper(ir_prog *irp, void *context)
-{
- inline_leave_functions_pass_t *pass = (inline_leave_functions_pass_t*)context;
-
- (void)irp;
- inline_leave_functions(
- pass->maxsize, pass->leavesize,
- pass->size, pass->ignore_runtime);
- return 0;
-}
-
-/* create a pass for inline_leave_functions() */
-ir_prog_pass_t *inline_leave_functions_pass(
- const char *name, unsigned maxsize, unsigned leavesize,
- unsigned size, int ignore_runtime)
-{
- inline_leave_functions_pass_t *pass = XMALLOCZ(inline_leave_functions_pass_t);
-
- pass->maxsize = maxsize;
- pass->leavesize = leavesize;
- pass->size = size;
- pass->ignore_runtime = ignore_runtime;
-
- return def_prog_pass_constructor(
- &pass->pass,
- name ? name : "inline_leave_functions",
- inline_leave_functions_wrapper);
-}
-