# include "config.h"
#endif
+#include "bitset.h"
+
#include <ctype.h>
#include <libcore/xprintf.h>
return arg_type_int;
}
+
+static int bitset_get_arg_type(const arg_occ_t *occ) {
+ return arg_type_ptr;
+}
+
+static int bitset_emit(appendable_t *app, const arg_occ_t *occ, const arg_value_t *arg)
+{
+ int res = 2;
+ bitset_t *b = arg->v_ptr;
+ bitset_pos_t p;
+ char buf[32];
+ const char *prefix = "";
+
+ arg_append(app, occ, "[", 1);
+ for(p = bitset_next_set(b, 0); p != -1; p = bitset_next_set(b, p)) {
+ int n;
+
+ n = snprintf(buf, sizeof(buf), "%s%d", prefix, (int) p);
+ arg_append(app, occ, buf, n);
+ prefix = ", ";
+ res += n;
+ }
+ arg_append(app, occ, "]", 1);
+
+ return res;
+}
+
/**
* emit a Firm object
*/
static arg_handler_t firm_handler = { firm_get_arg_type, firm_emit };
static arg_handler_t ident_handler = { firm_get_arg_type, firm_emit_ident };
static arg_handler_t indent_handler = { firm_get_arg_type_int, firm_emit_indent };
+ static arg_handler_t bitset_handler = { bitset_get_arg_type, bitset_emit };
static struct {
const char *name;
arg_register(env, "firm:ident", 'I', &ident_handler);
arg_register(env, "firm:indent", 'D', &indent_handler);
+ /* arg_register(env, "firm:bitset", 'b', &bitset_handler); */
}
return env;
* @author Sebastian Hack
* @date 14.1.2005
*/
+
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
* Only do something, if the old and new target differ.
*/
if(tgt != old_tgt) {
+ int is_block_edge = is_Block(src);
set *edges = _get_irg_edge_info(irg)->edges;
- ir_edge_t templ;
+ ir_block_edge_t space;
+ ir_edge_t *templ = (ir_edge_t *) &space;
ir_edge_t *edge;
+ size_t size;
+
+ /*
+ * This is scray, but:
+ * If two entries in a set do not have the same size, they are
+ * treated as unequal, ignoring the comparison function.
+ * So, edges from blocks have extra storage (they are
+ * ir_block_edge_t's).
+ */
+ size = is_block_edge ? sizeof(ir_block_edge_t) : sizeof(ir_edge_t);
/* Initialize the edge template to search in the set. */
+ memset(templ, 0, size);
#ifdef DEBUG_libfirm
- templ.src_nr = get_irn_node_nr(src);
+ templ->src_nr = get_irn_node_nr(src);
#endif
- templ.src = src;
- templ.pos = pos;
- templ.invalid = 0;
- templ.present = 0;
- INIT_LIST_HEAD(&templ.list);
+ templ->src = src;
+ templ->pos = pos;
+ templ->invalid = 0;
+ templ->present = 0;
/*
* If the target is NULL, the edge shall be deleted.
*/
if(tgt == NULL) {
/* search the edge in the set. */
- edge = set_find(edges, &templ, sizeof(templ), edge_hash(&templ));
+ edge = set_find(edges, templ, size, edge_hash(templ));
/* mark the edge invalid if it was found */
if(edge) {
+ ir_block_edge_t *block_edge = (ir_block_edge_t *) edge;
+
msg = "deleting";
list_del(&edge->list);
edge->invalid = 1;
edge->pos = -2;
edge->src = NULL;
+
+ /*
+ * If the edge is a cf edge, we delete it also
+ * from the list of all block successor edges.
+ */
+ if(is_block_edge)
+ list_del(&block_edge->succ_list);
}
/* If the edge was not found issue a warning on the debug stream */
else {
struct list_head *head = _get_irn_outs_head(tgt);
+ /*
+ * The list head in the block of the edges target.
+ * Therein all control flow edges directed at that block
+ * are recorded.
+ */
+ struct list_head *succ_head =
+ is_block_edge ? _get_block_succ_head(get_nodes_block(tgt)) : NULL;
+
+ ir_block_edge_t *block_edge;
+
if(!node_is_in_irgs_storage(irg, tgt))
return;
* insert the edge, if it is not yet in the set or return
* the instance in the set.
*/
- edge = set_insert(edges, &templ, sizeof(templ), edge_hash(&templ));
+ edge = set_insert(edges, templ, size, edge_hash(templ));
+ block_edge = (ir_block_edge_t *) edge;
#ifdef DEBUG_libfirm
assert(!edge->invalid && "Invalid edge encountered");
if(old_tgt) {
msg = "redirecting";
list_move(&edge->list, head);
+
+ /* If the edge is a cf edge, move it from the successor list. */
+ if(is_block_edge)
+ list_move(&block_edge->succ_list, succ_head);
+
_get_irn_edge_info(old_tgt)->out_count -= 1;
}
else {
msg = "adding";
list_add(&edge->list, head);
+
+ /*
+ * If the edge is cf edge, enter it into the successor list
+ * of the target node's block.
+ */
+ if(is_block_edge)
+ list_add(&block_edge->succ_list, succ_head);
}
_get_irn_edge_info(tgt)->out_count += 1;
edges_node_deleted(irn, irg);
}
-
static void build_edges_walker(ir_node *irn, void *data)
{
ir_graph *irg = data;
int i, n;
for(i = 0, n = get_irn_arity(irn) + not_a_block; i < n; ++i) {
- ir_edge_t templ;
+ ir_block_edge_t space;
+ ir_edge_t *templ = (ir_edge_t *) &space;
ir_edge_t *e;
+ size_t size = not_a_block ? sizeof(ir_edge_t) : sizeof(ir_block_edge_t);
- templ.src = irn;
- templ.pos = i - not_a_block;
+ templ->src = irn;
+ templ->pos = i - not_a_block;
- e = set_find(edges, &templ, sizeof(templ), edge_hash(&templ));
+ e = set_find(edges, templ, size, edge_hash(templ));
if(e != NULL)
e->present = 1;
else
- DBG((dbg, LEVEL_DEFAULT, "edge %n,%d is missing\n", irn, templ.pos));
+ DBG((dbg, LEVEL_DEFAULT, "edge %n,%d is missing\n", irn, templ->pos));
}
}
return _get_edge_src_pos(edge);
}
+int (get_irn_n_edges)(const ir_node *irn)
+{
+ return _get_irn_n_edges(irn);
+}
+
+
#endif /* FIRM_EDGES_INPLACE */
typedef struct _ir_edge_t ir_edge_t;
#endif
+#ifndef _IR_BLOCK_EDGE_TYPEDEF_
+#define _IR_BLOCK_EDGE_TYPEDEF_
+typedef struct _ir_block_edge_t ir_block_edge_t;
+#endif
+
/**
* Get the first edge pointing to some node.
* @note There is no order on out edges. First in this context only
#define foreach_out_edge(irn,edge) \
for(edge = get_irn_out_edge_first(irn); edge; edge = get_irn_out_edge_next(irn, edge))
+/**
+ * A convenience iteration macro for all control flow edges
+ * leaving a block, and thus are cf successor edges.
+ * @param bl The block.
+ * @param edge An @c ir_edge_t pointer which is set to the current edge.
+ */
+#define foreach_block_succ(bl,edge) \
+ for(edge = get_block_succ_first(bl); edge; edge = get_block_succ_next(bl, edge))
+
/*
* Get the source node of an edge.
* @param edge The edge.
*/
ir_node *get_edge_src_irn(const ir_edge_t *edge);
+/**
+ * Get the number of edges pointing to a node.
+ * @param irn The node.
+ * @return The number of edges pointing to this node.
+ */
+int get_irn_n_edges(const ir_node *irn);
+
/**
* Get the position of an edge.
* @param edge.
*/
extern int get_edge_src_pos(const ir_edge_t *edge);
+/**
+ * Check, if the out edges are activated.
+ * @param irg The graph.
+ * @return 1, if the edges are present for the given irg, 0 if not.
+ */
extern int edges_activated(const ir_graph *irg);
+/**
+ * Activate the edges for an irg.
+ * @param irg The graph to activate the edges for.
+ **/
extern void edges_activate(ir_graph *irg);
+/**
+ * Deactivate the edges for an irg.
+ * @param irg The graph.
+ */
extern void edges_deactivate(ir_graph *irg);
-
#endif /* _FIRM_EDGES_H */
#endif
ir_node *src; /**< The source node of the edge. */
int pos; /**< The position of the edge at @p src. */
- struct list_head list; /**< The list head to queue all out edges at a node. */
unsigned invalid : 1; /**< edges that are removed are marked invalid. */
unsigned present : 1; /**< Used by the verifier. Don't rely on its content. */
+ struct list_head list; /**< The list head to queue all out edges at a node. */
+};
+
+/**
+ * A block edge inherits from a normal edge.
+ * They represent edges leading from a block to a control flow node
+ * and are used to quickly find all control flow successors of
+ * a block.
+ */
+struct _ir_block_edge_t {
+ struct _ir_edge_t edge; /**< The inherited data. */
+ struct list_head succ_list; /**< List element listing all
+ control flow edges to the
+ successors of a block. */
};
/** Accessor for private irn info. */
*/
#define _get_irn_outs_head(irn) (&_get_irn_edge_info(irn)->outs_head)
+/**
+ * Convenience macro to get the succ_head from a block_attr
+ * struct.
+ */
+#define _get_block_succ_head(bl) (&((bl)->attr.block.succ_head))
+
/**
* Get the first edge pointing to some node.
* @note There is no order on out edges. First in this context only
return next == _get_irn_outs_head(irn) ? NULL : list_entry(next, ir_edge_t, list);
}
+/**
+ * Get the first successor edge of a block.
+ * A successor edge is an edge originated from another block, pointing
+ * to a mode_X node in the given block and is thus a control flow
+ * successor edge.
+ * @param irn The block.
+ * @return The first successor edge of the block.
+ */
+static INLINE const ir_edge_t *_get_block_succ_first(const ir_node *irn)
+{
+ const struct list_head *head;
+
+ assert(is_Block(irn) && "Node must be a block here");
+ head = _get_block_succ_head(irn);
+ return (ir_edge_t *) (list_empty(head) ? NULL :
+ list_entry(head->next, ir_block_edge_t, succ_list));
+}
+
+/**
+ * Get the next block successor edge.
+ * @see See _get_block_succ_first() for details.
+ * @param irn The block.
+ * @param last The last edge.
+ * @return The next edge, or NULL if there is no further.
+ */
+static INLINE const ir_edge_t *_get_block_succ_next(const ir_node *irn, const ir_edge_t *last)
+{
+ const ir_block_edge_t *block_edge;
+ struct list_head *next;
+
+ assert(is_Block(irn) && "Node must be a block here");
+ block_edge = (const ir_block_edge_t *) last;
+ next = block_edge->succ_list.next;
+ return (ir_edge_t *) (next == _get_block_succ_head(irn) ? NULL :
+ list_entry(next, ir_block_edge_t, succ_list));
+}
+
/**
* Get the source node of an edge.
* @param edge The edge.
return edge ? edge->pos : -1;
}
+/**
+ * Get the number of edges pointing to a node.
+ * @param irn The node.
+ * @return The number of edges pointing to this node.
+ */
+static INLINE int _get_irn_n_edges(const ir_node *irn)
+{
+ return _get_irn_edge_info(irn)->out_count;
+}
+
static INLINE int _edges_activated(const ir_graph *irg)
{
return _get_irg_edge_info(irg)->activated;
#define get_irn_out_edge_first(irn) _get_irn_out_edge_first(irn)
#define get_irn_out_edge_next(irn,last) _get_irn_out_edge_next(irn, last)
+#define get_block_succ_first(irn) _get_block_succ_first(irn)
+#define get_block_succ_next(irn,last) _get_block_succ_next(irn, last)
#define get_edge_src_irn(edge) _get_edge_src_irn(edge)
#define get_edge_src_pos(edge) _get_edge_src_pos(edge)
#define edges_activated(irg) _edges_activated(irg)
int not_a_block = is_no_Block(res);
INIT_LIST_HEAD(&res->edge_info.outs_head);
+ if(!not_a_block)
+ INIT_LIST_HEAD(&res->attr.block.succ_head);
+
for (i = 0, n = arity + not_a_block; i < n; ++i)
edges_notify_edge(res, i - not_a_block, res->in[i], NULL, irg);
@@@ @todo Ev. replace by bitfield! */
ir_extblk *extblk; /**< the extended basic block this block belongs to */
+ struct list_head succ_head; /**< A list head for all successor edges of a block. */
+
} block_attr;
/** Start attributes */
remove_Call_callee_arr(new_node);
}
+static void
+block_copy_attr(const ir_node *old_node, ir_node *new_node)
+{
+ default_copy_attr(old_node, new_node);
+ INIT_LIST_HEAD(&new_node->attr.block.succ_head);
+}
+
/**
* Sets the copy_attr operation for an ir_op
*/
static ir_op *firm_set_default_copy_attr(ir_op *op) {
if (op->code == iro_Call)
op->copy_attr = call_copy_attr;
+ else if (op->code == iro_Block)
+ op->copy_attr = block_copy_attr;
else
op->copy_attr = default_copy_attr;