Commit c20b5f64 authored by Matthias Braun's avatar Matthias Braun
Browse files

avoid putting interfering stuff into the same congruence class

[r26494]
parent b3e096e7
......@@ -179,7 +179,8 @@ void arch_put_non_ignore_regs(const arch_register_class_t *cls, bitset_t *bs)
}
}
int arch_reg_is_allocatable(const ir_node *irn, int pos, const arch_register_t *reg)
int arch_reg_is_allocatable(const ir_node *irn, int pos,
const arch_register_t *reg)
{
const arch_register_req_t *req = arch_get_register_req(irn, pos);
......@@ -187,7 +188,8 @@ int arch_reg_is_allocatable(const ir_node *irn, int pos, const arch_register_t *
return 0;
if(arch_register_req_is(req, limited)) {
assert(arch_register_get_class(reg) == req->cls);
if (arch_register_get_class(reg) != req->cls)
return 0;
return rbitset_is_set(req->limited, arch_register_get_index(reg));
}
......
......@@ -49,6 +49,7 @@
#include <float.h>
#include <stdbool.h>
#include <math.h>
#include "error.h"
#include "execfreq.h"
......@@ -113,7 +114,6 @@ struct allocation_info_t {
unsigned last_uses; /**< 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 */
unsigned char should_be_same[2];
float prefs[0]; /**< register preferences */
};
typedef struct allocation_info_t allocation_info_t;
......@@ -397,46 +397,143 @@ static void analyze_block(ir_node *block, void *data)
ir_nodeset_destroy(&live_nodes);
}
static void create_congurence_class(ir_node *node, void *data)
static void congruence_def(ir_nodeset_t *live_nodes, ir_node *node)
{
(void) data;
if (is_Phi(node)) {
int i;
int arity = get_irn_arity(node);
unsigned phi_idx = get_irn_idx(node);
phi_idx = uf_find(congruence_classes, phi_idx);
for (i = 0; i < arity; ++i) {
ir_node *op = get_Phi_pred(node, i);
int op_idx = get_irn_idx(op);
op_idx = uf_find(congruence_classes, op_idx);
phi_idx = uf_union(congruence_classes, phi_idx, op_idx);
if (get_irn_mode(node) == mode_T) {
const ir_edge_t *edge;
foreach_out_edge(node, edge) {
ir_node *def = get_edge_src_irn(edge);
congruence_def(live_nodes, def);
}
return;
}
if (!arch_irn_consider_in_reg_alloc(cls, node))
return;
/* should be same constraint? */
if (is_Proj(node)) {
const arch_register_req_t *req = arch_get_register_req_out(node);
if (req->type & arch_register_req_type_should_be_same) {
ir_node *pred = get_Proj_pred(node);
int arity = get_irn_arity(pred);
int i;
unsigned node_idx = get_irn_idx(node);
node_idx = uf_find(congruence_classes, node_idx);
for (i = 0; i < arity; ++i) {
ir_node *op;
unsigned op_idx;
if (!rbitset_is_set(&req->other_same, i))
continue;
const arch_register_req_t *req = arch_get_register_req_out(node);
if (req->type & arch_register_req_type_should_be_same) {
ir_node *insn = skip_Proj(node);
int arity = get_irn_arity(insn);
int i;
unsigned node_idx = get_irn_idx(node);
node_idx = uf_find(congruence_classes, node_idx);
op = get_irn_n(pred, i);
op_idx = get_irn_idx(op);
op_idx = uf_find(congruence_classes, op_idx);
node_idx = uf_union(congruence_classes, node_idx, op_idx);
for (i = 0; i < arity; ++i) {
ir_node *live;
ir_node *op;
int op_idx;
ir_nodeset_iterator_t iter;
if (!rbitset_is_set(&req->other_same, i))
continue;
op = get_irn_n(insn, i);
op_idx = get_irn_idx(op);
op_idx = uf_find(congruence_classes, op_idx);
/* do we interfere with the value */
bool interferes = false;
foreach_ir_nodeset(live_nodes, live, iter) {
int lv_idx = get_irn_idx(live);
lv_idx = uf_find(congruence_classes, lv_idx);
if (lv_idx == op_idx) {
interferes = true;
break;
}
}
/* don't put in same affinity class if we interfere */
if (interferes)
continue;
node_idx = uf_union(congruence_classes, node_idx, op_idx);
DB((dbg, LEVEL_3, "Merge %+F and %+F congruence classes\n",
node, op));
/* one should_be_same is enough... */
break;
}
}
}
static void create_congurence_class(ir_node *block, void *data)
{
ir_nodeset_t live_nodes;
ir_node *node;
(void) data;
ir_nodeset_init(&live_nodes);
be_liveness_end_of_block(lv, cls, block, &live_nodes);
/* check should be same constraints */
sched_foreach_reverse(block, node) {
if (is_Phi(node))
break;
congruence_def(&live_nodes, node);
be_liveness_transfer(cls, node, &live_nodes);
}
/* check phi congruence classes */
sched_foreach_reverse_from(node, node) {
int i;
int arity;
int node_idx;
assert(is_Phi(node));
if (!arch_irn_consider_in_reg_alloc(cls, node))
continue;
node_idx = get_irn_idx(node);
node_idx = uf_find(congruence_classes, node_idx);
arity = get_irn_arity(node);
for (i = 0; i < arity; ++i) {
ir_nodeset_iterator_t iter;
ir_node *live;
ir_node *phi;
ir_node *op = get_Phi_pred(node, i);
int op_idx = get_irn_idx(op);
op_idx = uf_find(congruence_classes, op_idx);
/* do we interfere with the value */
bool interferes = false;
foreach_ir_nodeset(&live_nodes, live, iter) {
int lv_idx = get_irn_idx(live);
lv_idx = uf_find(congruence_classes, lv_idx);
if (lv_idx == op_idx) {
interferes = true;
break;
}
}
/* don't put in same affinity class if we interfere */
if (interferes)
continue;
/* any other phi has the same input? */
sched_foreach(block, phi) {
ir_node *oop;
int oop_idx;
if (!is_Phi(phi))
break;
if (!arch_irn_consider_in_reg_alloc(cls, phi))
continue;
oop = get_Phi_pred(phi, i);
if (oop == op)
continue;
oop_idx = get_irn_idx(oop);
oop_idx = uf_find(congruence_classes, oop_idx);
if (oop_idx == op_idx) {
interferes = true;
break;
}
}
if (interferes)
continue;
node_idx = uf_union(congruence_classes, node_idx, op_idx);
DB((dbg, LEVEL_3, "Merge %+F and %+F congruence classes\n",
node, op));
}
return;
}
}
......@@ -494,7 +591,7 @@ static void combine_congruence_classes(void)
uf_init(congruence_classes, n);
/* create congruence classes */
irg_walk_graph(irg, create_congurence_class, NULL, NULL);
irg_block_walk_graph(irg, create_congurence_class, NULL, NULL);
/* merge preferences */
irg_walk_graph(irg, merge_congruence_prefs, NULL, NULL);
irg_walk_graph(irg, set_congruence_prefs, NULL, NULL);
......@@ -997,7 +1094,7 @@ static void enforce_constraints(ir_nodeset_t *live_nodes, ir_node *node,
unsigned *output_regs)
{
int arity = get_irn_arity(node);
int i, dummy, res;
int i, res;
hungarian_problem_t *bp;
unsigned l, r;
unsigned *assignment;
......@@ -1130,11 +1227,11 @@ static void enforce_constraints(ir_nodeset_t *live_nodes, ir_node *node,
}
}
//hungarian_print_costmatrix(bp, 1);
//hungarian_print_cost_matrix(bp, 1);
hungarian_prepare_cost_matrix(bp, HUNGARIAN_MODE_MAXIMIZE_UTIL);
assignment = ALLOCAN(unsigned, n_regs);
res = hungarian_solve(bp, (int*) assignment, &dummy, 0);
res = hungarian_solve(bp, (int*) assignment, NULL, 0);
assert(res == 0);
#if 0
......@@ -1331,6 +1428,91 @@ static void propagate_phi_register(ir_node *phi, unsigned r)
}
}
static void assign_phi_registers(ir_node *block)
{
int n_phis = 0;
int n;
int res;
int *assignment;
ir_node *node;
hungarian_problem_t *bp;
/* count phi nodes */
sched_foreach(block, node) {
if (!is_Phi(node))
break;
if (!arch_irn_consider_in_reg_alloc(cls, node))
continue;
++n_phis;
}
if (n_phis == 0)
return;
/* build a bipartite matching problem for all phi nodes */
bp = hungarian_new(n_phis, n_regs, HUNGARIAN_MATCH_PERFECT);
n = 0;
sched_foreach(block, node) {
unsigned r;
allocation_info_t *info;
if (!is_Phi(node))
break;
if (!arch_irn_consider_in_reg_alloc(cls, node))
continue;
/* give boni for predecessor colorings */
adapt_phi_prefs(node);
/* add stuff to bipartite problem */
info = get_allocation_info(node);
DB((dbg, LEVEL_3, "Prefs for %+F: ", node));
for (r = 0; r < n_regs; ++r) {
float costs;
if (!rbitset_is_set(normal_regs, r))
continue;
costs = info->prefs[r];
costs = costs < 0 ? -logf(-costs+1) : logf(costs+1);
costs *= 100;
costs += 10000;
hungarian_add(bp, n, r, costs);
DB((dbg, LEVEL_3, " %s(%f)", arch_register_for_index(cls, r)->name,
info->prefs[r]));
}
DB((dbg, LEVEL_3, "\n"));
++n;
}
//hungarian_print_cost_matrix(bp, 7);
hungarian_prepare_cost_matrix(bp, HUNGARIAN_MODE_MAXIMIZE_UTIL);
assignment = ALLOCAN(int, n_regs);
res = hungarian_solve(bp, assignment, NULL, 0);
assert(res == 0);
/* apply results */
n = 0;
sched_foreach(block, node) {
unsigned r;
const arch_register_t *reg;
if (!is_Phi(node))
break;
if (!arch_irn_consider_in_reg_alloc(cls, node))
continue;
r = assignment[n++];
assert(rbitset_is_set(normal_regs, r));
reg = arch_register_for_index(cls, r);
DB((dbg, LEVEL_2, "Assign %+F -> %s\n", node, reg->name));
use_reg(node, reg);
/* adapt preferences for phi inputs */
propagate_phi_register(node, r);
}
}
/**
* Walker: assign registers to all nodes of a block that
* need registers from the currently considered register class.
......@@ -1340,7 +1522,7 @@ static void allocate_coalesce_block(ir_node *block, void *data)
int i;
ir_nodeset_t live_nodes;
ir_nodeset_iterator_t iter;
ir_node *node, *start;
ir_node *node;
int n_preds;
block_info_t *block_info;
block_info_t **pred_block_infos;
......@@ -1449,26 +1631,7 @@ static void allocate_coalesce_block(ir_node *block, void *data)
rbitset_alloca(output_regs, n_regs);
/* handle phis... */
node = sched_first(block);
for ( ; is_Phi(node); node = sched_next(node)) {
const arch_register_t *reg;
if (!arch_irn_consider_in_reg_alloc(cls, node))
continue;
/* fill in regs already assigned */
reg = arch_get_irn_register(node);
if (reg != NULL) {
use_reg(node, reg);
} else {
adapt_phi_prefs(node);
assign_reg(block, node, output_regs);
reg = arch_get_irn_register(node);
propagate_phi_register(node, arch_register_get_index(reg));
}
}
start = node;
assign_phi_registers(block);
/* assign regs for live-in values */
foreach_ir_nodeset(&live_nodes, node, iter) {
......@@ -1482,9 +1645,13 @@ static void allocate_coalesce_block(ir_node *block, void *data)
}
/* assign instructions in the block */
for (node = start; !sched_is_end(node); node = sched_next(node)) {
sched_foreach(block, node) {
unsigned r;
/* phis are already assigned */
if (is_Phi(node))
continue;
rewire_inputs(node);
/* enforce use constraints */
......
Markdown is supported
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