* @brief Chordal register allocation.
* @author Sebastian Hack
* @date 08.12.2004
- * @version $Id$
*/
#include "config.h"
#include "list.h"
#include "bitset.h"
#include "raw_bitset.h"
-#include "iterator.h"
#include "bipartite.h"
#include "hungarian.h"
#include "irdump.h"
#include "irdom.h"
#include "irtools.h"
-#include "irbitset.h"
#include "debug.h"
#include "iredges.h"
#include "beirgmod.h"
#include "beifg.h"
#include "beinsn_t.h"
-#include "bestatevent.h"
+#include "statev_t.h"
#include "beirg.h"
#include "beintlive_t.h"
#include "bera.h"
DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
-#define NO_COLOR (-1)
-
-#define DUMP_INTERVALS
-
typedef struct be_chordal_alloc_env_t {
be_chordal_env_t *chordal_env;
bitset_t *live; /**< A liveness bitset. */
bitset_t *tmp_colors; /**< An auxiliary bitset which is as long as the number of colors in the class. */
bitset_t *colors; /**< The color mask. */
- bitset_t *in_colors; /**< Colors used by live in values. */
- int colors_n; /**< The number of colors. */
} be_chordal_alloc_env_t;
static int get_next_free_reg(const be_chordal_alloc_env_t *alloc_env, bitset_t *colors)
return bitset_next_set(tmp, 0);
}
-static bitset_t *get_decisive_partner_regs(bitset_t *bs, const be_operand_t *o1, const be_operand_t *o2)
+static bitset_t const *get_decisive_partner_regs(be_operand_t const *const o1)
{
- bitset_t *res = bs;
+ be_operand_t const *const o2 = o1->partner;
+ assert(!o2 || o1->req->cls == o2->req->cls);
- if (!o1) {
- bitset_copy(bs, o2->regs);
- return bs;
- }
-
- if (!o2) {
- bitset_copy(bs, o1->regs);
- return bs;
- }
-
- assert(o1->req->cls == o2->req->cls || ! o1->req->cls || ! o2->req->cls);
-
- if (bitset_contains(o1->regs, o2->regs)) {
- bitset_copy(bs, o1->regs);
+ if (!o2 || bitset_contains(o1->regs, o2->regs)) {
+ return o1->regs;
} else if (bitset_contains(o2->regs, o1->regs)) {
- bitset_copy(bs, o2->regs);
+ return o2->regs;
} else {
- res = NULL;
+ return NULL;
}
-
- return res;
}
static void pair_up_operands(const be_chordal_alloc_env_t *alloc_env, be_insn_t *insn)
}
}
-static ir_node *handle_constraints(be_chordal_alloc_env_t *alloc_env,
- ir_node *irn, int *silent)
+static void handle_constraints(be_chordal_alloc_env_t *alloc_env,
+ ir_node *irn)
{
int n_regs;
- bitset_t *bs;
ir_node **alloc_nodes;
//hungarian_problem_t *bp;
int *assignment;
pmap *partners;
int i, n_alloc;
- size_t col;
- const ir_edge_t *edge;
ir_node *perm = NULL;
//int match_res, cost;
be_chordal_env_t *env = alloc_env->chordal_env;
void *base = obstack_base(env->obst);
- be_insn_t *insn = chordal_scan_insn(env, irn);
- ir_node *res = insn->next_insn;
- int be_silent = *silent;
+ be_insn_t *insn = be_scan_insn(env, irn);
bipartite_t *bp;
if (insn->pre_colored) {
pset_insert_ptr(alloc_env->pre_colored, insn->ops[i].carrier);
}
- /*
- * If the current node is a barrier toggle the silent flag.
- * If we are in the start block, we are ought to be silent at the beginning,
- * so the toggling activates the constraint handling but skips the barrier.
- * If we are in the end block we handle the in requirements of the barrier
- * and set the rest to silent.
- */
- if (be_is_Barrier(irn))
- *silent = !*silent;
-
- if (be_silent)
- goto end;
-
/*
* Perms inserted before the constraint handling phase are considered to be
* correctly precolored. These Perms arise during the ABI handling phase.
*/
- if (!insn->has_constraints)
+ if (!insn->has_constraints || is_Phi(irn))
goto end;
n_regs = env->cls->n_regs;
- bs = bitset_alloca(n_regs);
alloc_nodes = ALLOCAN(ir_node*, n_regs);
//bp = hungarian_new(n_regs, n_regs, 2, HUNGARIAN_MATCH_PERFECT);
bp = bipartite_new(n_regs, n_regs);
DBG((dbg, LEVEL_2, "\tassociating %+F and %+F\n", op->carrier,
partner));
- bitset_clear_all(bs);
- get_decisive_partner_regs(bs, op, op->partner);
-
- DBG((dbg, LEVEL_2, "\tallowed registers for %+F: %B\n", op->carrier,
- bs));
+ bitset_t const *const bs = get_decisive_partner_regs(op);
+ if (bs) {
+ DBG((dbg, LEVEL_2, "\tallowed registers for %+F: %B\n", op->carrier, bs));
- bitset_foreach(bs, col) {
- //hungarian_add(bp, n_alloc, col, 1);
- bipartite_add(bp, n_alloc, col);
+ bitset_foreach(bs, col) {
+ //hungarian_add(bp, n_alloc, col, 1);
+ bipartite_add(bp, n_alloc, col);
+ }
+ } else {
+ DBG((dbg, LEVEL_2, "\tallowed registers for %+F: none\n", op->carrier));
}
n_alloc++;
DBG((dbg, LEVEL_2, "\tsetting %+F to register %s\n", irn, reg->name));
}
- irn = (ir_node*)pmap_get(partners, alloc_nodes[i]);
+ irn = pmap_get(ir_node, partners, alloc_nodes[i]);
if (irn != NULL) {
arch_set_irn_register(irn, reg);
(void) pset_hinsert_ptr(alloc_env->pre_colored, irn);
/* Allocate the non-constrained Projs of the Perm. */
if (perm != NULL) {
- bitset_clear_all(bs);
-
/* Put the colors of all Projs in a bitset. */
+ bitset_t *const bs = bitset_alloca(n_regs);
foreach_out_edge(perm, edge) {
ir_node *proj = get_edge_src_irn(edge);
const arch_register_t *reg = arch_get_irn_register(proj);
DBG((dbg, LEVEL_2, "\tchecking reg of %+F: %s\n", proj, reg ? reg->name : "<none>"));
if (reg == NULL) {
- col = get_next_free_reg(alloc_env, bs);
+ size_t const col = get_next_free_reg(alloc_env, bs);
reg = arch_register_for_index(env->cls, col);
bitset_set(bs, reg->index);
arch_set_irn_register(proj, reg);
end:
obstack_free(env->obst, base);
- return res;
}
/**
*/
static void constraints(ir_node *bl, void *data)
{
- /*
- * Start silent in the start block.
- * The silence remains until the first barrier is seen.
- * Each other block is begun loud.
- */
- int silent = bl == get_irg_start_block(get_irn_irg(bl));
be_chordal_alloc_env_t *env = (be_chordal_alloc_env_t*)data;
ir_node *irn;
- /*
- * If the block is the start block search the barrier and
- * start handling constraints from there.
- */
for (irn = sched_first(bl); !sched_is_end(irn);) {
- irn = handle_constraints(env, irn, &silent);
+ ir_node *const next = sched_next(irn);
+ handle_constraints(env, irn);
+ irn = next;
}
}
be_chordal_env_t *env = alloc_env->chordal_env;
bitset_t *live = alloc_env->live;
bitset_t *colors = alloc_env->colors;
- bitset_t *in_colors = alloc_env->in_colors;
struct list_head *head = get_block_border_head(env, block);
be_lv_t *lv = be_get_irg_liveness(env->irg);
- const ir_node *irn;
- border_t *b;
- int idx;
-
bitset_clear_all(colors);
bitset_clear_all(live);
- bitset_clear_all(in_colors);
DBG((dbg, LEVEL_4, "Assigning colors for block %+F\n", block));
DBG((dbg, LEVEL_4, "\tusedef chain for block\n"));
- list_for_each_entry(border_t, b, head, list) {
+ foreach_border_head(head, b) {
DBG((dbg, LEVEL_4, "\t%s %+F/%d\n", b->is_def ? "def" : "use",
b->irn, get_irn_idx(b->irn)));
}
* Since their colors have already been assigned (The dominators were
* allocated before), we have to mark their colors as used also.
*/
- be_lv_foreach(lv, block, be_lv_state_in, idx) {
- irn = be_lv_get_irn(lv, block, idx);
- if (has_reg_class(env, irn)) {
+ be_lv_foreach(lv, block, be_lv_state_in, irn) {
+ if (arch_irn_consider_in_reg_alloc(env->cls, irn)) {
const arch_register_t *reg = arch_get_irn_register(irn);
- int col;
assert(reg && "Node must have been assigned a register");
- col = arch_register_get_index(reg);
-
DBG((dbg, LEVEL_4, "%+F has reg %s\n", irn, reg->name));
/* Mark the color of the live in value as used. */
+ int const col = reg->index;
bitset_set(colors, col);
- bitset_set(in_colors, col);
/* Mark the value live in. */
bitset_set(live, get_irn_idx(irn));
* elimination order. So, coloring the definitions from first to last
* will work.
*/
- list_for_each_entry_reverse(border_t, b, head, list) {
+ foreach_border_head(head, b) {
ir_node *irn = b->irn;
int nr = get_irn_idx(irn);
int ignore = arch_irn_is_ignore(irn);
*/
if (b->is_def && !be_is_live_in(lv, block, irn)) {
const arch_register_t *reg;
- int col = NO_COLOR;
+ int col;
if (ignore || pset_find_ptr(alloc_env->pre_colored, irn)) {
reg = arch_get_irn_register(irn);
bitset_set(colors, col);
arch_set_irn_register(irn, reg);
- DBG((dbg, LEVEL_1, "\tassigning register %s(%d) to %+F\n", arch_register_get_name(reg), col, irn));
+ DBG((dbg, LEVEL_1, "\tassigning register %s(%d) to %+F\n", reg->name, col, irn));
assert(!bitset_is_set(live, nr) && "Value's definition must not have been encountered");
bitset_set(live, nr);
} else if (!b->is_def) {
/* Clear the color upon a use. */
const arch_register_t *reg = arch_get_irn_register(irn);
- int col;
assert(reg && "Register must have been assigned");
- col = arch_register_get_index(reg);
-
- bitset_clear(colors, col);
+ bitset_clear(colors, reg->index);
bitset_clear(live, nr);
}
}
}
-void be_ra_chordal_color(be_chordal_env_t *chordal_env)
+static void be_ra_chordal_color(be_chordal_env_t *const chordal_env)
{
be_chordal_alloc_env_t env;
char buf[256];
- be_lv_t *lv;
const arch_register_class_t *cls = chordal_env->cls;
- int colors_n = arch_register_class_n_regs(cls);
- ir_graph *irg = chordal_env->irg;
-
- lv = be_assure_liveness(irg);
- be_liveness_assure_sets(lv);
- be_liveness_assure_chk(lv);
+ int colors_n = arch_register_class_n_regs(cls);
+ ir_graph *irg = chordal_env->irg;
+ be_assure_live_sets(irg);
assure_doms(irg);
env.chordal_env = chordal_env;
- env.colors_n = colors_n;
env.colors = bitset_alloca(colors_n);
env.tmp_colors = bitset_alloca(colors_n);
- env.in_colors = bitset_alloca(colors_n);
env.pre_colored = pset_new_ptr_default();
+ be_timer_push(T_SPLIT);
+
+ if (chordal_env->opts->dump_flags & BE_CH_DUMP_SPLIT) {
+ snprintf(buf, sizeof(buf), "%s-split", chordal_env->cls->name);
+ dump_ir_graph(chordal_env->irg, buf);
+ }
+
+ be_timer_pop(T_SPLIT);
+
be_timer_push(T_CONSTR);
/* Handle register targeting constraints */
del_pset(env.pre_colored);
}
-BE_REGISTER_MODULE_CONSTRUCTOR(be_init_chordal);
+BE_REGISTER_MODULE_CONSTRUCTOR(be_init_chordal)
void be_init_chordal(void)
{
static be_ra_chordal_coloring_t coloring = {