* spills a node by placing a reload before each usage
*/
static
-void spill_node(daemel_env_t *env, ir_node *node, ir_nodeset_t *nodes)
+void spill_node(daemel_env_t *env, ir_node *node)
{
const ir_edge_t *edge;
spill_env_t *spill_env = env->spill_env;
foreach_out_edge(node, edge) {
ir_node *use = get_edge_src_irn(edge);
+ if(is_Anchor(use))
+ continue;
if(is_Phi(use)) {
int in = get_edge_src_pos(edge);
}
bitset_set(env->spilled_nodes, get_irn_idx(node));
- ir_nodeset_remove(nodes, node);
}
/**
* sets the spilled bits in env->spilled_nodes.
*/
static
-void do_spilling(daemel_env_t *env, ir_nodeset_t *nodes, ir_node *node)
+void do_spilling(daemel_env_t *env, ir_nodeset_t *live_nodes, ir_node *node)
{
- size_t node_count = ir_nodeset_size(nodes);
+ size_t node_count = ir_nodeset_size(live_nodes);
size_t additional_defines = 0;
size_t reload_values = 0;
int registers = env->n_regs;
/* mode_T nodes define several values at once. Count them */
if(get_irn_mode(node) == mode_T) {
- ir_node *proj = sched_next(node);
+ const ir_edge_t *edge;
+
+ foreach_out_edge(node, edge) {
+ const ir_node *proj = get_edge_src_irn(edge);
- while(is_Proj(proj)) {
if(arch_irn_consider_in_reg_alloc(arch_env, cls, proj)) {
++additional_defines;
}
- proj = sched_next(proj);
}
}
+ if(bitset_is_set(spilled_nodes, get_irn_idx(node)))
+ ++additional_defines;
- /* we might temporarily need registers for reloaded values */
+ /* we need registers for the non-live argument values */
arity = get_irn_arity(node);
for(i = 0; i < arity; ++i) {
ir_node *pred = get_irn_n(node, i);
- if(bitset_is_set(spilled_nodes, get_irn_idx(pred)))
+ if(arch_irn_consider_in_reg_alloc(arch_env, cls, pred)
+ && !ir_nodeset_contains(live_nodes, pred)) {
++reload_values;
+ }
}
if(reload_values > additional_defines)
return;
DBG((dbg, LEVEL_2, "\tspills needed after %+F: %d\n", node, spills_needed));
- candidates = malloc(node_count * sizeof(candidates[0]));
+ candidates = xmalloc(node_count * sizeof(candidates[0]));
/* construct array with spill candidates and calculate their costs */
i = 0;
- foreach_ir_nodeset(nodes, n, iter) {
+ foreach_ir_nodeset(live_nodes, n, iter) {
spill_candidate_t *candidate = & candidates[i];
+ assert(!bitset_is_set(spilled_nodes, get_irn_idx(n)));
+
candidate->node = n;
candidate->costs = get_spill_costs(env, n);
++i;
/* spill cheapest ones */
cand_idx = 0;
while(spills_needed > 0) {
- spill_candidate_t *candidate = &candidates[cand_idx];
- ir_node *cand_node = candidate->node;
- int is_use;
- ++cand_idx;
+ spill_candidate_t *candidate;
+ ir_node *cand_node;
+ int is_use;
- if(cand_idx >= node_count) {
+ if (cand_idx >= node_count) {
panic("can't spill enough values for node %+F\n", node);
}
- /* make sure the node is not a use of the instruction */
+
+ candidate = &candidates[cand_idx];
+ cand_node = candidate->node;
+ ++cand_idx;
+
+ if(arch_irn_is(arch_env, cand_node, dont_spill))
+ continue;
+
+ /* make sure the node is not an argument of the instruction */
is_use = 0;
- for(i = 0; i < arity; ++i) {
+ for (i = 0; i < arity; ++i) {
ir_node *in = get_irn_n(node, i);
if(in == cand_node) {
is_use = 1;
continue;
}
- spill_node(env, cand_node, nodes);
+ spill_node(env, cand_node);
+ ir_nodeset_remove(live_nodes, cand_node);
--spills_needed;
}
* into the liveness set
*/
static
-void liveness_transfer(daemel_env_t *env, ir_node *node, ir_nodeset_t *nodeset)
+void liveness_transfer_remove_defs(daemel_env_t *env, ir_node *node,
+ ir_nodeset_t *nodeset)
{
- int i, arity;
const arch_register_class_t *cls = env->cls;
const arch_env_t *arch_env = env->arch_env;
- const bitset_t *bitset = env->spilled_nodes;
/* You should better break out of your loop when hitting the first phi
* function. */
assert(!is_Phi(node) && "liveness_transfer produces invalid results for phi nodes");
+ if (get_irn_mode(node) == mode_T) {
+ const ir_edge_t *edge;
+
+ foreach_out_edge(node, edge) {
+ const ir_node *proj = get_edge_src_irn(edge);
+
+ if (arch_irn_consider_in_reg_alloc(arch_env, cls, proj)) {
+ ir_nodeset_remove(nodeset, proj);
+ }
+ }
+ }
+
if(arch_irn_consider_in_reg_alloc(arch_env, cls, node)) {
ir_nodeset_remove(nodeset, node);
}
+}
+
+static void liveness_transfer_add_uses(daemel_env_t *env, ir_node *node,
+ ir_nodeset_t *nodeset)
+{
+ int i, arity;
+ const arch_register_class_t *cls = env->cls;
+ const arch_env_t *arch_env = env->arch_env;
+ const bitset_t *bitset = env->spilled_nodes;
+
arity = get_irn_arity(node);
for(i = 0; i < arity; ++i) {
}
}
+static __attribute__((unused))
+void print_nodeset(ir_nodeset_t *nodeset)
+{
+ ir_nodeset_iterator_t iter;
+ ir_node *node;
+
+ foreach_ir_nodeset(nodeset, node, iter) {
+ ir_fprintf(stderr, "%+F ", node);
+ }
+ fprintf(stderr, "\n");
+}
+
/**
* make sure register pressure in a block is always equal or below the number
* of available registers
ir_nodeset_iterator_t iter;
ir_node *node;
bitset_t *spilled_nodes = env->spilled_nodes;
- int phi_count;
+ int phi_count, spilled_phis, regpressure, phi_spills_needed;
DBG((dbg, LEVEL_1, "spilling block %+F\n", block));
ir_nodeset_init(&live_nodes);
- be_liveness_end_of_block_ir_nodeset(lv, arch_env, cls, block, &live_nodes);
+ be_liveness_end_of_block(lv, arch_env, cls, block, &live_nodes);
foreach_ir_nodeset(&live_nodes, node, iter) {
- DBG((dbg, LEVEL_2, "\t%+F is live-in... ", node));
+ DBG((dbg, LEVEL_2, "\t%+F is live-end... ", node));
if(bitset_is_set(spilled_nodes, get_irn_idx(node))) {
DBG((dbg, LEVEL_2, "but spilled; removing.\n"));
+ ir_nodeset_remove_iterator(&live_nodes, &iter);
} else {
DBG((dbg, LEVEL_2, "keeping.\n"));
}
if(is_Phi(node))
break;
- if(is_Proj(node) || be_is_Keep(node)) {
- liveness_transfer(env, node, &live_nodes);
+ if(be_is_Keep(node)) {
+ /* remove defs should never do something for keep nodes, but we
+ * leave it here for consistency */
+ liveness_transfer_remove_defs(env, node, &live_nodes);
+ liveness_transfer_add_uses(env, node, &live_nodes);
continue;
}
+ liveness_transfer_remove_defs(env, node, &live_nodes);
do_spilling(env, &live_nodes, node);
- liveness_transfer(env, node, &live_nodes);
+ liveness_transfer_add_uses(env, node, &live_nodes);
}
- do_spilling(env, &live_nodes, node);
phi_count = 0;
- int spilled_phis = 0;
+ spilled_phis = 0;
sched_foreach(block, node) {
if(!is_Phi(node))
break;
++spilled_phis;
}
}
- int regpressure = ir_nodeset_size(&live_nodes) - spilled_phis;
- int phi_spills_needed = regpressure - env->n_regs;
+ regpressure = ir_nodeset_size(&live_nodes) + spilled_phis;
+ phi_spills_needed = regpressure - env->n_regs;
+ DBG((dbg, LEVEL_3, "Regpressure before phis: %d phispills: %d\n",
+ regpressure, phi_spills_needed));
sched_foreach(block, node) {
if(!is_Phi(node))
break;
if(n_regs == 0)
return;
- be_invalidate_liveness(birg);
- be_assure_liveness(birg);
+ be_liveness_assure_sets(be_assure_liveness(birg));
env.spill_env = be_new_spill_env(birg);
env.n_regs = n_regs;
env.lv = be_get_birg_liveness(birg);
env.spilled_nodes = bitset_malloc(get_irg_last_idx(irg));
+ DBG((dbg, LEVEL_1, "*** RegClass %s\n", cls->name));
+
irg_block_walk_graph(irg, spill_block, NULL, &env);
bitset_free(env.spilled_nodes);