static INLINE int has_reg_class(const be_chordal_env_t *env, const ir_node *irn)
{
- return arch_irn_has_reg_class(env->arch_env, irn, arch_pos_make_out(0), env->cls);
+ return arch_irn_has_reg_class(env->session_env->main_env->arch_env, irn, arch_pos_make_out(0), env->cls);
}
/**
struct list_head *head;
pset *live_in = put_live_in(block, pset_new_ptr_default());
pset *live_end = put_live_end(block, pset_new_ptr_default());
- const arch_register_class_t *cls = env->cls;
DBG((dbg, LEVEL_1, "Computing pressure in block %+F\n", block));
bitset_clear_all(live);
static void assign(ir_node *block, void *env_ptr)
{
be_chordal_env_t *env = env_ptr;
- struct obstack *obst = &env->obst;
bitset_t *live = env->live;
bitset_t *colors = env->colors;
bitset_t *in_colors = env->in_colors;
- const arch_register_class_t *cls = env->cls;
-
- /* Mark the obstack level and allocate the temporary tmp_colors */
- void *obstack_level = obstack_base(obst);
- /*bitset_t *tmp_colors = bitset_obstack_alloc(obst, env->colors_n);*/
+ const arch_env_t *arch_env = env->session_env->main_env->arch_env;
const ir_node *irn;
border_t *b;
*/
for(irn = pset_first(live_in); irn; irn = pset_next(live_in)) {
if(has_reg_class(env, irn)) {
- const arch_register_t *reg = arch_get_irn_register(env->arch_env, irn, 0);
+ const arch_register_t *reg = arch_get_irn_register(arch_env, irn, 0);
int col;
assert(reg && "Node must have been assigned a register");
col = bitset_next_clear(colors, 0);
reg = arch_register_for_index(env->cls, col);
- assert(arch_get_irn_register(env->arch_env, irn, 0) == NULL
+ assert(arch_get_irn_register(arch_env, irn, 0) == NULL
&& "This node must not have been assigned a register yet");
assert(!bitset_is_set(live, nr) && "Value's definition must not have been encountered");
bitset_set(colors, col);
bitset_set(live, nr);
- arch_set_irn_register(env->arch_env, irn, 0, reg);
+ arch_set_irn_register(arch_env, irn, 0, reg);
DBG((dbg, LEVEL_1, "\tassigning register %s(%d) to %+F\n",
arch_register_get_name(reg), col, irn));
}
/* Clear the color upon a use. */
else if(!b->is_def) {
- const arch_register_t *reg = arch_get_irn_register(env->arch_env, irn, 0);
+ const arch_register_t *reg = arch_get_irn_register(arch_env, irn, 0);
int col;
assert(reg && "Register must have been assigned");
}
}
- /* Free the auxillary data on the obstack. */
- //obstack_free(obst, obstack_level);
-
del_pset(live_in);
}
firm_dbg_set_mask(dbg, DBG_LEVEL);
}
-be_chordal_env_t *be_ra_chordal(ir_graph *irg,
- const arch_env_t *arch_env,
+be_chordal_env_t *be_ra_chordal(
+ const be_main_session_env_t *session,
const arch_register_class_t *cls)
{
+ ir_graph *irg = session->irg;
int node_count = get_graph_node_count(irg);
int colors_n = arch_register_class_n_regs(cls);
be_chordal_env_t *env = malloc(sizeof(*env));
env->nodes = new_set(if_node_cmp, node_count);
#endif
+ env->session_env = session;
env->live = bitset_obstack_alloc(&env->obst, node_count);
env->colors = bitset_obstack_alloc(&env->obst, colors_n);
env->in_colors = bitset_obstack_alloc(&env->obst, colors_n);
env->colors_n = colors_n;
env->cls = cls;
- env->arch_env = arch_env;
- env->irg = irg;
env->border_heads = pmap_create();
/* First, determine the pressure */
}
void be_ra_chordal_check(be_chordal_env_t *chordal_env) {
- const arch_env_t *arch_env;
+ const arch_env_t *arch_env = chordal_env->session_env->main_env->arch_env;
struct obstack ob;
pmap_entry *pme;
ir_node **nodes, *n1, *n2;
int i, o;
- arch_env = chordal_env->arch_env;
-
/* Collect all irns */
obstack_init(&ob);
pmap_foreach(chordal_env->border_heads, pme) {
#include "irnode.h"
#include "bearch.h"
+#include "bearch.h"
-typedef struct _be_chordal_env_t be_chordal_env_t;
-
-/**
- * Allocate registers for an ir graph.
- * @param irg The graph.
- * @return Some internal data to be freed with be_ra_chordal_done().
- */
-be_chordal_env_t *be_ra_chordal(ir_graph *irg,
- const arch_env_t *arch_env,
- const arch_register_class_t *cls);
-
-/**
- * Check current register allocation for correctness.
- * Interfering nodes have different colors
- * Register constraints
- * O(n^2)
- */
-void be_ra_chordal_check(be_chordal_env_t *chordal_env);
-
-/**
- * Free data from the chordal register allocation.
- * @param irg The graph.
- */
-void be_ra_chordal_done(be_chordal_env_t *info);
-
-/**
- * Init some things for the chordal register allocator.
- * This must be called before Firm is inited.
- */
-void be_ra_chordal_init(void);
#endif
if(b->is_def) {
const arch_register_t *reg = arch_get_irn_register(env->arch_env, b->irn, 0);
int col = arch_register_get_index(reg);
- int live_in = is_live_in(bl, b->irn);
int live_out = is_live_out(bl, b->irn);
int x = (col + 1) * opts->h_inter_gap;
int ystart = (b->step) * opts->v_inter_gap;
bbox.h = start_box->h + 2 * env->opts->y_margin;
p->vtab->begin(p, &bbox);
- irg_block_walk_graph(env->chordal_env->irg, draw_block, NULL, env);
+ irg_block_walk_graph(env->chordal_env->session_env->irg, draw_block, NULL, env);
p->vtab->finish(p);
}
{
draw_chordal_env_t env;
struct block_dims *start_dims;
- ir_node *start_block = get_irg_start_block(chordal_env->irg);
+ ir_node *start_block = get_irg_start_block(chordal_env->session_env->irg);
env.arch_env = arch_env;
env.opts = opts;
env.chordal_env = chordal_env;
obstack_init(&env.obst);
- irg_block_walk_graph(chordal_env->irg, block_dims_walker, NULL, &env);
+ irg_block_walk_graph(chordal_env->session_env->irg, block_dims_walker, NULL, &env);
layout(&env, start_block, opts->x_margin);
set_y(&env, start_block, opts->y_margin);
start_dims = pmap_get(env.block_dims, start_block);
#include "irnode.h"
#include "irgraph.h"
-#include "bechordal.h"
+
+#include "be_t.h"
+#include "bearch.h"
/** Defines an invalid register index. */
#define NO_COLOR (-1)
*/
struct _be_chordal_env_t {
struct obstack obst; /**< An obstack for temporary storage. */
+ const be_main_session_env_t *session_env; /**< The current session. */
pmap *border_heads; /**< Maps blocks to border heads. */
- ir_graph *irg; /**< The graph the reg alloc is running on. */
#ifdef BUILD_GRAPH
set *nodes; /**< The interference graph nodes. */
bitset_t *colors; /**< The color mask. */
bitset_t *in_colors; /**< Colors used by live in values. */
int colors_n; /**< The number of colors. */
- const arch_env_t *arch_env; /**< The arch interface environment. */
const arch_register_class_t *cls; /**< The current register class. */
void *data; /**< Some pointer, to which different
phases can attach data to. */
};
+typedef struct _be_chordal_env_t be_chordal_env_t;
+
static INLINE struct list_head *
_get_block_border_head(const be_chordal_env_t *inf, ir_node *bl)
{
extern void be_ra_chordal_spill(be_chordal_env_t *env);
+/**
+ * Allocate registers for an ir graph.
+ * @param irg The graph.
+ * @return Some internal data to be freed with be_ra_chordal_done().
+ */
+be_chordal_env_t *be_ra_chordal(
+ const be_main_session_env_t *env,
+ const arch_register_class_t *cls);
+
+/**
+ * Check current register allocation for correctness.
+ * Interfering nodes have different colors
+ * Register constraints
+ * O(n^2)
+ */
+void be_ra_chordal_check(be_chordal_env_t *chordal_env);
+
+/**
+ * Free data from the chordal register allocation.
+ * @param irg The graph.
+ */
+void be_ra_chordal_done(be_chordal_env_t *info);
+
+/**
+ * Init some things for the chordal register allocator.
+ * This must be called before Firm is inited.
+ */
+void be_ra_chordal_init(void);
+
#endif /* _BECHORDAL_T_H */
ir_node **confl, *cn;
int i, irn_col;
const be_chordal_env_t *chordal_env = qn->ou->co->chordal_env;
- const arch_env_t *arch_env = chordal_env->arch_env;
+ const arch_env_t *arch_env = get_arch_env(qn->ou->co);
const arch_register_class_t *cls = chordal_env->cls;
DBG((dbg, LEVEL_3, "\t %+F \tcaused col(%+F) \t%2d --> %2d\n", trigger, irn, qnode_get_new_color(qn, irn), col));
/* init queue */
INIT_LIST_HEAD(&ou->queue);
- arch_get_allocatable_regs(ou->co->chordal_env->arch_env, ou->nodes[0], arch_pos_make_out(0), ou->co->chordal_env->cls, pos_regs);
+ arch_get_allocatable_regs(get_arch_env(ou->co), ou->nodes[0], arch_pos_make_out(0), ou->co->chordal_env->cls, pos_regs);
bitset_foreach(pos_regs, i)
ou_insert_qnode(ou, new_qnode(ou, i));
#define is_removed(irn) pset_find_ptr(pi->removed, irn)
-#define is_color_possible(irn,color) arch_reg_is_allocatable(pi->co->chordal_env->arch_env, irn, arch_pos_make_out(0), arch_register_for_index(pi->co->chordal_env->cls, color))
+#define is_color_possible(irn,color) arch_reg_is_allocatable(get_arch_env(pi->co), irn, arch_pos_make_out(0), arch_register_for_index(pi->co->chordal_env->cls, color))
/*
* Some stuff for variable name handling.
while (redo) {
redo = 0;
for (ifn = set_first(if_nodes); ifn; ifn = set_next(if_nodes)) {
- ir_node *irn = get_irn_for_graph_nr(pi->co->chordal_env->irg, ifn->nnr);
- if (!is_removed(irn) && !is_optimizable(pi->co->chordal_env->arch_env, irn) &&
+ ir_node *irn = get_irn_for_graph_nr(get_irg(pi->co), ifn->nnr);
+ if (!is_removed(irn) && !is_optimizable(get_arch_env(pi->co), irn) &&
!is_optimizable_arg(pi->co, irn) && pi_is_simplicial(pi, ifn)) {
simpl_t *s = xmalloc(sizeof(*s));
s->ifn = ifn;
// iterate over all possible colors in order
bitset_clear_all(pos_regs);
- arch_get_allocatable_regs(pi->co->chordal_env->arch_env, curr->irn, arch_pos_make_out(0), pi->co->chordal_env->cls, pos_regs);
+ arch_get_allocatable_regs(get_arch_env(pi->co), curr->irn, arch_pos_make_out(0), pi->co->chordal_env->cls, pos_regs);
bitset_foreach(pos_regs, col) {
int var_idx;
mangle_var(pi->buf, 'x', nnr, col);
root = curr->nodes[0];
rootnr = get_irn_graph_nr(root);
bitset_clear_all(root_regs);
- arch_get_allocatable_regs(pi->co->chordal_env->arch_env, root, arch_pos_make_out(0), pi->co->chordal_env->cls, root_regs);
+ arch_get_allocatable_regs(get_arch_env(pi->co), root, arch_pos_make_out(0), pi->co->chordal_env->cls, root_regs);
/* for all arguments of root */
for (i = 1; i < curr->node_count; ++i) {
arg = curr->nodes[i];
argnr = get_irn_graph_nr(arg);
bitset_clear_all(arg_regs);
- arch_get_allocatable_regs(pi->co->chordal_env->arch_env, arg, arch_pos_make_out(0), pi->co->chordal_env->cls, arg_regs);
+ arch_get_allocatable_regs(get_arch_env(pi->co), arg, arch_pos_make_out(0), pi->co->chordal_env->cls, arg_regs);
/* Introduce new variable and set factor in objective function */
mangle_var(buf, 'y', rootnr, argnr);
* Only one of the phis can get the arg.
*/
static void pi_add_constr_M(problem_instance_t *pi) {
- dom_tree_walk_irg(pi->co->chordal_env->irg, M_constr_walker, NULL, pi);
+ dom_tree_walk_irg(get_irg(pi->co), M_constr_walker, NULL, pi);
}
/**
lpp_get_var_name(pi->curr_lp, i, var_name, sizeof(var_name));
/* split into components */
if (split_var(var_name, &nnr, &col) == 2) {
- assert(get_irn_col(pi->co, get_irn_for_graph_nr(pi->co->chordal_env->irg, nnr)) != -1);
- val = (get_irn_col(pi->co, get_irn_for_graph_nr(pi->co->chordal_env->irg, nnr)) == col) ? 1 : 0;
+ assert(get_irn_col(pi->co, get_irn_for_graph_nr(get_irg(pi->co), nnr)) != -1);
+ val = (get_irn_col(pi->co, get_irn_for_graph_nr(get_irg(pi->co), nnr)) == col) ? 1 : 0;
lpp_set_start_value(pi->curr_lp, i, val);
} else {
fprintf(stderr, "Variable name is: %s\n", var_name);
/* get free color by inspecting all neighbors */
ifn = simpl->ifn;
- irn = get_irn_for_graph_nr(pi->co->chordal_env->irg, ifn->nnr);
+ irn = get_irn_for_graph_nr(get_irg(pi->co), ifn->nnr);
bitset_clear_all(used_cols);
foreach_neighb(ifn, other) {
- other_irn = get_irn_for_graph_nr(pi->co->chordal_env->irg, other->nnr);
+ other_irn = get_irn_for_graph_nr(get_irg(pi->co), other->nnr);
if (!is_removed(other_irn)) /* only inspect nodes which are in graph right now */
bitset_set(used_cols, get_irn_col(pi->co, other_irn));
}
if (sol[i] > 1-EPSILON) { /* split varibale name into components */
lpp_get_var_name(pi->curr_lp, 1+i, var_name, sizeof(var_name));
if (split_var(var_name, &nnr, &col) == 2) {
- DBG((dbg, LEVEL_2, "Irn %n Idx %d Var %s Val %f\n", get_irn_for_graph_nr(pi->co->chordal_env->irg, nnr), i, var_name, sol[i]));
+ DBG((dbg, LEVEL_2, "Irn %n Idx %d Var %s Val %f\n", get_irn_for_graph_nr(get_irg(pi->co), nnr), i, var_name, sol[i]));
DBG((dbg, LEVEL_2, "x%d = %d\n", nnr, col));
- set_irn_col(pi->co, get_irn_for_graph_nr(pi->co->chordal_env->irg, nnr), col);
+ set_irn_col(pi->co, get_irn_for_graph_nr(get_irg(pi->co), nnr), col);
} else
assert(0 && "This should be a x-var");
}
static firm_dbg_module_t *dbg = NULL;
-#define is_curr_reg_class(irn) (arch_get_irn_reg_class(co->chordal_env->arch_env, irn, arch_pos_make_out(0)) == co->chordal_env->cls)
+#define is_curr_reg_class(irn) \
+ (arch_get_irn_reg_class(get_arch_env(co), \
+ irn, arch_pos_make_out(0)) == co->chordal_env->cls)
#define MIN(a,b) ((a<b)?(a):(b))
#define MAX(a,b) ((a<b)?(b):(a))
}
unit->nodes = xrealloc(unit->nodes, unit->node_count * sizeof(*unit->nodes));
unit->costs = xrealloc(unit->costs, unit->node_count * sizeof(*unit->costs));
- } else if (is_Copy(co->chordal_env->arch_env, root)) {
+ } else if (is_Copy(get_arch_env(co), root)) {
assert(!nodes_interfere(co->chordal_env, root, get_Copy_src(root)));
unit->nodes[1] = get_Copy_src(root);
unit->costs[1] = co->get_costs(root, unit->nodes[1], -1);
border_t *curr;
list_for_each_entry_reverse(border_t, curr, head, list)
- if (curr->is_def && curr->is_real && is_optimizable(co->chordal_env->arch_env, curr->irn))
+ if (curr->is_def && curr->is_real && is_optimizable(get_arch_env(co), curr->irn))
co_append_unit(co, curr->irn);
}
static void co_collect_units(copy_opt_t *co) {
DBG((dbg, LEVEL_1, "\tCollecting optimization units\n"));
co->roots = pset_new_ptr(64);
- dom_tree_walk_irg(co->chordal_env->irg, co_collect_in_block, NULL, co);
+ dom_tree_walk_irg(get_irg(co), co_collect_in_block, NULL, co);
del_pset(co->roots);
}
co->get_costs = get_costs;
s1 = get_irp_prog_name();
- s2 = get_entity_name(get_irg_entity(co->chordal_env->irg));
+ s2 = get_entity_name(get_irg_entity(get_irg(co)));
s3 = chordal_env->cls->name;
len = strlen(s1) + strlen(s2) + strlen(s3) + 5;
co->name = xmalloc(len);
int i, max;
for(i=0, max=get_irn_n_outs(irn); i<max; ++i) {
ir_node *n = get_irn_out(irn, i);
- if ((is_Phi(n) || is_Perm(co->chordal_env->arch_env, n)) && (irn == n || !nodes_interfere(co->chordal_env, irn, n)))
+ if ((is_Phi(n) || is_Perm(get_arch_env(co), n)) && (irn == n || !nodes_interfere(co->chordal_env, irn, n)))
return 1;
}
return 0;
} unit_t;
/* Helpers */
+#define get_arch_env(co) ((co)->chordal_env->session_env->main_env->arch_env)
+#define get_irg(co) ((co)->chordal_env->session_env->irg)
+#define get_irn_col(co, irn) \
+ arch_register_get_index(arch_get_irn_register(get_arch_env(co), irn, 0))
#define set_irn_col(co, irn, col) \
- arch_set_irn_register(co->chordal_env->arch_env, irn, 0, arch_register_for_index(co->chordal_env->cls, col))
+ arch_set_irn_register(get_arch_env(co), irn, 0, arch_register_for_index(co->chordal_env->cls, col))
-#define get_irn_col(co, irn) \
- arch_register_get_index(arch_get_irn_register(co->chordal_env->arch_env, irn, 0))
#define list_entry_units(lh) list_entry(lh, unit_t, units)
int lb, copy_costs;
/* BETTER: You can remove this if you replace all `grep get_irn_out *.c`*/
- compute_outs(chordal_env->irg);
+ compute_outs(chordal_env->session_env->irg);
co = new_copy_opt(chordal_env, get_costs_loop_depth);
DBG((dbg, LEVEL_1, "===> %s <===\n", co->name));
if (phi != arg) {
curr_vals[I_COPIES_MAX]++; /* if arg!=phi this is a possible copy */
if (nodes_interfere(chordal_env, phi, arg)) {
- DBG((dbg, LEVEL_1, "%e -- In Block %N: %n %N %n %N\n", get_irg_entity(chordal_env->irg), get_nodes_block(phi), phi, phi, arg, arg));
+ DBG((dbg, LEVEL_1, "%e -- In Block %N: %n %N %n %N\n",
+ get_irg_entity(chordal_env->session_env->irg), get_nodes_block(phi), phi, phi, arg, arg));
curr_vals[I_COPIES_IF]++;
}
}
xfree(members);
}
-#define is_curr_reg_class(irn) (arch_get_irn_reg_class(chordal_env->arch_env, irn, arch_pos_make_out(0)) == chordal_env->cls)
+#define is_curr_reg_class(irn) \
+ (arch_get_irn_reg_class(chordal_env->session_env->main_env->arch_env, irn, \
+ arch_pos_make_out(0)) == chordal_env->cls)
void copystat_collect_cls(be_chordal_env_t *chordal_env) {
ir_node *n;
#include "irflag_t.h"
#include "ircons_t.h"
#include "irnode_t.h"
+#include "ircons_t.h"
#include "irmode_t.h"
#include "irdom_t.h"
#include "iredges_t.h"
#include "bearch_firm.h"
#include "benode_t.h"
#include "beirgmod.h"
+#include "bespillilp.h"
#include "beasm_dump_globals.h"
#include "beasm_asm_gnu.h"
ir_graph *irg = get_irp_irg(i);
be_main_session_env_t session;
- DBG((env.dbg, LEVEL_1, "be irg: %F\n", irg));
+ DBG((env.dbg, LEVEL_1, "be irg: %F\n", irg));
/* Init the session. */
be_init_session_env(&session, &env, irg);
/* Verify the schedule */
sched_verify_irg(irg);
- /* Build liveness information */
- be_liveness(irg);
-
- /* Liveness analysis */
- be_liveness(irg);
+ /* Build liveness information */
+ be_liveness(irg);
copystat_reset();
copystat_collect_irg(irg, env.arch_env);
- /*
- * Verifying the schedule once again cannot hurt.
- */
- sched_verify_irg(irg);
+ /*
+ * Verifying the schedule once again cannot hurt.
+ */
+ sched_verify_irg(irg);
/* Perform the following for each register class. */
for(j = 0, m = isa->get_n_reg_class(); j < m; ++j) {
be_chordal_env_t *chordal_env;
const arch_register_class_t *cls = isa->get_reg_class(j);
- DBG((env.dbg, LEVEL_1, "\treg class: %s\n", cls->name));
+ DBG((env.dbg, LEVEL_1, "\treg class: %s\n", cls->name));
+
+ be_numbering(irg);
+ be_liveness(irg);
- be_numbering(irg);
- be_liveness(irg);
+ // be_spill_ilp(&session, cls);
- chordal_env = be_ra_chordal(irg, env.arch_env, cls);
+ chordal_env = be_ra_chordal(&session, cls);
#ifdef DUMP_ALLOCATED
dump_allocated_irg(env.arch_env, irg, "");
be_copy_opt(chordal_env);
- be_ssa_destruction(&session, chordal_env);
- be_ssa_destruction_check(&session, chordal_env);
- be_ra_chordal_check(chordal_env);
+ be_ssa_destruction(chordal_env);
+ be_ssa_destruction_check(chordal_env);
- be_ra_chordal_done(chordal_env);
- be_numbering_done(irg);
+ be_ra_chordal_check(chordal_env);
+ be_ra_chordal_done(chordal_env);
+ be_numbering_done(irg);
}
+ dump_ir_block_graph(session.irg, "-post");
copystat_dump_pretty(irg);
}
idx = redir_proj(&irn, 0);
bo = pmap_get(factory->irn_op_map, get_irn_op(irn));
+ /* TODO Implement */
return 0;
}
return perm;
}
+#if 0
typedef struct _phi_perm_info_t {
const be_main_session_env_t *env;
const arch_register_class_t *cls;
irg_block_walk_graph(env->irg, insert_phi_perms, NULL, &pi);
pmap_destroy(pi.perm_map);
}
+#endif
/* If there is no dominance relation, they do not interfere. */
if(a2b + b2a > 0) {
const ir_edge_t *edge;
- ir_node *ba = get_nodes_block(a);
ir_node *bb = get_nodes_block(b);
/*
#include "debug.h"
#include "besched_t.h"
-#include "besched.h"
+#include "beutil.h"
#include "belistsched.h"
FIRM_IMPL1(sched_get_time_step, int, const ir_node *)
return res;
}
+
+extern ir_node *sched_skip(ir_node *from, int forward,
+ sched_predicator_t *predicator, void *data)
+{
+ const ir_node *bl = get_block(from);
+ ir_node *curr;
+
+ for(curr = from; curr != bl && predicator(curr, data);
+ curr = forward ? sched_next(curr) : sched_prev(curr));
+ return curr;
+}
*/
extern int sched_verify_irg(ir_graph *irg);
+/**
+ * A predicate for a node.
+ * @param irn The node.
+ * @param data The custom data.
+ * @return 1 or 0, depending on your criteria.
+ */
+typedef int (sched_predicator_t)(const ir_node *irn, void *data);
+
+/**
+ * Skip nodes in a schedule.
+ * @param from The node to start from.
+ * @param forward The direction (1 for forward, 0 for backward).
+ * @param predicator The one who decides what is skipped.
+ * @param data Food for the predicator.
+ * @return The first node rejected by the predicator or the block
+ * itself if none was rejected.
+ */
+extern ir_node *sched_skip(ir_node *from, int forward,
+ sched_predicator_t *predicator, void *data);
#define sched_get_time_step(irn) _sched_get_time_step(irn)
#define sched_has_succ(irn) _sched_has_succ(irn)
#include "debug.h"
#include "set.h"
#include "pmap.h"
-#include "irnode.h"
+#include "irnode_t.h"
+#include "ircons_t.h"
#include "iredges_t.h"
+#include "irgmod.h"
#include "irdump.h"
#include "irprintf.h"
#define DEBUG_LVL SET_LEVEL_2
-#define get_reg(irn) arch_get_irn_register(chordal_env->arch_env, irn, 0)
-#define set_reg(irn, reg) arch_set_irn_register(chordal_env->arch_env, irn, 0, reg)
-
-/**
- * Maps blocks to perm nodes inserted during phi destruction.
- */
-typedef struct _block2perm_t {
- ir_node *block, *perm;
-} block2perm_t;
-
-static int set_cmp_b2p(const void *x, const void *y, size_t size) {
- const block2perm_t *b1 = x;
- const block2perm_t *b2 = y;
- return b1->block != b2->block;
-}
+#define get_chordal_arch(ce) ((ce)->session_env->main_env->arch_env)
+#define get_reg(irn) arch_get_irn_register(get_chordal_arch(chordal_env), irn, 0)
+#define set_reg(irn, reg) arch_set_irn_register(get_chordal_arch(chordal_env), irn, 0, reg)
#define is_Branch(irn) (arch_irn_classify(arch_env, irn) == arch_irn_class_branch)
#define is_Perm(irn) (arch_irn_classify(arch_env, irn) == arch_irn_class_perm)
#define get_reg_cls(irn) (arch_get_irn_reg_class(arch_env, irn, arch_pos_make_out(0)))
#define is_curr_reg_class(irn) (get_reg_cls(p) == chordal_env->cls)
-static ir_node *get_or_insert_perm(be_main_session_env_t *session, be_chordal_env_t *chordal_env, ir_node *block) {
- block2perm_t find, *found;
- ir_node *p;
- set *b2p = chordal_env->data;
- const arch_env_t *arch_env = chordal_env->arch_env;
-
-
- /* iff needed insert perm node */
- DBG((dbg, LEVEL_1, " Getting perm in %+F\n", block));
-
- /* .if the perm is in the pset return it */
- find.block = block;
- find.perm = NULL;
- found = set_insert(b2p, &find, sizeof(find), HASH_PTR(find.block));
- if (found->perm) {
- DBG((dbg, LEVEL_1, " found it %+F in map\n", found->perm));
- return found->perm;
- }
+static void clear_link(ir_node *irn, void *data)
+{
+ set_irn_link(irn, NULL);
+}
- /* .else look for a perm of right register class in the schedule */
- p = sched_last(find.block);
- while (!is_Block(p) && (is_Branch(p) || (is_Perm(p) && !is_curr_reg_class(p))))
- p = sched_prev(p);
+/**
+ * Build a list of phis of a block.
+ */
+static void collect_phis(ir_node *irn, void *data)
+{
+ be_chordal_env_t *env = data;
+ if(is_Phi(irn) &&
+ arch_irn_has_reg_class(env->session_env->main_env->arch_env,
+ irn, arch_pos_make_out(0), env->cls)) {
+
+ ir_node *bl = get_nodes_block(irn);
+ set_irn_link(irn, get_irn_link(bl));
+ set_irn_link(bl, irn);
+ }
+}
- /* if we haven't found a perm of the right register class create a new one */
- if (! (is_Perm(p) && is_curr_reg_class(p))) {
- DBG((dbg, LEVEL_1, " insert it after %+F\n", p));
- p = insert_Perm_after(session, chordal_env->cls, p);
- }
+/**
+ * Build a ring of phis for each block in the link field.
+ * @param env The chordal env.
+ */
+static INLINE void build_phi_rings(be_chordal_env_t *env)
+{
+ irg_walk_graph(env->session_env->irg, clear_link, collect_phis, env);
+}
- /* insert perm into pset and return it*/
- found->perm = p;
- return p;
+static int skip_cf_predicator(const ir_node *irn, void *data) {
+ be_chordal_env_t *ce = data;
+ arch_env_t *ae = ce->session_env->main_env->arch_env;
+ return arch_irn_classify(ae, irn) == arch_irn_class_branch;
}
#define is_pinned(irn) (get_irn_link(irn))
* by inserting perm nodes, if necessary.
* @param phi The phi node to adjust operands for
*/
-static void adjust_phi_arguments(be_main_session_env_t *session, be_chordal_env_t *chordal_env, ir_node *phi) {
+static void adjust_phi_arguments(be_chordal_env_t *chordal_env, ir_node *phi) {
int i, max;
ir_node *arg, *phi_block, *arg_block;
- arch_env_t *arch_env = session->main_env->arch_env;
+ arch_env_t *arch_env = get_chordal_arch(chordal_env);
+ const be_main_session_env_t *session = chordal_env->session_env;
const arch_register_t *phi_reg, *arg_reg;
const arch_register_class_t *cls;
assert(is_Phi(phi) && "Can only handle phi-destruction :)");
DBG((dbg, LEVEL_1, " for %+F\n", phi));
- cls = arch_get_irn_reg_class(session->main_env->arch_env, phi, arch_pos_make_out(0));
+ cls = arch_get_irn_reg_class(get_chordal_arch(chordal_env), phi, arch_pos_make_out(0));
phi_block = get_nodes_block(phi);
phi_reg = get_reg(phi);
arg_block = get_nodes_block(arg);
arg_reg = get_reg(arg);
perm = get_Proj_pred(arg);
- assert(is_Perm(perm));
+ // assert(is_Perm(perm));
DBG((dbg, LEVEL_1, " arg %+F has perm %+F\n", arg, perm));
/* if registers don't match ...*/
if (!is_pinned(arg)) {
DBG((dbg, LEVEL_1, " arg is not pinned\n"));
ir_node *other_phi = phi;
- while ((other_phi = get_irn_link(other_phi)) != phi) {
+ for(other_phi = get_irn_link(phi_block); other_phi; other_phi = get_irn_link(other_phi)) {
+ if(other_phi == phi)
+ continue;
assert(is_Phi(other_phi) && get_nodes_block(phi) == get_nodes_block(other_phi) && "link fields are screwed up");
if (get_irn_n(other_phi, i) == arg && get_reg(other_phi) == arg_reg) {
DBG((dbg, LEVEL_1, " other phi pinned the argument\n"));
}
}
+static void insert_all_perms_walker(ir_node *bl, void *data)
+{
+ be_chordal_env_t *ce = data;
+ pmap *perm_map = ce->data;
+ ir_graph *irg = ce->session_env->irg;
+ const be_node_factory_t *fact = ce->session_env->main_env->node_factory;
+
+ /* Dummy targets for the projs */
+ ir_node *dummy = new_rd_Unknown(irg, mode_T);
+
+ assert(is_Block(bl));
+
+ /* If the link flag is NULL, this block has no phis. */
+ if(get_irn_link(bl)) {
+ int i, n;
+
+ /* Look at all predecessors of the phi block */
+ for(i = 0, n = get_irn_arity(bl); i < n; ++i) {
+ ir_node *pred_bl = get_Block_cfgpred_block(bl, i);
+ ir_node *phi, *perm, *insert_after;
+ ir_node **in;
+ int j, n_projs = 0;
+ pmap_entry *ent;
+ pmap *arg_map = pmap_create();
+
+ assert(!pmap_contains(perm_map, pred_bl) && "Already permed that block");
+
+ /*
+ * Note that all phis in the ring are in the same register class
+ * by construction.
+ */
+ for(phi = get_irn_link(bl); phi; phi = get_irn_link(phi)) {
+ ir_node *arg = get_irn_n(phi, i);
+ ir_node *proj = pmap_get(arg_map, arg);
+
+ if(!proj) {
+ proj = new_r_Proj(irg, pred_bl, dummy, get_irn_mode(arg), n_projs++);
+ pmap_insert(arg_map, arg, proj);
+ }
+
+ set_irn_n(phi, i, proj);
+ }
+
+ j = 0;
+ in = malloc(n_projs * sizeof(in[0]));
+ pmap_foreach(arg_map, ent)
+ in[j++] = ent->key;
+
+ perm = new_Perm(fact, ce->cls, irg, pred_bl, n_projs, in);
+ insert_after = sched_skip(sched_last(pred_bl), 0, skip_cf_predicator, ce);
+ sched_add_after(insert_after, perm);
+ exchange(dummy, perm);
+
+ free(in);
+ pmap_destroy(arg_map);
+
+ /* register in perm map */
+ pmap_insert(perm_map, pred_bl, perm);
+ }
+ }
+}
-static void insert_all_perms(be_main_session_env_t *session, be_chordal_env_t *chordal_env) {
- pmap_entry *pme;
- int i, max;
- ir_node *first_phi, *recent_phi;
-
+static void insert_all_perms(be_chordal_env_t *chordal_env) {
DBG((dbg, LEVEL_1, "Placing perms...\n"));
-
- /* place perms in cf-preds of phis */
- pmap_foreach(chordal_env->border_heads, pme) {
- border_t *curr;
- struct list_head *head = pme->value;
-
- first_phi = NULL;
- /* iterate over the first ops in the block until a non-phi is reached */
- list_for_each_entry(border_t, curr, head, list) {
- ir_node *phi = curr->irn;
-
- if (curr->is_def && curr->is_real && is_Phi(phi)) {
- set_irn_link(phi, NULL);
- /* chain of phis in a block */
- if (first_phi == NULL)
- first_phi = phi;
- else
- set_irn_link(recent_phi, phi);
- recent_phi = phi;
-
- /* insert perms */
- DBG((dbg, LEVEL_1, " for %+F\n", phi));
- for(i=0, max=get_irn_arity(phi); i<max; ++i) {
- ir_node *perm;
-
- perm = get_or_insert_perm(session, chordal_env, get_Block_cfgpred_block(get_nodes_block(phi), i));
- DBG((dbg, LEVEL_1, " %+F in block %N\n", perm, get_Block_cfgpred_block(get_nodes_block(phi), i)));
- set_irn_link(perm, NULL);
- }
- }
- }
- if (first_phi)
- set_irn_link(recent_phi, first_phi);
- }
+ irg_block_walk_graph(chordal_env->session_env->irg, insert_all_perms_walker, NULL, chordal_env);
}
-static void set_regs_or_place_dupls(be_main_session_env_t *session, be_chordal_env_t *chordal_env) {
- pmap_entry *pme;
+static void set_regs_or_place_dupls_walker(ir_node *bl, void *data) {
+ be_chordal_env_t *chordal_env = data;
+ ir_node *phi;
DBG((dbg, LEVEL_1, "Setting regs and placing dupls...\n"));
+ for(phi = get_irn_link(bl); phi; phi = get_irn_link(phi))
+ adjust_phi_arguments(chordal_env, phi);
+}
- /* iterate over all blocks and correct color of arguments*/
- pmap_foreach(chordal_env->border_heads, pme) {
- border_t *curr;
- struct list_head *head = pme->value;
-
- /* iterate over the first ops in the block until a non-phi is reached */
- list_for_each_entry(border_t, curr, head, list)
- if (curr->is_def && curr->is_real && is_Phi(curr->irn))
- adjust_phi_arguments(session, chordal_env, curr->irn);
- }
+static void set_regs_or_place_dupls(be_chordal_env_t *chordal_env)
+{
+ irg_block_walk_graph(chordal_env->session_env->irg,
+ set_regs_or_place_dupls_walker, NULL, chordal_env);
}
-void be_ssa_destruction(be_main_session_env_t *session, be_chordal_env_t *chordal_env) {
- set *b2p;
+
+void be_ssa_destruction(be_chordal_env_t *chordal_env) {
+ pmap *perm_map = pmap_create();
+ ir_graph *irg = chordal_env->session_env->irg;
dbg = firm_dbg_register("ir.be.ssadestr");
firm_dbg_set_mask(dbg, DEBUG_LVL);
/* create a map for fast lookup of perms: block --> perm */
- b2p = new_set(set_cmp_b2p, 32);
- chordal_env->data = b2p;
+ chordal_env->data = perm_map;
- insert_all_perms(session, chordal_env);
- dump_ir_block_graph(session->irg, "-ssa_destr_perms_placed");
+ build_phi_rings(chordal_env);
+ insert_all_perms(chordal_env);
+ dump_ir_block_graph(irg, "-ssa_destr_perms_placed");
- set_regs_or_place_dupls(session, chordal_env);
- dump_ir_block_graph(session->irg, "-ssa_destr_regs_set");
+ set_regs_or_place_dupls(chordal_env);
+ dump_ir_block_graph(irg, "-ssa_destr_regs_set");
- del_set(b2p);
+ pmap_destroy(perm_map);
}
-void be_ssa_destruction_check(be_main_session_env_t *session, be_chordal_env_t *chordal_env) {
- pmap_entry *pme;
+static void ssa_destruction_check_walker(ir_node *bl, void *data)
+{
+ be_chordal_env_t *chordal_env = data;
+ ir_node *phi;
int i, max;
- /* iterate over all blocks */
- pmap_foreach(chordal_env->border_heads, pme) {
- border_t *curr;
- struct list_head *head = pme->value;
-
- /* iterate over the first ops in the block */
- list_for_each_entry(border_t, curr, head, list)
- if (curr->is_def && curr->is_real && is_Phi(curr->irn)) {
- const arch_register_t *phi_reg, *arg_reg;
- ir_node *phi = curr->irn;
-
- phi_reg = get_reg(phi);
- /* iterate over all args of phi */
- for(i=0, max=get_irn_arity(phi); i<max; ++i) {
- ir_node *arg = get_irn_n(phi, i);
- arg_reg = get_reg(arg);
- if(phi_reg != arg_reg) {
- ir_printf("Registers of %+F and %+F differ: %s %s\n", phi, arg, phi_reg->name, arg_reg->name);
- assert(0 && "Registers of phi and arg differ\n");
- }
- if(!is_pinned(arg))
- ir_printf("Warning: Arg %+F not pinned\n", arg);
- }
- }
- }
+ for(phi = get_irn_link(bl); phi; phi = get_irn_link(phi)) {
+ const arch_register_t *phi_reg, *arg_reg;
+
+ phi_reg = get_reg(phi);
+ /* iterate over all args of phi */
+ for(i=0, max=get_irn_arity(phi); i<max; ++i) {
+ ir_node *arg = get_irn_n(phi, i);
+ arg_reg = get_reg(arg);
+ if(phi_reg != arg_reg) {
+ ir_printf("Registers of %+F and %+F differ: %s %s\n",
+ phi, arg, phi_reg->name, arg_reg->name);
+ assert(0 && "Registers of phi and arg differ\n");
+ }
+ if(!is_pinned(arg))
+ ir_printf("Warning: Arg %+F not pinned\n", arg);
+ }
+ }
+}
+
+void be_ssa_destruction_check(be_chordal_env_t *chordal_env) {
+ irg_block_walk_graph(chordal_env->session_env->irg,
+ ssa_destruction_check_walker, NULL, chordal_env);
}
/**
* Performs SSA-Destruction. Arguments get adjusted, phi nodes just stay.
*/
-void be_ssa_destruction(be_main_session_env_t *session, be_chordal_env_t *chordal_env);
-void be_ssa_destruction_check(be_main_session_env_t *session, be_chordal_env_t *chordal_env);
+void be_ssa_destruction(be_chordal_env_t *chordal_env);
+void be_ssa_destruction_check(be_chordal_env_t *chordal_env);