typedef enum _arch_register_type_t {
arch_register_type_none = 0,
- arch_register_type_write_invariant,
arch_register_type_caller_saved, /**< The register must be saved by the caller
upon a function call. It thus can be overwritten
in the called function. */
* Some flags describing a node in more detail.
*/
typedef enum _arch_irn_flags_t {
- arch_irn_flags_spillable = 1,
- arch_irn_flags_rematerializable = 2
+ arch_irn_flags_dont_spill = 1, /**< This must not be spilled. */
+ arch_irn_flags_rematerializable = 2, /**< This should be replicated instead of spilled/reloaded. */
+ arch_irn_flags_ignore = 4, /**< Do not consider the node during register allocation. */
} arch_irn_flags_t;
struct _arch_irn_ops_if_t {
*/
extern arch_irn_flags_t arch_irn_get_flags(const arch_env_t *env, const ir_node *irn);
+#define arch_irn_is_ignore(env, irn) \
+ (arch_irn_get_flags(env, irn) == arch_irn_flags_ignore)
+
#define arch_irn_has_reg_class(env, irn, pos, cls) \
((cls) == arch_get_irn_reg_class(env, irn, pos))
+#define arch_irn_consider_in_reg_alloc(env, cls, irn) \
+ (arch_irn_has_reg_class(env, irn, -1, cls) && !arch_irn_is_ignore(env, irn))
+
/**
* Somebody who can be asked about nodes.
*/
for(pos = -1, n = get_irn_arity(irn); pos < n; ++pos) {
arch_get_register_req(aenv, &req, irn, pos);
- if(arch_irn_has_reg_class(aenv, irn, pos, cenv->cls) && arch_register_req_is(&req, limited)) {
+ if(arch_irn_has_reg_class(aenv, irn, pos, cenv->cls)
+ && arch_register_req_is(&req, limited)
+ && !arch_irn_is_ignore(aenv, irn)) {
/*
* If we inserted a perm,
return us;
}
-static int max_hops_walker(ir_node *irn, ir_node *tgt, int depth, unsigned visited_nr)
+static int max_hops_walker(reg_pressure_selector_env_t *env, ir_node *irn, ir_node *curr_bl, int depth, unsigned visited_nr)
{
- int i, n;
- int res = 0;
-
- if(irn != tgt) {
- res = INT_MAX;
+ ir_node *bl = get_nodes_block(irn);
+ /*
+ * If the reached node is not in the block desired,
+ * return the value passed for this situation.
+ */
+ if(get_nodes_block(irn) != bl)
+ return block_dominates(bl, curr_bl) ? 0 : INT_MAX;
+ /*
+ * If the node is in the current block but not
+ * yet scheduled, we keep on searching from that node.
+ */
+ if(!pset_find_ptr(env->already_scheduled, irn)) {
+ int i, n;
+ int res = 0;
for(i = 0, n = get_irn_arity(irn); i < n; ++i) {
ir_node *operand = get_irn_n(irn, i);
int tmp;
set_irn_visited(operand, visited_nr);
- tmp = max_hops_walker(operand, tgt, depth + 1, visited_nr);
+ tmp = max_hops_walker(env, operand, bl, depth + 1, visited_nr);
res = MAX(tmp, res);
}
}
+
+ return res;
}
- return res;
+ /*
+ * If the node is in the current block and scheduled, return
+ * the depth which indicates the number of steps to the
+ * region of scheduled nodes.
+ */
+ return depth;
}
static int compute_max_hops(reg_pressure_selector_env_t *env, ir_node *irn)
{
ir_node *bl = get_nodes_block(irn);
ir_graph *irg = get_irn_irg(bl);
- int res = INT_MAX;
+ int res = 0;
const ir_edge_t *edge;
foreach_out_edge(irn, edge) {
- ir_node *user = get_edge_src_irn(edge);
-
- if(get_nodes_block(user) == bl && !pset_find_ptr(env->already_scheduled, user)) {
- unsigned visited_nr = get_irg_visited(irg) + 1;
- int max_hops;
+ ir_node *user = get_edge_src_irn(edge);
+ unsigned visited_nr = get_irg_visited(irg) + 1;
+ int max_hops;
- set_irg_visited(irg, visited_nr);
- max_hops = max_hops_walker(user, irn, 0, visited_nr);
- res = MAX(res, max_hops);
- }
+ set_irg_visited(irg, visited_nr);
+ max_hops = max_hops_walker(env, user, irn, 0, visited_nr);
+ res = MAX(res, max_hops);
}
return res;
free(env);
}
+static int get_result_hops_sum(reg_pressure_selector_env_t *env, ir_node *irn)
+{
+ int res = 0;
+ if(get_irn_mode(irn) == mode_T) {
+ const ir_edge_t *edge;
+
+ foreach_out_edge(irn, edge)
+ res += get_result_hops_sum(env, get_edge_src_irn(edge));
+ }
+
+ else if(mode_is_data(get_irn_mode(irn)))
+ res = compute_max_hops(env, irn);
+
+
+ return res;
+}
+
static INLINE int reg_pr_costs(reg_pressure_selector_env_t *env, ir_node *irn)
{
int i, n;
sum += compute_max_hops(env, op);
}
+ sum += get_result_hops_sum(env, irn);
+
return sum;
}
-ir_node *reg_pressure_select(void *block_env, pset *ready_set)
+static ir_node *reg_pressure_select(void *block_env, pset *ready_set)
{
reg_pressure_selector_env_t *env = block_env;
ir_node *irn, *res = NULL;
}
else {
proj_T = new_r_Proj(current_ir_graph, block, call, mode_T, pn_Call_T_result);
+ last_proj = call;
}
/* Create for each caller save register a proj (keep node argument) */
NULL
};
-ir_node *insert_Perm_after(const arch_env_t *arch_env,
- const arch_register_class_t *cls,
- dom_front_info_t *dom_front,
- ir_node *pos)
+pset *nodes_live_at(const arch_env_t *arch_env, const arch_register_class_t *cls, const ir_node *pos, pset *live)
{
- 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("be.node");
-
+ firm_dbg_module_t *dbg = firm_dbg_register("firm.be.node");
+ ir_node *bl = get_nodes_block(pos);
+ ir_node *irn;
irn_live_t *li;
- ir_node *curr, *irn, *perm, **nodes;
- int i, n;
-
- DBG((dbg, LEVEL_1, "Insert Perm after: %+F\n", pos));
-
live_foreach(bl, li) {
ir_node *irn = (ir_node *) li->irn;
- if(live_is_end(li) && arch_irn_has_reg_class(arch_env, irn, -1, cls))
+ if(live_is_end(li) && arch_irn_consider_in_reg_alloc(arch_env, cls, irn))
pset_insert_ptr(live, irn);
}
sched_foreach_reverse(bl, irn) {
+ int i, n;
ir_node *x;
- /*
- * If we encounter the node we want to insert the Perm after,
- * exit immediately, so that this node is still live
- */
+ /*
+ * If we encounter the node we want to insert the Perm after,
+ * exit immediately, so that this node is still live
+ */
if(irn == pos)
- break;
+ return live;
DBG((dbg, LEVEL_1, "%+F\n", irn));
for(x = pset_first(live); x; x = pset_next(live))
for(i = 0, n = get_irn_arity(irn); i < n; ++i) {
ir_node *op = get_irn_n(irn, i);
- if(arch_irn_has_reg_class(arch_env, op, -1, cls))
+ if(arch_irn_consider_in_reg_alloc(arch_env, cls, op))
pset_insert_ptr(live, op);
}
}
+ return NULL;
+}
+
+ir_node *insert_Perm_after(const arch_env_t *arch_env,
+ const arch_register_class_t *cls,
+ dom_front_info_t *dom_front,
+ ir_node *pos)
+{
+ 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("be.node");
+
+ ir_node *curr, *irn, *perm, **nodes;
+ int i, n;
+
+ DBG((dbg, LEVEL_1, "Insert Perm after: %+F\n", pos));
+
+ if(!nodes_live_at(arch_env, cls, pos, live))
+ assert(0 && "position not found");
+
n = pset_count(live);
if(n == 0)
int be_is_Perm(const ir_node *irn);
int be_is_Keep(const ir_node *irn);
-void be_set_Spill_offset(ir_node *irn, unsigned offset);
+void be_set_Spill_offset(ir_node *irn, unsigned offset);
unsigned be_get_spill_offset(ir_node *irn);
ir_node *be_get_Spill_context(const ir_node *irn);
static arch_irn_flags_t firm_get_flags(const void *self, const ir_node *irn)
{
- arch_irn_flags_t res = arch_irn_flags_spillable;
+ arch_irn_flags_t res = 0;
if(get_irn_op(irn) == op_imm)
res |= arch_irn_flags_rematerializable;