Commit 87d3e7eb authored by Daniel Grund's avatar Daniel Grund
Browse files

Refactoring, Bugfixes, added path constraints

parent 96390291
......@@ -3,18 +3,11 @@
* Date: 28.02.2006
* Copyright: (c) Universitaet Karlsruhe
* Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
* $Id$
*
* Common stuff used by all ILP fomulations.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef WITH_ILP
#include "becopyilp_t.h"
#include "beifg_t.h"
......@@ -76,7 +69,11 @@ void sr_remove(size_red_t *sr) {
while (redo) {
redo = 0;
be_ifg_foreach_node(ifg, iter, irn) {
if (!sr_is_removed(sr, irn) && !co_is_optimizable_root(sr->co, irn) && !co_is_optimizable_arg(sr->co, irn)) {
arch_register_req_t req;
arch_get_register_req(sr->co->aenv, &req, irn, -1);
if (!arch_register_req_is(&req, limited) && !sr_is_removed(sr, irn) && !co_gs_is_optimizable(sr->co, irn)) {
if (sr_is_simplicial(sr, irn)) {
coloring_suffix_t *cs = obstack_alloc(&sr->ob, sizeof(*cs));
......@@ -137,6 +134,8 @@ void free_size_red(size_red_t *sr) {
*****************************************************************************/
#include <stdio.h>
ilp_env_t *new_ilp_env(copy_opt_t *co, ilp_callback build, ilp_callback apply, void *env) {
ilp_env_t *res = malloc(sizeof(*res));
assert(res);
......@@ -151,6 +150,9 @@ ilp_env_t *new_ilp_env(copy_opt_t *co, ilp_callback build, ilp_callback apply, v
}
lpp_sol_state_t ilp_go(ilp_env_t *ienv) {
FILE *f;
char buf[256];
sr_remove(ienv->sr);
ienv->build(ienv);
......@@ -161,6 +163,11 @@ lpp_sol_state_t ilp_go(ilp_env_t *ienv) {
lpp_solve_cplex(ienv->lp);
#endif
snprintf(buf, sizeof(buf), "%s.ilp", ienv->co->name);
f = fopen(buf, "wt");
lpp_dump_plain(ienv->lp, f);
fclose(f);
ienv->apply(ienv);
sr_reinsert(ienv->sr);
......@@ -173,10 +180,3 @@ void free_ilp_env(ilp_env_t *ienv) {
free_lpp(ienv->lp);
free(ienv);
}
#else /* WITH_ILP */
static void only_that_you_can_compile_without_WITH_ILP_defined(void) {
}
#endif /* WITH_ILP */
......@@ -18,262 +18,6 @@
#ifdef WITH_ILP
#include "becopyilp_t.h"
#include "benumb_t.h"
#include "belive_t.h"
#include "irdom_t.h"
#include "irgwalk.h"
#include "xmalloc.h"
#include "pset.h"
#include "irprog.h"
#include "irdom_t.h"
#include "iredges_t.h"
#include "becopystat.h"
#include "besched_t.h"
#include "phiclass.h"
#if 0 //temporary
#define PATH_CONSTRAINTS_FOR_CLASSES
typedef struct _problem_instance_t {
const copy_opt_t *co; /**< the copy opt problem */
size_red_t *sr; /**< problem size reduction. removes simple nodes */
lpp_t *lp; /**< the linear programming problem */
/* Helpers for maintaining indices and finding variables */
int first_nnc_var_idx; /**< the first index of a constraint belonging to no-null-colors stuff*/
int cst_counter, first_x_var, last_x_var;
char buf[32];
pset *done;
} problem_instance_t;
#define is_color_possible(irn,color) arch_reg_is_allocatable(pi->co->aenv, irn, -1, arch_register_for_index(pi->co->cls, color))
/*
* Some stuff for variable name handling.
*/
#define mangle_cst(buf, prefix, nr) \
snprintf((buf), sizeof(buf), "%c%d", (prefix), (nr))
#define mangle_var1(buf, prefix, color) \
snprintf((buf), sizeof(buf), "%c%d", (prefix), (color))
#define mangle_var2(buf, prefix, node_nr, color) \
snprintf((buf), sizeof(buf), "%c%d_%d", (prefix), (node_nr), (color))
#define mangle_var3(buf, prefix, n1, n2, col) \
snprintf((buf), sizeof(buf), "%c%d_%d_%d", (prefix), (n1), (n2), (col))
#define mangle_var_irn(buf, prefix, irn, color) \
mangle_var2((buf), (prefix), get_irn_graph_nr(irn), (color))
#define split_var(var, nnr, col) \
sscanf(var, "x%d_%d", (nnr), (col))
#ifndef PATH_CONSTRAINTS_FOR_CLASSES
/**
* Matrix P: Path contraints.
* If 2 nodes interfere and there is a path of equal-color-edges
* connecting them, then at least one of those equal-color-edges
* will break and cause some costs.
*/
static void pi_add_path_cstr(problem_instance_t *pi) {
unit_t *curr;
int cst_counter = 0;
DBG((dbg, LEVEL_2, "Adding path constraints...\n"));
/* for all optimization units (only phis) */
list_for_each_entry(unit_t, curr, &pi->co->units, units) {
int i, o, rootnr;
if (curr->min_nodes_costs == 0)
continue;
rootnr = get_irn_graph_nr(curr->nodes[0]);
/* check all argument pairs for interference */
for (i=1; i<curr->node_count; ++i) {
const ir_node *arg1 = curr->nodes[i];
int arg1nr = get_irn_graph_nr(arg1);
for (o=i+1; o<curr->node_count; ++o) {
const ir_node *arg2 = curr->nodes[o];
int arg2nr = get_irn_graph_nr(arg2);
if (nodes_interfere(pi->co->cenv, arg1, arg2)) {
int cst_idx, y_idx;
char buf[32];
mangle_cst(buf, 'P', cst_counter++);
cst_idx = lpp_add_cst(pi->curr_lp, buf, lpp_greater, 1);
mangle_var2(buf, 'y', rootnr, arg1nr);
y_idx = lpp_get_var_idx(pi->curr_lp, buf);
lpp_set_factor_fast(pi->curr_lp, cst_idx, y_idx, 1);
mangle_var2(buf, 'y', rootnr, arg2nr);
y_idx = lpp_get_var_idx(pi->curr_lp, buf);
lpp_set_factor_fast(pi->curr_lp, cst_idx, y_idx, 1);
}
}
}
}
}
#endif
#ifdef PATH_CONSTRAINTS_FOR_CLASSES
static INLINE int get_y_var_idx(problem_instance_t *pi, int nnr1, int nnr2) {
int res;
char buf[30];
mangle_var2(buf, 'y', nnr1, nnr2);
if ((res = lpp_get_var_idx(pi->curr_lp, buf)) != -1)
return res;
mangle_var2(buf, 'y', nnr2, nnr1);
if ((res = lpp_get_var_idx(pi->curr_lp, buf)) != -1)
return res;
assert(0 && "One of them must work");
return -1;
}
static void check_ecc_and_add_cut(problem_instance_t *pi, ir_node **path, int length, pset *remain, ir_node *tgt) {
if (path[length-1] == tgt) { /* we found a path */
int cst_idx, var_idx, i, nnr1, nnr2;
char buf[30];
/* add cut to ilp */
mangle_cst(buf, 'Q', pi->cst_counter++);
cst_idx = lpp_add_cst(pi->curr_lp, buf, lpp_greater, 1);
/* add all vars along the path */
nnr2 = get_irn_graph_nr(path[0]);
for (i=1; i<length; ++i) {
nnr1 = nnr2;
nnr2 = get_irn_graph_nr(path[i]);
var_idx = get_y_var_idx(pi, nnr1, nnr2);
lpp_set_factor_fast(pi->curr_lp, cst_idx, var_idx, 1);
}
} else { /* try to extend the path */
be_chordal_env_t *cenv = pi->co->cenv;
const ir_edge_t *edge;
ir_node *end = path[length-1];
ir_node **next = alloca(pset_count(remain) * sizeof(*next));
int i, o, max, next_pos = 0;
pset *done = pset_new_ptr_default();
/* find all potential next nodes on path */
/* args of phis */
if (is_Phi(end))
for(i=0, max=get_irn_arity(end); i<max; ++i) {
ir_node *arg = get_irn_n(end, i);
if (!pset_find_ptr(done, arg) && pset_find_ptr(remain, arg)) {
next[next_pos++] = arg;
pset_insert_ptr(done, arg);
}
}
/* outs of phis and other nodes */
foreach_out_edge(end, edge) {
ir_node *user = edge->src;
if (is_Phi(user) && !pset_find_ptr(done, user) && pset_find_ptr(remain, user)) {
next[next_pos++] = user;
pset_insert_ptr(done, user);
}
}
del_pset(done);
/* delete all potential nodes with interferences to other nodes in the path */
for (i=0; i<next_pos; ++i) {
ir_node *nn = next[i];
/* if next is the tgt, it may interfere with path[0],
* so skip the first check */
o = (nn == tgt && length > 1) ? 1 : 0;
for(; o<length; ++o)
if (nodes_interfere(cenv, nn, path[o])) {
next[i] = NULL;
break;
}
}
/* now we have all possible nodes in next; impossibles are NULL */
/* try to finish path with all possible nodes */
for (i=0; i<next_pos; ++i) {
if (!next[i]) /* this was an impossible node */
continue;
path[length] = next[i];
pset_remove_ptr(remain, next[i]);
check_ecc_and_add_cut(pi, path, length+1, remain, tgt);
pset_insert_ptr(remain, next[i]);
}
}
}
static void path_cstr_for_classes_walker(ir_node *irn, void *env) {
problem_instance_t *pi = env;
be_chordal_env_t *cenv;
int i, o, max;
ir_node *m, **cls;
pset *class = get_phi_class(irn);
if (!class || pset_find_ptr(pi->done, class))
return;
pset_insert_ptr(pi->done, class);
/* pset to array */
max = pset_count(class);
cls = alloca(max * sizeof(*cls));
for(i=0, m = pset_first(class); m; i++, m = pset_next(class)) {
DBG((dbg, LEVEL_1, " class member: %+F\n", m));
cls[i] = m;
}
cenv = pi->co->cenv;
for(i=0; i<max; ++i) {
ir_node **path = alloca(max * sizeof(*path));
pset *remain = pset_new_ptr(8);
pset_insert_pset_ptr(remain, class);
/* add cls[i] to path and remove it from remainder */
path[0] = cls[i];
pset_remove_ptr(remain, cls[i]);
for(o=i+1; o<max; ++o)
if (nodes_interfere(cenv, cls[i], cls[o]))
check_ecc_and_add_cut(pi, path, 1, remain, cls[o]);
/* insert back into remainder */
pset_insert_ptr(remain, cls[i]);
}
}
/**
* Matrix P: Path contraints.
* If 2 nodes interfere and there is a path of equal-color-edges
* connecting them, then at least one of those equal-color-edges
* will break and cause some costs.
*/
static void pi_add_path_cstr_for_classes(problem_instance_t *pi) {
DBG((dbg, LEVEL_2, "Adding path constraints for phi classes...\n"));
pi->cst_counter = 0;
pi->done = pset_new_ptr_default();
irg_walk_graph(pi->co->irg, path_cstr_for_classes_walker, NULL, pi);
del_pset(pi->done);
}
#endif
static void pi_construct(problem_instance_t *pi) {
pi_add_path_cstr_for_classes(pi);
pi_add_path_cstr(pi);
pi_add_clique_path_cstr(pi);
}
#endif
#include "becopyilp_t.h"
#define DEBUG_LVL 1
......
......@@ -32,6 +32,9 @@
#ifdef WITH_ILP
#include <bitset.h>
#include "pdeq.h"
#include "irtools.h"
#include "irgwalk.h"
#include "becopyilp_t.h"
......@@ -113,8 +116,13 @@ static void build_interference_cstr(ilp_env_t *ienv) {
/* for each maximal clique */
be_ifg_foreach_clique(ifg, iter, clique, &size) {
int realsize = 0;
for (i=0; i<size; ++i)
if (!sr_is_removed(ienv->sr, clique[i]))
++realsize;
if (size < 2)
if (realsize < 2)
continue;
/* for all colors */
......@@ -166,7 +174,7 @@ static void build_affinity_cstr(ilp_env_t *ienv) {
lpp_set_factor_fast(ienv->lp, cst_idx, root_idx, 1.0);
lpp_set_factor_fast(ienv->lp, cst_idx, arg_idx, -1.0);
lpp_set_factor_fast(ienv->lp, cst_idx, root_idx, -1.0);
lpp_set_factor_fast(ienv->lp, cst_idx, y_idx, -1.0);
}
}
}
......@@ -198,7 +206,7 @@ static INLINE edge_t *add_edge(set *edges, ir_node *n1, ir_node *n2, int *counte
new_edge.n1 = n2;
new_edge.n2 = n1;
}
*counter++;
(*counter)++;
return set_insert(edges, &new_edge, sizeof(new_edge), HASH_EDGE(&new_edge));
}
......@@ -229,7 +237,7 @@ static INLINE void remove_edge(set *edges, ir_node *n1, ir_node *n2, int *counte
if (e) {
e->n1 = NULL;
e->n2 = NULL;
*counter--;
(*counter)--;
}
}
......@@ -241,13 +249,13 @@ static INLINE void remove_edge(set *edges, ir_node *n1, ir_node *n2, int *counte
* At most 1 node of the clique can be colored equally with the external node.
*/
static void build_clique_star_cstr(ilp_env_t *ienv) {
node_t *node;
affinity_t *aff;
/* for each node with affinity edges */
co_gs_foreach_node(ienv->co, node) {
co_gs_foreach_aff_node(ienv->co, aff) {
struct obstack ob;
neighb_t *nbr;
ir_node *center = node->irn;
ir_node *center = aff->irn;
ir_node **nodes;
set *edges;
int i, o, n_nodes, n_edges;
......@@ -257,7 +265,7 @@ static void build_clique_star_cstr(ilp_env_t *ienv) {
/* get all affinity neighbours */
n_nodes = 0;
co_gs_foreach_neighb(node, nbr) {
co_gs_foreach_neighb(aff, nbr) {
obstack_ptr_grow(&ob, nbr->irn);
++n_nodes;
}
......@@ -280,9 +288,9 @@ static void build_clique_star_cstr(ilp_env_t *ienv) {
for (e=set_first(edges); !e->n1; e=set_next(edges))
/*nothing*/ ;
remove_edge(edges, e->n1, e->n2, &n_edges);
pset_insert_ptr(clique, e->n1);
pset_insert_ptr(clique, e->n2);
remove_edge(edges, e->n1, e->n2, &n_edges);
/* while the clique is growing */
do {
......@@ -345,11 +353,86 @@ static void build_clique_star_cstr(ilp_env_t *ienv) {
}
}
static void extend_path(ilp_env_t *ienv, pdeq *path, ir_node *irn) {
be_ifg_t *ifg = ienv->co->cenv->ifg;
int i, len;
ir_node **curr_path;
affinity_t *aff;
neighb_t *nbr;
/* do not walk backwards or in circles */
if (pdeq_contains(path, irn))
return;
/* insert the new irn */
pdeq_putr(path, irn);
/* check for forbidden interferences */
len = pdeq_len(path);
curr_path = alloca(len * sizeof(*curr_path));
pdeq_copyl(path, curr_path);
for (i=1; i<len; ++i)
if (be_ifg_connected(ifg, irn, curr_path[i]))
goto end;
/* check for terminating interference */
if (be_ifg_connected(ifg, irn, curr_path[0])) {
/* One node is not a path. */
/* And a path of length 2 is covered by a clique star constraint. */
if (len > 2) {
/* finally build the constraint */
int cst_idx = lpp_add_cst(ienv->lp, NULL, lpp_greater, 1.0);
for (i=1; i<len; ++i) {
char buf[16];
int nr_1 = get_irn_node_nr(curr_path[i-1]);
int nr_2 = get_irn_node_nr(curr_path[i]);
int var_idx = lpp_get_var_idx(ienv->lp, name_cdd_sorted(buf, 'y', nr_1, nr_2));
lpp_set_factor_fast(ienv->lp, cst_idx, var_idx, 1.0);
}
}
/* this path cannot be extended anymore */
goto end;
}
/* recursively extend the path */
aff = get_affinity_info(ienv->co, irn);
co_gs_foreach_neighb(aff, nbr)
extend_path(ienv, path, nbr->irn);
end:
/* remove the irn */
pdeq_getr(path);
}
/**
*
* Search a path of affinity edges, whose ends are connected
* by an interference edge and there are no other interference
* edges in between.
* Then at least one of these affinity edges must break.
*/
static void build_path_cstr(ilp_env_t *ienv) {
affinity_t *aff_info;
/* for each node with affinity edges */
co_gs_foreach_aff_node(ienv->co, aff_info) {
pdeq *path = new_pdeq();
extend_path(ienv, path, aff_info->irn);
del_pdeq(path);
}
}
static void ilp2_build(ilp_env_t *ienv) {
......@@ -374,28 +457,32 @@ static void ilp2_apply(ilp_env_t *ienv) {
lpp_sol_state_t state;
int i, count;
count = lenv->last_x_var - lenv->first_x_var + 1;
sol = xmalloc(count * sizeof(sol[0]));
state = lpp_get_solution(ienv->lp, sol, lenv->first_x_var, lenv->last_x_var);
if (state != lpp_optimal) {
printf("WARNING %s: Solution state is not 'optimal': %d\n", ienv->co->name, state);
assert(state >= lpp_feasible && "The solution should at least be feasible!");
}
/* first check if there was sth. to optimize */
if (lenv->first_x_var >= 0) {
count = lenv->last_x_var - lenv->first_x_var + 1;
sol = xmalloc(count * sizeof(sol[0]));
state = lpp_get_solution(ienv->lp, sol, lenv->first_x_var, lenv->last_x_var);
if (state != lpp_optimal) {
printf("WARNING %s: Solution state is not 'optimal': %d\n", ienv->co->name, state);
assert(state >= lpp_feasible && "The solution should at least be feasible!");
}
for (i=0; i<count; ++i) {
int nodenr, color;
char var_name[16];
for (i=0; i<count; ++i) {
int nodenr, color;
char var_name[16];
if (sol[i] > 1-EPSILON) { /* split variable name into components */
lpp_get_var_name(ienv->lp, lenv->first_x_var+i, var_name, sizeof(var_name));
if (sol[i] > 1-EPSILON) { /* split variable name into components */
lpp_get_var_name(ienv->lp, lenv->first_x_var+i, var_name, sizeof(var_name));
if (sscanf(var_name, "x_%d_%d", &nodenr, &color) == 2) {
ir_node *irn = pmap_get(lenv->nr_2_irn, INT_TO_PTR(nodenr));
assert(irn && "This node number must be present in the map");
if (sscanf(var_name, "x_%d_%d", &nodenr, &color) == 2) {
ir_node *irn = pmap_get(lenv->nr_2_irn, INT_TO_PTR(nodenr));
assert(irn && "This node number must be present in the map");
set_irn_col(ienv->co, irn, color);
} else
assert(0 && "This should be a x-var");
set_irn_col(ienv->co, irn, color);
} else
assert(0 && "This should be a x-var");
}
}
}
......
......@@ -88,6 +88,8 @@ int co_is_optimizable_root(const copy_opt_t *co, ir_node *irn) {
int co_is_optimizable_arg(const copy_opt_t *co, ir_node *irn) {
const ir_edge_t *edge;
assert(0 && "Is buggy and obsolete. Do not use");
if (arch_irn_is_ignore(co->aenv, irn))
return 0;
......@@ -419,22 +421,22 @@ int co_get_lower_bound(const copy_opt_t *co) {
|_| |___/
******************************************************************************/
static int compare_node_t(const void *k1, const void *k2, size_t size) {
const node_t *n1 = k1;
const node_t *n2 = k2;
static int compare_affinity_t(const void *k1, const void *k2, size_t size) {
const affinity_t *n1 = k1;
const affinity_t *n2 = k2;
return (n1->irn != n2->irn);
}
static void add_edge(copy_opt_t *co, ir_node *n1, ir_node *n2, int costs) {
node_t new_node, *node;
affinity_t new_node, *node;
neighb_t new_nbr, *nbr;
int allocnew;
new_node.irn = n1;
new_node.count = 0;
new_node.neighbours = NULL;
node = set_insert(co->nodes, new_node.irn, sizeof(new_node), HASH_PTR(new_node.irn));
node = set_insert(co->nodes, &new_node, sizeof(new_node), HASH_PTR(new_node.irn));
allocnew = 1;
for (nbr = node->neighbours; nbr; nbr = nbr->next)
......@@ -493,7 +495,7 @@ static void build_graph_walker(ir_node *irn, void *env) {
void co_build_graph_structure(copy_opt_t *co) {
obstack_init(&co->obst);
co->nodes = new_set(compare_node_t, 32);
co->nodes = new_set(compare_affinity_t, 32);
irg_walk_graph(co->irg, build_graph_walker, NULL, co);
}
......@@ -506,10 +508,10 @@ void co_free_graph_structure(copy_opt_t *co) {
/* co_solve_ilp1() co_solve_ilp2() are implemented in becopyilpX.c */
int co_gs_is_optimizable(copy_opt_t *co, ir_node *irn) {
node_t new_node, *n;
affinity_t new_node, *n;
new_node.irn = irn;
n = set_find(co->nodes, new_node.irn, sizeof(new_node), HASH_PTR(new_node.irn));
n = set_find(co->nodes, &new_node, sizeof(new_node), HASH_PTR(new_node.irn));
if (n) {
return (n->count > 0);
} else
......
......@@ -96,7 +96,7 @@ typedef struct _unit_t {
******************************************************************************/
typedef struct _neighb_t neighb_t;
typedef struct _node_t node_t;
typedef struct _affinity_t affinity_t;
struct _neighb_t {
......@@ -105,17 +105,25 @@ struct _neighb_t {
int costs; /** the costs of the edge (node_t->irn, neighb_t->irn) */
};
struct _node_t {
struct _affinity_t {
ir_node *irn; /** a node with affinity edges */
int count; /** number of affinity edges in the linked list below */
neighb_t *neighbours; /** a linked list of all affinity neighbours */
};