+ 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 = 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;
+}
+
+/**
+ * Calculate the parameter weights for transmitting the address of a local variable.
+ */
+static unsigned calc_method_local_weight(ir_node *arg) {
+ int i, j, k;
+ unsigned v, weight = 0;
+
+ for (i = get_irn_n_outs(arg) - 1; i >= 0; --i) {
+ ir_node *succ = get_irn_out(arg, i);
+
+ switch (get_irn_opcode(succ)) {
+ case iro_Load:
+ case iro_Store:
+ /* Loads and Store can be removed */
+ weight += 3;
+ break;
+ case iro_Sel:
+ /* check if all args are constant */
+ for (j = get_Sel_n_indexs(succ) - 1; j >= 0; --j) {
+ ir_node *idx = get_Sel_index(succ, j);
+ if (! is_Const(idx))
+ return 0;
+ }
+ /* Check users on this Sel. Note: if a 0 is returned here, there was
+ some unsupported node. */
+ v = calc_method_local_weight(succ);
+ if (v == 0)
+ return 0;
+ /* we can kill one Sel with constant indexes, this is cheap */
+ weight += v + 1;
+ break;
+ case iro_Id:
+ /* when looking backward we might find Id nodes */
+ weight += calc_method_local_weight(succ);
+ break;
+ case iro_Tuple:
+ /* unoptimized tuple */
+ for (j = get_Tuple_n_preds(succ) - 1; j >= 0; --j) {
+ ir_node *pred = get_Tuple_pred(succ, j);
+ if (pred == arg) {
+ /* look for Proj(j) */
+ for (k = get_irn_n_outs(succ) - 1; k >= 0; --k) {
+ ir_node *succ_succ = get_irn_out(succ, k);
+ if (is_Proj(succ_succ)) {
+ if (get_Proj_proj(succ_succ) == j) {
+ /* found */
+ weight += calc_method_local_weight(succ_succ);
+ }
+ } else {
+ /* this should NOT happen */
+ return 0;
+ }
+ }
+ }
+ }
+ break;
+ default:
+ /* any other node: unsupported yet or bad. */
+ return 0;
+ }
+ }
+ return weight;
+}
+
+/**
+ * Calculate the parameter weights for transmitting the address of a local variable.
+ */
+static void analyze_irg_local_weights(inline_irg_env *env, ir_graph *irg) {
+ ir_entity *ent = get_irg_entity(irg);
+ ir_type *mtp;
+ int nparams, i, proj_nr;
+ ir_node *irg_args, *arg;
+
+ mtp = get_entity_type(ent);
+ nparams = get_method_n_params(mtp);
+
+ /* allocate a new array. currently used as 'analysed' flag */
+ env->local_weights = NEW_ARR_D(unsigned, &temp_obst, nparams);
+
+ /* If the method haven't parameters we have nothing to do. */
+ if (nparams <= 0)
+ return;
+
+ assure_irg_outs(irg);
+ irg_args = get_irg_args(irg);
+ for (i = get_irn_n_outs(irg_args) - 1; i >= 0; --i) {
+ arg = get_irn_out(irg_args, i);
+ proj_nr = get_Proj_proj(arg);
+ env->local_weights[proj_nr] = calc_method_local_weight(arg);
+ }
+}
+
+/**
+ * Calculate the benefice for transmitting an local variable address.
+ * After inlining, the local variable might be transformed into a
+ * SSA variable by scalar_replacement().
+ */
+static unsigned get_method_local_adress_weight(ir_graph *callee, int pos) {
+ inline_irg_env *env = get_irg_link(callee);
+
+ if (env->local_weights != NULL) {
+ if (pos < ARR_LEN(env->local_weights))
+ return env->local_weights[pos];
+ return 0;
+ }
+
+ analyze_irg_local_weights(env, callee);
+
+ if (pos < ARR_LEN(env->local_weights))
+ return env->local_weights[pos];
+ return 0;
+}
+
+/**
+ * calculate a benefice value for inlining the given call.
+ */
+static int calc_inline_benefice(ir_node *call, ir_graph *callee, unsigned *local_adr) {
+ ir_entity *ent = get_irg_entity(callee);
+ ir_node *frame_ptr;
+ ir_type *mtp;
+ int weight = 0;
+ int i, n_params, all_const;
+ unsigned cc, v;
+
+ inline_irg_env *curr_env, *callee_env;
+
+ if (get_entity_additional_properties(ent) & mtp_property_noreturn) {
+ /* do NOT inline noreturn calls */
+ return INT_MIN;
+ }
+
+ /* costs for every passed parameter */
+ n_params = get_Call_n_params(call);
+ mtp = get_entity_type(ent);
+ cc = get_method_calling_convention(mtp);
+ if (cc & cc_reg_param) {
+ /* register parameter, smaller costs for register parameters */
+ int max_regs = cc & ~cc_bits;
+
+ if (max_regs < n_params)
+ weight += max_regs * 2 + (n_params - max_regs) * 5;
+ else
+ weight += n_params * 2;
+ } else {
+ /* parameters are passed an stack */
+ weight += 5 * n_params;
+ }
+
+ /* constant parameters improve the benefice */
+ frame_ptr = get_irg_frame(current_ir_graph);
+ all_const = 1;
+ for (i = 0; i < n_params; ++i) {
+ ir_node *param = get_Call_param(call, i);
+
+ if (is_Const(param))
+ weight += get_method_param_weight(ent, i);
+ else {
+ all_const = 0;
+ if (is_SymConst(param))
+ weight += get_method_param_weight(ent, i);
+ else if (is_Sel(param) && get_Sel_ptr(param) == frame_ptr) {
+ /*
+ * An address of a local variable is transmitted. After inlining,
+ * scalar_replacement might be able to remove the local variable,
+ * so honor this.
+ */
+ v = get_method_local_adress_weight(callee, i);
+ weight += v;
+ if (v > 0)
+ *local_adr = 1;
+ }
+ }
+ }
+
+ callee_env = get_irg_link(callee);
+ if (get_entity_visibility(ent) == visibility_local &&
+ callee_env->n_callers_orig == 1 &&
+ callee != current_ir_graph) {
+ /* we are the only caller, give big bonus */
+ weight += 5000;
+ }
+
+ /* do not inline big functions */
+ weight -= callee_env->n_nodes;
+
+ /* reduce the benefice if the current function is already big */
+ curr_env = get_irg_link(current_ir_graph);
+ weight -= curr_env->n_nodes / 50;
+
+ /* give a bonus for functions with one block */
+ if (callee_env->n_blocks == 1)
+ weight = weight * 3 / 2;
+
+ /* and one for small non-recursive functions: we want them to be inlined in mostly every case */
+ else if (callee_env->n_nodes < 20 && !callee_env->recursive)
+ weight += 5000;
+
+ /* and finally for leaves: they do not increase the register pressure
+ because of callee safe registers */
+ else if (callee_env->n_call_nodes == 0)
+ weight += 25;
+
+ /*
+ * Reduce the weight for recursive function IFF not all arguments are const.
+ * inlining recursive functions is rarely good.
+ */
+ if (callee_env->recursive && !all_const)
+ weight -= 500;
+
+ /*
+ * All arguments constant is probably a good sign, give an extra bonus
+ */
+ if (all_const)
+ weight += 100;
+
+ return weight;
+}