X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fir%2Firgopt.c;h=560d47e081ae7ebfd47d8d16c86aae0bd8bf7d03;hb=169fd803ea2ed08171113c1fd7ab4e528e1ebc26;hp=c24181c939418a9a40ac54ac77545c49a35ebb53;hpb=a58a82dcc39d39e7797cdfe3912bac5363e2a7b9;p=libfirm diff --git a/ir/ir/irgopt.c b/ir/ir/irgopt.c index c24181c93..560d47e08 100644 --- a/ir/ir/irgopt.c +++ b/ir/ir/irgopt.c @@ -42,6 +42,7 @@ #include "irflag_t.h" #include "irhooks.h" #include "iredges_t.h" +#include "irtools.h" /* Defined in iropt.c */ pset *new_identities (void); @@ -91,6 +92,7 @@ optimize_in_place_wrapper (ir_node *n, void *env) { static INLINE void do_local_optimize(ir_node *n) { /* Handle graph state */ assert(get_irg_phase_state(current_ir_graph) != phase_building); + 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) @@ -99,7 +101,6 @@ static INLINE void do_local_optimize(ir_node *n) { set_irg_dom_inconsistent(current_ir_graph); set_irg_loopinfo_inconsistent(current_ir_graph); - /* Clean the value_table in irg for the CSE. */ del_identities(current_ir_graph->value_table); current_ir_graph->value_table = new_identities(); @@ -117,11 +118,23 @@ void local_optimize_node(ir_node *n) { current_ir_graph = rem; } +/** + * Block-Walker: uses dominance depth to mark dead blocks. + */ +static void kill_dead_blocks(ir_node *block, void *env) +{ + if (get_Block_dom_depth(block) < 0) + set_Block_dead(block); +} + void local_optimize_graph (ir_graph *irg) { ir_graph *rem = current_ir_graph; current_ir_graph = irg; + if (get_irg_dom_state(current_ir_graph) == dom_consistent) + irg_block_walk_graph(irg, NULL, kill_dead_blocks, NULL); + do_local_optimize(irg->end); current_ir_graph = rem; @@ -143,11 +156,10 @@ set_new_node (ir_node *old, ir_node *new) } /** - * Get this new node, before the old node is forgotton. + * Get this new node, before the old node is forgotten. */ static INLINE ir_node * -get_new_node (ir_node * n) -{ +get_new_node (ir_node * n) { return n->link; } @@ -211,28 +223,27 @@ static INLINE void new_backedge_info(ir_node *n) { * * Note: Also used for loop unrolling. */ -static void -firm_copy_node (ir_node *n, void *env) { +static void copy_node(ir_node *n, void *env) { ir_node *nn, *block; int new_arity; - opcode op = get_irn_opcode(n); + ir_op *op = get_irn_op(n); int copy_node_nr = env != NULL; /* The end node looses it's flexible in array. This doesn't matter, as dead node elimination builds End by hand, inlineing doesn't use the End node. */ - /* assert(n->op == op_End || ((_ARR_DESCR(n->in))->cookie != ARR_F_MAGIC)); */ + /* assert(op == op_End || ((_ARR_DESCR(n->in))->cookie != ARR_F_MAGIC)); */ - if (op == iro_Bad) { + if (op == op_Bad) { /* node copied already */ return; - } else if (op == iro_Block) { + } else if (op == op_Block) { block = NULL; new_arity = compute_new_arity(n); n->attr.block.graph_arr = NULL; } else { block = get_nodes_block(n); - if (get_irn_opcode(n) == iro_Phi) { + if (op == op_Phi) { new_arity = compute_new_arity(block); } else { new_arity = get_irn_arity(n); @@ -241,16 +252,15 @@ firm_copy_node (ir_node *n, void *env) { nn = new_ir_node(get_irn_dbg_info(n), current_ir_graph, block, - get_irn_op(n), + op, get_irn_mode(n), new_arity, - get_irn_in(n)); + get_irn_in(n) + 1); /* 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_node_attr(n, nn); new_backedge_info(nn); - set_new_node(n, nn); #if DEBUG_libfirm if (copy_node_nr) { @@ -259,8 +269,7 @@ firm_copy_node (ir_node *n, void *env) { } #endif - /* printf("\n old node: "); DDMSG2(n); - printf(" new node: "); DDMSG2(nn); */ + set_new_node(n, nn); } /** @@ -386,7 +395,7 @@ copy_graph (int copy_node_nr) { set_new_node(om, nm); /* copy the live nodes */ - irg_walk(get_nodes_block(oe), firm_copy_node, copy_preds, (void *)copy_node_nr); + irg_walk(get_nodes_block(oe), copy_node, copy_preds, INT_TO_PTR(copy_node_nr)); /* copy_preds for the end node ... */ set_nodes_block(ne, get_new_node(get_nodes_block(oe))); @@ -400,7 +409,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, firm_copy_node, copy_preds, (void *)copy_node_nr); + irg_walk(ka, copy_node, copy_preds, INT_TO_PTR(copy_node_nr)); add_End_keepalive(ne, get_new_node(ka)); } } @@ -413,7 +422,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, firm_copy_node, copy_preds, (void *)copy_node_nr); + irg_walk(ka, copy_node, copy_preds, INT_TO_PTR(copy_node_nr)); } add_End_keepalive(ne, get_new_node(ka)); } @@ -458,19 +467,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) { - firm_copy_node (get_irg_frame(current_ir_graph), (void *)copy_node_nr); + copy_node (get_irg_frame(current_ir_graph), INT_TO_PTR(copy_node_nr)); copy_preds(get_irg_frame(current_ir_graph), NULL); } if (get_irn_link(get_irg_globals(current_ir_graph)) == NULL) { - firm_copy_node (get_irg_globals(current_ir_graph), (void *)copy_node_nr); + copy_node (get_irg_globals(current_ir_graph), INT_TO_PTR(copy_node_nr)); copy_preds(get_irg_globals(current_ir_graph), NULL); } if (get_irn_link(get_irg_initial_mem(current_ir_graph)) == NULL) { - firm_copy_node (get_irg_initial_mem(current_ir_graph), (void *)copy_node_nr); + copy_node (get_irg_initial_mem(current_ir_graph), INT_TO_PTR(copy_node_nr)); copy_preds(get_irg_initial_mem(current_ir_graph), NULL); } if (get_irn_link(get_irg_args(current_ir_graph)) == NULL) { - firm_copy_node (get_irg_args(current_ir_graph), (void *)copy_node_nr); + copy_node (get_irg_args(current_ir_graph), INT_TO_PTR(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))); @@ -483,13 +492,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) { - firm_copy_node(get_irg_bad(current_ir_graph), (void *)copy_node_nr); + copy_node(get_irg_bad(current_ir_graph), INT_TO_PTR(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) { - firm_copy_node(get_irg_no_mem(current_ir_graph), (void *)copy_node_nr); + copy_node(get_irg_no_mem(current_ir_graph), INT_TO_PTR(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))); @@ -575,7 +584,7 @@ static void relink_bad_block_predecessors(ir_node *n, void *env) { get_irn_link(n) == NULL) { /* save old predecessors in link field (position 0 is the block operand)*/ - set_irn_link(n, (void *)get_irn_in(n)); + set_irn_link(n, get_irn_in(n)); /* count predecessors without bad nodes */ old_irn_arity = get_irn_arity(n); @@ -585,19 +594,19 @@ static void relink_bad_block_predecessors(ir_node *n, void *env) { /* arity changing: set new predecessors without bad nodes */ if (new_irn_arity < old_irn_arity) { /* Get new predecessor array. We do not resize the array, as we must - keep the old one to update Phis. */ + keep the old one to update Phis. */ new_in = NEW_ARR_D (ir_node *, current_ir_graph->obst, (new_irn_arity+1)); /* set new predecessors in array */ new_in[0] = NULL; new_irn_n = 1; for (i = 0; i < old_irn_arity; i++) { - irn = get_irn_n(n, i); - if (!is_Bad(irn)) { - new_in[new_irn_n] = irn; - is_backedge(n, i) ? set_backedge(n, new_irn_n-1) : set_not_backedge(n, new_irn_n-1); - new_irn_n++; - } + irn = get_irn_n(n, i); + if (!is_Bad(irn)) { + new_in[new_irn_n] = irn; + is_backedge(n, i) ? set_backedge(n, new_irn_n-1) : set_not_backedge(n, new_irn_n-1); + new_irn_n++; + } } //ARR_SETLEN(int, n->attr.block.backedge, new_irn_arity); ARR_SHRINKLEN(n->attr.block.backedge, new_irn_arity); @@ -637,14 +646,14 @@ static void relink_bad_predecessors(ir_node *n, void *env) { /* Relink Phi predecessors if count of predecessors changed */ if (old_irn_arity != ARR_LEN(get_irn_in(block))) { /* set new predecessors in array - n->in[0] remains the same block */ + n->in[0] remains the same block */ new_irn_arity = 1; for(i = 1; i < old_irn_arity; i++) - if (!is_Bad((ir_node *)old_in[i])) { - n->in[new_irn_arity] = n->in[i]; - is_backedge(n, i) ? set_backedge(n, new_irn_arity) : set_not_backedge(n, new_irn_arity); - new_irn_arity++; - } + if (!is_Bad((ir_node *)old_in[i])) { + n->in[new_irn_arity] = n->in[i]; + is_backedge(n, i) ? set_backedge(n, new_irn_arity) : set_not_backedge(n, new_irn_arity); + new_irn_arity++; + } ARR_SETLEN(ir_node *, n->in, new_irn_arity); ARR_SETLEN(int, n->attr.phi_backedge, new_irn_arity); @@ -668,14 +677,14 @@ void remove_bad_predecessors(ir_graph *irg) { /*--------------------------------------------------------------------*/ -/* Funcionality for inlining */ +/* Functionality for inlining */ /*--------------------------------------------------------------------*/ /** * Copy node for inlineing. Updates attributes that change when * inlineing but not for dead node elimination. * - * Copies the node by calling firm_copy_node and then updates the entity if + * Copies the node by calling 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. @@ -685,7 +694,7 @@ copy_node_inline (ir_node *n, void *env) { ir_node *new; type *frame_tp = (type *)env; - firm_copy_node(n, NULL); + copy_node(n, NULL); if (get_irn_op(n) == op_Sel) { new = get_new_node (n); assert(get_irn_op(new) == op_Sel); @@ -924,7 +933,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: - firm_copy_node only generated 'D' arrays. */ + copy_node() only generated 'D' arrays. */ /* -- Replace Return nodes by Jump nodes. -- */ n_ret = 0; @@ -1221,7 +1230,7 @@ typedef struct { } inline_irg_env; /** - * Allocate a new nvironment for inlining. + * Allocate a new environment for inlining. */ static inline_irg_env *new_inline_irg_env(void) { inline_irg_env *env = xmalloc(sizeof(*env)); @@ -1261,7 +1270,7 @@ static void collect_calls2(ir_node *call, void *env) { if (op != op_Call) return; /* collect all call nodes */ - eset_insert(x->call_nodes, (void *)call); + eset_insert(x->call_nodes, call); x->n_call_nodes++; x->n_call_nodes_orig++; @@ -1425,6 +1434,8 @@ void inline_leave_functions(int maxsize, int leavesize, int size) { /** * Returns non-zero, is a block is not reachable from Start. + * + * @param block the block to test */ static int is_Block_unreachable(ir_node *block) { @@ -1437,21 +1448,31 @@ is_Block_unreachable(ir_node *block) { * * We have to avoid calls to get_nodes_block() here * because the graph is floating. + * + * move_out_of_loops() expects that place_floats_early() have placed + * all "living" nodes into a living block. That's why we must + * move nodes in dead block with "live" successors into a valid + * block. + * We move them just into the same block as it's successor (or + * in case of a Phi into the effective use block). For Phi successors, + * this may still be a dead block, but then there is no real use, as + * the control flow will be dead later. */ static void place_floats_early(ir_node *n, pdeq *worklist) { - int i, start, irn_arity; + int i, irn_arity; /* we must not run into an infinite loop */ - assert (irn_not_visited(n)); + assert(irn_not_visited(n)); mark_irn_visited(n); /* Place floating nodes. */ if (get_irn_pinned(n) == op_pin_state_floats) { - int depth = 0; - ir_node *b = NULL; /* The block to place this node in */ - int bad_recursion = is_Block_unreachable(get_irn_n(n, -1)); + ir_node *curr_block = get_irn_n(n, -1); + int in_dead_block = is_Block_unreachable(curr_block); + int depth = 0; + ir_node *b = NULL; /* The block to place this node in */ assert(get_irn_op(n) != op_Block); @@ -1467,29 +1488,43 @@ place_floats_early(ir_node *n, pdeq *worklist) /* find the block for this node. */ irn_arity = get_irn_arity(n); for (i = 0; i < irn_arity; i++) { - ir_node *dep = get_irn_n(n, i); - ir_node *dep_block; - - if ((irn_not_visited(dep)) - && (get_irn_pinned(dep) == op_pin_state_floats)) { - place_floats_early(dep, worklist); + ir_node *pred = get_irn_n(n, i); + ir_node *pred_block; + + if ((irn_not_visited(pred)) + && (get_irn_pinned(pred) == op_pin_state_floats)) { + + /* + * If the current node is NOT in a dead block, but one of its + * predecessors is, we must move the predecessor to a live block. + * Such thing can happen, if global CSE chose a node from a dead block. + * We move it simple to our block. + * Note that neither Phi nor End nodes are floating, so we don't + * need to handle them here. + */ + if (! in_dead_block) { + if (get_irn_pinned(pred) == op_pin_state_floats && + is_Block_unreachable(get_irn_n(pred, -1))) + set_nodes_block(pred, curr_block); + } + place_floats_early(pred, worklist); } /* * A node in the Bad block must stay in the bad block, * so don't compute a new block for it. */ - if (bad_recursion) + if (in_dead_block) continue; /* Because all loops contain at least one op_pin_state_pinned node, now all - our inputs are either op_pin_state_pinned or place_early has already + our inputs are either op_pin_state_pinned or place_early() has already been finished on them. We do not have any unfinished inputs! */ - dep_block = get_irn_n(dep, -1); - if ((!is_Block_dead(dep_block)) && - (get_Block_dom_depth(dep_block) > depth)) { - b = dep_block; - depth = get_Block_dom_depth(dep_block); + pred_block = get_irn_n(pred, -1); + if ((!is_Block_dead(pred_block)) && + (get_Block_dom_depth(pred_block) > depth)) { + b = pred_block; + depth = get_Block_dom_depth(pred_block); } /* Avoid that the node is placed in the Start block */ if ((depth == 1) && (get_Block_dom_depth(get_irn_n(n, -1)) > 1)) { @@ -1502,13 +1537,83 @@ place_floats_early(ir_node *n, pdeq *worklist) set_nodes_block(n, b); } - /* Add predecessors of non floating nodes on worklist. */ - start = (get_irn_op(n) == op_Block) ? 0 : -1; + /* + * Add predecessors of non floating nodes and non-floating predecessors + * of floating nodes to worklist and fix their blocks if the are in dead block. + */ irn_arity = get_irn_arity(n); - for (i = start; i < irn_arity; i++) { - ir_node *pred = get_irn_n(n, i); - if (irn_not_visited(pred)) { - pdeq_putr (worklist, pred); + + if (get_irn_op(n) == op_End) { + /* + * Simplest case: End node. Predecessors are keep-alives, + * no need to move out of dead block. + */ + for (i = -1; i < irn_arity; ++i) { + ir_node *pred = get_irn_n(n, i); + if (irn_not_visited(pred)) + pdeq_putr(worklist, pred); + } + } + else if (is_Block(n)) { + /* + * Blocks: Predecessors are control flow, no need to move + * them out of dead block. + */ + for (i = irn_arity - 1; i >= 0; --i) { + ir_node *pred = get_irn_n(n, i); + if (irn_not_visited(pred)) + pdeq_putr(worklist, pred); + } + } + else if (is_Phi(n)) { + ir_node *pred; + ir_node *curr_block = get_irn_n(n, -1); + int in_dead_block = is_Block_unreachable(curr_block); + + /* + * Phi nodes: move nodes from dead blocks into the effective use + * of the Phi-input if the Phi is not in a bad block. + */ + pred = get_irn_n(n, -1); + if (irn_not_visited(pred)) + pdeq_putr(worklist, pred); + + for (i = irn_arity - 1; i >= 0; --i) { + ir_node *pred = get_irn_n(n, i); + + if (irn_not_visited(pred)) { + if (! in_dead_block && + get_irn_pinned(pred) == op_pin_state_floats && + is_Block_unreachable(get_irn_n(pred, -1))) { + set_nodes_block(pred, get_Block_cfgpred_block(curr_block, i)); + } + pdeq_putr(worklist, pred); + } + } + } + else { + ir_node *pred; + ir_node *curr_block = get_irn_n(n, -1); + int in_dead_block = is_Block_unreachable(curr_block); + + /* + * All other nodes: move nodes from dead blocks into the same block. + */ + pred = get_irn_n(n, -1); + if (irn_not_visited(pred)) + pdeq_putr(worklist, pred); + + for (i = irn_arity - 1; i >= 0; --i) { + ir_node *pred = get_irn_n(n, i); + + if (irn_not_visited(pred)) { + if (! in_dead_block && + get_irn_pinned(pred) == op_pin_state_floats && + is_Block_unreachable(get_irn_n(pred, -1))) { + set_nodes_block(pred, curr_block); + } + pdeq_putr(worklist, pred); + } } } } @@ -1527,9 +1632,10 @@ static INLINE void place_early(pdeq *worklist) { place_floats_early(get_irg_end(current_ir_graph), worklist); /* Work the content of the worklist. */ - while (!pdeq_empty (worklist)) { - ir_node *n = pdeq_getl (worklist); - if (irn_not_visited(n)) place_floats_early(n, worklist); + while (!pdeq_empty(worklist)) { + ir_node *n = pdeq_getl(worklist); + if (irn_not_visited(n)) + place_floats_early(n, worklist); } set_irg_outs_inconsistent(current_ir_graph); @@ -1569,7 +1675,7 @@ static ir_node *calc_dca(ir_node *dca, ir_node *block) * A data flow edge points from producer to consumer. */ static ir_node * -consumer_dom_dca (ir_node *dca, ir_node *consumer, ir_node *producer) +consumer_dom_dca(ir_node *dca, ir_node *consumer, ir_node *producer) { ir_node *block = NULL; @@ -1593,8 +1699,8 @@ consumer_dom_dca (ir_node *dca, ir_node *consumer, ir_node *producer) if (! block) block = get_irn_n(producer, -1); - - } else { + } + else { assert(is_no_Block(consumer)); block = get_nodes_block(consumer); } @@ -1659,9 +1765,9 @@ static void place_floats_late(ir_node *n, pdeq *worklist) { int i; - ir_node *early; + ir_node *early_blk; - assert (irn_not_visited(n)); /* no multiple placement */ + assert(irn_not_visited(n)); /* no multiple placement */ mark_irn_visited(n); @@ -1669,9 +1775,9 @@ place_floats_late(ir_node *n, pdeq *worklist) if ((get_irn_op(n) != op_Block) && (!is_cfop(n)) && (get_irn_mode(n) != mode_X)) { - /* Remember the early placement of this block to move it - out of loop no further than the early placement. */ - early = get_irn_n(n, -1); + /* Remember the early_blk placement of this block to move it + out of loop no further than the early_blk placement. */ + early_blk = get_irn_n(n, -1); /* * BEWARE: Here we also get code, that is live, but @@ -1693,30 +1799,41 @@ place_floats_late(ir_node *n, pdeq *worklist) place_floats_late(succ, worklist); } - /* We have to determine the final block of this node... except for - constants. */ - if ((get_irn_pinned(n) == op_pin_state_floats) && - (get_irn_op(n) != op_Const) && - (get_irn_op(n) != op_SymConst)) { - ir_node *dca = NULL; /* deepest common ancestor in the - dominator tree of all nodes' - blocks depending on us; our final - placement has to dominate DCA. */ - for (i = 0; i < get_irn_n_outs(n); ++i) { - ir_node *out = get_irn_out(n, i); - - /* ignore if out is in dead code */ - ir_node *outbl = get_nodes_block(out); - if (is_Block_unreachable(outbl)) - continue; - dca = consumer_dom_dca(dca, out, n); - } - if (dca) { - set_nodes_block(n, dca); + if (! is_Block_dead(early_blk)) { + /* do only move things that where not dead */ + + /* We have to determine the final block of this node... except for + constants. */ + if ((get_irn_pinned(n) == op_pin_state_floats) && + (get_irn_op(n) != op_Const) && + (get_irn_op(n) != op_SymConst)) { + ir_node *dca = NULL; /* deepest common ancestor in the + dominator tree of all nodes' + blocks depending on us; our final + placement has to dominate DCA. */ + for (i = get_irn_n_outs(n) - 1; i >= 0; --i) { + ir_node *succ = get_irn_out(n, i); + ir_node *succ_blk; + + if (get_irn_op(succ) == op_End) { + /* + * This consumer is the End node, a keep alive edge. + * This is not a real consumer, so we ignore it + */ + continue; + } - move_out_of_loops (n, early); + /* ignore if succ is in dead code */ + succ_blk = get_irn_n(succ, -1); + if (is_Block_unreachable(succ_blk)) + continue; + dca = consumer_dom_dca(dca, succ, n); + } + if (dca) { + set_nodes_block(n, dca); + move_out_of_loops(n, early_blk); + } } - /* else all outs are in dead code */ } } @@ -1725,7 +1842,7 @@ place_floats_late(ir_node *n, pdeq *worklist) 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))) { - pdeq_putr (worklist, succ); + pdeq_putr(worklist, succ); } } } @@ -1738,9 +1855,10 @@ static INLINE void place_late(pdeq *worklist) { place_floats_late(get_irg_start_block(current_ir_graph), worklist); /* And now empty the worklist again... */ - while (!pdeq_empty (worklist)) { - ir_node *n = pdeq_getl (worklist); - if (irn_not_visited(n)) place_floats_late(n, worklist); + while (!pdeq_empty(worklist)) { + ir_node *n = pdeq_getl(worklist); + if (irn_not_visited(n)) + place_floats_late(n, worklist); } } @@ -1767,8 +1885,9 @@ void place_code(ir_graph *irg) { worklist = new_pdeq(); place_early(worklist); - /* place_early invalidates the outs, place_late needs them. */ + /* place_early() invalidates the outs, place_late needs them. */ compute_irg_outs(irg); + /* Now move the nodes down in the dominator tree. This reduces the unnecessary executions of the node. */ place_late(worklist);