--- /dev/null
+/* Copyright (c) 2002 by Universität Karlsruhe (TH). All Rights Reserved */
+//
+// Time-stamp: <02/03/04 17:24:07 liekweg>
+//
+
+/***
+ NAME
+ exc
+ PURPOSE
+ Helper functions for exceptions
+ NOTES
+ not quite complete
+ HISTORY
+ liekweg - Mar 4, 2002: Created.
+ CVS:
+ $Id$
+***/
+
+# include "exc.h"
+# include "st.h"
+# include "irop.h"
+# include "irouts.h"
+
+# include <bool.h>
+
+/*
+ Return true iff (block b is a handler entry AND a dominates b) OR
+ (b has a CFG successor that is both a handler entry AND is dominated
+ by a)
+*/
+static bool has_handler (ir_graph *graph, ir_node *b, ir_node *a)
+{
+ int i = 0;
+ int n = get_irn_n_outs (b);
+ ir_node *succ = 0;
+
+ assert (0 && "Wrongly implemented");
+ // must check for _immediate_ dominance !!!
+
+ if (is_handler_entry (graph, b) && dominates (graph, a, b))
+ return (true);
+
+ for (i = 0; i < n; i ++)
+ {
+ succ = get_irn_out (b, i);
+
+ if (has_handler (graph, succ, a))
+ return (true);
+ }
+
+ return (false);
+}
+
+/*
+ Return true iff the given node represents an exception jump
+*/
+static bool is_exc_jmp (ir_node *node)
+{
+ ir_op *op = get_irn_op (node);
+
+ // Proj_X (Load), Proj_X (Sto), Proj_X (Div_Int),
+ // Proj_X (Raise), Proj_X (Call), Proj_X (Alloc)
+ if (op == op_Proj)
+ {
+ op = get_irn_op (get_Proj_pred (node));
+
+ // ToDo: Check for proper Proj attr?!?
+ if ((op == op_Load) || (op == op_Store) ||
+ (op == op_Div ) || (op == op_Raise) ||
+ (op == op_Call) || (op == op_Alloc))
+ return (true);
+ }
+ else
+ {
+ return (false);
+ }
+}
+
+/*
+Return true iff the given node represents a normal cfg jump
+*/
+static bool is_cfg_jmp (ir_node *node)
+{
+ ir_op *op = get_irn_op (node);
+
+ if (op == op_Proj)
+ {
+ op = get_irn_op (get_Proj_pred (node));
+
+ // Proj_X (Proj_Cmp (Cond))
+ if (op_Proj == op)
+ return (true); /* check for op == op_Cmp and op == op_Cond */
+ }
+
+ return (false);
+}
+
+/*
+ Return true iff a new exception region must be left upon entry of this block.
+
+ If all CFG preds of this block are exception jumps, then we must
+ return true.
+*/
+bool is_handler_entry (ir_graph *graph, ir_node *block)
+{
+ bool is_entry = true;
+ int i = 0;
+ int n = get_irn_arity (block);
+ ir_node *node = 0;
+ ir_op* op = op_Bad;
+
+ if (exc_invalid == get_Block_exc (block))
+ {
+ for (i = 0; (i < n) && is_entry; i ++)
+ if (is_exc_jmp (get_irn_n (block, i)))
+ continue;
+ else
+ is_entry = false;
+
+ if (true == is_entry)
+ set_Block_exc (block, exc_entry);
+ }
+
+ return (exc_entry == get_Block_exc (block));
+}
+
+/*
+ Return true iff a new exception region must be started upon entry of this block.
+
+ If this block immediately dominates a handler entry, we must return true.
+*/
+bool is_region_entry (ir_graph *graph, ir_node *block)
+{
+ assert (0 && "Not implemented");
+
+ if (exc_invalid == get_Block_exc (block))
+ {
+ int i = 0;
+ int n = get_irn_n_outs (block);
+ ir_node *succ = 0;
+
+ bool no_handler = true;
+
+ for (i = 0; (i < n) && no_handler; i ++)
+ {
+ succ = get_irn_out (block, i);
+
+ if (has_handler (graph, succ, block))
+ no_handler = false;
+ }
+
+ if (false == no_handler)
+ set_Block_exc (block, exc_region);
+ }
+
+ return (exc_region == get_Block_exc (block));
+
+ return (TRUE);
+}
+
+/*
+ Return true iff this block is part of handler code.
+
+ If this block is dominated by a block for which {@link
+ is_handler_entry} is true, then this block is part of the handler.
+*/
+bool is_handler_block (ir_graph *graph, ir_node *block)
+{
+ assert (0 && "Not implemented");
+
+ if (exc_invalid == get_Block_exc (block))
+ {
+ bool no_handler = true;
+ dom_env_t *env = get_dom_env (graph, block);
+ int block_index = env->index_a;
+ bs_t block_mask = 0x00000001 << block_index;
+ int n_blocks = env->dt->n_blocks;
+ int i = 0;
+
+ for (i = 0; (i < n_blocks) && no_handler; i ++)
+ if (0 != (env->dt->masks [i] & block_mask)) /* if dominator */
+ if (is_handler_entry (graph, env->dt->blocks [i])) /* is handler entry */
+ no_handler = false;
+
+ delete_dom_env (env);
+
+ if (false == no_handler)
+ set_Block_exc (block, exc_handler);
+ }
+
+ return (exc_handler == get_Block_exc (block));
+}
+
+/*
+ Return true iff a new exception region must be left upon exit of the
+ non-exception blocks among the CFG predecessors of this block.
+
+ If this block has CFG predecessors that are partly handler blocks and
+ partly normal blocks, then we must return true.
+*/
+bool is_cont_entry (ir_graph *graph, ir_node *block)
+{
+ assert (0 && "Not implemented");
+
+ if (exc_invalid == get_Block_exc (block))
+ {
+ bool has_exc = false; /* wether we have exception cfg predecessors */
+ bool has_cfg = false; /* wether we have normal cfg predecessors */
+
+ int i = 0;
+ int n = get_irn_arity (block);
+
+ ir_node *pred = 0;
+
+ for (i = 0; (i < n) && (!has_exc && !has_cfg); i ++)
+ {
+ pred = get_irn_n (block, i);
+
+ if (is_exc_jmp (pred))
+ has_exc = true;
+ else if (is_cfg_jmp (pred))
+ has_cfg = true;
+ }
+
+ if (has_cfg && has_exc)
+ set_Block_exc (block, exc_cont);
+ }
+
+ return (exc_cont == get_Block_exc (block));
+}
--- /dev/null
+/* Copyright (c) 2002 by Universität Karlsruhe (TH). All Rights Reserved */
+//
+// Time-stamp: <02/03/04 16:57:32 liekweg>
+//
+
+/***
+ NAME
+ st.h
+ PURPOSE
+ provide some auxilliary structures for firm graphs.
+ NOTES
+ not quite complete
+ HISTORY
+ liekweg - Feb 26, 2002: Created.
+ CVS:
+ $Id$
+***/
+
+# include "st.h"
+
+# include "irgwalk.h"
+
+# include <stdio.h>
+# ifdef DEBUG_libfirm
+# endif /* def DEBUG_libfirm */
+# include <malloc.h>
+
+/* init globals: */
+static dtree_t *trees = 0;
+static dtree_t *last = 0;
+
+// --------------------------------------------------------------------
+// Helper Functions
+// --------------------------------------------------------------------
+/*
+ Helper function for get_n_blocks
+*/
+static void count_block (ir_node *block, void *env)
+{
+ int *n = (int*) env;
+
+# ifdef DEBUG_libfirm
+ assert (block && "no block");
+ assert (env && "no env");
+# endif /* def DEBUG_libfirm */
+
+ fprintf (stdout, "%s: Block(%p) has # (%i)\n",
+ __FILE__ ":" __PRETTY_FUNCTION__, block, *n);
+
+ (*n) ++;
+}
+
+/*
+ Count the number of blocks in the given graph
+*/
+static int get_n_blocks (ir_graph *graph)
+{
+ int n = 0;
+
+ ir_node *end_block = get_irg_end (graph);
+
+# ifdef DEBUG_libfirm
+ assert (graph && "no graph");
+ assert (end_block && "no end block");
+# endif /* def DEBUG_libfirm */
+
+ irg_block_walk (end_block, count_block, NULL, &n);
+ // irg_block_walk (end_block, NULL, NULL, NULL);
+
+ // return (24);
+
+ fprintf (stdout, "%s: Graph(%p) has (%i) blocks\n",
+ __FILE__ ":" __PRETTY_FUNCTION__, graph, n);
+
+ return (n);
+}
+
+/*
+ Build an empty dominator relation entry
+*/
+static dtree_t *new_dtree (dt_t *tree, ir_graph *graph)
+{
+ dtree_t *res = (dtree_t*) malloc (sizeof (dtree_t));
+
+# ifdef DEBUG_libfirm
+ assert (res && "no memory for dtree");
+# endif /* def DEBUG_libfirm */
+
+ res->tree = tree;
+ res->graph = graph;
+ res->next = 0;
+
+ return (res);
+}
+
+/*
+ Build an empty dominator relation
+*/
+static dt_t *new_dt (ir_graph *graph)
+{
+ int i;
+ int n_blocks = get_n_blocks (graph);
+
+ dt_t *res = (dt_t*) malloc (sizeof (dt_t));
+
+# ifdef DEBUG_libfirm
+ assert (n_blocks && "no blocks for dt");
+ assert (res && "no memory for dt");
+# endif /* def DEBUG_libfirm */
+
+ res->n_blocks = n_blocks;
+ res->graph = graph;
+ res->blocks = (ir_node**) calloc (n_blocks, sizeof (ir_node*));
+ res->idoms = (ir_node**) calloc (n_blocks, sizeof (ir_node*));
+ res->masks = (bs_t*) calloc (n_blocks, sizeof (bs_t));
+
+ assert (res && "no dt");
+
+ return (res);
+}
+
+static void free_dt (dt_t *dt)
+{
+ free (dt->blocks); dt->blocks = 0;
+ free (dt->masks); dt->masks = 0;
+ free (dt);
+}
+
+
+// --------------------------------------------------------------------
+// Private Functions
+// --------------------------------------------------------------------
+
+/*
+ Given a graph, find its dominator tree in the global list:
+
+ @return The tree, if it exists, and 0 else
+*/
+static dt_t *get_dominator_tree (ir_graph *graph)
+{
+ dtree_t *iter = trees;
+
+# ifdef DEBUG_libfirm
+ assert (graph && "no graph");
+ // assert (iter && "no trees");
+# endif /* def DEBUG_libfirm */
+
+ while ((0 != iter) && (graph != iter->graph))
+ iter = iter->next;
+
+ if (0 != iter)
+ {
+# ifdef DEBUG_libfirm
+ assert ((graph == iter->tree->graph) && "wrong graph");
+# endif /* def DEBUG_libfirm */
+
+ return (iter->tree);
+ }
+ else
+ {
+ return (0);
+ }
+}
+
+/*
+ Given a dominator tree and a graph, enter the tree into the global list.
+*/
+static void add_dominator_tree (dt_t *tree)
+{
+ dtree_t *dtree = 0;
+ ir_graph *graph = tree->graph;
+
+# ifdef DEBUG_libfirm
+ assert (tree && "no tree" );
+ assert (graph && "no graph");
+# endif /* def DEBUG_libfirm */
+
+ dtree = new_dtree (tree, graph);
+
+# ifdef VERBOSE_libfirm
+ fprintf (stdout, "%s: Adding dtree(%p) into trees(%p)\n",
+ __FILE__ ":" __PRETTY_FUNCTION__, dtree, trees);
+# endif /* def VERBOSE_libfirm */
+
+ //enter in global list:
+ dtree->next = trees;
+ trees = dtree;
+}
+
+/*
+ Get (or create) the index for a given block
+*/
+static int get_index (dt_t *dt, ir_node *block)
+{
+ int i;
+
+# ifdef DEBUG_libfirm
+ assert (dt && "no dt");
+ assert (block && "no block");
+# endif /* def DEBUG_libfirm */
+
+ for (i = 0; (i < dt->n_blocks) && (0 != dt->blocks [i]); i ++)
+ if (block == dt->blocks [i])
+ return (i);
+
+ /* not found . . . enter new one: */
+ dt->blocks [i] = block;
+ if (block == get_irg_start_block (dt->graph))
+ {
+ dt->masks [i] = 0x00000001 << i;
+
+# ifdef VERBOSE_libfirm
+ fprintf (stdout, "%s: Adding block(%p)[%i] with [%#010lx]\n",
+ __FILE__ ":" __PRETTY_FUNCTION__, block, i, dt->masks [i]);
+# endif /* def VERBOSE_libfirm */
+ }
+ else
+ {
+ dt->masks [i] = ~0x00000000;
+
+# ifdef VERBOSE_libfirm
+ fprintf (stdout, "%s: Adding block(%p)[%i] with [%#010lx]\n",
+ __FILE__ ":" __PRETTY_FUNCTION__, block, i, dt->masks [i]);
+# endif /* def VERBOSE_libfirm */
+ }
+
+ return (i);
+}
+
+/*
+ Get the bit mask for a block
+*/
+static bs_t _get_mask (dt_t*, int);
+static bs_t get_mask (dt_t *dt, ir_node *block)
+{
+ int index = get_index (dt, block);
+
+# ifdef DEBUG_libfirm
+ assert (dt && "no dt");
+ assert (block && "no block");
+# endif /* def DEBUG_libfirm */
+
+ return (_get_mask (dt, index));
+}
+
+/*
+ Get the bit mask for a block index
+*/
+static bs_t _get_mask (dt_t *dt, int index)
+{
+# ifdef DEBUG_libfirm
+ assert (dt && "no dt");
+# endif /* def DEBUG_libfirm */
+
+ return (dt->masks [index]);
+}
+
+/*
+ Set the bit mask for a block
+*/
+static void _set_mask (dt_t*, int, bs_t);
+static void set_mask (dt_t *dt, ir_node *block, bs_t mask)
+{
+ int index = get_index (dt, block);
+
+# ifdef DEBUG_libfirm
+ assert (dt && "no dt");
+ assert (block && "no block");
+# endif /* def DEBUG_libfirm */
+
+ _set_mask (dt, index, mask);
+}
+
+/*
+ Set the bit mask for a block index
+*/
+static void _set_mask (dt_t *dt, int index, bs_t mask)
+{
+# ifdef DEBUG_libfirm
+ assert (dt && "no dt");
+# endif /* def DEBUG_libfirm */
+
+ dt->masks [index] = mask;
+}
+
+/*
+ Update the list of dominators of a given block
+*/
+typedef struct dt_walk_env_t // grrr
+{
+ dt_t *dt; // the dominator relation we're building
+ ir_node *start_block; // need to know the start block of this graph
+ bool changed; // wether the relation has changed recently
+}
+dt_walk_env_t;
+
+/*
+ Helper function for build_dominator_tree
+*/
+static void update_dominators (ir_node *block, void *env)
+{
+ int i;
+ dt_walk_env_t *w = (dt_walk_env_t*) env;
+ dt_t *dt = w->dt;
+
+ int block_index = get_index (dt, block);
+ int n_ins = get_irn_arity (block);
+
+ bs_t old_mask = _get_mask (dt, block_index);
+ bs_t new_mask = ~0x00000000;
+
+ // Special handling of Start Block:
+ if (block == w->start_block)
+ return;
+
+ // check preds:
+ for (i = 0; i < n_ins; i ++)
+ {
+ ir_node *in = get_nodes_Block (get_irn_n (block, i)); // hope that's the block
+ bs_t in_mask = get_mask (dt, in);
+
+ new_mask &= in_mask;
+ }
+
+ // and remember ourselves:
+ new_mask |= (0x00000001 << block_index);
+
+ if (new_mask != old_mask)
+ {
+ w->changed = TRUE;
+ _set_mask (dt, block_index, new_mask);
+
+# ifdef VERBOSE_libfirm
+ fprintf (stdout, "%s: Updating block(%p)[%i] from [%#010lx] to [%#010lx]\n",
+ __FILE__ ":" __PRETTY_FUNCTION__,
+ block, block_index, old_mask, new_mask);
+# endif /* def VERBOSE_libfirm */
+ }
+}
+
+/*
+ Say wether a dominates b
+*/
+
+static bool _dominates (dt_t *dt, ir_node *a, ir_node *b)
+{
+ int index_a = get_index (dt, a);
+ bs_t b_mask = get_mask (dt, b);
+
+ return (0 != (b_mask & (0x00000001 << index_a)));
+}
+
+/*
+ Return the immediate dominator of block a
+*/
+static ir_node *_get_idom (dt_t *dt, ir_node *block)
+{
+ ir_node *idom = 0;
+ int block_index = get_index (dt, block);
+
+ if (0 != (idom = dt->idoms [block_index]))
+ return (idom);
+
+ // check all CFG preds:
+ // Question: Shouldn't it be good enough to just ask our first CFG predecessor?
+ {
+ int i = 0;
+ int n = get_irn_arity (block);
+ ir_node *pred = 0;
+
+ idom = block; // prime the loop:
+
+ for (i = 0; i < n; i ++)
+ {
+ ir_node *ndom = 0;
+
+ pred = get_nodes_Block (get_irn_n (block, i));
+ ndom = _get_idom (dt, pred);
+
+ if (ndom != idom)
+ if (_dominates (dt, idom, ndom))
+ idom = ndom;
+ }
+ }
+
+ assert (idom && "Something terribly wrong in _get_idom");
+
+# ifdef VERBOSE_libfirm
+ fprintf (stdout, "%s: idom(%p) = %p\n",
+ __FILE__ ":" __PRETTY_FUNCTION__,
+ block, idom);
+# endif /* def VERBOSE_libfirm */
+
+ // remember it:
+ dt->idoms [block_index] = idom;
+
+ return (idom);
+}
+
+// --------------------------------------------------------------------
+// Public Functions
+// --------------------------------------------------------------------
+
+/*
+ Say wether a dominates b
+*/
+bool dominates (ir_graph *g, ir_node *a, ir_node *b)
+{
+ dt_t *dt = get_dominator_tree (g);
+
+ return (_dominates (dt, a, b));
+}
+
+/*
+ Return the immediate dominator of block a
+*/
+ir_node *get_idom (ir_graph *g, ir_node *a)
+{
+ dt_t *dt = get_dominator_tree (g);
+
+ return (_get_idom (dt, a));
+}
+
+/*
+ Allow for precomputation of necessary data
+ This will allow for a slightly faster lookup of the dominator
+ relation if one node is checked for dominance against many other nodes.
+*/
+dom_env_t *get_dom_env (ir_graph *graph, ir_node *a)
+{
+ dom_env_t *env = (dom_env_t*) calloc (1, sizeof (dom_env_t));
+
+ env->graph = graph;
+ env->dt = get_dominator_tree (graph);
+ env->a = a;
+ env->index_a = get_index (env->dt, a);
+}
+
+/*
+ Dispose a dominator environment
+*/
+void delete_dom_env (dom_env_t *env)
+{
+ env->dt = 0;
+ env->a = 0;
+ env->graph = 0;
+ env->index_a = -1;
+
+ free (env);
+}
+
+/*
+ Say wether the node in env dominates b
+
+ see get_dom_env
+*/
+bool dominates_l (dom_env_t *env, ir_node *b)
+{
+ int index_a = env->index_a;
+ dt_t *dt = env->dt;
+ bs_t b_mask = get_mask (dt, b);
+
+ return (0 != (b_mask & (0x00000001 << index_a)));
+}
+
+/*
+ Build a new dominator tree for the given graph
+*/
+void build_dominator_tree (ir_graph *graph)
+{
+ /*
+ dt_walk_env_t *w = (dt_walk_env_t*) alloca (sizeof (dt_walk_env_t));
+
+ ir_node *end_block = get_irg_end_block (graph);
+ ir_node *start_block = get_irg_start_block (graph);
+ int n_blocks = get_n_blocks (graph);
+ dt_t *dt = get_dominator_tree (graph);
+ */
+
+ dt_walk_env_t *w = 0;
+ ir_node *end_block = 0;
+ ir_node *start_block = 0;
+ int n_blocks = 0;
+ dt_t *dt = 0;
+
+ w = (dt_walk_env_t*) alloca (sizeof (dt_walk_env_t));
+ end_block = get_irg_end_block (graph);
+ start_block = get_irg_start_block (graph);
+ n_blocks = get_n_blocks (graph);
+ dt = get_dominator_tree (graph);
+
+# ifdef DEBUG_libfirm
+ assert (graph && "no graph");
+# endif /* def DEBUG_libfirm */
+
+# ifdef VERBOSE_libfirm
+ fprintf (stdout, "%s: for graph(%p)\n", __FILE__ ":" __PRETTY_FUNCTION__, graph);
+# endif /* def VERBOSE_libfirm */
+
+ //if (0 != dt)
+ //free_dt (dt);
+
+ dt = new_dt (graph);
+
+ w->dt = dt;
+ w->start_block = start_block; // grrr
+ w->changed = TRUE; // at least one walk
+
+ // do the walk:
+ {
+ int walks = 0;
+
+ while (w->changed)
+ {
+ w->changed = FALSE;
+ irg_block_walk (end_block, update_dominators, update_dominators, (void*) w);
+ walks ++;
+ }
+
+# ifdef VERBOSE_libfirm
+ fprintf (stdout, "%s: for graph(%p): %i passes\n",
+ __FILE__ ":" __PRETTY_FUNCTION__, graph, walks);
+# endif /* def VERBOSE_libfirm */
+ }
+
+ /* ok, now remember it: */
+ add_dominator_tree (dt);
+}