* @brief Preference Guided Register Assignment
* @author Matthias Braun
* @date 14.2.2009
- * @version $Id$
*
* The idea is to allocate registers in 2 passes:
* 1. A first pass to determine "preferred" registers for live-ranges. This
#include "irnode_t.h"
#include "irprintf.h"
#include "irdump.h"
+#include "irtools.h"
+#include "util.h"
#include "obst.h"
#include "raw_bitset.h"
#include "unionfind.h"
static ir_graph *irg;
static const arch_register_class_t *cls;
static be_lv_t *lv;
-static const ir_exec_freq *execfreqs;
static unsigned n_regs;
static unsigned *normal_regs;
static int *congruence_classes;
unsigned last_uses[2]; /**< bitset indicating last uses (input pos) */
ir_node *current_value; /**< copy of the value that should be used */
ir_node *original_value; /**< for copies point to original value */
- float prefs[0]; /**< register preferences */
+ float prefs[]; /**< register preferences */
};
typedef struct allocation_info_t allocation_info_t;
/** per basic-block information */
struct block_info_t {
bool processed; /**< indicate whether block is processed */
- ir_node *assignments[0]; /**< register assignments at end of block */
+ ir_node *assignments[]; /**< register assignments at end of block */
};
typedef struct block_info_t block_info_t;
float penalty, const unsigned* limited,
ir_node *node)
{
- ir_nodeset_iterator_t iter;
- unsigned r;
- size_t n_allowed;
- allocation_info_t *info = get_allocation_info(node);
- ir_node *neighbor;
+ unsigned r;
+ size_t n_allowed;
+ allocation_info_t *info = get_allocation_info(node);
/* give penalty for all forbidden regs */
for (r = 0; r < n_regs; ++r) {
*/
static void analyze_block(ir_node *block, void *data)
{
- float weight = (float)get_block_execfreq(execfreqs, block);
- ir_nodeset_t live_nodes;
- ir_node *node;
+ float weight = (float)get_block_execfreq(block);
+ ir_nodeset_t live_nodes;
(void) data;
ir_nodeset_init(&live_nodes);
node_idx = uf_find(congruence_classes, node_idx);
for (i = 0; i < arity; ++i) {
- ir_node *live;
- ir_node *op;
- int op_idx;
- ir_nodeset_iterator_t iter;
- bool interferes = false;
+ ir_node *op;
+ int op_idx;
+ bool interferes = false;
if (!rbitset_is_set(&req->other_same, i))
continue;
static void create_congruence_class(ir_node *block, void *data)
{
- ir_nodeset_t live_nodes;
- ir_node *node;
+ ir_nodeset_t live_nodes;
(void) data;
ir_nodeset_init(&live_nodes);
be_liveness_end_of_block(lv, cls, block, &live_nodes);
/* check should be same constraints */
+ ir_node *last_phi = NULL;
sched_foreach_reverse(block, node) {
ir_node *value;
- if (is_Phi(node))
+ if (is_Phi(node)) {
+ last_phi = node;
break;
+ }
be_foreach_definition(node, cls, value,
congruence_def(&live_nodes, value);
);
be_liveness_transfer(cls, node, &live_nodes);
}
+ if (!last_phi)
+ return;
/* check phi congruence classes */
- sched_foreach_reverse_from(node, node) {
+ sched_foreach_reverse_from(last_phi, phi) {
int i;
int arity;
int node_idx;
- assert(is_Phi(node));
+ assert(is_Phi(phi));
- if (!arch_irn_consider_in_reg_alloc(cls, node))
+ if (!arch_irn_consider_in_reg_alloc(cls, phi))
continue;
- node_idx = get_irn_idx(node);
+ node_idx = get_irn_idx(phi);
node_idx = uf_find(congruence_classes, node_idx);
- arity = get_irn_arity(node);
+ arity = get_irn_arity(phi);
for (i = 0; i < arity; ++i) {
- bool interferes = false;
- ir_nodeset_iterator_t iter;
- unsigned r;
- int old_node_idx;
- ir_node *live;
- ir_node *phi;
- allocation_info_t *head_info;
- allocation_info_t *other_info;
- ir_node *op = get_Phi_pred(node, i);
- int op_idx = get_irn_idx(op);
+ bool interferes = false;
+ unsigned r;
+ int old_node_idx;
+ allocation_info_t *head_info;
+ allocation_info_t *other_info;
+ ir_node *op = get_Phi_pred(phi, i);
+ int op_idx = get_irn_idx(op);
op_idx = uf_find(congruence_classes, op_idx);
/* do we interfere with the value */
old_node_idx = node_idx;
node_idx = uf_union(congruence_classes, node_idx, op_idx);
DB((dbg, LEVEL_3, "Merge %+F and %+F congruence classes\n",
- node, op));
+ phi, op));
old_node_idx = node_idx == old_node_idx ? op_idx : old_node_idx;
head_info = get_allocation_info(get_idx_irn(irg, node_idx));
from_reg = arch_get_irn_register(to_split);
from_r = arch_register_get_index(from_reg);
block = get_nodes_block(before);
- split_threshold = (float)get_block_execfreq(execfreqs, block) * SPLIT_DELTA;
+ split_threshold = (float)get_block_execfreq(block) * SPLIT_DELTA;
if (pref_delta < split_threshold*0.5)
return false;
return false;
reg = arch_register_for_index(cls, r);
- copy = be_new_Copy(cls, block, to_split);
+ copy = be_new_Copy(block, to_split);
mark_as_copy_of(copy, to_split);
/* hacky, but correct here */
if (assignments[arch_register_get_index(from_reg)] == to_split)
info = get_allocation_info(node);
in_node = skip_Proj(node);
if (req->type & arch_register_req_type_should_be_same) {
- float weight = (float)get_block_execfreq(execfreqs, block);
+ float weight = (float)get_block_execfreq(block);
int arity = get_irn_arity(in_node);
int i;
/* create a copy */
src = assignments[old_r];
- copy = be_new_Copy(cls, block, src);
+ copy = be_new_Copy(block, src);
sched_add_before(before, copy);
reg = arch_register_for_index(cls, r);
DB((dbg, LEVEL_2, "Copy %+F (from %+F, before %+F) -> %s\n",
/* solve lpp */
{
- ir_graph *irg = get_irn_irg(node);
- be_options_t *options = be_get_irg_options(irg);
- unsigned *assignment;
- lpp_solve(lpp, options->ilp_server, options->ilp_solver);
+ unsigned *assignment;
+ lpp_solve(lpp, be_options.ilp_server, be_options.ilp_solver);
if (!lpp_is_sol_valid(lpp))
panic("ilp solution not valid!");
lpp_free(lpp);
}
+static bool is_aligned(unsigned num, unsigned alignment)
+{
+ unsigned mask = alignment-1;
+ assert(is_po2(alignment));
+ return (num&mask) == 0;
+}
+
/**
* Enforce constraints at a node by live range splits.
*
/* construct a list of register occupied by live-through values */
unsigned *live_through_regs = NULL;
- /* see if any use constraints are not met */
+ /* see if any use constraints are not met and whether double-width
+ * values are involved */
bool double_width = false;
bool good = true;
for (i = 0; i < arity; ++i) {
req = arch_get_irn_register_req_in(node, i);
if (req->width > 1)
double_width = true;
+ reg = arch_get_irn_register(op);
+ reg_index = arch_register_get_index(reg);
+ if (req->type & arch_register_req_type_aligned) {
+ if (!is_aligned(reg_index, req->width)) {
+ good = false;
+ continue;
+ }
+ }
if (!(req->type & arch_register_req_type_limited))
continue;
limited = req->limited;
- reg = arch_get_irn_register(op);
- reg_index = arch_register_get_index(reg);
if (!rbitset_is_set(limited, reg_index)) {
/* found an assignment outside the limited set */
good = false;
- break;
+ continue;
}
}
continue;
/* give bonus for already assigned register */
- weight = (float)get_block_execfreq(execfreqs, pred_block);
+ weight = (float)get_block_execfreq(pred_block);
r = arch_register_get_index(reg);
info->prefs[r] += weight * AFF_PHI;
}
ir_node *pred_block = get_Block_cfgpred_block(block, i);
unsigned r;
float weight
- = (float)get_block_execfreq(execfreqs, pred_block) * AFF_PHI;
+ = (float)get_block_execfreq(pred_block) * AFF_PHI;
if (info->prefs[assigned_r] >= weight)
continue;
int n;
int res;
unsigned *assignment;
- ir_node *node;
hungarian_problem_t *bp;
/* count phi nodes */
*/
static void allocate_coalesce_block(ir_node *block, void *data)
{
- int i;
ir_nodeset_t live_nodes;
- ir_node *node;
int n_preds;
block_info_t *block_info;
block_info_t **pred_block_infos;
/* gather regalloc infos of predecessor blocks */
n_preds = get_Block_n_cfgpreds(block);
pred_block_infos = ALLOCAN(block_info_t*, n_preds);
- for (i = 0; i < n_preds; ++i) {
+ for (int i = 0; i < n_preds; ++i) {
ir_node *pred = get_Block_cfgpred_block(block, i);
block_info_t *pred_info = get_block_info(pred);
pred_block_infos[i] = pred_info;
phi_ins = ALLOCAN(ir_node*, n_preds);
/* collect live-in nodes and preassigned values */
- be_lv_foreach(lv, block, be_lv_state_in, i) {
+ be_lv_foreach(lv, block, be_lv_state_in, node) {
bool need_phi = false;
const arch_register_req_t *req;
const arch_register_t *reg;
int p;
- node = be_lv_get_irn(lv, block, i);
req = arch_get_irn_register_req(node);
if (req->cls != cls)
continue;
if (need_phi) {
ir_mode *mode = get_irn_mode(node);
- ir_node *phi = be_new_Phi(block, n_preds, phi_ins, mode, cls);
+ ir_node *phi = be_new_Phi(block, n_preds, phi_ins, mode,
+ cls->class_req);
DB((dbg, LEVEL_3, "Create Phi %+F (for %+F) -", phi, node));
#ifdef DEBUG_libfirm
/* all live-ins must have a register */
#ifdef DEBUG_libfirm
- {
- ir_nodeset_iterator_t iter;
- foreach_ir_nodeset(&live_nodes, node, iter) {
- const arch_register_t *reg = arch_get_irn_register(node);
- assert(reg != NULL);
- }
+ foreach_ir_nodeset(&live_nodes, node, iter) {
+ const arch_register_t *reg = arch_get_irn_register(node);
+ assert(reg != NULL);
}
#endif
/* we may not use registers used for inputs for optimistic splits */
arity = get_irn_arity(node);
- for (i = 0; i < arity; ++i) {
+ for (int i = 0; i < arity; ++i) {
ir_node *op = get_irn_n(node, i);
const arch_register_t *reg;
if (!arch_irn_consider_in_reg_alloc(cls, op))
block_costs_t *cost_info;
ir_node *block = blocklist[--p];
- float execfreq = (float)get_block_execfreq(execfreqs, block);
+ float execfreq = (float)get_block_execfreq(block);
float costs = execfreq;
int n_cfgpreds = get_Block_n_cfgpreds(block);
int p2;
{
size_t i;
- lv = be_assure_liveness(irg);
- be_liveness_assure_sets(lv);
+ be_assure_live_sets(irg);
+ lv = be_get_irg_liveness(irg);
ir_reserve_resources(irg, IR_RESOURCE_IRN_LINK);
static void dump(int mask, ir_graph *irg, const char *suffix)
{
- if (be_get_irg_options(irg)->dump_flags & mask)
+ if (be_options.dump_flags & mask)
dump_ir_graph(irg, suffix);
}
obstack_init(&obst);
- irg = new_irg;
- execfreqs = be_get_irg_exec_freq(irg);
+ irg = new_irg;
/* determine a good coloring order */
determine_block_order();
/* verify schedule and register pressure */
be_timer_push(T_VERIFY);
- if (be_get_irg_options(irg)->verify_option == BE_VERIFY_WARN) {
+ if (be_options.verify_option == BE_VERIFY_WARN) {
be_verify_schedule(irg);
be_verify_register_pressure(irg, cls);
- } else if (be_get_irg_options(irg)->verify_option == BE_VERIFY_ASSERT) {
+ } else if (be_options.verify_option == BE_VERIFY_ASSERT) {
assert(be_verify_schedule(irg) && "Schedule verification failed");
assert(be_verify_register_pressure(irg, cls)
&& "Register pressure verification failed");
/* we most probably constructed new Phis so liveness info is invalid
* now */
- /* TODO: test liveness_introduce */
- be_liveness_invalidate(lv);
+ be_invalidate_live_sets(irg);
free(normal_regs);
stat_ev_ctx_pop("regcls");
be_timer_pop(T_RA_SPILL_APPLY);
be_timer_push(T_VERIFY);
- if (be_get_irg_options(irg)->verify_option == BE_VERIFY_WARN) {
+ if (be_options.verify_option == BE_VERIFY_WARN) {
be_verify_register_allocation(irg);
- } else if (be_get_irg_options(irg)->verify_option == BE_VERIFY_ASSERT) {
+ } else if (be_options.verify_option == BE_VERIFY_ASSERT) {
assert(be_verify_register_allocation(irg)
&& "Register allocation invalid");
}