include backend headers without "../"
[libfirm] / ir / opt / opt_inline.c
index edadecd..6792f2c 100644 (file)
@@ -155,6 +155,9 @@ static void find_addr(ir_node *node, void *env)
                                /* access to value_type */
                                *allow_inline = false;
                        }
+                       if (is_parameter_entity(ent)) {
+                               *allow_inline = false;
+                       }
                }
        } else if (is_Alloc(node) && get_Alloc_where(node) == stack_alloc) {
                /* From GCC:
@@ -291,6 +294,7 @@ static void copy_frame_entities(ir_graph *from, ir_graph *to)
                ir_entity *old_ent = get_class_member(from_frame, i);
                ir_entity *new_ent = copy_entity_own(old_ent, to_frame);
                set_entity_link(old_ent, new_ent);
+               assert (!is_parameter_entity(old_ent));
        }
 }
 
@@ -299,7 +303,7 @@ int inline_method(ir_node *call, ir_graph *called_graph)
 {
        ir_node       *pre_call;
        ir_node       *post_call, *post_bl;
-       ir_node       *in[pn_Start_max];
+       ir_node       *in[pn_Start_max+1];
        ir_node       *end, *end_bl, *block;
        ir_node       **res_pred;
        ir_node       **cf_pred;
@@ -343,12 +347,11 @@ int inline_method(ir_node *call, ir_graph *called_graph)
        assert(get_irg_phase_state(irg) != phase_building);
        assert(get_irg_pinned(irg) == op_pin_state_pinned);
        assert(get_irg_pinned(called_graph) == op_pin_state_pinned);
-       set_irg_outs_inconsistent(irg);
-       set_irg_extblk_inconsistent(irg);
-       set_irg_doms_inconsistent(irg);
-       set_irg_loopinfo_inconsistent(irg);
+       clear_irg_state(irg, IR_GRAPH_STATE_CONSISTENT_DOMINANCE
+                          | IR_GRAPH_STATE_VALID_EXTENDED_BLOCKS
+                          | IR_GRAPH_STATE_CONSISTENT_ENTITY_USAGE);
        set_irg_callee_info_state(irg, irg_callee_info_inconsistent);
-       set_irg_entity_usage_state(irg, ir_entity_usage_not_computed);
+       clear_irg_state(irg, IR_GRAPH_STATE_CONSISTENT_ENTITY_USAGE);
        edges_deactivate(irg);
 
        /* here we know we WILL inline, so inform the statistics */
@@ -394,7 +397,7 @@ int inline_method(ir_node *call, ir_graph *called_graph)
        in[pn_Start_X_initial_exec] = new_r_Jmp(post_bl);
        in[pn_Start_P_frame_base]   = get_irg_frame(irg);
        in[pn_Start_T_args]         = new_r_Tuple(post_bl, n_params, args_in);
-       pre_call = new_r_Tuple(post_bl, pn_Start_max, in);
+       pre_call = new_r_Tuple(post_bl, pn_Start_max+1, in);
        post_call = call;
 
        /* --
@@ -414,7 +417,6 @@ int inline_method(ir_node *call, ir_graph *called_graph)
        {
                ir_node *start_block;
                ir_node *start;
-               ir_node *bad;
                ir_node *nomem;
 
                start_block = get_irg_start_block(called_graph);
@@ -425,10 +427,6 @@ int inline_method(ir_node *call, ir_graph *called_graph)
                set_new_node(start, pre_call);
                mark_irn_visited(start);
 
-               bad = get_irg_bad(called_graph);
-               set_new_node(bad, get_irg_bad(irg));
-               mark_irn_visited(bad);
-
                nomem = get_irg_no_mem(called_graph);
                set_new_node(nomem, get_irg_no_mem(irg));
                mark_irn_visited(nomem);
@@ -436,7 +434,7 @@ int inline_method(ir_node *call, ir_graph *called_graph)
 
        /* entitiy link is used to link entities on old stackframe to the
         * new stackframe */
-       irp_reserve_resources(irp, IR_RESOURCE_ENTITY_LINK);
+       irp_reserve_resources(irp, IRP_RESOURCE_ENTITY_LINK);
 
        /* copy entities and nodes */
        assert(!irn_visited(get_irg_end(called_graph)));
@@ -444,7 +442,7 @@ int inline_method(ir_node *call, ir_graph *called_graph)
        irg_walk_core(get_irg_end(called_graph), copy_node_inline, set_preds_inline,
                      irg);
 
-       irp_free_resources(irp, IR_RESOURCE_ENTITY_LINK);
+       irp_free_resources(irp, IRP_RESOURCE_ENTITY_LINK);
 
        /* -- Merge the end of the inlined procedure with the call site -- */
        /* We will turn the old Call node into a Tuple with the following
@@ -492,7 +490,7 @@ int inline_method(ir_node *call, ir_graph *called_graph)
 
        /* build a Tuple for all results of the method.
         * add Phi node if there was more than one Return. */
-       turn_into_tuple(post_call, pn_Call_max);
+       turn_into_tuple(post_call, pn_Call_max+1);
        /* First the Memory-Phi */
        n_mem_phi = 0;
        for (i = 0; i < arity; i++) {
@@ -537,10 +535,9 @@ int inline_method(ir_node *call, ir_graph *called_graph)
                                }
                        }
                        if (n_ret > 0) {
-                               ir_mode *mode = get_irn_mode(cf_pred[0]);
-                               phi = new_r_Phi(post_bl, n_ret, cf_pred, mode);
+                               phi = new_r_Phi(post_bl, n_ret, cf_pred, res_mode);
                        } else {
-                               phi = new_r_Bad(irg);
+                               phi = new_r_Bad(irg, res_mode);
                        }
                        res_pred[j] = phi;
                        /* Conserve Phi-list for further inlinings -- but might be optimized */
@@ -552,7 +549,7 @@ int inline_method(ir_node *call, ir_graph *called_graph)
                result_tuple = new_r_Tuple(post_bl, n_res, res_pred);
                set_Tuple_pred(call, pn_Call_T_result, result_tuple);
        } else {
-               set_Tuple_pred(call, pn_Call_T_result, new_r_Bad(irg));
+               set_Tuple_pred(call, pn_Call_T_result, new_r_Bad(irg, mode_T));
        }
        /* handle the regular call */
        set_Tuple_pred(call, pn_Call_X_regular, new_r_Jmp(post_bl));
@@ -588,7 +585,7 @@ int inline_method(ir_node *call, ir_graph *called_graph)
                                set_Tuple_pred(call, pn_Call_X_except, new_r_Jmp(block));
                        }
                } else {
-                       set_Tuple_pred(call, pn_Call_X_except, new_r_Bad(irg));
+                       set_Tuple_pred(call, pn_Call_X_except, new_r_Bad(irg, mode_X));
                }
        } else {
                ir_node *main_end_bl;
@@ -615,7 +612,7 @@ int inline_method(ir_node *call, ir_graph *called_graph)
                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_r_Bad(irg));
+               set_Tuple_pred(call, pn_Call_X_except, new_r_Bad(irg, mode_X));
                free(end_preds);
        }
        free(res_pred);
@@ -993,7 +990,7 @@ void inline_leave_functions(unsigned maxsize, unsigned leavesize,
                assert(get_irg_phase_state(irg) != phase_building);
                free_callee_info(irg);
 
-               assure_cf_loop(irg);
+               assure_loopinfo(irg);
                wenv.x = (inline_irg_env*)get_irg_link(irg);
                irg_walk_graph(irg, NULL, collect_calls2, &wenv);
        }
