Commit 6d538617 authored by Sebastian Hack's avatar Sebastian Hack
Browse files

Re-implemented constraint handling

parent b5015a46
......@@ -58,6 +58,7 @@
typedef struct _be_chordal_alloc_env_t {
be_chordal_env_t *chordal_env;
pset *pre_colored; /**< Set of precolored nodes. */
bitset_t *live; /**< A liveness bitset. */
bitset_t *colors; /**< The color mask. */
bitset_t *in_colors; /**< Colors used by live in values. */
......@@ -161,90 +162,186 @@ static INLINE int has_reg_class(const be_chordal_env_t *env, const ir_node *irn)
return arch_irn_has_reg_class(env->main_env->arch_env, irn, -1, env->cls);
}
static border_t *handle_constraint_perm(be_chordal_alloc_env_t *alloc_env, border_t *perm_border)
{
const arch_env_t *arch_env = alloc_env->chordal_env->main_env->arch_env;
bitset_t *bs = bitset_alloca(alloc_env->chordal_env->cls->n_regs);
ir_node *perm = perm_border->irn;
int n = get_irn_arity(perm_border->irn);
int n_projs = 0;
#define has_limited_constr(req, irn) \
(arch_get_register_req(arch_env, (req), irn, -1) && (req)->type == arch_register_req_type_limited)
border_t *b, *next_border, *cnstr_border;
/**
* Handle register targeting constraints signaled by a Perm.
* @param alloc_env Private data for the allocation phase.
* @param perm The Perm node guarding the constrained node.
* @return The constrained node.
Pro-coloring works as follows:
+-----------------------------------+
| Perm |
+---.-------.--------.---------.----+
| | | |
+---+--+ | | |
| Proj | | | |
+------+ | | |
| | |
+--+---+ | |
| Proj | | |
+--.---+ | |
| | |
| +--+---+ |
| | Proj | |
| +------+ |
| |
| +---+--+
`-. | Proj | Result:
`._ +---.--+ R1
`. |
`-. |
`._ |
+`.-+--+
|Constr| Result:
+------+ R2
1) Look at all Projs of the Perm if they have output constraints.
If one has an output constraint, pre-color it, else record it
in the set leftover. Its color has to be chosen after all
constrained nodes are colored. Furthermore record all colors
used in the pre-coloring in the set colors_used.
2) Look whether the first node not a Proj (this is the constrained
node due to which the Perm has been inserted) has an output
constraint. If yes, pre-color the node accordingly else do nothing
since the node's input constraints are modelled by the Proj's
output constraint.
There's one subtle point here: If thenode has an output constraint
and the live range of some Proj ends at that node, we must give
that Proj the color of the constrained node. Otherwise the
available colors may not suffice for the rest of the projs.
3) At last, color the Projs which have not been colored yet with the
left over colors.
So afterwards, everything including the constrained node will
be colored and the assign() phase can complete this coloring.
Note that therefore, we put the pre-colored nodes in a set
called pre_colored().
arch_register_req_t req;
ir_node *cnstr;
*/
static ir_node *handle_constraints_at_perm(be_chordal_alloc_env_t *alloc_env, ir_node *perm)
{
be_chordal_env_t *env = alloc_env->chordal_env;
firm_dbg_module_t *dbg = env->dbg;
const arch_env_t *arch_env = env->main_env->arch_env;
pset *leftover = pset_new_ptr(8);
bitset_t *bs = bitset_alloca(env->cls->n_regs);
bitset_t *colors_used = bitset_alloca(env->cls->n_regs);
ir_node *irn, *cnstr;
int has_cnstr = 0;
int i, m;
int col;
arch_register_req_t req;
const arch_register_t *reg, *cnstr_reg = NULL;
assert(is_Perm(perm));
assert(be_is_Perm(perm));
DBG((dbg, LEVEL_2, "Constraints on %+F\n", perm));
/*
* After the Perm, there must be a sequence of Projs
* which extract the permuted values of the Perm.
* Color constrained Projs first.
*/
for(b = perm_border; is_Proj(b->irn); b = border_next(b)) {
assert(is_Proj(b->irn));
assert(b->is_def);
n_projs++;
}
for(irn = sched_next(perm); is_Proj(irn); irn = sched_next(irn)) {
arch_register_req_t req;
cnstr_border = b;
next_border = border_next(b);
cnstr = b->irn;
if(has_limited_constr(&req, irn)) {
bitset_clear_all(bs);
req.data.limited(irn, -1, bs);
col = bitset_next_set(bs, 0);
reg = arch_register_for_index(env->cls, col);
assert(n_projs == n && "There must be as many Projs as the Perm is wide");
pset_insert_ptr(alloc_env->pre_colored, irn);
arch_set_irn_register(arch_env, irn, reg);
bitset_set(colors_used, col);
/* The node after the last perm proj must be the constrained node. */
cnstr = b->irn;
for(i = -1, m = get_irn_arity(cnstr); i < m; ++i) {
req.type = arch_register_req_type_normal;
if(arch_get_register_req(arch_env, &req, cnstr, i) && req.type == arch_register_req_type_limited) {
has_cnstr = 1;
break;
DBG((dbg, LEVEL_2, "\tPerm Proj with constraints: %+F set to %s\n", irn, reg->name));
}
else
pset_insert_ptr(leftover, irn);
}
cnstr = irn;
assert(has_cnstr && "The node must have a register constraint");
if(has_limited_constr(&req, cnstr)) {
bitset_clear_all(bs);
req.data.limited(cnstr, -1, bs);
col = bitset_next_set(colors_used, 0);
reg = arch_register_for_index(env->cls, col);
/*
* Consider the code in beconstrperm.c
* We turned each input constraint of a node into an output
* constraint of the Perm's Proj. So we only have to
* consider output constraints here.
*/
for(b = perm_border; b != next_border; b = border_next(b)) {
ir_node *irn = b->irn;
arch_set_irn_register(arch_env, cnstr, reg);
pset_insert_ptr(alloc_env->pre_colored, cnstr);
req.type = arch_register_req_type_normal;
if(arch_get_register_req(arch_env, &req, irn, -1) && req.type == arch_register_req_type_limited) {
const arch_register_t *reg;
int col;
DBG((dbg, LEVEL_2, "\tConstrained node: %+F set to %s\n", irn, reg->name));
bitset_clear_all(bs);
req.data.limited(irn, -1, bs);
col = bitset_next_set(bs, 0);
reg = arch_register_for_index(alloc_env->chordal_env->cls, col);
/*
* The color of the constrained node must not be used!
* The Proj which has been assigned that color might
* interfere with the constrained node which leads
* to an invalid register allocation.
*/
assert(!bitset_is_set(colors_used, reg->index));
arch_set_irn_register(arch_env, irn, reg);
bitset_set(alloc_env->colors, col);
/*
* Look for a Proj not interfering with the constrained node.
* This Proj can be safely set to the constrafined nodes
* color.
*/
for(irn = pset_first(leftover); irn; irn = pset_next(leftover)) {
if(!values_interfere(irn, cnstr)) {
DBG((dbg, LEVEL_2, "\tFound Proj not interfering with contr node %+F set to %s\n", irn, reg->name));
pset_insert_ptr(alloc_env->pre_colored, irn);
arch_set_irn_register(arch_env, irn, reg);
bitset_set(colors_used, reg->index);
pset_remove_ptr(leftover, irn);
pset_break(leftover);
break;
}
}
}
for(b = perm_border; b != next_border; b = border_next(b)) {
ir_node *irn = b->irn;
int nr = get_irn_graph_nr(irn);
bitset_set(alloc_env->live, nr);
/*
* Color the leftover Projs with the leftover colors.
*/
for(irn = pset_first(leftover); irn; irn = pset_next(leftover)) {
col = bitset_next_clear(colors_used, 0);
reg = arch_register_for_index(env->cls, col);
if(arch_get_irn_register(arch_env, irn) == NULL) {
int col = bitset_next_clear(alloc_env->colors, 0);
const arch_register_t *reg = arch_register_for_index(alloc_env->chordal_env->cls, col);
arch_set_irn_register(arch_env, irn, reg);
pset_insert_ptr(alloc_env->pre_colored, irn);
bitset_set(colors_used, col);
arch_set_irn_register(arch_env, irn, reg);
}
DBG((dbg, LEVEL_2, "\tLeft over %+F set to %s\n", irn, reg->name));
}
return cnstr_border;
del_pset(leftover);
return cnstr;
}
/**
* Handle constraint nodes in each basic block.
* be_insert_constr_perms() inserts Perm nodes which perm
* over all values live at the constrained node right in front
* of the constrained node. These Perms signal a constrained node.
* For further comments, refer to handle_constraints_at_perm().
*/
static void constraints(ir_node *bl, void *data)
{
be_chordal_alloc_env_t *env = data;
arch_env_t *arch_env = env->chordal_env->main_env->arch_env;
ir_node *irn;
for(irn = sched_first(bl); !sched_is_end(irn); irn = sched_next(irn)) {
if(be_is_Perm(irn))
irn = handle_constraints_at_perm(env, irn);
}
}
/**
......@@ -425,18 +522,26 @@ static void assign(ir_node *block, void *env_ptr)
DBG((dbg, LEVEL_4, "\tcolors in use: %b\n", colors));
col = bitset_next_clear(colors, 0);
reg = arch_register_for_index(env->cls, col);
if(pset_find_ptr(alloc_env->pre_colored, irn)) {
reg = arch_get_irn_register(arch_env, irn);
col = reg->index;
assert(!bitset_is_set(colors, col) && "pre-colored register must be free");
}
assert(arch_get_irn_register(arch_env, irn) == 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");
else {
col = bitset_next_clear(colors, 0);
reg = arch_register_for_index(env->cls, col);
assert(arch_get_irn_register(arch_env, irn) == NULL && "This node must not have been assigned a register yet");
}
bitset_set(colors, col);
bitset_set(live, nr);
arch_set_irn_register(arch_env, irn, reg);
DBG((dbg, LEVEL_1, "\tassigning register %s(%d) to %+F\n",
arch_register_get_name(reg), col, irn));
assert(!bitset_is_set(live, nr) && "Value's definition must not have been encountered");
bitset_set(live, nr);
}
/* Clear the color upon a use. */
......@@ -451,18 +556,6 @@ static void assign(ir_node *block, void *env_ptr)
bitset_clear(colors, col);
bitset_clear(live, nr);
/*
* If we encounter a Perm, it is due to register constraints.
* To achieve a valid coloring in the presence of register
* constraints, we invoke a special function which takes care
* that all constraints are fulfilled.
* This function assigned valid colors to the projs of the
* Perm and the constrained node itself and skips these
* nodes in the border list.
*/
if(is_Perm(b->irn))
b = handle_constraint_perm(alloc_env, border_next(b));
}
}
......@@ -485,6 +578,10 @@ void be_ra_chordal_color(be_chordal_env_t *chordal_env)
env.colors = bitset_malloc(colors_n);
env.in_colors = bitset_malloc(colors_n);
env.colors_n = colors_n;
env.pre_colored = pset_new_ptr_default();
/* Handle register targeting constraints */
dom_tree_walk_irg(irg, constraints, NULL, &env);
/* First, determine the pressure */
dom_tree_walk_irg(irg, pressure, NULL, &env);
......@@ -508,4 +605,6 @@ void be_ra_chordal_color(be_chordal_env_t *chordal_env)
free(env.live);
free(env.colors);
free(env.in_colors);
del_pset(env.pre_colored);
}
......@@ -341,7 +341,7 @@ ir_node *be_reload(const be_node_factory_t *factory,
ir_node *bl = get_nodes_block(irn);
ir_graph *irg = get_irn_irg(bl);
assert(is_Spill(spill)
assert(be_is_Spill(spill)
|| (is_Phi(spill) && get_irn_mode(spill) == mode_M));
reload = new_Reload(factory, cls, irg, bl, mode, spill);
......@@ -351,17 +351,6 @@ ir_node *be_reload(const be_node_factory_t *factory,
return reload;
}
static INLINE arch_register_req_t *get_Perm_reqs(ir_node *perm)
{
be_node_attr_t *attr = (be_node_attr_t *) &perm->attr;
char *ptr = (char *) &perm->attr;
ptr += sizeof(be_node_attr_t);
ptr += sizeof(arch_register_t *) * attr->n_regs;
return (arch_register_req_t *) ptr;
}
/**
* If the node is a proj, reset the node to the proj's target and return
* the proj number.
......@@ -387,10 +376,6 @@ static const arch_register_req_t *
be_node_get_irn_reg_req(const arch_irn_ops_t *_self,
arch_register_req_t *req, const ir_node *irn, int pos)
{
be_op_t *bo;
const be_node_factory_t *factory =
container_of(_self, const be_node_factory_t, irn_ops);
/* We cannot get output requirements for tuple nodes. */
if(get_irn_mode(irn) == mode_T && pos < 0)
return NULL;
......@@ -401,10 +386,9 @@ be_node_get_irn_reg_req(const arch_irn_ops_t *_self,
if(pos < 0)
pos = redir_proj((const ir_node **) &irn, pos);
/* look if the node is one of ours. */
bo = pmap_get(factory->irn_op_map, get_irn_op(irn));
if(bo) {
if(is_be_node(irn)) {
const be_node_attr_t *a = (const be_node_attr_t *) &irn->attr;
const be_op_t *bo = a->op;
int i;
for(i = 0; i < bo->n_pos; ++i) {
......@@ -421,10 +405,8 @@ be_node_get_irn_reg_req(const arch_irn_ops_t *_self,
* if an output requirement is requested,
* return the one stored in the node.
*/
else {
be_node_attr_t *attr = (be_node_attr_t *) &irn->attr;
*req = attr->reg_data[pos].req;
}
else
*req = a->reg_data[-pos - 1].req;
return req;
}
......@@ -437,10 +419,7 @@ be_node_get_irn_reg_req(const arch_irn_ops_t *_self,
void be_set_Perm_out_req(ir_node *irn, int pos, const arch_register_req_t *req)
{
be_node_attr_t *a = get_attr_and_check(irn, node_kind_perm);
assert(pos >= 0 && pos < get_irn_arity(irn) && "position out of range");
assert(a->op->kind == node_kind_perm && "node must be a perm node");
a->reg_data[pos].req = *req;
}
......@@ -541,12 +520,22 @@ const arch_irn_handler_t *be_node_get_irn_handler(const be_node_factory_t *f)
return &f->handler;
}
int is_Spill(const ir_node *irn)
int be_is_Spill(const ir_node *irn)
{
return is_be_kind(irn, node_kind_spill);
}
int is_Perm(const ir_node *irn)
int be_is_Reload(const ir_node *irn)
{
return is_be_kind(irn, node_kind_reload);
}
int be_is_Copy(const ir_node *irn)
{
return is_be_kind(irn, node_kind_copy);
}
int be_is_Perm(const ir_node *irn)
{
return is_be_kind(irn, node_kind_perm);
}
......@@ -655,13 +644,12 @@ ir_node *insert_Perm_after(const be_main_env_t *env,
ir_node *bl = is_Block(pos) ? pos : get_nodes_block(pos);
ir_graph *irg = get_irn_irg(bl);
pset *live = pset_new_ptr_default();
firm_dbg_module_t *dbg = firm_dbg_register("firm.be.node");
firm_dbg_module_t *dbg = firm_dbg_register("be.node");
irn_live_t *li;
ir_node *curr, *irn, *perm, **nodes;
int i, n;
firm_dbg_set_mask(dbg, DBG_LEVEL);
DBG((dbg, LEVEL_1, "Insert Perm after: %+F\n", pos));
......
......@@ -66,7 +66,10 @@ ir_node *be_reload(
const arch_register_class_t *cls,
ir_node *irn, int pos, ir_mode *mode, ir_node *spill);
int is_Spill(const ir_node *irn);
int be_is_Spill(const ir_node *irn);
int be_is_Reload(const ir_node *irn);
int be_is_Copy(const ir_node *irn);
int be_is_Perm(const ir_node *irn);
void set_Spill_offset(ir_node *irn, unsigned offset);
unsigned get_Spill_offset(ir_node *irn);
......@@ -74,8 +77,6 @@ unsigned get_Spill_offset(ir_node *irn);
ir_node *get_Spill_context(const ir_node *irn);
int is_Perm(const ir_node *irn);
/**
* Modify the output register requirements of a Perm.
* This function incur register constraints to an output value of a Perm.
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment