#include "array.h"
#include "pset.h"
+#include "pmap.h"
#include "eset.h"
#include "pdeq.h" /* Fuer code placement */
#include "xmalloc.h"
#include "cgana.h"
#include "trouts.h"
+
#include "irflag_t.h"
#include "irhooks.h"
#include "iredges_t.h"
+#include "irtools.h"
/* 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. */
/*------------------------------------------------------------------*/
-static void init_link (ir_node *n, void *env) {
- set_irn_link(n, NULL);
-}
-
-#if 0 /* Old version. Avoids Ids.
- 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
-optimize_in_place_wrapper (ir_node *n, void *env) {
- int i, irn_arity;
- ir_node *optimized, *old;
-
- irn_arity = get_irn_arity(n);
- for (i = 0; i < irn_arity; i++) {
- /* get_irn_n skips Id nodes, so comparison old != optimized does not
- show all optimizations. Therefore always set new predecessor. */
- old = get_irn_intra_n(n, i);
- optimized = optimize_in_place_2(old);
- set_irn_n(n, i, optimized);
- }
-
- if (get_irn_op(n) == op_Block) {
- optimized = optimize_in_place_2(n);
- if (optimized != n) exchange (n, optimized);
- }
-}
-#else
-static void
-optimize_in_place_wrapper (ir_node *n, void *env) {
+/**
+ * A wrapper around optimize_inplace_2() to be called from a walker.
+ */
+static void optimize_in_place_wrapper (ir_node *n, void *env) {
ir_node *optimized = optimize_in_place_2(n);
if (optimized != n) exchange (n, optimized);
}
-#endif
-
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)
- set_irg_outs_inconsistent(current_ir_graph);
- if (get_irg_dom_state(current_ir_graph) == dom_consistent)
- set_irg_dom_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);
-
/* Clean the value_table in irg for the CSE. */
del_identities(current_ir_graph->value_table);
current_ir_graph->value_table = new_identities();
/* walk over the graph */
- irg_walk(n, init_link, optimize_in_place_wrapper, NULL);
+ irg_walk(n, firm_clear_link, optimize_in_place_wrapper, NULL);
}
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)
+ if (block != get_irg_end_block(current_ir_graph)) {
+ /* we don't want that the end block of graphs with
+ endless loops is marked bad (although it is of course */
+ set_Block_dead(block);
+ }
+}
+
void
local_optimize_graph (ir_graph *irg) {
ir_graph *rem = current_ir_graph;
current_ir_graph = irg;
- do_local_optimize(irg->end);
+ if (get_irg_dom_state(current_ir_graph) == dom_consistent)
+ irg_block_walk_graph(irg, NULL, kill_dead_blocks, NULL);
+
+ do_local_optimize(get_irg_end(irg));
current_ir_graph = rem;
}
+/**
+ * Data flow optimization walker.
+ */
+static void opt_walker(ir_node *n, void *env) {
+ pdeq *waitq = env;
+ ir_node *optimized;
+
+ optimized = optimize_in_place_2(n);
+ set_irn_link(optimized, NULL);
+
+ if (optimized != n) {
+ const ir_edge_t *edge;
+
+ exchange(n, optimized);
+ foreach_out_edge(optimized, edge) {
+ ir_node *succ = get_edge_src_irn(edge);
+
+ if (get_irn_link(succ) != waitq) {
+ pdeq_putr(waitq, succ);
+ set_irn_link(succ, waitq);
+ }
+ }
+ }
+}
+
+void optimize_graph_df(ir_graph *irg) {
+ pdeq *waitq = new_pdeq();
+ int state = edges_activated(irg);
+
+ if (! state)
+ edges_activate(irg);
+
+ if (get_opt_global_cse())
+ set_irg_pinned(current_ir_graph, op_pin_state_floats);
+
+ /* Clean the value_table in irg for the CSE. */
+ del_identities(irg->value_table);
+ irg->value_table = new_identities();
+
+ if (get_irg_dom_state(current_ir_graph) == dom_consistent)
+ irg_block_walk_graph(irg, NULL, kill_dead_blocks, NULL);
+
+ /* invalidate info */
+ set_irg_outs_inconsistent(irg);
+ set_irg_doms_inconsistent(irg);
+ set_irg_loopinfo_inconsistent(irg);
+
+ /* walk over the graph */
+ irg_walk_graph(irg, NULL, opt_walker, waitq);
+
+ /* finish the wait queue */
+ while (! pdeq_empty(waitq)) {
+ ir_node *n = pdeq_getl(waitq);
+ opt_walker(n, waitq);
+ }
+
+ del_pdeq(waitq);
+
+ if (! state)
+ edges_deactivate(irg);
+}
+
/*------------------------------------------------------------------*/
/* Routines for dead node elimination / copying garbage collection */
/**
* Remember the new node in the old node by using a field all nodes have.
*/
-static INLINE void
-set_new_node (ir_node *old, ir_node *new)
-{
- old->link = new;
-}
+#define set_new_node(oldn, newn) set_irn_link(oldn, newn)
/**
- * 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)
-{
- return n->link;
-}
+#define get_new_node(oldn) get_irn_link(oldn)
+
+/**
+ * Check if a new node was set.
+ */
+#define has_new_node(n) (get_new_node(n) != NULL)
/**
* We use the block_visited flag to mark that we have computed the
}
}
-/* TODO: add an ir_op operation */
-static INLINE void new_backedge_info(ir_node *n) {
- switch(get_irn_opcode(n)) {
- case iro_Block:
- n->attr.block.cg_backedge = NULL;
- n->attr.block.backedge = new_backedge_arr(current_ir_graph->obst, get_irn_arity(n));
- break;
- case iro_Phi:
- n->attr.phi_backedge = new_backedge_arr(current_ir_graph->obst, get_irn_arity(n));
- break;
- case iro_Filter:
- n->attr.filter.backedge = new_backedge_arr(current_ir_graph->obst, get_irn_arity(n));
- break;
- default: ;
- }
-}
-
/**
* Copies the node to the new obstack. The Ins of the new node point to
* the predecessors on the old obstack. For block/phi nodes not all
*
* 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);
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) {
}
#endif
- /* printf("\n old node: "); DDMSG2(n);
- printf(" new node: "); DDMSG2(nn); */
+ set_new_node(n, nn);
+ hook_dead_node_elim_subst(current_ir_graph, n, nn);
}
/**
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.
- @@@ inlinening aborts if we identify End. Why? */
+ @@@ inlining aborts if we identify End. Why? */
if (get_irn_op(nn) != op_End)
add_identities (current_ir_graph->value_table, nn);
}
/**
- * Copies the graph recursively, compacts the keepalive of the end node.
+ * Copies the graph recursively, compacts the keep-alives of the end node.
*
+ * @param irg the graph to be copied
* @param copy_node_nr If non-zero, the node number will be copied
*/
-static void
-copy_graph (int copy_node_nr) {
+static void copy_graph(ir_graph *irg, int copy_node_nr) {
ir_node *oe, *ne, *ob, *nb, *om, *nm; /* old end, new end, old bad, new bad, old NoMem, new NoMem */
ir_node *ka; /* keep alive */
int i, irn_arity;
+ unsigned long vfl;
+
+ /* Some nodes must be copied by hand, sigh */
+ vfl = get_irg_visited(irg);
+ set_irg_visited(irg, vfl + 1);
- oe = get_irg_end(current_ir_graph);
+ oe = get_irg_end(irg);
+ mark_irn_visited(oe);
/* copy the end node by hand, allocate dynamic in array! */
ne = new_ir_node(get_irn_dbg_info(oe),
- current_ir_graph,
+ irg,
NULL,
op_End,
mode_X,
set_new_node(oe, ne);
/* copy the Bad node */
- ob = get_irg_bad(current_ir_graph);
- nb = new_ir_node(get_irn_dbg_info(ob),
- current_ir_graph,
+ ob = get_irg_bad(irg);
+ mark_irn_visited(ob);
+ nb = new_ir_node(get_irn_dbg_info(ob),
+ irg,
NULL,
op_Bad,
mode_T,
0,
NULL);
+ copy_node_attr(ob, nb);
set_new_node(ob, nb);
/* copy the NoMem node */
- om = get_irg_no_mem(current_ir_graph);
- nm = new_ir_node(get_irn_dbg_info(om),
- current_ir_graph,
+ om = get_irg_no_mem(irg);
+ mark_irn_visited(om);
+ nm = new_ir_node(get_irn_dbg_info(om),
+ irg,
NULL,
op_NoMem,
mode_M,
0,
NULL);
+ copy_node_attr(om, nm);
set_new_node(om, nm);
/* copy the live nodes */
- irg_walk(get_nodes_block(oe), firm_copy_node, copy_preds, (void *)copy_node_nr);
+ set_irg_visited(irg, vfl);
+ irg_walk(get_nodes_block(oe), copy_node, copy_preds, INT_TO_PTR(copy_node_nr));
+
+ /* Note: from yet, the visited flag of the graph is equal to vfl + 1 */
+
+ /* visit the anchors as well */
+ for (i = anchor_max - 1; i >= 0; --i) {
+ ir_node *n = irg->anchors[i];
+
+ if (n && (get_irn_visited(n) <= vfl)) {
+ set_irg_visited(irg, vfl);
+ irg_walk(n, 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)));
irn_arity = get_irn_arity(oe);
for (i = 0; i < irn_arity; i++) {
ka = get_irn_intra_n(oe, i);
- if ((get_irn_op(ka) == op_Block) &&
- (get_irn_visited(ka) < get_irg_visited(current_ir_graph))) {
+ if (is_Block(ka) &&
+ (get_irn_visited(ka) <= vfl)) {
/* 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);
+ set_irg_visited(irg, vfl);
+ irg_walk(ka, copy_node, copy_preds, INT_TO_PTR(copy_node_nr));
add_End_keepalive(ne, get_new_node(ka));
}
}
- /* Now pick the Phis. Here we will keep all! */
+ /* Now pick other nodes. Here we will keep all! */
irn_arity = get_irn_arity(oe);
for (i = 0; i < irn_arity; i++) {
ka = get_irn_intra_n(oe, i);
- if ((get_irn_op(ka) == op_Phi)) {
- 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);
+ if (!is_Block(ka)) {
+ if (get_irn_visited(ka) <= vfl) {
+ /* We didn't copy the node yet. */
+ set_irg_visited(irg, vfl);
+ irg_walk(ka, copy_node, copy_preds, INT_TO_PTR(copy_node_nr));
}
add_End_keepalive(ne, get_new_node(ka));
}
*/
static void
copy_graph_env (int copy_node_nr) {
- ir_node *old_end;
- /* Not all nodes remembered in current_ir_graph might be reachable
+ ir_graph *irg = current_ir_graph;
+ ir_node *old_end, *n;
+ int i;
+
+ /* remove end_except and end_reg nodes */
+ old_end = get_irg_end(irg);
+ set_irg_end_except (irg, old_end);
+ set_irg_end_reg (irg, old_end);
+
+ /* Not all nodes remembered in irg might be reachable
from the end node. Assure their link is set to NULL, so that
we can test whether new nodes have been computed. */
- set_irn_link(get_irg_frame (current_ir_graph), NULL);
- set_irn_link(get_irg_globals (current_ir_graph), NULL);
- set_irn_link(get_irg_args (current_ir_graph), NULL);
- set_irn_link(get_irg_initial_mem(current_ir_graph), NULL);
- set_irn_link(get_irg_no_mem (current_ir_graph), NULL);
+ for (i = anchor_max - 1; i >= 0; --i)
+ if (irg->anchors[i])
+ set_new_node(irg->anchors[i], NULL);
/* we use the block walk flag for removing Bads from Blocks ins. */
- inc_irg_block_visited(current_ir_graph);
+ inc_irg_block_visited(irg);
/* copy the graph */
- copy_graph(copy_node_nr);
-
- /* fix the fields in current_ir_graph */
- old_end = get_irg_end(current_ir_graph);
- set_irg_end (current_ir_graph, get_new_node(old_end));
- set_irg_end_except (current_ir_graph, get_irg_end(current_ir_graph));
- set_irg_end_reg (current_ir_graph, get_irg_end(current_ir_graph));
- 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_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_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_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_preds(get_irg_args(current_ir_graph), NULL);
+ copy_graph(irg, copy_node_nr);
+
+ /* fix the fields in irg */
+ old_end = get_irg_end(irg);
+ for (i = anchor_max - 1; i >= 0; --i) {
+ n = irg->anchors[i];
+ if (n)
+ irg->anchors[i] = get_new_node(n);
}
- set_irg_start (current_ir_graph, get_new_node(get_irg_start(current_ir_graph)));
-
- set_irg_start_block(current_ir_graph,
- get_new_node(get_irg_start_block(current_ir_graph)));
- set_irg_frame (current_ir_graph, get_new_node(get_irg_frame(current_ir_graph)));
- set_irg_globals (current_ir_graph, get_new_node(get_irg_globals(current_ir_graph)));
- set_irg_initial_mem(current_ir_graph, get_new_node(get_irg_initial_mem(current_ir_graph)));
- 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_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_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)));
+ free_End(old_end);
}
/**
struct obstack *graveyard_obst = NULL;
struct obstack *rebirth_obst = NULL;
- edges_init_graph(irg);
+ if (get_opt_optimize() && get_opt_dead_node_elimination()) {
+ assert(! edges_activated(irg) && "dead node elimination requires disabled edges");
- /* inform statistics that we started a dead-node elimination run */
- hook_dead_node_elim_start(irg);
+ /* inform statistics that we started a dead-node elimination run */
+ hook_dead_node_elim(irg, 1);
- /* Remember external state of current_ir_graph. */
- rem = current_ir_graph;
- current_ir_graph = irg;
- set_interprocedural_view(false);
+ /* Remember external state of current_ir_graph. */
+ rem = current_ir_graph;
+ current_ir_graph = irg;
+ set_interprocedural_view(0);
- /* Handle graph state */
- 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);
+ assert(get_irg_phase_state(current_ir_graph) != phase_building);
- if (get_opt_optimize() && get_opt_dead_node_elimination()) {
+ /* Handle graph state */
+ free_callee_info(current_ir_graph);
+ free_irg_outs(current_ir_graph);
+ free_trouts();
+
+ /* @@@ so far we loose loops when copying */
+ free_loop_information(current_ir_graph);
+
+ set_irg_doms_inconsistent(irg);
/* A quiet place, where the old obstack can rest in peace,
until it will be cremated. */
rebirth_obst = xmalloc (sizeof(*rebirth_obst));
current_ir_graph->obst = rebirth_obst;
obstack_init (current_ir_graph->obst);
+ current_ir_graph->last_node_idx = 0;
/* We also need a new hash table for cse */
del_identities (irg->value_table);
/* Free memory from old unoptimized obstack */
obstack_free(graveyard_obst, 0); /* First empty the obstack ... */
xfree (graveyard_obst); /* ... then free it. */
- }
- /* inform statistics that the run is over */
- hook_dead_node_elim_stop(irg);
+ /* inform statistics that the run is over */
+ hook_dead_node_elim(irg, 0);
- current_ir_graph = rem;
- set_interprocedural_view(rem_ipview);
+ current_ir_graph = rem;
+ set_interprocedural_view(rem_ipview);
+ }
}
/**
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);
/* 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);
/* 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);
* changes).
*/
void remove_bad_predecessors(ir_graph *irg) {
- irg_walk_graph(irg, init_link, relink_bad_predecessors, NULL);
+ irg_walk_graph(irg, firm_clear_link, relink_bad_predecessors, NULL);
+}
+
+
+/*
+ __ _ __ __
+ (_ __ 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;
+ }
+}
+
+/**
+ * Hook called when dead node elimination replaces old by nw.
+ */
+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);
+ }
+}
/*--------------------------------------------------------------------*/
-/* 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.
*/
static INLINE void
copy_node_inline (ir_node *n, void *env) {
- ir_node *new;
- type *frame_tp = (type *)env;
+ ir_node *nn;
+ ir_type *frame_tp = (ir_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);
+ 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;
}
}
*/
static int can_inline(ir_node *call, ir_graph *called_graph)
{
- type *call_type = get_Call_type(call);
+ ir_type *call_type = get_Call_type(call);
int params, ress, i, res;
assert(is_Method_type(call_type));
/* check params */
for (i = 0; i < params; ++i) {
- type *p_type = get_method_param_type(call_type, i);
+ ir_type *p_type = get_method_param_type(call_type, i);
if (is_compound_type(p_type))
return 0;
/* check res */
for (i = 0; i < ress; ++i) {
- type *r_type = get_method_res_type(call_type, i);
+ ir_type *r_type = get_method_res_type(call_type, i);
if (is_compound_type(r_type))
return 0;
ir_node *ret, *phi;
int arity, n_ret, n_exc, n_res, i, j, rem_opt, irn_arity;
int exc_handling;
- type *called_frame;
+ ir_type *called_frame;
irg_inline_property prop = get_irg_inline_property(called_graph);
if ( (prop != irg_inline_forced) &&
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)),
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;
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++;
}
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++;
}
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)) {
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)) {
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);
} 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));
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++;
/**
* 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) {
*
* 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);
/* 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)) {
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);
+ }
}
}
}
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);
- current_ir_graph->op_pin_state_pinned = op_pin_state_pinned;
+ set_irg_pinned(current_ir_graph, op_pin_state_pinned);
}
/**
* 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;
if (! block)
block = get_irn_n(producer, -1);
-
- } else {
+ }
+ else {
assert(is_no_Block(consumer));
block = get_nodes_block(consumer);
}
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);
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
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 */
}
}
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);
}
}
}
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);
}
}
worklist = new_pdeq();
place_early(worklist);
- /* place_early invalidates the outs, place_late needs them. */
- compute_outs(irg);
+ /* 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);
* 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; i<arity; i++) {
pre = get_irn_n(n, i);
- /* Predecessor has multiple successors. Insert new flow edge */
- if ((NULL != pre) &&
- (op_Proj == get_irn_op(pre)) &&
- op_Raise != get_irn_op(skip_Proj(pre))) {
-
- /* set predecessor array for new block */
- in = NEW_ARR_D (ir_node *, current_ir_graph->obst, 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);
+ }
+
}