X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fir%2Firgopt.c;h=547dc8100f3bd3f25ab9b299a3a8b16d36a4b077;hb=6ce54897086db42a2f4a59d946e9895954cc9ef3;hp=4ab6a0b4c813d05a676d671da3d23622f7ad408c;hpb=5751a1b589b02dadded2c60d705394fca4333ba5;p=libfirm diff --git a/ir/ir/irgopt.c b/ir/ir/irgopt.c index 4ab6a0b4c..547dc8100 100644 --- a/ir/ir/irgopt.c +++ b/ir/ir/irgopt.c @@ -29,6 +29,7 @@ #include "array.h" #include "pset.h" +#include "pmap.h" #include "eset.h" #include "pdeq.h" /* Fuer code placement */ #include "xmalloc.h" @@ -39,6 +40,7 @@ #include "cgana.h" #include "trouts.h" + #include "irflag_t.h" #include "irhooks.h" #include "iredges_t.h" @@ -47,7 +49,7 @@ /* Defined in iropt.c */ pset *new_identities (void); void del_identities (pset *value_table); -void add_identities (pset *value_table, ir_node *node); +void add_identities (pset *value_table, ir_node *node); /*------------------------------------------------------------------*/ /* apply optimizations of iropt to all nodes. */ @@ -95,8 +97,7 @@ static INLINE void do_local_optimize(ir_node *n) { if (get_opt_global_cse()) set_irg_pinned(current_ir_graph, op_pin_state_floats); - if (get_irg_outs_state(current_ir_graph) == outs_consistent) - set_irg_outs_inconsistent(current_ir_graph); + set_irg_outs_inconsistent(current_ir_graph); set_irg_doms_inconsistent(current_ir_graph); set_irg_loopinfo_inconsistent(current_ir_graph); @@ -250,6 +251,7 @@ static void copy_node(ir_node *n, void *env) { #endif set_new_node(n, nn); + hook_dead_node_elim_subst(current_ir_graph, n, nn); } /** @@ -505,7 +507,7 @@ dead_node_elimination(ir_graph *irg) { struct obstack *rebirth_obst = NULL; if (get_opt_optimize() && get_opt_dead_node_elimination()) { - assert(! edges_activated(irg) && "dead node elimination requieres disabled edges"); + assert(! edges_activated(irg) && "dead node elimination requires disabled edges"); /* inform statistics that we started a dead-node elimination run */ hook_dead_node_elim(irg, 1); @@ -664,6 +666,118 @@ void remove_bad_predecessors(ir_graph *irg) { } +/* + __ _ __ __ + (_ __ o _ | \/ |_ + __)|_| | \_/ | \_/(/_ |_/\__|__ + + The following stuff implements a facility that automatically patches + registered ir_node pointers to the new node when a dead node elimination occurs. +*/ + +struct _survive_dce_t { + struct obstack obst; + pmap *places; + pmap *new_places; + hook_entry_t dead_node_elim; + hook_entry_t dead_node_elim_subst; +}; + +typedef struct _survive_dce_list_t { + struct _survive_dce_list_t *next; + ir_node **place; +} survive_dce_list_t; + +static void dead_node_hook(void *context, ir_graph *irg, int start) +{ + survive_dce_t *sd = context; + + /* Create a new map before the dead node elimination is performed. */ + if(start) { + sd->new_places = pmap_create_ex(pmap_count(sd->places)); + } + + /* Patch back all nodes if dead node elimination is over and something is to be done. */ + else { + pmap_destroy(sd->places); + sd->places = sd->new_places; + sd->new_places = NULL; + } +} + +static void dead_node_subst_hook(void *context, ir_graph *irg, ir_node *old, ir_node *nw) +{ + survive_dce_t *sd = context; + survive_dce_list_t *list = pmap_get(sd->places, old); + + /* If the node is to be patched back, write the new address to all registered locations. */ + if(list) { + survive_dce_list_t *p; + + for(p = list; p; p = p->next) + *(p->place) = nw; + + pmap_insert(sd->new_places, nw, list); + } +} + +/** + * Make a new Survive DCE environment. + */ +survive_dce_t *new_survive_dce(void) +{ + survive_dce_t *res = xmalloc(sizeof(res[0])); + obstack_init(&res->obst); + res->places = pmap_create(); + res->new_places = NULL; + + res->dead_node_elim.hook._hook_dead_node_elim = dead_node_hook; + res->dead_node_elim.context = res; + res->dead_node_elim.next = NULL; + + res->dead_node_elim_subst.hook._hook_dead_node_elim_subst = dead_node_subst_hook; + res->dead_node_elim_subst.context = res; + res->dead_node_elim_subst.next = NULL; + + register_hook(hook_dead_node_elim, &res->dead_node_elim); + register_hook(hook_dead_node_elim_subst, &res->dead_node_elim_subst); + return res; +} + +/** + * Free a Survive DCE environment. + */ +void free_survive_dce(survive_dce_t *sd) +{ + obstack_free(&sd->obst, NULL); + pmap_destroy(sd->places); + unregister_hook(hook_dead_node_elim, &sd->dead_node_elim); + unregister_hook(hook_dead_node_elim_subst, &sd->dead_node_elim_subst); + free(sd); +} + +/** + * Register a node pointer to be patched upon DCE. + * When DCE occurs, the node pointer specified by @p place will be + * patched to the new address of the node it is pointing to. + * + * @param sd The Survive DCE environment. + * @param place The address of the node pointer. + */ +void survive_dce_register_irn(survive_dce_t *sd, ir_node **place) +{ + if(*place != NULL) { + ir_node *irn = *place; + survive_dce_list_t *curr = pmap_get(sd->places, irn); + survive_dce_list_t *nw = obstack_alloc(&sd->obst, sizeof(nw)); + + nw->next = curr; + nw->place = place; + + pmap_insert(sd->places, irn, nw); + } +} + /*--------------------------------------------------------------------*/ /* Functionality for inlining */ /*--------------------------------------------------------------------*/ @@ -679,19 +793,19 @@ void remove_bad_predecessors(ir_graph *irg) { */ static INLINE void copy_node_inline (ir_node *n, void *env) { - ir_node *new; + ir_node *nn; ir_type *frame_tp = (ir_type *)env; copy_node(n, NULL); if (get_irn_op(n) == op_Sel) { - new = get_new_node (n); - assert(get_irn_op(new) == op_Sel); + nn = get_new_node (n); + assert(is_Sel(nn)); if (get_entity_owner(get_Sel_entity(n)) == frame_tp) { - set_Sel_entity(new, get_entity_link(get_Sel_entity(n))); + set_Sel_entity(nn, get_entity_link(get_Sel_entity(n))); } } else if (get_irn_op(n) == op_Block) { - new = get_new_node (n); - new->attr.block.irg = current_ir_graph; + nn = get_new_node (n); + nn->attr.block.irg = current_ir_graph; } } @@ -780,13 +894,14 @@ int inline_method(ir_node *call, ir_graph *called_graph) { assert(get_irg_phase_state(current_ir_graph) != phase_building); assert(get_irg_pinned(current_ir_graph) == op_pin_state_pinned); assert(get_irg_pinned(called_graph) == op_pin_state_pinned); - if (get_irg_outs_state(current_ir_graph) == outs_consistent) - set_irg_outs_inconsistent(current_ir_graph); + set_irg_outs_inconsistent(current_ir_graph); + set_irg_extblk_inconsistent(current_ir_graph); + set_irg_doms_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); + assert(is_Call(call)); /* @@@ does not work for InterfaceIII.java after cgana assert(get_Call_type(call) == get_entity_type(get_irg_entity(called_graph))); assert(smaller_type(get_entity_type(get_irg_entity(called_graph)), @@ -928,7 +1043,7 @@ int inline_method(ir_node *call, ir_graph *called_graph) { for (i = 0; i < arity; i++) { ir_node *ret; ret = get_irn_n(end_bl, i); - if (get_irn_op(ret) == op_Return) { + if (is_Return(ret)) { cf_pred[n_ret] = new_r_Jmp(current_ir_graph, get_nodes_block(ret)); n_ret++; } @@ -942,7 +1057,7 @@ int inline_method(ir_node *call, ir_graph *called_graph) { n_ret = 0; for (i = 0; i < arity; i++) { ret = get_irn_n(end_bl, i); - if (get_irn_op(ret) == op_Return) { + if (is_Return(ret)) { cf_pred[n_ret] = get_Return_mem(ret); n_ret++; } @@ -1008,7 +1123,7 @@ int inline_method(ir_node *call, ir_graph *called_graph) { for (i = 0; i < arity; i++) { ir_node *ret; ret = skip_Proj(get_irn_n(end_bl, i)); - if (get_irn_op(ret) == op_Call) { + if (is_Call(ret)) { cf_pred[n_exc] = new_r_Proj(current_ir_graph, get_nodes_block(ret), ret, mode_M, 3); n_exc++; } else if (is_fragile_op(ret)) { @@ -1131,7 +1246,7 @@ static ir_graph *get_call_called_irg(ir_node *call) { ir_node *addr; ir_graph *called_irg = NULL; - assert(get_irn_op(call) == op_Call); + assert(is_Call(call)); addr = get_Call_ptr(call); if ((get_irn_op(addr) == op_SymConst) && (get_SymConst_kind (addr) == symconst_addr_ent)) { @@ -1144,7 +1259,7 @@ static ir_graph *get_call_called_irg(ir_node *call) { static void collect_calls(ir_node *call, void *env) { ir_node *addr; - if (get_irn_op(call) != op_Call) return; + if (! is_Call(call)) return; addr = get_Call_ptr(call); @@ -1892,47 +2007,48 @@ void place_code(ir_graph *irg) { * Place an empty block to an edge between a blocks of multiple * predecessors and a block of multiple successors. * - * @param n IR node - * @param env Environment of walker. This field is unused and has - * the value NULL. + * @param n IR node + * @param env Environment of walker. The changed field. */ static void walk_critical_cf_edges(ir_node *n, void *env) { int arity, i; - ir_node *pre, *block, **in, *jmp; + ir_node *pre, *block, *jmp; + int *changed = env; /* Block has multiple predecessors */ - if ((op_Block == get_irn_op(n)) && - (get_irn_arity(n) > 1)) { - arity = get_irn_arity(n); - + if (is_Block(n) && (get_irn_arity(n) > 1)) { if (n == get_irg_end_block(current_ir_graph)) return; /* No use to add a block here. */ + arity = get_irn_arity(n); for (i=0; iobst, 1); - /* set predecessor of new block */ - in[0] = pre; - block = new_Block(1, in); - /* insert new jmp node to new block */ - set_cur_block(block); - jmp = new_Jmp(); - set_cur_block(n); - /* set successor of new block */ - set_irn_n(n, i, jmp); - + /* Predecessor has multiple successors. Insert new control flow edge. */ + if (op_Raise != get_irn_op(skip_Proj(pre))) { + /* set predecessor of new block */ + block = new_Block(1, &pre); + /* insert new jmp node to new block */ + set_cur_block(block); + jmp = new_Jmp(); + set_cur_block(n); + /* set successor of new block */ + set_irn_n(n, i, jmp); + *changed = 1; } /* predecessor has multiple successors */ } /* for all predecessors */ } /* n is a block */ } void remove_critical_cf_edges(ir_graph *irg) { - if (get_opt_critical_edges()) - irg_walk_graph(irg, NULL, walk_critical_cf_edges, NULL); + int changed = 0; + irg_walk_graph(irg, NULL, walk_critical_cf_edges, &changed); + + if (changed) { + /* control flow changed */ + set_irg_outs_inconsistent(irg); + set_irg_extblk_inconsistent(irg); + set_irg_doms_inconsistent(current_ir_graph); + set_irg_loopinfo_inconsistent(current_ir_graph); + } + }