X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fir%2Firgopt.c;h=4bd87a2d277ca94ca4fa34b715352a720b7c81a3;hb=637542932dc27dcdfc7def09b58d9d5d4c34fb77;hp=48c2197a71f12666edf902317f095d6fc9467a16;hpb=a036bad22ad913907a083f25ae037b3ec8192fca;p=libfirm diff --git a/ir/ir/irgopt.c b/ir/ir/irgopt.c index 48c2197a7..4bd87a2d2 100644 --- a/ir/ir/irgopt.c +++ b/ir/ir/irgopt.c @@ -12,11 +12,10 @@ #ifdef HAVE_CONFIG_H -# include +# include "config.h" #endif #include -#include #include "irnode_t.h" #include "irgraph_t.h" @@ -32,14 +31,17 @@ #include "pset.h" #include "eset.h" #include "pdeq.h" /* Fuer code placement */ +#include "xmalloc.h" #include "irouts.h" #include "irloop_t.h" #include "irbackedge_t.h" #include "cgana.h" +#include "trouts.h" #include "irflag_t.h" -#include "firmstat.h" +#include "irhooks.h" +#include "iredges_t.h" /* Defined in iropt.c */ pset *new_identities (void); @@ -55,7 +57,7 @@ static void init_link (ir_node *n, void *env) { } #if 0 /* Old version. Avoids Ids. - This is not necessary: we do a postwalk, and get_irn_n + This is not necessary: we do a post walk, and get_irn_n removes ids anyways. So it's much cheaper to call the optimization less often and use the exchange() algorithm. */ static void @@ -98,7 +100,7 @@ static INLINE void do_local_optimize(ir_node *n) { set_irg_loopinfo_inconsistent(current_ir_graph); - /* Clean the value_table in irg for the cse. */ + /* Clean the value_table in irg for the CSE. */ del_identities(current_ir_graph->value_table); current_ir_graph->value_table = new_identities(); @@ -113,7 +115,6 @@ void local_optimize_node(ir_node *n) { do_local_optimize(n); current_ir_graph = rem; - } void @@ -207,9 +208,11 @@ static INLINE void new_backedge_info(ir_node *n) { * * @param n The node to be copied * @param env if non-NULL, the node number attribute will be copied to the new node + * + * Note: Also used for loop unrolling. */ static void -copy_node (ir_node *n, void *env) { +firm_copy_node (ir_node *n, void *env) { ir_node *nn, *block; int new_arity; opcode op = get_irn_opcode(n); @@ -245,7 +248,7 @@ copy_node (ir_node *n, void *env) { /* Copy the attributes. These might point to additional data. If this was allocated on the old obstack the pointers now are dangling. This frees e.g. the memory of the graph_arr allocated in new_immBlock. */ - copy_attrs(n, nn); + copy_node_attr(n, nn); new_backedge_info(nn); set_new_node(n, nn); @@ -264,7 +267,7 @@ copy_node (ir_node *n, void *env) { * Copies new predecessors of old node to new node remembered in link. * Spare the Bad predecessors of Phi and Block nodes. */ -static void +void copy_preds (ir_node *n, void *env) { ir_node *nn, *block; int i, j, irn_arity; @@ -330,7 +333,7 @@ copy_preds (ir_node *n, void *env) { for (i = -1; i < irn_arity; i++) set_irn_n (nn, i, get_new_node(get_irn_n(n, i))); } - /* Now the new node is complete. We can add it to the hash table for cse. + /* Now the new node is complete. We can add it to the hash table for CSE. @@@ inlinening aborts if we identify End. Why? */ if(get_irn_op(nn) != op_End) add_identities (current_ir_graph->value_table, nn); @@ -357,7 +360,7 @@ copy_graph (int copy_node_nr) { -1, NULL); /* Copy the attributes. Well, there might be some in the future... */ - copy_attrs(oe, ne); + copy_node_attr(oe, ne); set_new_node(oe, ne); /* copy the Bad node */ @@ -383,7 +386,7 @@ copy_graph (int copy_node_nr) { set_new_node(om, nm); /* copy the live nodes */ - irg_walk(get_nodes_block(oe), copy_node, copy_preds, (void *)copy_node_nr); + irg_walk(get_nodes_block(oe), firm_copy_node, copy_preds, (void *)copy_node_nr); /* copy_preds for the end node ... */ set_nodes_block(ne, get_new_node(get_nodes_block(oe))); @@ -397,7 +400,7 @@ copy_graph (int copy_node_nr) { (get_irn_visited(ka) < get_irg_visited(current_ir_graph))) { /* We must keep the block alive and copy everything reachable */ set_irg_visited(current_ir_graph, get_irg_visited(current_ir_graph)-1); - irg_walk(ka, copy_node, copy_preds, (void *)copy_node_nr); + irg_walk(ka, firm_copy_node, copy_preds, (void *)copy_node_nr); add_End_keepalive(ne, get_new_node(ka)); } } @@ -410,7 +413,7 @@ copy_graph (int copy_node_nr) { if (get_irn_visited(ka) < get_irg_visited(current_ir_graph)) { /* We didn't copy the Phi yet. */ set_irg_visited(current_ir_graph, get_irg_visited(current_ir_graph)-1); - irg_walk(ka, copy_node, copy_preds, (void *)copy_node_nr); + irg_walk(ka, firm_copy_node, copy_preds, (void *)copy_node_nr); } add_End_keepalive(ne, get_new_node(ka)); } @@ -455,19 +458,19 @@ copy_graph_env (int copy_node_nr) { free_End(old_end); set_irg_end_block (current_ir_graph, get_new_node(get_irg_end_block(current_ir_graph))); if (get_irn_link(get_irg_frame(current_ir_graph)) == NULL) { - copy_node (get_irg_frame(current_ir_graph), (void *)copy_node_nr); + firm_copy_node (get_irg_frame(current_ir_graph), (void *)copy_node_nr); copy_preds(get_irg_frame(current_ir_graph), NULL); } if (get_irn_link(get_irg_globals(current_ir_graph)) == NULL) { - copy_node (get_irg_globals(current_ir_graph), (void *)copy_node_nr); + firm_copy_node (get_irg_globals(current_ir_graph), (void *)copy_node_nr); copy_preds(get_irg_globals(current_ir_graph), NULL); } if (get_irn_link(get_irg_initial_mem(current_ir_graph)) == NULL) { - copy_node (get_irg_initial_mem(current_ir_graph), (void *)copy_node_nr); + firm_copy_node (get_irg_initial_mem(current_ir_graph), (void *)copy_node_nr); copy_preds(get_irg_initial_mem(current_ir_graph), NULL); } if (get_irn_link(get_irg_args(current_ir_graph)) == NULL) { - copy_node (get_irg_args(current_ir_graph), (void *)copy_node_nr); + firm_copy_node (get_irg_args(current_ir_graph), (void *)copy_node_nr); copy_preds(get_irg_args(current_ir_graph), NULL); } set_irg_start (current_ir_graph, get_new_node(get_irg_start(current_ir_graph))); @@ -480,13 +483,13 @@ copy_graph_env (int copy_node_nr) { set_irg_args (current_ir_graph, get_new_node(get_irg_args(current_ir_graph))); if (get_irn_link(get_irg_bad(current_ir_graph)) == NULL) { - copy_node(get_irg_bad(current_ir_graph), (void *)copy_node_nr); + firm_copy_node(get_irg_bad(current_ir_graph), (void *)copy_node_nr); copy_preds(get_irg_bad(current_ir_graph), NULL); } set_irg_bad(current_ir_graph, get_new_node(get_irg_bad(current_ir_graph))); if (get_irn_link(get_irg_no_mem(current_ir_graph)) == NULL) { - copy_node(get_irg_no_mem(current_ir_graph), (void *)copy_node_nr); + firm_copy_node(get_irg_no_mem(current_ir_graph), (void *)copy_node_nr); copy_preds(get_irg_no_mem(current_ir_graph), NULL); } set_irg_no_mem(current_ir_graph, get_new_node(get_irg_no_mem(current_ir_graph))); @@ -497,8 +500,8 @@ copy_graph_env (int copy_node_nr) { * from block nodes and the corresponding inputs from Phi nodes. * Merges single exit blocks with single entry blocks and removes * 1-input Phis. - * Adds all new nodes to a new hash table for cse. Does not - * perform cse, so the hash table might contain common subexpressions. + * Adds all new nodes to a new hash table for CSE. Does not + * perform CSE, so the hash table might contain common subexpressions. */ void dead_node_elimination(ir_graph *irg) { @@ -507,8 +510,10 @@ dead_node_elimination(ir_graph *irg) { struct obstack *graveyard_obst = NULL; struct obstack *rebirth_obst = NULL; + edges_init_graph(irg); + /* inform statistics that we started a dead-node elimination run */ - stat_dead_node_elim_start(irg); + hook_dead_node_elim_start(irg); /* Remember external state of current_ir_graph. */ rem = current_ir_graph; @@ -519,6 +524,7 @@ dead_node_elimination(ir_graph *irg) { assert(get_irg_phase_state(current_ir_graph) != phase_building); free_callee_info(current_ir_graph); free_outs(current_ir_graph); + free_trouts(); /* @@@ so far we loose loops when copying */ free_loop_information(current_ir_graph); @@ -529,7 +535,7 @@ dead_node_elimination(ir_graph *irg) { graveyard_obst = irg->obst; /* A new obstack, where the reachable nodes will be copied to. */ - rebirth_obst = (struct obstack *) xmalloc (sizeof (struct obstack)); + rebirth_obst = xmalloc (sizeof(*rebirth_obst)); current_ir_graph->obst = rebirth_obst; obstack_init (current_ir_graph->obst); @@ -546,14 +552,14 @@ dead_node_elimination(ir_graph *irg) { } /* inform statistics that the run is over */ - stat_dead_node_elim_stop(irg); + hook_dead_node_elim_stop(irg); current_ir_graph = rem; set_interprocedural_view(rem_ipview); } /** - * Relink bad predeseccors of a block and store the old in array to the + * Relink bad predecessors of a block and store the old in array to the * link field. This function is called by relink_bad_predecessors(). * The array of link field starts with the block operand at position 0. * If block has bad predecessors, create a new in array without bad preds. @@ -564,7 +570,7 @@ static void relink_bad_block_predecessors(ir_node *n, void *env) { int i, new_irn_n, old_irn_arity, new_irn_arity = 0; /* if link field of block is NULL, look for bad predecessors otherwise - this is allready done */ + this is already done */ if (get_irn_op(n) == op_Block && get_irn_link(n) == NULL) { @@ -582,7 +588,7 @@ static void relink_bad_block_predecessors(ir_node *n, void *env) { keep the old one to update Phis. */ new_in = NEW_ARR_D (ir_node *, current_ir_graph->obst, (new_irn_arity+1)); - /* set new predeseccors in array */ + /* set new predecessors in array */ new_in[0] = NULL; new_irn_n = 1; for (i = 0; i < old_irn_arity; i++) { @@ -602,25 +608,25 @@ static void relink_bad_block_predecessors(ir_node *n, void *env) { } /* Block is not relinked */ } -/* - * Relinks Bad predecesors from Bocks and Phis called by walker +/** + * Relinks Bad predecessors from Blocks and Phis called by walker * remove_bad_predecesors(). If n is a Block, call - * relink_bad_block_redecessors(). If n is a Phinode, call also the relinking + * relink_bad_block_redecessors(). If n is a Phi-node, call also the relinking * function of Phi's Block. If this block has bad predecessors, relink preds - * of the Phinode. + * of the Phi-node. */ static void relink_bad_predecessors(ir_node *n, void *env) { ir_node *block, **old_in; int i, old_irn_arity, new_irn_arity; - /* relink bad predeseccors of a block */ + /* relink bad predecessors of a block */ if (get_irn_op(n) == op_Block) relink_bad_block_predecessors(n, env); /* If Phi node relink its block and its predecessors */ if (get_irn_op(n) == op_Phi) { - /* Relink predeseccors of phi's block */ + /* Relink predecessors of phi's block */ block = get_nodes_block(n); if (get_irn_link(block) == NULL) relink_bad_block_predecessors(block, env); @@ -628,9 +634,9 @@ static void relink_bad_predecessors(ir_node *n, void *env) { old_in = (ir_node **)get_irn_link(block); /* Of Phi's Block */ old_irn_arity = ARR_LEN(old_in); - /* Relink Phi predeseccors if count of predeseccors changed */ + /* Relink Phi predecessors if count of predecessors changed */ if (old_irn_arity != ARR_LEN(get_irn_in(block))) { - /* set new predeseccors in array + /* set new predecessors in array n->in[0] remains the same block */ new_irn_arity = 1; for(i = 1; i < old_irn_arity; i++) @@ -648,7 +654,7 @@ static void relink_bad_predecessors(ir_node *n, void *env) { } /* - * Removes Bad Bad predecesors from Blocks and the corresponding + * Removes Bad Bad predecessors from Blocks and the corresponding * inputs to Phi nodes as in dead_node_elimination but without * copying the graph. * On walking up set the link field to NULL, on walking down call @@ -669,7 +675,7 @@ void remove_bad_predecessors(ir_graph *irg) { * Copy node for inlineing. Updates attributes that change when * inlineing but not for dead node elimination. * - * Copies the node by calling copy_node and then updates the entity if + * Copies the node by calling firm_copy_node and then updates the entity if * it's a local one. env must be a pointer of the frame type of the * inlined procedure. The new entities must be in the link field of * the entities. @@ -679,7 +685,7 @@ copy_node_inline (ir_node *n, void *env) { ir_node *new; type *frame_tp = (type *)env; - copy_node(n, NULL); + firm_copy_node(n, NULL); if (get_irn_op(n) == op_Sel) { new = get_new_node (n); assert(get_irn_op(new) == op_Sel); @@ -711,7 +717,7 @@ static int can_inline(ir_node *call, ir_graph *called_graph) { type *call_type = get_Call_type(call); int params, ress, i, res; - assert(is_method_type(call_type)); + assert(is_Method_type(call_type)); params = get_method_n_params(call_type); ress = get_method_n_ress(call_type); @@ -780,6 +786,7 @@ int inline_method(ir_node *call, ir_graph *called_graph) { if (get_irg_outs_state(current_ir_graph) == outs_consistent) set_irg_outs_inconsistent(current_ir_graph); set_irg_loopinfo_inconsistent(current_ir_graph); + set_irg_callee_info_state(current_ir_graph, irg_callee_info_inconsistent); /* -- Check preconditions -- */ assert(get_irn_op(call) == op_Call); @@ -795,7 +802,7 @@ int inline_method(ir_node *call, ir_graph *called_graph) { } /* here we know we WILL inline, so inform the statistics */ - stat_inline(call, called_graph); + hook_inline(call, called_graph); /* -- Decide how to handle exception control flow: Is there a handler for the Call node, or do we branch directly to End on an exception? @@ -906,8 +913,8 @@ int inline_method(ir_node *call, ir_graph *called_graph) { arity = get_irn_arity(end_bl); /* arity = n_exc + n_ret */ n_res = get_method_n_ress(get_Call_type(call)); - res_pred = (ir_node **) malloc (n_res * sizeof (ir_node *)); - cf_pred = (ir_node **) malloc (arity * sizeof (ir_node *)); + res_pred = xmalloc (n_res * sizeof(*res_pred)); + cf_pred = xmalloc (arity * sizeof(*res_pred)); set_irg_current_block(current_ir_graph, post_bl); /* just to make sure */ @@ -917,7 +924,7 @@ int inline_method(ir_node *call, ir_graph *called_graph) { add_End_keepalive(get_irg_end(current_ir_graph), get_irn_n(end, i)); /* The new end node will die. We need not free as the in array is on the obstack: - copy_node only generated 'D' arrays. */ + firm_copy_node only generated 'D' arrays. */ /* -- Replace Return nodes by Jump nodes. -- */ n_ret = 0; @@ -1038,7 +1045,7 @@ int inline_method(ir_node *call, ir_graph *called_graph) { } main_end_bl = get_irg_end_block(current_ir_graph); main_end_bl_arity = get_irn_arity(main_end_bl); - end_preds = (ir_node **) malloc ((n_exc + main_end_bl_arity) * sizeof (ir_node *)); + end_preds = xmalloc ((n_exc + main_end_bl_arity) * sizeof(*end_preds)); for (i = 0; i < main_end_bl_arity; ++i) end_preds[i] = get_irn_n(main_end_bl, i); @@ -1082,7 +1089,7 @@ int inline_method(ir_node *call, ir_graph *called_graph) { if (i < get_Block_n_cfgpreds(end_bl)) { bl = get_nodes_block(cf_op); arity = get_Block_n_cfgpreds(end_bl) + get_Block_n_cfgpreds(bl) - 1; - cf_pred = (ir_node **) malloc (arity * sizeof (ir_node *)); + cf_pred = xmalloc (arity * sizeof(*cf_pred)); for (j = 0; j < i; j++) cf_pred[j] = get_Block_cfgpred(end_bl, j); for (j = j; j < i + get_Block_n_cfgpreds(bl); j++) @@ -1097,7 +1104,7 @@ int inline_method(ir_node *call, ir_graph *called_graph) { } #endif - /* -- Turn cse back on. -- */ + /* -- Turn CSE back on. -- */ set_optimize(rem_opt); return 1; @@ -1190,7 +1197,7 @@ void inline_small_irgs(ir_graph *irg, int size) { for (i = 0; i < env.pos; i++) { ir_graph *callee; callee = get_entity_irg(get_SymConst_entity(get_Call_ptr(env.calls[i]))); - if (((_obstack_memory_used(callee->obst) - obstack_room(callee->obst)) < size) || + if (((_obstack_memory_used(callee->obst) - (int)obstack_room(callee->obst)) < size) || (get_irg_inline_property(callee) == irg_inline_forced)) { inline_method(env.calls[i], callee); } @@ -1213,29 +1220,39 @@ typedef struct { int n_callers_orig; /**< for statistics */ } inline_irg_env; +/** + * Allocate a new nvironment for inlining. + */ static inline_irg_env *new_inline_irg_env(void) { - inline_irg_env *env = malloc(sizeof(inline_irg_env)); - env->n_nodes = -2; /* uncount Start, End */ - env->n_nodes_orig = -2; /* uncount Start, End */ - env->call_nodes = eset_create(); - env->n_call_nodes = 0; + inline_irg_env *env = xmalloc(sizeof(*env)); + env->n_nodes = -2; /* do not count count Start, End */ + env->n_nodes_orig = -2; /* do not count Start, End */ + env->call_nodes = eset_create(); + env->n_call_nodes = 0; env->n_call_nodes_orig = 0; - env->n_callers = 0; - env->n_callers_orig = 0; + env->n_callers = 0; + env->n_callers_orig = 0; return env; } +/** + * destroy an environment for inlining. + */ static void free_inline_irg_env(inline_irg_env *env) { eset_destroy(env->call_nodes); free(env); } +/** + * post-walker: collect all calls in the inline-environment + * of a graph and sum some statistics. + */ static void collect_calls2(ir_node *call, void *env) { inline_irg_env *x = (inline_irg_env *)env; ir_op *op = get_irn_op(call); ir_graph *callee; - /* count nodes in irg */ + /* count meaningful nodes in irg */ if (op != op_Proj && op != op_Tuple && op != op_Sync) { x->n_nodes++; x->n_nodes_orig++; @@ -1251,15 +1268,23 @@ static void collect_calls2(ir_node *call, void *env) { /* count all static callers */ callee = get_call_called_irg(call); if (callee) { - ((inline_irg_env *)get_irg_link(callee))->n_callers++; - ((inline_irg_env *)get_irg_link(callee))->n_callers_orig++; + inline_irg_env *callee_env = get_irg_link(callee); + callee_env->n_callers++; + callee_env->n_callers_orig++; } } +/** + * Returns TRUE if the number of callers in 0 in the irg's environment, + * hence this irg is a leave. + */ INLINE static int is_leave(ir_graph *irg) { return (((inline_irg_env *)get_irg_link(irg))->n_call_nodes == 0); } +/** + * Returns TRUE if the number of callers is smaller size in the irg's environment. + */ INLINE static int is_smaller(ir_graph *callee, int size) { return (((inline_irg_env *)get_irg_link(callee))->n_nodes < size); } @@ -1281,7 +1306,7 @@ void inline_leave_functions(int maxsize, int leavesize, int size) { if (!(get_opt_optimize() && get_opt_inline())) return; - /* extend all irgs by a temporary data structure for inlineing. */ + /* extend all irgs by a temporary data structure for inlining. */ for (i = 0; i < n_irgs; ++i) set_irg_link(get_irp_irg(i), new_inline_irg_env()); @@ -1309,8 +1334,10 @@ void inline_leave_functions(int maxsize, int leavesize, int size) { env = (inline_irg_env *)get_irg_link(current_ir_graph); for (call = eset_first(env->call_nodes); call; call = eset_next(env->call_nodes)) { - if (get_irn_op(call) == op_Tuple) continue; /* We already inlined. */ - ir_graph *callee = get_call_called_irg(call); + ir_graph *callee; + + if (get_irn_op(call) == op_Tuple) continue; /* We already have inlined this call. */ + callee = get_call_called_irg(call); if (env->n_nodes > maxsize) continue; // break; @@ -1347,8 +1374,10 @@ void inline_leave_functions(int maxsize, int leavesize, int size) { walkset = env->call_nodes; env->call_nodes = eset_create(); for (call = eset_first(walkset); call; call = eset_next(walkset)) { + ir_graph *callee; + if (get_irn_op(call) == op_Tuple) continue; /* We already inlined. */ - ir_graph *callee = get_call_called_irg(call); + callee = get_call_called_irg(call); if (callee && ((is_smaller(callee, size) && (env->n_nodes < maxsize)) || /* small function */ @@ -1533,10 +1562,7 @@ consumer_dom_dca (ir_node *dca, ir_node *consumer, ir_node *producer) if (get_irn_n(consumer, i) == producer) { ir_node *new_block = get_nodes_block(get_Block_cfgpred(phi_block, i)); - if (block) - block = calc_dca(block, new_block); - else - block = new_block; + block = calc_dca(block, new_block); } } } else { @@ -1548,6 +1574,8 @@ consumer_dom_dca (ir_node *dca, ir_node *consumer, ir_node *producer) return calc_dca(dca, block); } +/* FIXME: the name clashes here with the function from ana/field_temperature.c + * please rename. */ static INLINE int get_irn_loop_depth(ir_node *n) { return get_loop_depth(get_irn_loop(n)); } @@ -1591,7 +1619,7 @@ move_out_of_loops (ir_node *n, ir_node *early) * `optimal' Block between the latest and earliest legal block. * The `optimal' block is the dominance-deepest block of those * with the least loop-nesting-depth. This places N out of as many - * loops as possible and then makes it as control dependant as + * loops as possible and then makes it as control dependent as * possible. */ static void @@ -1658,7 +1686,7 @@ place_floats_late(ir_node *n, pdeq *worklist) } /* Add predecessors of all non-floating nodes on list. (Those of floating - nodes are placeded already and therefore are marked.) */ + nodes are placeed already and therefore are marked.) */ for (i = 0; i < get_irn_n_outs(n); i++) { ir_node *succ = get_irn_out(n, i); if (irn_not_visited(get_irn_out(n, i))) {