* to remember all roots.
*/
static void co_append_unit(copy_opt_t *co, ir_node *root) {
- int i, arity;
+ int i, arity, inevitable_costs = 0;
unit_t *unit;
struct list_head *tmp;
arity = get_irn_arity(root);
unit = xcalloc(1, sizeof(*unit));
unit->co = co;
- unit->node_count = 1;
unit->nodes = xmalloc((arity+1) * sizeof(*unit->nodes));
unit->costs = xmalloc((arity+1) * sizeof(*unit->costs));
+ unit->node_count = 1;
unit->nodes[0] = root;
- unit->complete_costs = 0;
- unit->sort_key = 0;
INIT_LIST_HEAD(&unit->queue);
/* check all args */
if (is_Phi(root)) {
for (i=0; i<arity; ++i) {
+ int o, arg_pos = 0;
ir_node *arg = get_irn_n(root, i);
+
assert(is_curr_reg_class(arg) && "Argument not in same register class.");
- if (arg != root) {
- int o, arg_pos = 0;
- if (nodes_interfere(co->chordal_env, root, arg))
- assert(0 && "root and arg interfere");
- DBG((dbg, LEVEL_1, "\t Member: %n %N\n", arg, arg));
-
- /* check if arg has occurred at a prior position in the arg/list */
- for (o=0; o<unit->node_count; ++o)
- if (unit->nodes[o] == arg) {
- arg_pos = o;
- break;
- }
-
- if (!arg_pos) { /* a new argument */
- /* insert node, set costs */
- unit->nodes[unit->node_count] = arg;
- unit->costs[unit->node_count] = co->get_costs(root, arg, i);
- unit->node_count++;
- } else { /* arg has occured before in same phi */
- /* increase costs for existing arg */
- unit->costs[arg_pos] = co->get_costs(root, arg, i);
+ if (arg == root)
+ continue;
+ if (nodes_interfere(co->chordal_env, root, arg)) {
+ inevitable_costs += co->get_costs(root, arg, i);
+ continue;
+ }
+
+ /* Else insert the argument of the phi to the members of this ou */
+ DBG((dbg, LEVEL_1, "\t Member: %n %N\n", arg, arg));
+
+ /* Check if arg has occurred at a prior position in the arg/list */
+ for (o=0; o<unit->node_count; ++o)
+ if (unit->nodes[o] == arg) {
+ arg_pos = o;
+ break;
}
+
+ if (!arg_pos) { /* a new argument */
+ /* insert node, set costs */
+ unit->nodes[unit->node_count] = arg;
+ unit->costs[unit->node_count] = co->get_costs(root, arg, i);
+ unit->node_count++;
+ } else { /* arg has occured before in same phi */
+ /* increase costs for existing arg */
+ unit->costs[arg_pos] += co->get_costs(root, arg, i);
}
}
unit->nodes = xrealloc(unit->nodes, unit->node_count * sizeof(*unit->nodes));
/* TODO add ou's for 2-addr-code instructions */
+ /* Init costs with inevitable_costs */
+ unit->all_nodes_costs = inevitable_costs;
+ unit->min_nodes_costs = inevitable_costs;
+
+ /* Determine the maximum costs this unit can cause: all_nodes_cost */
for(i=1; i<unit->node_count; ++i) {
unit->sort_key = MAX(unit->sort_key, unit->costs[i]);
- unit->complete_costs += unit->costs[i];
+ unit->all_nodes_costs += unit->costs[i];
}
- /* insert according to average costs */
+ /* Determine the minimal costs this unit will cause: min_nodes_costs */
+ unit->min_nodes_costs += unit->all_nodes_costs - ou_max_ind_set_costs(unit);
+
+ /* Insert the new ou according to its sort_key */
tmp = &co->units;
while (tmp->next != &co->units && list_entry_units(tmp->next)->sort_key > unit->sort_key)
tmp = tmp->next;
list_add(&unit->units, tmp);
-
- /* Init ifg_mis_size to node_count. So get_lower_bound returns correct results. */
- unit->minimal_costs = unit->complete_costs - ou_max_ind_set_costs(unit);
}
static void co_collect_in_block(ir_node *block, void *env) {
int res = 0;
unit_t *curr;
list_for_each_entry(unit_t, curr, &co->units, units)
- res += curr->minimal_costs;
+ res += curr->min_nodes_costs;
return res;
}
#include "benode_t.h"
#include "besched_t.h"
+static firm_dbg_module_t *dbg = NULL;
+#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)
#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 */
-
- /* .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)
- return found->perm;
-
- /* .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);
-
- /* 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)))
+ 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;
+ }
+
+ /* .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);
+
+ /* 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);
+ }
- /* insert perm into pset */
- found->perm = p;
- return p;
+ /* insert perm into pset and return it*/
+ found->perm = p;
+ return p;
}
#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_arguments(be_main_session_env_t *session, be_chordal_env_t *chordal_env, ir_node *phi) {
+static void adjust_phi_arguments(be_main_session_env_t *session, be_chordal_env_t *chordal_env, ir_node *phi) {
int i, max;
ir_node *arg, *phi_block, *arg_block;
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));
phi_block = get_nodes_block(phi);
phi_reg = get_reg(phi);
- /* all arguments of the phi */
+
+ /* process all arguments of the phi */
for(i=0, max=get_irn_arity(phi); i<max; ++i) {
ir_node *perm;
arg_reg = get_reg(arg);
perm = get_Proj_pred(arg);
+ DBG((dbg, LEVEL_1, " arg %+F has perm %+F\n", arg, perm));
/* if registers don't match ...*/
if (phi_reg != arg_reg) {
+ DBG((dbg, LEVEL_1, " regs don't match %d %d\n", phi_reg, arg_reg));
/* First check if there is another phi in the same block
- * having arg at the same pos in its arg-list */
+ * having arg at the same pos in its arg-list and the same color as arg */
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) {
- assert(is_Phi(other_phi) && "link fields are screwed up");
- if (get_irn_n(other_phi, i) == arg && get_reg(other_phi) == arg_reg)
+ 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"));
pin_irn(arg, phi_block);
+ }
}
}
- if (is_pinned(arg)) {
+ /* If arg is pinned, another phi set the color of arg and pinned it.
+ * So this phi can't change the color again and a duplicate must be inserted.
+ *
+ * If arg interferes with phi, one can never set the same color for both
+ * Hence, a duplicate must be inserted */
+ if (is_pinned(arg) || nodes_interfere(chordal_env, phi, arg)) {
ir_node *dupl, *tmp;
- /* Arg is pinned. So another phi has locked it.
- * Hence, a duplicate must be inserted */
assert(get_pinning_block(arg) == phi_block && "If arg is pinned it must be due to a phi in the same block");
+
dupl = new_Copy(session->main_env->node_factory, cls, session->irg, arg_block, arg);
set_irn_n(phi, i, dupl);
set_reg(dupl, phi_reg);
+ DBG((dbg, LEVEL_1, " inserting dupl %+F\n", dupl));
/* Add dupl to schedule */
tmp = sched_next(perm);
* livein(PhiBl) = liveout(ArgBl), if all phis are processed then
* every color is used exactly once.
*/
- set_reg(arg, phi_reg);
+ DBG((dbg, LEVEL_1, " just set color\n"));
+ set_reg(arg, phi_reg);
}
}
- /* Now the color of the arg and the phi-result are equal.
- * Pin it, so everyone knows
+
+ /* Now the color of the arg (arg may be a dupl now) and the phi-result are equal.
+ * Pin it, so everyone knows and it never gets changed again.
* An arg never is a phi, because perms were inserted. So the link field is free */
+ DBG((dbg, LEVEL_1, " arg has correct color (now), so pin it\n"));
pin_irn(arg, phi_block);
}
}
-void be_ssa_destruction(be_main_session_env_t *session, be_chordal_env_t *chordal_env) {
+
+static void insert_all_perms(be_main_session_env_t *session, be_chordal_env_t *chordal_env) {
pmap_entry *pme;
- set *b2p;
int i, max;
ir_node *first_phi, *recent_phi;
- b2p = new_set(set_cmp_b2p, 32);
- chordal_env->data = b2p;
+ DBG((dbg, LEVEL_1, "Placing perms...\n"));
/* place perms in cf-preds of phis */
pmap_foreach(chordal_env->border_heads, pme) {
/* 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) {
- if (!is_Phi(phi))
- break;
+ 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)
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;
- ir_printf("Placing perm for %+F \n", phi);
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);
}
+}
- dump_ir_block_graph(session->irg, "-ssa_destr_perms_placed");
+static void set_regs_or_place_dupls(be_main_session_env_t *session, be_chordal_env_t *chordal_env) {
+ pmap_entry *pme;
+
+ DBG((dbg, LEVEL_1, "Setting regs and placing dupls...\n"));
/* iterate over all blocks and correct color of arguments*/
pmap_foreach(chordal_env->border_heads, pme) {
/* 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) {
- if (!is_Phi(curr->irn))
- break;
- adjust_arguments(session, chordal_env, curr->irn);
- }
+ if (curr->is_def && curr->is_real && is_Phi(curr->irn))
+ adjust_phi_arguments(session, chordal_env, curr->irn);
}
+}
+
+void be_ssa_destruction(be_main_session_env_t *session, be_chordal_env_t *chordal_env) {
+ set *b2p;
+
+ 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;
+
+ insert_all_perms(session, chordal_env);
+ dump_ir_block_graph(session->irg, "-ssa_destr_perms_placed");
+
+ set_regs_or_place_dupls(session, chordal_env);
+ dump_ir_block_graph(session->irg, "-ssa_destr_regs_set");
- dump_ir_block_graph(session->irg, "-ssa_destr_colors_set");
del_set(b2p);
}
/* 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;
- if (!is_Phi(phi))
- break;
-
- 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 (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);
}
- if(!is_pinned(arg))
- ir_printf("Warning: Arg not pinned %n %N\n", arg, arg);
}
- }
}
}