#include "ircons.h"
#include "debug.h"
-#include "irhooks.h"
#include "xmalloc.h"
#include "irnodeset.h"
#include "irnodemap.h"
DEBUG_ONLY(static firm_dbg_module_t *dbg;)
DEBUG_ONLY(static firm_dbg_module_t *dbg_constr;)
+DEBUG_ONLY(static firm_dbg_module_t *dbg_permmove;)
/** Associates an ir_node with it's copy and CopyKeep. */
typedef struct {
perm_type_t type; /**< type (CHAIN or CYCLE) */
} perm_cycle_t;
-/** Compare the in registers of two register pairs. */
-static int compare_reg_pair(const void *a, const void *b) {
- const reg_pair_t *pair_a = a;
- const reg_pair_t *pair_b = b;
-
- if (pair_a->in_reg->index > pair_b->in_reg->index)
- return 1;
- else
- return -1;
-}
-
/** returns the number register pairs marked as checked. */
-static int get_n_checked_pairs(reg_pair_t *pairs, int n) {
- int i, n_checked = 0;
+static int get_n_unchecked_pairs(reg_pair_t const *const pairs, int const n)
+{
+ int n_unchecked = 0;
+ int i;
for (i = 0; i < n; i++) {
- if (pairs[i].checked)
- n_checked++;
+ if (!pairs[i].checked)
+ n_unchecked++;
}
- return n_checked;
+ return n_unchecked;
}
/**
* Gets an array of register pairs and tries to identify a cycle or chain
* starting at position start.
*
- * @param cycle Variable to hold the cycle
- * @param pairs Array of register pairs
- * @param start Index to start
+ * @param cycle Variable to hold the cycle
+ * @param pairs Array of register pairs
+ * @param n length of the pairs array
+ * @param start Index to start
+ *
* @return The cycle or chain
*/
static void get_perm_cycle(perm_cycle_t *const cycle,
{
int head = pairs[start].in_reg->index;
int cur_idx = pairs[start].out_reg->index;
- int const n_pairs_done = get_n_checked_pairs(pairs, n);
+ int const n_pairs_todo = get_n_unchecked_pairs(pairs, n);
perm_type_t cycle_tp = PERM_CYCLE;
int idx;
}
/* assume worst case: all remaining pairs build a cycle or chain */
- cycle->elems = XMALLOCNZ(const arch_register_t*, (n - n_pairs_done) * 2);
+ cycle->elems = XMALLOCNZ(const arch_register_t*, n_pairs_todo * 2);
cycle->n_elems = 2; /* initial number of elements is 2 */
cycle->elems[0] = pairs[start].in_reg;
cycle->elems[1] = pairs[start].out_reg;
*
* @param irn The perm node
* @param block The block the perm node belongs to
- * @param walk_env The environment
+ * @param env The lowerer environment
*/
-static void lower_perm_node(ir_node *irn, void *walk_env)
+static void lower_perm_node(ir_node *irn, lower_env_t *env)
{
- lower_env_t *const env = walk_env;
const arch_register_class_t *const reg_class = arch_get_irn_register(get_irn_n(irn, 0))->reg_class;
ir_graph *const irg = get_irn_irg(irn);
ir_node *const block = get_nodes_block(irn);
- int const n = get_irn_arity(irn);
- reg_pair_t *const pairs = alloca(n * sizeof(pairs[0]));
+ int const arity = get_irn_arity(irn);
+ reg_pair_t *const pairs = ALLOCAN(reg_pair_t, arity);
int keep_perm = 0;
int do_copy = env->do_copy;
/* Get the schedule predecessor node to the perm.
* nodes after this node, everything should be ok. */
ir_node * sched_point = sched_prev(irn);
const ir_edge_t * edge;
+ const ir_edge_t * next;
+ int n;
int i;
DBG((dbg, LEVEL_1, "perm: %+F, sched point is %+F\n", irn, sched_point));
assert(sched_point && "Perm is not scheduled or has no predecessor");
- assert(n == get_irn_n_edges(irn) && "perm's in and out numbers different");
+ assert(arity == get_irn_n_edges(irn) && "perm's in and out numbers different");
/* build the list of register pairs (in, out) */
- i = 0;
- foreach_out_edge(irn, edge) {
- reg_pair_t *const pair = &pairs[i++];
- ir_node *const out = get_edge_src_irn(edge);
- long const pn = get_Proj_proj(out);
- ir_node *const in = get_irn_n(irn, pn);
+ n = 0;
+ foreach_out_edge_safe(irn, edge, next) {
+ ir_node *const out = get_edge_src_irn(edge);
+ long const pn = get_Proj_proj(out);
+ ir_node *const in = get_irn_n(irn, pn);
+ arch_register_t const *const in_reg = arch_get_irn_register(in);
+ arch_register_t const *const out_reg = arch_get_irn_register(out);
+ reg_pair_t * pair;
+
+ if (in_reg == out_reg) {
+ DBG((dbg, LEVEL_1, "%+F removing equal perm register pair (%+F, %+F, %s)\n",
+ irn, in, out, out_reg->name));
+ exchange(out, in);
+ continue;
+ }
+ pair = &pairs[n++];
pair->in_node = in;
pair->in_reg = arch_get_irn_register(in);
pair->out_node = out;
pair->checked = 0;
}
- /* sort the register pairs by the indices of the in registers */
- qsort(pairs, n, sizeof(pairs[0]), compare_reg_pair);
-
- /* Mark all equal pairs as checked, and exchange the OUT proj with the IN
- * node. */
- for (i = 0; i < n; i++) {
- reg_pair_t *const pair = &pairs[i];
-
- if (pair->in_reg->index != pair->out_reg->index)
- continue;
-
- DBG((dbg, LEVEL_1, "%+F removing equal perm register pair (%+F, %+F, %s)\n",
- irn, pair->in_node, pair->out_node, pair->out_reg->name));
-
- /* reroute the edges from the proj to the argument */
- exchange(pair->out_node, pair->in_node);
-
- pair->checked = 1;
- }
+ DBG((dbg, LEVEL_1, "%+F has %d unresolved constraints\n", irn, n));
/* Set do_copy to 0 if it's on but we have no free register */
/* TODO check for free register */
}
/* check for cycles and chains */
- while (get_n_checked_pairs(pairs, n) < n) {
+ while (get_n_unchecked_pairs(pairs, n) > 0) {
perm_cycle_t cycle;
int j;
}
DB((dbg, LEVEL_1, "\n"));
- if (n == 2 && cycle.type == PERM_CYCLE) {
+ if (cycle.type == PERM_CYCLE && arity == 2) {
/* We don't need to do anything if we have a Perm with two elements
* which represents a cycle, because those nodes already represent
* exchange nodes */
}
static void gen_assure_different_pattern(ir_node *irn, ir_node *other_different, constraint_env_t *env) {
- be_irg_t *birg = env->birg;
- ir_graph *irg = be_get_birg_irg(birg);
- ir_nodemap_t *op_set = &env->op_set;
- ir_node *block = get_nodes_block(irn);
- const arch_register_class_t *cls = arch_get_irn_reg_class(other_different, -1);
- ir_node *in[2], *keep, *cpy;
+ ir_graph *irg;
+ ir_nodemap_t *op_set;
+ ir_node *block;
+ const arch_register_class_t *cls;
+ ir_node *keep, *cpy;
op_copy_assoc_t *entry;
- if (arch_irn_is(other_different, ignore) ||
+ if (arch_irn_is_ignore(other_different) ||
!mode_is_datab(get_irn_mode(other_different))) {
DBG((dbg_constr, LEVEL_1, "ignore constraint for %+F because other_irn is ignore or not a datab node\n", irn));
return;
}
+ irg = be_get_birg_irg(env->birg);
+ op_set = &env->op_set;
+ block = get_nodes_block(irn);
+ cls = arch_get_irn_reg_class_out(other_different);
+
/* Make a not spillable copy of the different node */
/* this is needed because the different irn could be */
/* in block far far away */
cpy = find_copy(skip_Proj(irn), other_different);
if (! cpy) {
cpy = be_new_Copy(cls, irg, block, other_different);
- be_node_set_flags(cpy, BE_OUT_POS(0), arch_irn_flags_dont_spill);
+ arch_irn_set_flags(cpy, arch_irn_flags_dont_spill);
DBG((dbg_constr, LEVEL_1, "created non-spillable %+F for value %+F\n", cpy, other_different));
- }
- else {
+ } else {
DBG((dbg_constr, LEVEL_1, "using already existing %+F for value %+F\n", cpy, other_different));
}
- in[0] = irn;
- in[1] = cpy;
-
/* Add the Keep resp. CopyKeep and reroute the users */
/* of the other_different irn in case of CopyKeep. */
if (has_irn_users(other_different)) {
keep = be_new_CopyKeep_single(cls, irg, block, cpy, irn, get_irn_mode(other_different));
- be_node_set_reg_class(keep, 1, cls);
- }
- else {
+ be_node_set_reg_class_in(keep, 1, cls);
+ } else {
+ ir_node *in[2];
+
+ in[0] = irn;
+ in[1] = cpy;
keep = be_new_Keep(cls, irg, block, 2, in);
}
ir_nodeset_insert(&entry->copies, cpy);
/* insert keep in case of CopyKeep */
- if (be_is_CopyKeep(keep)) {
+ if (be_is_CopyKeep(keep))
ir_nodeset_insert(&entry->copies, keep);
- }
}
/**
* @param env the constraint environment
*/
static void assure_different_constraints(ir_node *irn, ir_node *skipped_irn, constraint_env_t *env) {
- const arch_register_req_t *req = arch_get_register_req(irn, -1);
+ const arch_register_req_t *req = arch_get_register_req_out(irn);
if (arch_register_req_is(req, must_be_different)) {
const unsigned other = req->other_different;
/* set register class for all kept inputs */
for (j = 1; j <= n_melt; ++j)
- be_node_set_reg_class(new_ck, j, entry->cls);
+ be_node_set_reg_class_in(new_ck, j, entry->cls);
ir_nodeset_insert(&entry->copies, new_ck);
void assure_constraints(be_irg_t *birg) {
ir_graph *irg = be_get_birg_irg(birg);
constraint_env_t cenv;
- ir_node **nodes;
ir_nodemap_iterator_t map_iter;
ir_nodemap_entry_t map_entry;
/* for all */
foreach_ir_nodemap(&cenv.op_set, map_entry, map_iter) {
- op_copy_assoc_t *entry = map_entry.data;
- int n;
- ir_node *cp;
- ir_nodeset_iterator_t iter;
+ op_copy_assoc_t *entry = map_entry.data;
+ int n = ir_nodeset_size(&entry->copies);
+ ir_node **nodes = ALLOCAN(ir_node*, n);
+ ir_node *cp;
+ ir_nodeset_iterator_t iter;
be_ssa_construction_env_t senv;
- n = ir_nodeset_size(&entry->copies);
- nodes = alloca(n * sizeof(nodes[0]));
-
/* put the node in an array */
DBG((dbg_constr, LEVEL_1, "introduce copies for %+F ", map_entry.node));
/* so we transform unnecessary ones into Keeps. */
foreach_ir_nodeset(&entry->copies, cp, iter) {
if (be_is_CopyKeep(cp) && get_irn_n_edges(cp) < 1) {
- ir_node *keep;
- int n = get_irn_arity(cp);
+ const arch_register_class_t *cls = arch_get_irn_reg_class_out(cp);
+ int n = get_irn_arity(cp);
+ ir_node *keep;
- keep = be_new_Keep(arch_get_irn_reg_class(cp, -1),
- irg, get_nodes_block(cp), n, get_irn_in(cp) + 1);
+ keep = be_new_Keep(cls, irg, get_nodes_block(cp), n, get_irn_in(cp) + 1);
sched_add_before(cp, keep);
/* Set all ins (including the block) of the CopyKeep BAD to keep the verifier happy. */
* @note This routine needs interference.
* @note Probably, we can implement it a little more efficient.
* Especially searching the frontier lazily might be better.
- * @param perm The perm.
- * @param data The walker data (lower_env_t).
+ *
+ * @param perm The perm
+ * @param env The lowerer environment
+ *
* @return 1, if there is something left to perm over.
* 0, if removed the complete perm.
*/
-static int push_through_perm(ir_node *perm, void *data)
+static int push_through_perm(ir_node *perm, lower_env_t *env)
{
- lower_env_t *env = data;
-
ir_graph *irg = get_irn_irg(perm);
ir_node *bl = get_nodes_block(perm);
ir_node *node;
int n_moved;
int new_size;
ir_node *frontier = bl;
- FIRM_DBG_REGISTER(firm_dbg_module_t *mod, "firm.be.lower.permmove");
-
+ ir_node *irn;
int i, n;
- const ir_edge_t *edge;
- ir_node *one_proj = NULL, *irn;
- const arch_register_class_t *cls = NULL;
-
- DBG((mod, LEVEL_1, "perm move %+F irg %+F\n", perm, irg));
/* get some Proj and find out the register class of that Proj. */
- edge = get_irn_out_edge_first_kind(perm, EDGE_KIND_NORMAL);
- one_proj = get_edge_src_irn(edge);
+ const ir_edge_t *edge = get_irn_out_edge_first_kind(perm, EDGE_KIND_NORMAL);
+ ir_node *one_proj = get_edge_src_irn(edge);
+ const arch_register_class_t *cls = arch_get_irn_reg_class_out(one_proj);
assert(is_Proj(one_proj));
- cls = arch_get_irn_reg_class(one_proj, -1);
+
+ DBG((dbg_permmove, LEVEL_1, "perm move %+F irg %+F\n", perm, irg));
/* Find the point in the schedule after which the
* potentially movable nodes must be defined.
* the former dead operand would be live now at the point of
* the Perm, increasing the register pressure by one.
*/
- sched_foreach_reverse_from (sched_prev(perm), irn) {
+ sched_foreach_reverse_from(sched_prev(perm), irn) {
for (i = get_irn_arity(irn) - 1; i >= 0; --i) {
ir_node *op = get_irn_n(irn, i);
if (arch_irn_consider_in_reg_alloc(cls, op) &&
}
found_front:
- DBG((mod, LEVEL_2, "\tfrontier: %+F\n", frontier));
+ DBG((dbg_permmove, LEVEL_2, "\tfrontier: %+F\n", frontier));
node = sched_prev(perm);
n_moved = 0;
- while(!sched_is_begin(node)) {
+ while (!sched_is_begin(node)) {
const arch_register_req_t *req;
int input = -1;
ir_node *proj;
}
}
/* it wasn't an input to the perm, we can't do anything more */
- if(input < 0)
+ if (input < 0)
break;
- if(!sched_comes_after(frontier, node))
+ if (!sched_comes_after(frontier, node))
break;
if (arch_irn_is(node, modify_flags))
break;
- if(is_Proj(node)) {
- req = arch_get_register_req(get_Proj_pred(node),
- -1 - get_Proj_proj(node));
- } else {
- req = arch_get_register_req(node, -1);
- }
- if(req->type != arch_register_req_type_normal)
+ req = arch_get_register_req_out(node);
+ if (req->type != arch_register_req_type_normal)
break;
- for(i = get_irn_arity(node) - 1; i >= 0; --i) {
+ for (i = get_irn_arity(node) - 1; i >= 0; --i) {
ir_node *opop = get_irn_n(node, i);
if (arch_irn_consider_in_reg_alloc(cls, opop)) {
break;
}
}
- if(i >= 0)
+ if (i >= 0)
break;
- DBG((mod, LEVEL_2, "\tmoving %+F after %+F, killing %+F\n", node, perm, proj));
+ DBG((dbg_permmove, LEVEL_2, "\tmoving %+F after %+F, killing %+F\n", node, perm, proj));
/* move the movable node in front of the Perm */
sched_remove(node);
new_size = arity - n_moved;
if(new_size == 0) {
+ sched_remove(perm);
+ kill_node(perm);
return 0;
}
- map = alloca(new_size * sizeof(map[0]));
- proj_map = alloca(arity * sizeof(proj_map[0]));
+ map = ALLOCAN(int, new_size);
+ proj_map = ALLOCAN(int, arity);
memset(proj_map, -1, sizeof(proj_map[0]));
n = 0;
- for(i = 0; i < arity; ++i) {
- if(bitset_is_set(moved, i))
+ for (i = 0; i < arity; ++i) {
+ if (bitset_is_set(moved, i))
continue;
map[n] = i;
proj_map[i] = n;
return;
perm_stayed = push_through_perm(irn, walk_env);
- if (!perm_stayed)
- return;
-
- lower_perm_node(irn, walk_env);
+ if (perm_stayed)
+ lower_perm_node(irn, walk_env);
}
/**
ir_graph *irg;
FIRM_DBG_REGISTER(dbg, "firm.be.lower");
+ FIRM_DBG_REGISTER(dbg_permmove, "firm.be.lower.permmove");
env.birg = birg;
env.do_copy = do_copy;