X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fopt%2Fopt_inline.c;h=072f2177fa5bd75787cddbfb696974b1cb820030;hb=16b814ebb6d59409fb74416bdde1a891028b26fb;hp=6a605d4d4b3ed9da3931abda326d76789dd48a4a;hpb=a8a06f66c66fab835f88bda648db4b207fec21dd;p=libfirm diff --git a/ir/opt/opt_inline.c b/ir/opt/opt_inline.c index 6a605d4d4..072f2177f 100644 --- a/ir/opt/opt_inline.c +++ b/ir/opt/opt_inline.c @@ -60,6 +60,7 @@ #include "irflag_t.h" #include "irhooks.h" #include "irtools.h" +#include "iropt_dbg.h" DEBUG_ONLY(static firm_dbg_module_t *dbg;) @@ -439,7 +440,8 @@ void dead_node_elimination(ir_graph *irg) { #endif struct obstack *graveyard_obst = NULL; struct obstack *rebirth_obst = NULL; - assert(! edges_activated(irg) && "dead node elimination requires disabled edges"); + + edges_deactivate(irg); /* inform statistics that we started a dead-node elimination run */ hook_dead_node_elim(irg, 1); @@ -726,8 +728,7 @@ void survive_dce_register_irn(survive_dce_t *sd, ir_node **place) { * inlined procedure. The new entities must be in the link field of * the entities. */ -static INLINE void -copy_node_inline(ir_node *n, void *env) { +static void copy_node_inline(ir_node *n, void *env) { ir_node *nn; ir_type *frame_tp = (ir_type *)env; @@ -744,6 +745,27 @@ copy_node_inline(ir_node *n, void *env) { } } +/** + * Copies new predecessors of old node and move constants to + * the Start Block. + */ +static void copy_preds_inline(ir_node *n, void *env) { + ir_node *nn; + + copy_preds(n, env); + nn = skip_Id(get_new_node(n)); + if (is_irn_constlike(nn)) { + /* move Constants into the start block */ + set_nodes_block(nn, get_irg_start_block(current_ir_graph)); + + n = identify_remember(current_ir_graph->value_table, nn); + if (nn != n) { + DBG_OPT_CSE(nn, n); + exchange(nn, n); + } + } +} + /** * Walker: checks if P_value_arg_base is used. */ @@ -821,53 +843,55 @@ 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 *end, *end_bl; + ir_node *end, *end_bl, *block; ir_node **res_pred; ir_node **cf_pred; + ir_node **args_in; ir_node *ret, *phi; - int arity, n_ret, n_exc, n_res, i, n, j, rem_opt, irn_arity; + int arity, n_ret, n_exc, n_res, i, n, j, rem_opt, irn_arity, n_params; enum exc_mode exc_handling; - ir_type *called_frame, *curr_frame; + ir_type *called_frame, *curr_frame, *mtp, *ctp; ir_entity *ent; ir_graph *rem, *irg; irg_inline_property prop = get_irg_inline_property(called_graph); + unsigned long visited; if (prop == irg_inline_forbidden) return 0; ent = get_irg_entity(called_graph); - /* Do not inline variadic functions. */ - if (get_method_variadicity(get_entity_type(ent)) == variadicity_variadic) { - /* Arg, KR functions are marked as variadic one's, so check further */ - ir_type *mtp = get_entity_type(ent); - ir_type *ctp = get_Call_type(call); - int n_params = get_method_n_params(mtp); - int i; - - /* This is too strong, but probably ok. Function calls with a wrong number of - parameters should not be inlined. */ - if (n_params != get_method_n_params(ctp)) - return 0; - - /* check types: for K&R calls, this was not done by the compiler. Again, this is - too strong, but ok for now. */ - 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); + 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. */ + return 0; + } - if (param_tp != arg_tp) + /* 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); + 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); + + if (param_tp != arg_tp) { + ir_mode *pmode = get_type_mode(param_tp); + ir_mode *amode = get_type_mode(arg_tp); + + if (pmode == NULL || amode == NULL) return 0; + if (get_mode_size_bits(pmode) != get_mode_size_bits(amode)) + return 0; + if (get_mode_arithmetic(pmode) != get_mode_arithmetic(amode)) + return 0; + /* otherwise we can simply "reinterpret" the bits */ } - DB((dbg, LEVEL_1, "Inlining allowed for variadic function %+F\n", called_graph)); - /* types match, fine: when the frame is access, the inliner stops at can_inline() */ - } - - if (get_method_n_params(get_entity_type(ent)) > get_method_n_params(get_Call_type(call))) { - /* 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. */ - return 0; } irg = get_irn_irg(call); @@ -930,6 +954,21 @@ int inline_method(ir_node *call, ir_graph *called_graph) { else { exc_handling = exc_no_handler; } /* !Mproj && !Xproj */ } + /* create the argument tuple */ + NEW_ARR_A(ir_type *, args_in, n_params); + + block = get_nodes_block(call); + for (i = n_params - 1; i >= 0; --i) { + ir_node *arg = get_Call_param(call, i); + ir_type *param_tp = get_method_param_type(mtp, i); + ir_mode *mode = get_type_mode(param_tp); + + if (mode != get_irn_mode(arg)) { + arg = new_r_Conv(irg, block, arg, mode); + } + args_in[i] = arg; + } + /* -- the procedure and later replaces the Start node of the called graph. Post_call is the old Call node and collects the results of the called @@ -941,7 +980,7 @@ int inline_method(ir_node *call, ir_graph *called_graph) { in[pn_Start_M] = get_Call_mem(call); 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(get_Call_n_params(call), get_Call_param_arr(call)); + 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); @@ -956,20 +995,26 @@ int inline_method(ir_node *call, ir_graph *called_graph) { /* Visited flags in calling irg must be >= flag in called irg. Else walker and arity computation will not work. */ if (get_irg_visited(irg) <= get_irg_visited(called_graph)) - set_irg_visited(irg, get_irg_visited(called_graph)+1); + set_irg_visited(irg, get_irg_visited(called_graph) + 1); if (get_irg_block_visited(irg) < get_irg_block_visited(called_graph)) set_irg_block_visited(irg, get_irg_block_visited(called_graph)); + visited = get_irg_visited(irg); + /* Set pre_call as new Start node in link field of the start node of calling graph and pre_calls block as new block for the start block of calling graph. Further mark these nodes so that they are not visited by the copying. */ set_irn_link(get_irg_start(called_graph), pre_call); - set_irn_visited(get_irg_start(called_graph), get_irg_visited(irg)); + set_irn_visited(get_irg_start(called_graph), visited); set_irn_link(get_irg_start_block(called_graph), get_nodes_block(pre_call)); - set_irn_visited(get_irg_start_block(called_graph), get_irg_visited(irg)); - set_irn_link(get_irg_bad(called_graph), get_irg_bad(irg)); - set_irn_visited(get_irg_bad(called_graph), get_irg_visited(irg)); + set_irn_visited(get_irg_start_block(called_graph), visited); + + set_irn_link(get_irg_bad(called_graph), get_irg_bad(current_ir_graph)); + set_irn_visited(get_irg_bad(called_graph), visited); + + set_irn_link(get_irg_no_mem(called_graph), get_irg_no_mem(current_ir_graph)); + set_irn_visited(get_irg_no_mem(called_graph), visited); /* Initialize for compaction of in arrays */ inc_irg_block_visited(irg); @@ -993,7 +1038,7 @@ int inline_method(ir_node *call, ir_graph *called_graph) { /* -- Performing dead node elimination inlines the graph -- */ /* Copies the nodes to the obstack of current_ir_graph. Updates links to new entities. */ - irg_walk(get_irg_end(called_graph), copy_node_inline, copy_preds, + irg_walk(get_irg_end(called_graph), copy_node_inline, copy_preds_inline, get_irg_frame_type(called_graph)); /* Repair called_graph */ @@ -1018,7 +1063,7 @@ int inline_method(ir_node *call, ir_graph *called_graph) { /* -- Precompute some values -- */ end_bl = get_new_node(get_irg_end_block(called_graph)); end = get_new_node(get_irg_end(called_graph)); - arity = get_irn_arity(end_bl); /* arity = n_exc + n_ret */ + 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)); @@ -1041,7 +1086,7 @@ int inline_method(ir_node *call, ir_graph *called_graph) { n_ret = 0; for (i = 0; i < arity; i++) { ir_node *ret; - ret = get_irn_n(end_bl, i); + ret = get_Block_cfgpred(end_bl, i); if (is_Return(ret)) { cf_pred[n_ret] = new_r_Jmp(irg, get_nodes_block(ret)); n_ret++; @@ -1055,7 +1100,7 @@ int inline_method(ir_node *call, ir_graph *called_graph) { /* First the Memory-Phi */ n_ret = 0; for (i = 0; i < arity; i++) { - ret = get_irn_n(end_bl, i); + ret = get_Block_cfgpred(end_bl, i); if (is_Return(ret)) { cf_pred[n_ret] = get_Return_mem(ret); n_ret++; @@ -1073,7 +1118,7 @@ int inline_method(ir_node *call, ir_graph *called_graph) { for (j = 0; j < n_res; j++) { n_ret = 0; for (i = 0; i < arity; i++) { - ret = get_irn_n(end_bl, i); + ret = get_Block_cfgpred(end_bl, i); if (is_Return(ret)) { cf_pred[n_ret] = get_Return_res(ret, j); n_ret++; @@ -1114,7 +1159,7 @@ int inline_method(ir_node *call, ir_graph *called_graph) { n_exc = 0; for (i = 0; i < arity; i++) { ir_node *ret, *irn; - ret = get_irn_n(end_bl, i); + ret = get_Block_cfgpred(end_bl, i); irn = skip_Proj(ret); if (is_fragile_op(irn) || is_Raise(irn)) { cf_pred[n_exc] = ret; @@ -1128,7 +1173,7 @@ int inline_method(ir_node *call, ir_graph *called_graph) { n_exc = 0; for (i = 0; i < arity; i++) { ir_node *ret; - ret = skip_Proj(get_irn_n(end_bl, i)); + 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); n_exc++; @@ -1154,7 +1199,7 @@ int inline_method(ir_node *call, ir_graph *called_graph) { /* assert(exc_handling == 1 || no exceptions. ) */ n_exc = 0; for (i = 0; i < arity; i++) { - ir_node *ret = get_irn_n(end_bl, i); + ir_node *ret = get_Block_cfgpred(end_bl, i); ir_node *irn = skip_Proj(ret); if (is_fragile_op(irn) || is_Raise(irn)) { @@ -1853,7 +1898,12 @@ static unsigned get_method_local_adress_weight(ir_graph *callee, int pos) { } /** - * calculate a benefice value for inlining the given call. + * Calculate a benefice value for inlining the given call. + * + * @param call the call node we have to inspect + * @param callee the called graph + * @param local_adr set after return if an address of a local variable is + * transmitted as a parameter */ static int calc_inline_benefice(ir_node *call, ir_graph *callee, unsigned *local_adr) { ir_entity *ent = get_irg_entity(callee); @@ -1893,9 +1943,9 @@ static int calc_inline_benefice(ir_node *call, ir_graph *callee, unsigned *local for (i = 0; i < n_params; ++i) { ir_node *param = get_Call_param(call, i); - if (is_Const(param)) + if (is_Const(param)) { weight += get_method_param_weight(ent, i); - else { + } else { all_const = 0; if (is_SymConst(param)) weight += get_method_param_weight(ent, i); @@ -2116,6 +2166,12 @@ void inline_functions(int maxsize, int inline_threshold) { curr_call = curr_call->next; } + } + + for (i = 0; i < n_irgs; ++i) { + ir_graph *irg = get_irp_irg(i); + + env = get_irg_link(irg); if (env->got_inline) { /* this irg got calls inlined: optimize it */