condeval is called jump threading now
[libfirm] / ir / opt / opt_inline.c
index 00e6036..59e10ed 100644 (file)
@@ -23,9 +23,7 @@
  * @author   Michael Beck, Goetz Lindenmaier
  * @version  $Id$
  */
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
+#include "config.h"
 
 #include <limits.h>
 #include <assert.h>
@@ -94,7 +92,7 @@ DEBUG_ONLY(static firm_dbg_module_t *dbg;)
  * accesses.  This function is called for all Phi and Block nodes
  * in a Block.
  */
-static INLINE int
+static inline int
 compute_new_arity(ir_node *b) {
        int i, res, irn_arity;
        int irg_v, block_v;
@@ -166,15 +164,10 @@ static void copy_node(ir_node *n, void *env) {
        }
        copy_node_attr(n, nn);
 
-#ifdef DEBUG_libfirm
-       {
-               int copy_node_nr = env != NULL;
-               if (copy_node_nr) {
-                       /* for easier debugging, we want to copy the node numbers too */
-                       nn->node_nr = n->node_nr;
-               }
+       if (env != NULL) {
+               /* for easier debugging, we want to copy the node numbers too */
+               nn->node_nr = n->node_nr;
        }
-#endif
 
        set_new_node(n, nn);
        hook_dead_node_elim_subst(current_ir_graph, n, nn);
@@ -223,9 +216,10 @@ static void copy_preds(ir_node *n, void *env) {
                   in array contained Bads.  Now it's possible.
                   We don't call optimize_in_place as it requires
                   that the fields in ir_graph are set properly. */
-               if ((get_opt_control_flow_straightening()) &&
-                       (get_Block_n_cfgpreds(nn) == 1) &&
-                       is_Jmp(get_Block_cfgpred(nn, 0))) {
+               if (!has_Block_entity(nn) &&
+                   get_opt_control_flow_straightening() &&
+                   get_Block_n_cfgpreds(nn) == 1 &&
+                   is_Jmp(get_Block_cfgpred(nn, 0))) {
                        ir_node *old = get_nodes_block(get_Block_cfgpred(nn, 0));
                        if (nn == old) {
                                /* Jmp jumps into the block it is in -- deal self cycle. */
@@ -472,7 +466,7 @@ void dead_node_elimination(ir_graph *irg) {
        graveyard_obst = irg->obst;
 
        /* A new obstack, where the reachable nodes will be copied to. */
-       rebirth_obst = xmalloc(sizeof(*rebirth_obst));
+       rebirth_obst = XMALLOC(struct obstack);
        irg->obst = rebirth_obst;
        obstack_init(irg->obst);
        irg->last_node_idx = 0;
@@ -663,7 +657,7 @@ static void dead_node_subst_hook(void *context, ir_graph *irg, ir_node *old, ir_
  * Make a new Survive DCE environment.
  */
 survive_dce_t *new_survive_dce(void) {
-       survive_dce_t *res = xmalloc(sizeof(res[0]));
+       survive_dce_t *res = XMALLOC(survive_dce_t);
        obstack_init(&res->obst);
        res->places     = pmap_create();
        res->new_places = NULL;
@@ -676,10 +670,6 @@ survive_dce_t *new_survive_dce(void) {
        res->dead_node_elim_subst.context = res;
        res->dead_node_elim_subst.next    = NULL;
 
-#ifndef FIRM_ENABLE_HOOKS
-       assert(0 && "need hooks enabled");
-#endif
-
        register_hook(hook_dead_node_elim, &res->dead_node_elim);
        register_hook(hook_dead_node_elim_subst, &res->dead_node_elim_subst);
        return res;
@@ -736,14 +726,15 @@ static void copy_node_inline(ir_node *n, void *env) {
 
        copy_node(n, NULL);
        if (is_Sel(n)) {
-               nn = get_new_node (n);
+               nn = get_new_node(n);
                assert(is_Sel(nn));
+               /* use copied entities from the new frame */
                if (get_entity_owner(get_Sel_entity(n)) == frame_tp) {
                        set_Sel_entity(nn, get_entity_link(get_Sel_entity(n)));
                }
        } else if (is_Block(n)) {
-               nn = get_new_node (n);
-               nn->attr.block.irg = current_ir_graph;
+               nn = get_new_node(n);
+               nn->attr.block.irg.irg = current_ir_graph;
        }
 }
 
@@ -773,10 +764,16 @@ static void copy_preds_inline(ir_node *n, void *env) {
  */
 static void find_addr(ir_node *node, void *env) {
        int *allow_inline = env;
-       if (is_Proj(node) &&
-                       is_Start(get_Proj_pred(node)) &&
-                       get_Proj_proj(node) == pn_Start_P_value_arg_base) {
-               *allow_inline = 0;
+       if (is_Sel(node)) {
+               ir_graph *irg = current_ir_graph;
+               if (get_Sel_ptr(node) == get_irg_frame(irg)) {
+                       /* access to frame */
+                       ir_entity *ent = get_Sel_entity(node);
+                       if (get_entity_owner(ent) != get_irg_frame_type(irg)) {
+                               /* access to value_type */
+                               *allow_inline = 0;
+                       }
+               }
        } else if (is_Alloc(node) && get_Alloc_where(node) == stack_alloc) {
                /* From GCC:
                 * Refuse to inline alloca call unless user explicitly forced so as this
@@ -865,19 +862,22 @@ int inline_method(ir_node *call, ir_graph *called_graph) {
 
        mtp = get_entity_type(ent);
        ctp = get_Call_type(call);
-       if (get_method_n_params(mtp) > get_method_n_params(ctp)) {
-               /* this is a bad feature of C: without a prototype, we can can call a function with less
-               parameters than needed. Currently we don't support this, although it would be
-               to use Unknown than. */
+       n_params = get_method_n_params(mtp);
+       n_res    = get_method_n_ress(mtp);
+       if (n_params > get_method_n_params(ctp)) {
+               /* this is a bad feature of C: without a prototype, we can
+                * call a function with less parameters than needed. Currently
+                * we don't support this, although we could use Unknown than. */
+               return 0;
+       }
+       if (n_res != get_method_n_ress(ctp)) {
                return 0;
        }
 
        /* Argh, compiling C has some bad consequences:
-          the call type AND the method type might be different.
-          It is implementation defendant what happens in that case.
-          We support inlining, if the bitsize of the types matches AND
-          the same arithmetic is used. */
-       n_params = get_method_n_params(mtp);
+        * It is implementation dependent what happens in that case.
+        * We support inlining, if the bitsize of the types matches AND
+        * the same arithmetic is used. */
        for (i = n_params - 1; i >= 0; --i) {
                ir_type *param_tp = get_method_param_type(mtp, i);
                ir_type *arg_tp   = get_method_param_type(ctp, i);
@@ -895,6 +895,22 @@ int inline_method(ir_node *call, ir_graph *called_graph) {
                        /* otherwise we can simply "reinterpret" the bits */
                }
        }
+       for (i = n_res - 1; i >= 0; --i) {
+               ir_type *decl_res_tp = get_method_res_type(mtp, i);
+               ir_type *used_res_tp = get_method_res_type(ctp, i);
+
+               if (decl_res_tp != used_res_tp) {
+                       ir_mode *decl_mode = get_type_mode(decl_res_tp);
+                       ir_mode *used_mode = get_type_mode(used_res_tp);
+                       if (decl_mode == NULL || used_mode == NULL)
+                               return 0;
+                       if (get_mode_size_bits(decl_mode) != get_mode_size_bits(used_mode))
+                               return 0;
+                       if (get_mode_arithmetic(decl_mode) != get_mode_arithmetic(used_mode))
+                               return 0;
+                       /* otherwise we can "reinterpret" the bits */
+               }
+       }
 
        irg = get_irn_irg(call);
 
@@ -931,6 +947,7 @@ int inline_method(ir_node *call, ir_graph *called_graph) {
        set_irg_doms_inconsistent(irg);
        set_irg_loopinfo_inconsistent(irg);
        set_irg_callee_info_state(irg, irg_callee_info_inconsistent);
+       set_irg_entity_usage_state(irg, ir_entity_usage_not_computed);
 
        /* -- Check preconditions -- */
        assert(is_Call(call));
@@ -966,7 +983,7 @@ int inline_method(ir_node *call, ir_graph *called_graph) {
                ir_mode *mode     = get_type_mode(param_tp);
 
                if (mode != get_irn_mode(arg)) {
-                       arg = new_r_Conv(irg, block, arg, mode);
+                       arg = new_r_Conv(block, arg, mode);
                }
                args_in[i] = arg;
        }
@@ -983,9 +1000,7 @@ int inline_method(ir_node *call, ir_graph *called_graph) {
        in[pn_Start_P_frame_base]     = get_irg_frame(irg);
        in[pn_Start_P_tls]            = get_irg_tls(irg);
        in[pn_Start_T_args]           = new_Tuple(n_params, args_in);
-       /* in[pn_Start_P_value_arg_base] = ??? */
-       assert(pn_Start_P_value_arg_base == pn_Start_max - 1 && "pn_Start_P_value_arg_base not supported, fix");
-       pre_call = new_Tuple(pn_Start_max - 1, in);
+       pre_call = new_Tuple(pn_Start_max, in);
        post_call = call;
 
        /* --
@@ -1023,6 +1038,7 @@ int inline_method(ir_node *call, ir_graph *called_graph) {
 
        /* -- Replicate local entities of the called_graph -- */
        /* copy the entities. */
+       irp_reserve_resources(irp, IR_RESOURCE_ENTITY_LINK);
        called_frame = get_irg_frame_type(called_graph);
        curr_frame   = get_irg_frame_type(irg);
        for (i = 0, n = get_class_n_members(called_frame); i < n; ++i) {
@@ -1043,6 +1059,8 @@ int inline_method(ir_node *call, ir_graph *called_graph) {
        irg_walk(get_irg_end(called_graph), copy_node_inline, copy_preds_inline,
                 get_irg_frame_type(called_graph));
 
+       irp_free_resources(irp, IR_RESOURCE_ENTITY_LINK);
+
        /* Repair called_graph */
        set_irg_visited(called_graph, get_irg_visited(irg));
        set_irg_block_visited(called_graph, get_irg_block_visited(irg));
@@ -1068,8 +1086,8 @@ int inline_method(ir_node *call, ir_graph *called_graph) {
        arity = get_Block_n_cfgpreds(end_bl);    /* arity = n_exc + n_ret  */
        n_res = get_method_n_ress(get_Call_type(call));
 
-       res_pred = xmalloc(n_res * sizeof(*res_pred));
-       cf_pred  = xmalloc(arity * sizeof(*res_pred));
+       res_pred = XMALLOCN(ir_node*, n_res);
+       cf_pred  = XMALLOCN(ir_node*, arity);
 
        set_irg_current_block(irg, post_bl); /* just to make sure */
 
@@ -1090,7 +1108,7 @@ int inline_method(ir_node *call, ir_graph *called_graph) {
                ir_node *ret;
                ret = get_Block_cfgpred(end_bl, i);
                if (is_Return(ret)) {
-                       cf_pred[n_ret] = new_r_Jmp(irg, get_nodes_block(ret));
+                       cf_pred[n_ret] = new_r_Jmp(get_nodes_block(ret));
                        n_ret++;
                }
        }
@@ -1118,11 +1136,18 @@ int inline_method(ir_node *call, ir_graph *called_graph) {
        /* Now the real results */
        if (n_res > 0) {
                for (j = 0; j < n_res; j++) {
+                       ir_type *res_type = get_method_res_type(ctp, j);
+                       ir_mode *res_mode = get_type_mode(res_type);
                        n_ret = 0;
                        for (i = 0; i < arity; i++) {
                                ret = get_Block_cfgpred(end_bl, i);
                                if (is_Return(ret)) {
-                                       cf_pred[n_ret] = get_Return_res(ret, j);
+                                       ir_node *res = get_Return_res(ret, j);
+                                       if (get_irn_mode(res) != res_mode) {
+                                               ir_node *block = get_nodes_block(res);
+                                               res = new_r_Conv(block, res, res_mode);
+                                       }
+                                       cf_pred[n_ret] = res;
                                        n_ret++;
                                }
                        }
@@ -1169,7 +1194,9 @@ int inline_method(ir_node *call, ir_graph *called_graph) {
                        }
                }
                if (n_exc > 0) {
-                       new_Block(n_exc, cf_pred);      /* watch it: current_block is changed! */
+                       ir_node *block = new_Block(n_exc, cf_pred);
+                       set_cur_block(block);
+
                        set_Tuple_pred(call, pn_Call_X_except, new_Jmp());
                        /* The Phi for the memories with the exception objects */
                        n_exc = 0;
@@ -1177,14 +1204,14 @@ int inline_method(ir_node *call, ir_graph *called_graph) {
                                ir_node *ret;
                                ret = skip_Proj(get_Block_cfgpred(end_bl, i));
                                if (is_Call(ret)) {
-                                       cf_pred[n_exc] = new_r_Proj(irg, get_nodes_block(ret), ret, mode_M, 3);
+                                       cf_pred[n_exc] = new_r_Proj(get_nodes_block(ret), ret, mode_M, 3);
                                        n_exc++;
                                } else if (is_fragile_op(ret)) {
                                        /* We rely that all cfops have the memory output at the same position. */
-                                       cf_pred[n_exc] = new_r_Proj(irg, get_nodes_block(ret), ret, mode_M, 0);
+                                       cf_pred[n_exc] = new_r_Proj(get_nodes_block(ret), ret, mode_M, 0);
                                        n_exc++;
                                } else if (is_Raise(ret)) {
-                                       cf_pred[n_exc] = new_r_Proj(irg, get_nodes_block(ret), ret, mode_M, 1);
+                                       cf_pred[n_exc] = new_r_Proj(get_nodes_block(ret), ret, mode_M, 1);
                                        n_exc++;
                                }
                        }
@@ -1209,17 +1236,17 @@ int inline_method(ir_node *call, ir_graph *called_graph) {
                                n_exc++;
                        }
                }
-               main_end_bl = get_irg_end_block(irg);
+               main_end_bl       = get_irg_end_block(irg);
                main_end_bl_arity = get_irn_arity(main_end_bl);
-               end_preds =  xmalloc((n_exc + main_end_bl_arity) * sizeof(*end_preds));
+               end_preds         = XMALLOCN(ir_node*, n_exc + main_end_bl_arity);
 
                for (i = 0; i < main_end_bl_arity; ++i)
                        end_preds[i] = get_irn_n(main_end_bl, i);
                for (i = 0; i < n_exc; ++i)
                        end_preds[main_end_bl_arity + i] = cf_pred[i];
                set_irn_in(main_end_bl, n_exc + main_end_bl_arity, end_preds);
-               set_Tuple_pred(call, pn_Call_X_except,  new_Bad());
-               set_Tuple_pred(call, pn_Call_M_except,  new_Bad());
+               set_Tuple_pred(call, pn_Call_X_except, new_Bad());
+               set_Tuple_pred(call, pn_Call_M_except, new_Bad());
                free(end_preds);
        }
        free(res_pred);
@@ -1328,6 +1355,7 @@ void inline_small_irgs(ir_graph *irg, int size) {
 
        if (! list_empty(&env.calls)) {
                /* There are calls to inline */
+               ir_reserve_resources(irg, IR_RESOURCE_IRN_LINK|IR_RESOURCE_PHI_LIST);
                collect_phiprojs(irg);
 
                list_for_each_entry(call_entry, entry, &env.calls, list) {
@@ -1344,6 +1372,7 @@ void inline_small_irgs(ir_graph *irg, int size) {
                                inline_method(entry->call, callee);
                        }
                }
+               ir_free_resources(irg, IR_RESOURCE_IRN_LINK|IR_RESOURCE_PHI_LIST);
        }
        obstack_free(&env.obst, NULL);
        current_ir_graph = rem;
@@ -1460,7 +1489,7 @@ static void collect_calls2(ir_node *call, void *ctx) {
  * Returns TRUE if the number of callers is 0 in the irg's environment,
  * hence this irg is a leave.
  */
-INLINE static int is_leave(ir_graph *irg) {
+inline static int is_leave(ir_graph *irg) {
        inline_irg_env *env = get_irg_link(irg);
        return env->n_call_nodes == 0;
 }
@@ -1469,7 +1498,7 @@ INLINE static int is_leave(ir_graph *irg) {
  * Returns TRUE if the number of nodes in the callee is
  * smaller then size in the irg's environment.
  */
-INLINE static int is_smaller(ir_graph *callee, unsigned size) {
+inline static int is_smaller(ir_graph *callee, unsigned size) {
        inline_irg_env *env = get_irg_link(callee);
        return env->n_nodes < size;
 }
@@ -1577,6 +1606,7 @@ void inline_leave_functions(unsigned maxsize, unsigned leavesize,
                        current_ir_graph = get_irp_irg(i);
                        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;
@@ -1619,6 +1649,7 @@ void inline_leave_functions(unsigned maxsize, unsigned leavesize,
                                        }
                                }
                        }
+                       ir_free_resources(current_ir_graph, IR_RESOURCE_IRN_LINK|IR_RESOURCE_PHI_LIST);
                }
        } while (did_inline);
 
@@ -1630,6 +1661,8 @@ void inline_leave_functions(unsigned maxsize, unsigned leavesize,
                current_ir_graph = get_irp_irg(i);
                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;
@@ -1666,6 +1699,8 @@ void inline_leave_functions(unsigned maxsize, unsigned leavesize,
                                        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
@@ -1676,6 +1711,8 @@ void inline_leave_functions(unsigned maxsize, unsigned leavesize,
                                        /* 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);
@@ -1729,6 +1766,7 @@ void inline_leave_functions(unsigned maxsize, unsigned leavesize,
                                }
                        }
                }
+               ir_free_resources(current_ir_graph, IR_RESOURCE_IRN_LINK|IR_RESOURCE_PHI_LIST);
        }
 
        for (i = 0; i < n_irgs; ++i) {
@@ -2012,8 +2050,7 @@ static ir_graph **create_irg_list(void) {
        compute_callgraph();
 
        last_irg = 0;
-       irgs     = xmalloc(n_irgs * sizeof(*irgs));
-       memset(irgs, 0, sizeof(n_irgs * sizeof(*irgs)));
+       irgs     = XMALLOCNZ(ir_graph*, n_irgs);
 
        callgraph_walk(NULL, callgraph_walker, NULL);
        assert(n_irgs == last_irg);
@@ -2022,8 +2059,7 @@ static ir_graph **create_irg_list(void) {
 }
 
 /**
- * Push a call onto the priority list if its
- * benefice is big enough.
+ * Push a call onto the priority list if its benefice is big enough.
  *
  * @param pqueue   the priority queue of calls
  * @param call     the call entry
@@ -2037,11 +2073,12 @@ static void maybe_push_call(pqueue_t *pqueue, call_entry *call,
        irg_inline_property prop     = get_irg_inline_property(callee);
        int                 benefice = calc_inline_benefice(call, callee);
 
-               DB((dbg, LEVEL_2, "In %+F Call %+F to %+F has benefice %d\n",
-                       get_irn_irg(call->call), call->call, callee, benefice));
+       DB((dbg, LEVEL_2, "In %+F Call %+F to %+F has benefice %d\n",
+           get_irn_irg(call->call), call->call, callee, benefice));
 
-       if (benefice < inline_threshold && prop < irg_inline_forced)
+       if (prop < irg_inline_forced && benefice < inline_threshold) {
                return;
+       }
 
        pqueue_put(pqueue, call, benefice);
 }
@@ -2075,6 +2112,7 @@ static void inline_into(ir_graph *irg, unsigned maxsize,
        }
 
        current_ir_graph = irg;
+       ir_reserve_resources(irg, IR_RESOURCE_IRN_LINK|IR_RESOURCE_PHI_LIST);
 
        /* put irgs into the pqueue */
        pqueue = new_pqueue();
@@ -2139,6 +2177,8 @@ static void inline_into(ir_graph *irg, unsigned maxsize,
                        if (benefice < inline_threshold)
                                continue;
 
+                       ir_free_resources(irg, IR_RESOURCE_IRN_LINK|IR_RESOURCE_PHI_LIST);
+
                        /*
                         * No copy yet, create one.
                         * Note that recursive methods are never leaves, so it is
@@ -2149,6 +2189,8 @@ static void inline_into(ir_graph *irg, unsigned maxsize,
                        /* create_irg_copy() destroys the Proj links, recompute them */
                        phiproj_computed = 0;
 
+                       ir_reserve_resources(irg, IR_RESOURCE_IRN_LINK|IR_RESOURCE_PHI_LIST);
+
                        /* allocate a new environment */
                        callee_env = alloc_inline_irg_env();
                        set_irg_link(copy, callee_env);
@@ -2218,7 +2260,7 @@ static void inline_into(ir_graph *irg, unsigned maxsize,
                env->n_nodes += callee_env->n_nodes;
                --callee_env->n_callers;
        }
-
+       ir_free_resources(irg, IR_RESOURCE_IRN_LINK|IR_RESOURCE_PHI_LIST);
        del_pqueue(pqueue);
 }
 
@@ -2274,22 +2316,18 @@ void inline_functions(unsigned maxsize, int inline_threshold) {
                env = get_irg_link(irg);
                if (env->got_inline) {
                        /* this irg got calls inlined: optimize it */
-
-                       if (0) {
-                               /* scalar replacement does not work well with Tuple nodes, so optimize them away */
-                               optimize_graph_df(irg);
-
+                       if (get_opt_combo()) {
+                               if (env->local_vars) {
+                                       scalar_replacement_opt(irg);
+                               }
+                               combo(irg);
+                       } else {
                                if (env->local_vars) {
                                        if (scalar_replacement_opt(irg)) {
                                                optimize_graph_df(irg);
                                        }
                                }
                                optimize_cf(irg);
-                       } else {
-                               if (env->local_vars) {
-                                       scalar_replacement_opt(irg);
-                               }
-                               combo(irg);
                        }
                }
                if (env->got_inline || (env->n_callers_orig != env->n_callers)) {