+ * Try to inline calls into a graph.
+ *
+ * @param irg the graph into which we inline
+ * @param maxsize do NOT inline if the size of irg gets
+ * bigger than this amount
+ * @param inline_threshold
+ * threshold value for inline decision
+ * @param copied_graphs
+ * map containing copied of recursive graphs
+ */
+static void inline_into(ir_graph *irg, unsigned maxsize,
+ int inline_threshold, pmap *copied_graphs)
+{
+ int phiproj_computed = 0;
+ inline_irg_env *env = get_irg_link(irg);
+ call_entry *curr_call;
+ wenv_t wenv;
+ pqueue_t *pqueue;
+
+ if (env->n_call_nodes == 0)
+ return;
+
+ if (env->n_nodes > maxsize) {
+ DB((dbg, LEVEL_2, "%+F: too big (%d)\n", irg, env->n_nodes));
+ return;
+ }
+
+ current_ir_graph = irg;
+
+ /* put irgs into the pqueue */
+ pqueue = new_pqueue();
+
+ list_for_each_entry(call_entry, curr_call, &env->calls, list) {
+ assert(is_Call(curr_call->call));
+ maybe_push_call(pqueue, curr_call, inline_threshold);
+ }
+
+ /* note that the list of possible calls is updated during the process */
+ while (!pqueue_empty(pqueue)) {
+ int did_inline;
+ call_entry *curr_call = pqueue_pop_front(pqueue);
+ ir_graph *callee = curr_call->callee;
+ ir_node *call_node = curr_call->call;
+ inline_irg_env *callee_env = get_irg_link(callee);
+ irg_inline_property prop = get_irg_inline_property(callee);
+ int loop_depth;
+ const call_entry *centry;
+ pmap_entry *e;
+
+ if ((prop < irg_inline_forced) && env->n_nodes + callee_env->n_nodes > maxsize) {
+ DB((dbg, LEVEL_2, "%+F: too big (%d) + %+F (%d)\n", irg,
+ env->n_nodes, callee, callee_env->n_nodes));
+ continue;
+ }
+
+ e = pmap_find(copied_graphs, callee);
+ if (e != NULL) {
+ int benefice = curr_call->benefice;
+ /*
+ * Reduce the weight for recursive function IFF not all arguments are const.
+ * inlining recursive functions is rarely good.
+ */
+ if (!curr_call->all_const)
+ benefice -= 2000;
+ if (benefice < inline_threshold)
+ continue;
+
+ /*
+ * Remap callee if we have a copy.
+ */
+ callee = e->value;
+ callee_env = get_irg_link(callee);
+ }
+
+ 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.
+ */
+ int benefice = curr_call->benefice;
+ ir_graph *copy;
+
+ /*
+ * Reduce the weight for recursive function IFF not all arguments are const.
+ * inlining recursive functions is rarely good.
+ */
+ if (!curr_call->all_const)
+ benefice -= 2000;
+ if (benefice < inline_threshold)
+ continue;
+
+ /*
+ * 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;
+
+ /* allocate a new environment */
+ callee_env = alloc_inline_irg_env();
+ set_irg_link(copy, callee_env);
+
+ assure_cf_loop(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_node, callee);
+ if (!did_inline)
+ continue;
+
+ /* call was inlined, Phi/Projs for current graph must be recomputed */
+ phiproj_computed = 0;
+
+ /* remove it from the caller list */
+ list_del(&curr_call->list);
+
+ /* callee was inline. Append it's call list. */
+ env->got_inline = 1;
+ if (curr_call->local_adr)
+ env->local_vars = 1;
+ --env->n_call_nodes;
+
+ /* we just generate a bunch of new calls */
+ loop_depth = curr_call->loop_depth;
+ list_for_each_entry(call_entry, centry, &callee_env->calls, list) {
+ inline_irg_env *penv = get_irg_link(centry->callee);
+ ir_node *new_call;
+ call_entry *new_entry;
+
+ /* after we have inlined callee, all called methods inside
+ * callee are now called once more */
+ ++penv->n_callers;
+
+ /* 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. */
+ new_call = get_irn_link(centry->call);
+ assert(is_Call(new_call));
+
+ new_entry = duplicate_call_entry(centry, new_call, loop_depth);
+ list_add_tail(&new_entry->list, &env->calls);
+ maybe_push_call(pqueue, new_entry, inline_threshold);
+ }
+
+ env->n_call_nodes += callee_env->n_call_nodes;
+ env->n_nodes += callee_env->n_nodes;
+ --callee_env->n_callers;
+ }
+
+ del_pqueue(pqueue);
+}
+
+/*
+ * Heuristic inliner. Calculates a benefice value for every call and inlines