@@ -1120,7 +1117,7 @@ void inline_leave_functions(unsigned maxsize, unsigned leavesize,
                                        callee_env = alloc_inline_irg_env();
                                        set_irg_link(copy, callee_env);
 
-                                       assure_cf_loop(copy);
+                                       assure_loopinfo(copy);
                                        wenv.x              = callee_env;
                                        wenv.ignore_callers = 1;
                                        irg_walk_graph(copy, NULL, collect_calls2, &wenv);
@@ -1365,10 +1362,12 @@ static int calc_inline_benefice(call_entry *entry, ir_graph *callee)
 {
        ir_node   *call = entry->call;
        ir_entity *ent  = get_irg_entity(callee);
+       ir_type   *callee_frame;
+       size_t    i, n_members, n_params;
        ir_node   *frame_ptr;
        ir_type   *mtp;
        int       weight = 0;
-       int       i, n_params, all_const;
+       int       all_const;
        unsigned  cc, v;
        irg_inline_property prop;
 
@@ -1381,6 +1380,18 @@ static int calc_inline_benefice(call_entry *entry, ir_graph *callee)
                return entry->benefice = INT_MIN;
        }
 
+       callee_frame = get_irg_frame_type(callee);
+       n_members = get_class_n_members(callee_frame);
+       for (i = 0; i < n_members; ++i) {
+               ir_entity *frame_ent = get_class_member(callee_frame, i);
+               if (is_parameter_entity(frame_ent)) {
+                       // TODO inliner should handle parameter entities by inserting Store operations
+                       DB((dbg, LEVEL_2, "In %+F Call to %+F: inlining forbidden due to parameter entity\n", call, callee));
+                       set_irg_inline_property(callee, irg_inline_forbidden);
+                       return entry->benefice = INT_MIN;
+               }
+       }
+
        if (get_irg_additional_properties(callee) & mtp_property_noreturn) {
                DB((dbg, LEVEL_2, "In %+F Call to %+F: not inlining noreturn or weak\n",
                    call, callee));
@@ -1393,7 +1404,7 @@ static int calc_inline_benefice(call_entry *entry, ir_graph *callee)
        cc       = get_method_calling_convention(mtp);
        if (cc & cc_reg_param) {
                /* register parameter, smaller costs for register parameters */
-               int max_regs = cc & ~cc_bits;
+               size_t max_regs = cc & ~cc_bits;
 
                if (max_regs < n_params)
                        weight += max_regs * 2 + (n_params - max_regs) * 5;
@@ -1642,7 +1653,8 @@ static void inline_into(ir_graph *irg, unsigned maxsize,
                        callee_env = alloc_inline_irg_env();
                        set_irg_link(copy, callee_env);
 
-                       assure_cf_loop(copy);
+                       assure_loopinfo(copy);
+                       memset(&wenv, 0, sizeof(wenv));
                        wenv.x              = callee_env;
                        wenv.ignore_callers = 1;
                        irg_walk_graph(copy, NULL, collect_calls2, &wenv);
@@ -1694,6 +1706,13 @@ static void inline_into(ir_graph *irg, unsigned maxsize,
                         * but we need Call nodes in our graph. Luckily the inliner leaves
                         * this information in the link field. */
                        new_call = (ir_node*)get_irn_link(centry->call);
+                       if (get_irn_irg(new_call) != irg) {
+                               /* centry->call has not been copied, which means it is dead.
+                                * This might happen during inlining, if a const function,
+                                * which cannot be inlined is only used as an unused argument
+                                * of another function, which is inlined. */
+                               continue;
+                       }
                        assert(is_Call(new_call));
 
                        new_entry = duplicate_call_entry(centry, new_call, loop_depth);
@@ -1746,7 +1765,7 @@ void inline_functions(unsigned maxsize, int inline_threshold,
                free_callee_info(irg);
 
                wenv.x = (inline_irg_env*)get_irg_link(irg);
-               assure_cf_loop(irg);
+               assure_loopinfo(irg);
                irg_walk_graph(irg, NULL, collect_calls2, &wenv);
        }