#else
{
copy_opt_t *co = new_copy_opt(&chordal_env, co_get_costs_loop_depth);
+ co_build_ou_structure(co);
co_solve_heuristic(co);
+ co_free_ou_structure(co);
free_copy_opt(co);
}
#endif
void *iter = be_ifg_neighbours_iter_alloca(ifg);
while (redo) {
- arch_register_req_t req;
redo = 0;
be_ifg_foreach_node(ifg, iter, irn) {
- if (!sr_is_removed(sr, irn) && !co_is_optimizable(sr->co->aenv, irn, &req) && !co_is_optimizable_arg(sr->co, irn)) {
+ if (!sr_is_removed(sr, irn) && !co_is_optimizable_root(sr->co, irn) && !co_is_optimizable_arg(sr->co, irn)) {
if (sr_is_simplicial(sr, irn)) {
coloring_suffix_t *cs = obstack_alloc(&sr->ob, sizeof(*cs));
#if 0 //temporary
#define PATH_CONSTRAINTS_FOR_CLASSES
-#undef DUMP_MPS
-
-static firm_dbg_module_t *dbg = NULL;
-#define SLOTS_LIVING 32
typedef struct _problem_instance_t {
const copy_opt_t *co; /**< the copy opt problem */
sscanf(var, "x%d_%d", (nnr), (col))
-/**
- * Add coloring-force conditions
- * Matrix A: knapsack constraint for each node
- */
-static void pi_add_constr_A(problem_instance_t *pi) {
- pmap_entry *pme;
-
- DBG((dbg, LEVEL_2, "Add A constraints...\n"));
- /* iterate over all blocks */
- pmap_foreach(pi->co->cenv->border_heads, pme) {
- struct list_head *head = pme->value;
- border_t *curr;
- bitset_t *pos_regs = bitset_alloca(pi->co->cenv->cls->n_regs);
-
- list_for_each_entry_reverse(border_t, curr, head, list)
- if (curr->is_def && curr->is_real && !sr_is_removed(pi->sr->curr->irn)) {
- int cst_idx, nnr, col;
-
- nnr = get_irn_graph_nr(curr->irn);
- mangle_cst(pi->buf, 'A', nnr);
- cst_idx = lpp_add_cst(pi->curr_lp, pi->buf, lpp_equal, 1);
-
- /* iterate over all possible colors in order */
- bitset_clear_all(pos_regs);
- arch_get_allocatable_regs(pi->co->aenv, curr->irn, -1, pos_regs);
- bitset_foreach(pos_regs, col) {
- int var_idx;
- mangle_var2(pi->buf, 'x', nnr, col);
- var_idx = lpp_add_var(pi->curr_lp, pi->buf, lpp_binary, 0);
- if (!pi->first_x_var)
- pi->first_x_var = var_idx;
- pi->last_x_var = var_idx;
- lpp_set_factor_fast(pi->curr_lp, cst_idx, var_idx, 1);
- }
- }
- }
-}
-
-/**
- * Checks if all nodes in @p living are live in in block @p block.
- * @return 1 if all are live in
- * 0 else
- */
-static INLINE int all_live_in(ir_node *block, pset *living) {
- ir_node *n;
- for (n = pset_first(living); n; n = pset_next(living))
- if (!is_live_in(block, n)) {
- pset_break(living);
- return 0;
- }
- return 1;
-}
-
-/**
- * Finds cliques in the interference graph, considering only nodes
- * for which the color @p color is possible. Finds only 'maximal-cliques',
- * viz cliques which are not contained in another one.
- * Matrix B: interference constraints using cliques
- */
-static void pi_add_constr_B(problem_instance_t *pi, int color) {
- enum phase_t {growing, shrinking} phase = growing;
- border_t *b;
- pmap_entry *pme;
- pset *living = pset_new_ptr(SLOTS_LIVING);
-
- DBG((dbg, LEVEL_2, "Add B constraints (col = %d)...\n", color));
- /* iterate over all blocks */
- pmap_foreach(pi->co->cenv->border_heads, pme) {
- ir_node *block = pme->key;
- struct list_head *head = pme->value;
-
- list_for_each_entry_reverse(border_t, b, head, list) {
- const ir_node *irn = b->irn;
- if (is_removed(irn) || !is_color_possible(irn, color))
- continue;
-
- if (b->is_def) {
- DBG((dbg, LEVEL_2, "Def %n\n", irn));
- pset_insert_ptr(living, irn);
- phase = growing;
- } else { /* is_use */
- DBG((dbg, LEVEL_2, "Use %n\n", irn));
-
- /* before shrinking the set, store the current 'maximum' clique;
- * do NOT if clique is a single node
- * do NOT if all values are live_in (in this case they were contained in a live-out clique elsewhere) */
- if (phase == growing && pset_count(living) >= 2 && !all_live_in(block, living)) {
- int cst_idx;
- ir_node *n;
- mangle_cst(pi->buf, 'B', pi->cst_counter);
- cst_idx = lpp_add_cst(pi->curr_lp, pi->buf, lpp_less, 1);
- for (n = pset_first(living); n; n = pset_next(living)) {
- int var_idx;
- mangle_var_irn(pi->buf, 'x', n, color);
- var_idx = lpp_get_var_idx(pi->curr_lp, pi->buf);
- lpp_set_factor_fast(pi->curr_lp, cst_idx, var_idx, 1);
- }
- pi->cst_counter++;
- }
- pset_remove_ptr(living, irn);
- phase = shrinking;
- }
- }
- }
- assert(0 == pset_count(living));
- del_pset(living);
-}
-
-/**
- * Generates constraints which interrelate x with y variables.
- * x1 and x2 have the different colors ==> y_12 = 1
- */
-static void pi_add_constr_E(problem_instance_t *pi) {
- unit_t *curr;
- bitset_t *root_regs, *arg_regs, *work_regs;
- int cst_counter = 0;
- unsigned nregs = pi->co->cenv->cls->n_regs;
- root_regs = bitset_alloca(nregs);
- arg_regs = bitset_alloca(nregs);
- work_regs = bitset_alloca(nregs);
-
- DBG((dbg, LEVEL_2, "Add E constraints...\n"));
- /* for all roots of optimization units */
- list_for_each_entry(unit_t, curr, &pi->co->units, units) {
- ir_node *root, *arg;
- int rootnr, argnr, color;
- int y_idx, i;
- char buf[32];
-
- root = curr->nodes[0];
- rootnr = get_irn_graph_nr(root);
- bitset_clear_all(root_regs);
- arch_get_allocatable_regs(pi->co->aenv, root, -1, root_regs);
-
- /* for all arguments of root */
- for (i = 1; i < curr->node_count; ++i) {
- arg = curr->nodes[i];
- argnr = get_irn_graph_nr(arg);
- bitset_clear_all(arg_regs);
- arch_get_allocatable_regs(pi->co->aenv, arg, -1, arg_regs);
-
- /* Introduce new variable and set factor in objective function */
- mangle_var2(buf, 'y', rootnr, argnr);
- y_idx = lpp_add_var(pi->curr_lp, buf, lpp_binary, curr->costs[i]);
-
- /* set starting value */
- lpp_set_start_value(pi->curr_lp, y_idx, (get_irn_col(pi->co, root) != get_irn_col(pi->co, arg)));
-
- /* For all colors root and arg have in common, add 2 constraints to E */
- bitset_copy(work_regs, root_regs);
- bitset_and(work_regs, arg_regs);
- bitset_foreach(work_regs, color) {
- int root_idx, arg_idx, cst_idx;
- mangle_var2(buf, 'x', rootnr, color);
- root_idx = lpp_get_var_idx(pi->curr_lp, buf);
- mangle_var2(buf, 'x', argnr, color);
- arg_idx = lpp_get_var_idx(pi->curr_lp, buf);
-
- /* add root-arg-y <= 0 */
- mangle_cst(buf, 'E', cst_counter++);
- cst_idx = lpp_add_cst(pi->curr_lp, buf, lpp_less, 0);
- lpp_set_factor_fast(pi->curr_lp, cst_idx, root_idx, 1);
- lpp_set_factor_fast(pi->curr_lp, cst_idx, arg_idx, -1);
- lpp_set_factor_fast(pi->curr_lp, cst_idx, y_idx, -1);
-
- /* add arg-root-y <= 0 */
- mangle_cst(buf, 'E', cst_counter++);
- cst_idx = lpp_add_cst(pi->curr_lp, buf, lpp_less, 0);
- lpp_set_factor_fast(pi->curr_lp, cst_idx, root_idx, -1);
- lpp_set_factor_fast(pi->curr_lp, cst_idx, arg_idx, 1);
- lpp_set_factor_fast(pi->curr_lp, cst_idx, y_idx, -1);
- }
- /* For all colors root and arg have "disjunct", add 1 constraints to E.
- * If root gets a color the arg is not possible to get then they will
- * definetly get different colors. So y has to be 1.
- * Vice versa for arg.
- */
- bitset_copy(work_regs, root_regs);
- bitset_xor(work_regs, arg_regs);
- bitset_foreach(work_regs, color) {
- int root_idx, arg_idx, cst_idx;
- mangle_var2(buf, 'x', rootnr, color);
- root_idx = lpp_get_var_idx(pi->curr_lp, buf);
- mangle_var2(buf, 'x', argnr, color);
- arg_idx = lpp_get_var_idx(pi->curr_lp, buf);
-
- mangle_cst(buf, 'E', cst_counter++);
- cst_idx = lpp_add_cst(pi->curr_lp, buf, lpp_less, 0);
- if (bitset_is_set(root_regs, color)) {
- /* add root-y <= 0 */
- lpp_set_factor_fast(pi->curr_lp, cst_idx, root_idx, 1);
- lpp_set_factor_fast(pi->curr_lp, cst_idx, y_idx, -1);
- } else {
- assert(bitset_is_set(arg_regs, color) && "bitset_xor is buggy");
- /* add arg-y <= 0 */
- lpp_set_factor_fast(pi->curr_lp, cst_idx, arg_idx, 1);
- lpp_set_factor_fast(pi->curr_lp, cst_idx, y_idx, -1);
- }
- }
- }
- }
-}
-
-static void clique_path_walker(ir_node *block, void *env) {
- problem_instance_t *pi = env;
- int count, arity, row, col, other_row, *costs;
- ir_node **phis, *phi, *irn, **phi_matrix;
- pset *done;
- bitset_t *candidates;
-
- /* Count all phi nodes of this block */
- for (count=0, irn = sched_first(block); is_Phi(irn); irn = sched_next(irn))
- count++;
-
- /* We at least 2 phi nodes for this class of inequalities */
- if (count < 2)
- return;
-
- /* Build the \Phi-Matrix */
- arity = get_irn_arity(sched_first(block));
- phis = alloca(count * sizeof(*phis));
- costs = alloca(count * sizeof(costs));
- phi_matrix = alloca(count*arity * sizeof(*phi_matrix));
- candidates = bitset_alloca(count);
-
- phi = sched_first(block);
- for (row=0; row<count; ++row) {
- phis[row] = phi;
- for (col=0; col<arity; ++col) {
- ir_node *arg = get_irn_n(phi, col);
- /* Sort out all arguments interfering with its phi */
- if (nodes_interfere(pi->co->cenv, phi, arg)) {
- phi_matrix[row*arity + col] = NULL;
- } else
- phi_matrix[row*arity + col] = arg;
- }
- phi = sched_next(phi);
- }
-
- /* Now find the interesting patterns in the matrix:
- * All nodes which are used at least twice in a column. */
- /* columnwise ... */
- for (col=0; col<arity; ++col) {
- done = pset_new_ptr_default();
- for (row=0; row<count; ++row) {
- irn = phi_matrix[row*arity + col];
- /*
- * is this an interfering arg (NULL)
- * or has the irn already been processed in this col?
- */
- if (!irn || pset_find_ptr(done, irn))
- continue;
- else
- pset_insert_ptr(done, irn);
-
- /* insert irn in candidates */
- bitset_clear_all(candidates);
- bitset_set(candidates, row);
- /* search the irn in the rows below */
- for (other_row = row+1; other_row<count; ++other_row)
- if (irn == phi_matrix[other_row*arity + col]) {
- /* found the irn in the same col in another row */
- bitset_set(candidates, other_row);
- }
-
- /* now we know all occurences of irn in this col */
- if (bitset_popcnt(candidates) < 2)
- continue;
-
- /* generate an unequation finally.
- * phis are indexed in the bitset,
- * shared argument is irn
- * rhs is phi_count - 1 */
- {
- char buf[32];
- ir_node *root;
- int pos, irnnr, rootnr, cst_idx, y_idx, cst_counter = 0;
- int minimal_unequal_count = bitset_popcnt(candidates)-1;
-
- irnnr = get_irn_graph_nr(irn);
- mangle_cst(buf, 'M', cst_counter++);
- cst_idx = lpp_add_cst(pi->curr_lp, buf, lpp_greater, minimal_unequal_count);
-
- /* for all phis */
- bitset_foreach(candidates, pos) {
- root = phis[pos];
- rootnr = get_irn_graph_nr(root);
- mangle_var2(buf, 'y', rootnr, irnnr);
- y_idx = lpp_get_var_idx(pi->curr_lp, buf);
- lpp_set_factor_fast(pi->curr_lp, cst_idx, y_idx, 1);
- }
- }
- }
- del_pset(done); /* clear set for next row */
- } /*next col*/
-}
-
-/**
- * Matrix M: Multi-Arg-Use. Interrelates different \phi-functions
- * in the same block, iff they use the same arg at the same pos.
- * Only one of the phis can get the arg.
- */
-static void pi_add_clique_path_cstr(problem_instance_t *pi) {
- DBG((dbg, LEVEL_2, "Adding clique path constraints...\n"));
- dom_tree_walk_irg(pi->co->irg, clique_path_walker, NULL, pi);
-}
-
#ifndef PATH_CONSTRAINTS_FOR_CLASSES
/**
* Matrix P: Path contraints.
}
#endif
-
-
-/**
- * Generate the initial problem matrices and vectors.
- */
-static problem_instance_t *new_pi(const copy_opt_t *co) {
- problem_instance_t *pi;
- int col;
-
- DBG((dbg, LEVEL_2, "Generating new instance...\n"));
- pi = xcalloc(1, sizeof(*pi));
- pi->co = co;
- pi->sr = new_size_red(co);
- pi->lp = new_lpp(co->name, lpp_minimize);
-
- return pi;
-}
-
static void pi_construct(problem_instance_t *pi) {
- pi_add_constr_A(pi);
- for (col = 0; col < pi->co->cls->n_regs; ++col)
- pi_add_constr_B(pi, col);
- pi_add_constr_E(pi);
-
-#ifdef PATH_CONSTRAINTS_FOR_CLASSES
pi_add_path_cstr_for_classes(pi);
-#else
pi_add_path_cstr(pi);
-#endif
pi_add_clique_path_cstr(pi);
}
-
-/**
- * Clean the problem instance
- */
-static void free_pi(problem_instance_t *pi) {
- simpl_t *simpl, *tmp;
-
- DBG((dbg, LEVEL_2, "Free instance...\n"));
- free_lpp(pi->lp);
- free_size_red(pi->sr);
- free(pi);
-}
-
-
-/**
- * Set starting values for the mip problem according
- * to the current coloring of the graph.
- */
-static void pi_set_start_sol(problem_instance_t *pi) {
- int i;
- char var_name[64];
- DBG((dbg, LEVEL_2, "Set start solution...\n"));
- for (i=pi->first_x_var; i<=pi->last_x_var; ++i) {
- int nnr, col;
- double val;
- /* get variable name */
- lpp_get_var_name(pi->curr_lp, i, var_name, sizeof(var_name));
- /* split into components */
- if (split_var(var_name, &nnr, &col) == 2) {
- assert(get_irn_col(pi->co, get_irn_for_graph_nr(pi->co->irg, nnr)) != -1);
- val = (get_irn_col(pi->co, get_irn_for_graph_nr(pi->co->irg, nnr)) == col) ? 1 : 0;
- lpp_set_start_value(pi->curr_lp, i, val);
- } else {
- fprintf(stderr, "Variable name is: %s\n", var_name);
- assert(0 && "x vars always look like this 'x123_45'");
- }
- }
-}
-
-
-/**
- * Invoke a solver
- */
-static void pi_solve_ilp(problem_instance_t *pi, double time_limit) {
- double lower_bound;
-#ifdef DUMP_MPS
- char buf[512];
- snprintf(buf, sizeof(buf), "%s.ilp1", co->name);
- lpp_dump(pi->lp, buf);
-#endif
-
- pi_set_start_sol(pi);
-
- lower_bound = co_get_lower_bound(pi->co) - co_get_inevit_copy_costs(pi->co);
- lpp_set_bound(pi->curr_lp, lower_bound);
-
- lpp_set_time_limit(pi->curr_lp, time_limit);
-
-#ifdef LPP_SOLVE_REMOTE
- lpp_solve_net(pi->curr_lp, LPP_HOST, LPP_SOLVER);
-#else
- lpp_solve_cplex(pi->curr_lp);
-#endif
- DBG((dbg, LEVEL_1, "Solution time: %.2f\n", pi->curr_lp->sol_time));
-}
-
-
-/**
- * Sets the colors of irns according to the values of variables
- * provided by the solution of the solver.
- */
-static int pi_apply_solution(problem_instance_t *pi) {
- int res = 1, i;
- double *sol;
- lpp_sol_state_t state;
- DBG((dbg, LEVEL_2, "Applying solution...\n"));
-
-#ifdef COPYOPT_STAT
- copystat_add_ilp_time((int)(1000.0*lpp_get_sol_time(pi->curr_lp))); //now we have ms
- copystat_add_ilp_vars(lpp_get_var_count(pi->curr_lp));
- copystat_add_ilp_csts(lpp_get_cst_count(pi->curr_lp));
- copystat_add_ilp_iter(lpp_get_iter_cnt(pi->curr_lp));
-#endif
-
- sol = xmalloc((pi->last_x_var - pi->first_x_var + 1) * sizeof(*sol));
- state = lpp_get_solution(pi->curr_lp, sol, pi->first_x_var, pi->last_x_var);
- if (state != lpp_optimal) {
- printf("WARNING %s: Solution state is not 'optimal': %d\n", pi->co->name, state);
- assert(state >= lpp_feasible && "The solution should at least be feasible!");
- res = 0;
- }
- for (i=0; i<pi->last_x_var - pi->first_x_var + 1; ++i) {
- int nnr, col;
- char var_name[64];
-
- if (sol[i] > 1-EPSILON) { /* split varibale name into components */
- lpp_get_var_name(pi->curr_lp, pi->first_x_var+i, var_name, sizeof(var_name));
- if (split_var(var_name, &nnr, &col) == 2) {
- DBG((dbg, LEVEL_2, "Irn %n Idx %d Var %s Val %f\n", get_irn_for_graph_nr(pi->co->irg, nnr), i, var_name, sol[i]));
- DBG((dbg, LEVEL_2, "x%d = %d\n", nnr, col));
- set_irn_col(pi->co, get_irn_for_graph_nr(pi->co->irg, nnr), col);
- } else
- assert(0 && "This should be a x-var");
- }
- }
- return res;
-}
-
-
-int co_solve_ilp11(copy_opt_t *co, double time_limit) {
- int res = 1;
- problem_instance_t *pi;
-
- dbg = firm_dbg_register("ir.be.copyoptilp1");
-
- pi = new_pi(co);
-
- sr_remove(pi->sr); /* problem size reduction */
- pi_construct(pi); /* set up the problem */
- pi_solve_ilp(pi, time_limit); /* solve it */
- res = pi_apply_solution(pi); /* apply solution */
- sr_reinsert(pi->sr); /* complete the partial solution */
-
- free_pi(pi);
- return res;
-}
#endif
#include "becopyilp_t.h"
}
int co_solve_ilp1(copy_opt_t *co, double time_limit) {
- lpp_sol_state_t sol_state;
- ilp_env_t *ienv;
- my_env_t my;
- firm_dbg_module_t *dbg = firm_dbg_register("ir.be.coilp1");
-
- firm_dbg_set_mask(dbg, DEBUG_LVL);
-
- // my.bla = TODO
-
- ienv = new_ilp_env(co, ilp1_build, ilp1_apply, &my);
-
- sol_state = ilp_go(ienv);
-
- free_ilp_env(ienv);
-
- return sol_state == lpp_optimal;
+ return 1;
}
* Copyright: (c) Universitaet Karlsruhe
* Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
*
+ *
* ILP formalization using G=(V, E, Q):
- * - 1 class of variables: equal color vars
+ * - 2 class of variables: coloring vars x_ic and equal color vars y_ij
* - Path constraints
- * - Clique path constraints
+ * - Clique-star constraints
*
*
* \min \sum_{ (i,j) \in Q } w_ij y_ij
*
- * y_ij = 1 (i,j) \in E
+ * \sum_c x_nc = 1 n \in N, c \in C
*
- * \sum_c y_nc = |C| - 1 n \in N, c \in C
+ * x_nc = 0 n \in N, c \not\in C(n)
*
- * y_nc = 1 n \in N, c \not\in C(n)
+ * \sum x_nc <= 1 x_nc \in Clique \in AllCliques, c \in C
*
* \sum_{e \in p} y_e >= 1 p \in P path constraints
*
- * \sum_{e \in cp} y_e >= |cp| - 1 cp \in CP clique-path constraints
+ * \sum_{e \in cs} y_e >= |cs| - 1 cs \in CP clique-star constraints
*
- * y_ij \in N, w_ij \in R^+
+ * x_nc, y_ij \in N, w_ij \in R^+
*/
#ifdef HAVE_CONFIG_H
#ifdef WITH_ILP
+#include "irtools.h"
+#include "irgwalk.h"
#include "becopyilp_t.h"
#include "beifg_t.h"
-#include "irtools.h"
+#include "besched_t.h"
#define DEBUG_LVL 1
}
}
-static void build_path_cstr(ilp_env_t *ienv) {
+/**
+ *
+ */
+static void build_clique_star_cstr(ilp_env_t *ienv) {
}
-static void build_clique_path_cstr(ilp_env_t *ienv) {
+/**
+ *
+ */
+static void build_path_cstr(ilp_env_t *ienv) {
}
build_coloring_cstr(ienv);
build_interference_cstr(ienv);
build_affinity_cstr(ienv);
+ build_clique_star_cstr(ienv);
build_path_cstr(ienv);
- build_clique_path_cstr(ienv);
lower_bound = co_get_lower_bound(ienv->co) - co_get_inevit_copy_costs(ienv->co);
lpp_set_bound(ienv->lp, lower_bound);
void *env;
ilp_callback build;
ilp_callback apply;
-
};
ilp_env_t *new_ilp_env(copy_opt_t *co, ilp_callback build, ilp_callback apply, void *env);
#include "bearch.h"
#include "beutil.h"
+#include "beifg_t.h"
#include "becopyopt_t.h"
#include "becopystat.h"
+/******************************************************************************
+ _____ _
+ / ____| | |
+ | | __ ___ _ __ ___ _ __ __ _| |
+ | | |_ |/ _ \ '_ \ / _ \ '__/ _` | |
+ | |__| | __/ | | | __/ | | (_| | |
+ \_____|\___|_| |_|\___|_| \__,_|_|
+
+ ******************************************************************************/
static firm_dbg_module_t *dbg = NULL;
+void be_copy_opt_init(void) {
+}
+
+copy_opt_t *new_copy_opt(be_chordal_env_t *chordal_env, int (*get_costs)(ir_node*, ir_node*, int)) {
+ const char *s1, *s2, *s3;
+ int len;
+ copy_opt_t *co;
+
+ dbg = firm_dbg_register("ir.be.copyopt");
+
+ co = xcalloc(1, sizeof(*co));
+ co->cenv = chordal_env;
+ co->aenv = chordal_env->birg->main_env->arch_env;
+ co->irg = chordal_env->irg;
+ co->cls = chordal_env->cls;
+ co->get_costs = get_costs;
+
+ s1 = get_irp_prog_name();
+ s2 = get_entity_name(get_irg_entity(co->irg));
+ s3 = chordal_env->cls->name;
+ len = strlen(s1) + strlen(s2) + strlen(s3) + 5;
+ co->name = xmalloc(len);
+ snprintf(co->name, len, "%s__%s__%s", s1, s2, s3);
+
+ return co;
+}
+
+void free_copy_opt(copy_opt_t *co) {
+ xfree(co->name);
+}
+
+int co_is_optimizable_root(const copy_opt_t *co, ir_node *irn) {
+ arch_register_req_t req;
+
+ if (arch_irn_is_ignore(co->aenv, irn))
+ return 0;
+
+ if (is_Reg_Phi(irn) || is_Perm_Proj(co->aenv, irn) || is_2addr_code(co->aenv, irn, &req))
+ return 1;
+
+ return 0;
+}
+
+int co_is_optimizable_arg(const copy_opt_t *co, ir_node *irn) {
+ const ir_edge_t *edge;
+
+ if (arch_irn_is_ignore(co->aenv, irn))
+ return 0;
+
+ foreach_out_edge(irn, edge) {
+ ir_node *n = edge->src;
+
+ if (!nodes_interfere(co->cenv, irn, n) || irn == n) {
+ arch_register_req_t req;
+ arch_get_register_req(co->aenv, &req, n, -1);
+
+ if(is_Reg_Phi(n) ||
+ is_Perm(co->aenv, n) ||
+ (arch_register_req_is(&req, should_be_same) && req.other_same == irn)
+ )
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int co_get_costs_loop_depth(ir_node *root, ir_node* arg, int pos) {
+ int cost = 0;
+ ir_loop *loop;
+ ir_node *root_block = get_nodes_block(root);
+
+ if (is_Phi(root)) {
+ /* for phis the copies are placed in the corresponding pred-block */
+ loop = get_irn_loop(get_Block_cfgpred_block(root_block, pos));
+ } else {
+ /* a perm places the copy in the same block as it resides */
+ loop = get_irn_loop(root_block);
+ }
+ if (loop) {
+ int d = get_loop_depth(loop);
+ cost = d*d;
+ }
+ return cost+1;
+}
+
+int co_get_costs_all_one(ir_node *root, ir_node* arg, int pos) {
+ return 1;
+}
+
+/******************************************************************************
+ ____ _ _ _ _ _ _____ _
+ / __ \ | | | | | | (_) | / ____| |
+ | | | |_ __ | |_| | | |_ __ _| |_ ___ | (___ | |_ ___ _ __ __ _ __ _ ___
+ | | | | '_ \| __| | | | '_ \| | __/ __| \___ \| __/ _ \| '__/ _` |/ _` |/ _ \
+ | |__| | |_) | |_| |__| | | | | | |_\__ \ ____) | || (_) | | | (_| | (_| | __/
+ \____/| .__/ \__|\____/|_| |_|_|\__|___/ |_____/ \__\___/|_| \__,_|\__, |\___|
+ | | __/ |
+ |_| |___/
+ ******************************************************************************/
+
/**
* Determines a maximum weighted independent set with respect to
* the interference and conflict edges of all nodes in a qnode.
if (!is_curr_reg_class(co, irn))
return;
- if (!co_is_optimizable(co->aenv, irn, &req))
+ if (!co_is_optimizable_root(co, irn))
return;
/* Init a new unit */
/* Proj of a perm with corresponding arg */
if (is_Perm_Proj(co->aenv, irn)) {
- assert(!nodes_interfere(co->cenv, irn, get_Copy_src(irn)));
+ assert(!nodes_interfere(co->cenv, irn, get_Perm_src(irn)));
unit->nodes = xmalloc(2 * sizeof(*unit->nodes));
unit->costs = xmalloc(2 * sizeof(*unit->costs));
unit->node_count = 2;
unit->nodes[0] = irn;
- unit->nodes[1] = get_Copy_src(irn);
+ unit->nodes[1] = get_Perm_src(irn);
unit->costs[1] = co->get_costs(irn, unit->nodes[1], -1);
} else
}
}
-void be_copy_opt_init(void) {
- dbg = firm_dbg_register("ir.be.copyoptmain");
-}
-
-copy_opt_t *new_copy_opt(be_chordal_env_t *chordal_env, int (*get_costs)(ir_node*, ir_node*, int)) {
- const char *s1, *s2, *s3;
- int len;
- copy_opt_t *co;
-
- dbg = firm_dbg_register("ir.be.copyopt");
-
- co = xcalloc(1, sizeof(*co));
- co->cenv = chordal_env;
- co->aenv = chordal_env->birg->main_env->arch_env;
- co->irg = chordal_env->irg;
- co->cls = chordal_env->cls;
- co->get_costs = get_costs;
-
- s1 = get_irp_prog_name();
- s2 = get_entity_name(get_irg_entity(co->irg));
- s3 = chordal_env->cls->name;
- len = strlen(s1) + strlen(s2) + strlen(s3) + 5;
- co->name = xmalloc(len);
- snprintf(co->name, len, "%s__%s__%s", s1, s2, s3);
-
+void co_build_ou_structure(copy_opt_t *co) {
DBG((dbg, LEVEL_1, "\tCollecting optimization units\n"));
INIT_LIST_HEAD(&co->units);
irg_walk_graph(co->irg, co_collect_units, NULL, co);
- return co;
}
-void free_copy_opt(copy_opt_t *co) {
+void co_free_ou_structure(copy_opt_t *co) {
unit_t *curr, *tmp;
- xfree(co->name);
list_for_each_entry_safe(unit_t, curr, tmp, &co->units, units) {
xfree(curr->nodes);
xfree(curr->costs);
}
}
-int co_is_optimizable_arg(const copy_opt_t *co, ir_node *irn) {
- const ir_edge_t *edge;
-
- if (arch_irn_is_ignore(co->aenv, irn))
- return 0;
-
- foreach_out_edge(irn, edge) {
- ir_node *n = edge->src;
-
- if (!nodes_interfere(co->cenv, irn, n) || irn == n) {
- arch_register_req_t req;
- arch_get_register_req(co->aenv, &req, n, -1);
-
- if(is_Reg_Phi(n) ||
- is_Perm(co->aenv, n) ||
- (arch_register_req_is(&req, should_be_same) && req.other_same == irn)
- )
- return 1;
- }
- }
-
- return 0;
-}
-
-int co_get_costs_loop_depth(ir_node *root, ir_node* arg, int pos) {
- int cost = 0;
- ir_loop *loop;
- ir_node *root_block = get_nodes_block(root);
-
- if (is_Phi(root)) {
- /* for phis the copies are placed in the corresponding pred-block */
- loop = get_irn_loop(get_Block_cfgpred_block(root_block, pos));
- } else {
- /* a perm places the copy in the same block as it resides */
- loop = get_irn_loop(root_block);
- }
- if (loop) {
- int d = get_loop_depth(loop);
- cost = d*d;
- }
- return cost+1;
-}
-
-int co_get_costs_all_one(ir_node *root, ir_node* arg, int pos) {
- return 1;
-}
+/* co_solve_heuristic() is implemented in becopyheur.c */
int co_get_max_copy_costs(const copy_opt_t *co) {
int i, res = 0;
res += curr->inevitable_costs + curr->min_nodes_costs;
return res;
}
+
+/******************************************************************************
+ _____ _ _____ _
+ / ____| | | / ____| |
+ | | __ _ __ __ _ _ __ | |__ | (___ | |_ ___ _ __ __ _ __ _ ___
+ | | |_ | '__/ _` | '_ \| '_ \ \___ \| __/ _ \| '__/ _` |/ _` |/ _ \
+ | |__| | | | (_| | |_) | | | | ____) | || (_) | | | (_| | (_| | __/
+ \_____|_| \__,_| .__/|_| |_| |_____/ \__\___/|_| \__,_|\__, |\___|
+ | | __/ |
+ |_| |___/
+ ******************************************************************************/
+
+static int compare_node_t(const void *k1, const void *k2, size_t size) {
+ const node_t *n1 = k1;
+ const node_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;
+ 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));
+
+ allocnew = 1;
+ for (nbr = node->neighbours; nbr; nbr = nbr->next)
+ if (nbr->irn == n2) {
+ allocnew = 0;
+ break;
+ }
+
+ /* if we did not find n2 in n1's neighbourhood insert it */
+ if (allocnew) {
+ obstack_grow(&co->obst, &new_nbr, sizeof(new_nbr));
+ nbr = obstack_finish(&co->obst);
+ nbr->irn = n2;
+ nbr->costs = 0;
+ nbr->next = node->neighbours;
+ node->neighbours = nbr;
+ node->count++;
+ }
+
+ /* now nbr points to n1's neighbour-entry of n2 */
+ nbr->costs += costs;
+}
+
+static INLINE void add_edges(copy_opt_t *co, ir_node *n1, ir_node *n2, int costs) {
+ if (! be_ifg_connected(co->cenv->ifg, n1, n2)) {
+ add_edge(co, n1, n2, costs);
+ add_edge(co, n2, n1, costs);
+ }
+}
+
+static void build_graph_walker(ir_node *irn, void *env) {
+ copy_opt_t *co = env;
+ int pos, max;
+ arch_register_req_t req;
+
+ if (!is_curr_reg_class(co, irn) || arch_irn_is_ignore(co->aenv, irn))
+ return;
+
+ /* Phis */
+ if (is_Reg_Phi(irn))
+ for (pos=0, max=get_irn_arity(irn); pos<max; ++pos) {
+ ir_node *arg = get_irn_n(irn, pos);
+ add_edges(co, irn, arg, co->get_costs(irn, arg, pos));
+ }
+
+ /* Perms */
+ else if (is_Perm_Proj(co->aenv, irn)) {
+ ir_node *arg = get_Perm_src(irn);
+ add_edges(co, irn, arg, co->get_costs(irn, arg, 0));
+ }
+
+ /* 2-address code */
+ else if (is_2addr_code(co->aenv, irn, &req))
+ add_edges(co, irn, req.other_same, co->get_costs(irn, req.other_same, 0));
+}
+
+void co_build_graph_structure(copy_opt_t *co) {
+ obstack_init(&co->obst);
+ co->nodes = new_set(compare_node_t, 32);
+
+ irg_walk_graph(co->irg, build_graph_walker, NULL, co);
+}
+
+void co_free_graph_structure(copy_opt_t *co) {
+ del_set(co->nodes);
+ obstack_free(&co->obst, NULL);
+}
+
+/* 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;
+
+ new_node.irn = irn;
+ return (int)set_find(co->nodes, new_node.irn, sizeof(new_node), HASH_PTR(new_node.irn));
+}
#include "irnode.h"
#include "bechordal.h"
-
-typedef int(*cost_fct_t)(ir_node*, ir_node*, int);
-
-typedef struct _copy_opt_t copy_opt_t;
-
/**
* Has to be called during the firm init phase
*/
void be_copy_opt_init(void);
+typedef int(*cost_fct_t)(ir_node*, ir_node*, int);
+
+typedef struct _copy_opt_t copy_opt_t;
+
/**
* Generate the problem. Collect all information and optimizable nodes.
*/
*/
void free_copy_opt(copy_opt_t *co);
+/**
+ * Checks if a node is optimizable, viz. has somthing to do with coalescing
+ * @param arch The architecture environment
+ * @param irn The irn to check
+ * @param req A register_requirement structure (used to check for 2-addr-code)
+ */
+int co_is_optimizable_root(const copy_opt_t *co, ir_node *irn);
+
+/**
+ * Checks if the irn is a non-interfering argument of a node which 'is_optimizable'
+ */
+int co_is_optimizable_arg(const copy_opt_t *co, ir_node *irn);
+
/**
* Computes the costs of a copy according to loop depth
* @param pos: the argument position of arg in the root arguments
*/
int co_get_costs_all_one(ir_node *root, ir_node* arg, int pos);
+
+
+
+/**
+ * Build internal optimization units structure
+ */
+void co_build_ou_structure(copy_opt_t *co);
+
+/**
+ * Frees the space used by the opt unit representation.
+ * Does NOT free the whole copyopt structure
+ */
+void co_free_ou_structure(copy_opt_t *co);
+
/**
* Solves the problem using a heuristic approach
*/
int co_solve_heuristic(copy_opt_t *co);
+/**
+ * Returns the maximal costs possible, i.e. the costs if all
+ * pairs would be assigned different registers.
+ */
+int co_get_max_copy_costs(const copy_opt_t *co);
+
+/**
+ * Returns the inevitable costs, i.e. the costs of
+ * all copy pairs which interfere.
+ */
+int co_get_inevit_copy_costs(const copy_opt_t *co);
+
+/**
+ * Returns the current costs the copies are causing.
+ * The result includes inevitable costs and the costs
+ * of the copies regarding the current register allocation
+ */
+int co_get_copy_costs(const copy_opt_t *co);
+
+/**
+ * Returns a lower bound for the costs of copies in this ou.
+ * The result includes inevitable costs and the costs of a
+ * minimal costs caused by the nodes of the ou.
+ */
+int co_get_lower_bound(const copy_opt_t *co);
+
+
+
+
+
+/**
+ * Constructs another internal representation of the affinity edges
+ */
+void co_build_graph_structure(copy_opt_t *co);
+
+/**
+ * Frees the space used by the graph representation.
+ * Does NOT free the whole copyopt structure
+ */
+void co_free_graph_structure(copy_opt_t *co);
+
/**
* Solves the problem using mixed integer programming
* @returns 1 iff solution state was optimal
*/
int co_solve_ilp2(copy_opt_t *co, double time_limit);
+/**
+ * Checks if a node is optimizable, viz. has somthing to do with coalescing.
+ * Uses the graph representation
+ */
+int co_gs_is_optimizable(copy_opt_t *co, ir_node *irn);
+
#endif
#ifndef _BECOPYOPT_T_H
#define _BECOPYOPT_T_H
+#include <obstack.h>
#include "list.h"
#include "bearch.h"
#include "bechordal_t.h"
#include "becopyopt.h"
-#define MIS_HEUR_TRIGGER 8
-
/**
* Data representing the problem of copy minimization.
*/
const arch_env_t *aenv;
ir_graph *irg;
char *name; /**< ProgName__IrgName__RegClassName */
+ cost_fct_t get_costs; /**< function ptr used to get costs for copies */
+ /** Representation as optimization units */
struct list_head units; /**< all units to optimize in specific order */
- cost_fct_t get_costs; /**< function ptr used to get costs for copies */
- struct obstack ob;
+
+ /** Representation in graph structure. Only build on demand */
+ struct obstack obst;
+ set *nodes;
};
-/**
- * A single unit of optimization. Lots of these form a copy-opt problem
- */
+/* Helpers */
+#define get_irn_col(co, irn) arch_register_get_index(arch_get_irn_register((co)->aenv, irn))
+#define set_irn_col(co, irn, col) arch_set_irn_register((co)->aenv, irn, arch_register_for_index((co)->cls, col))
+#define is_curr_reg_class(co, irn) (arch_get_irn_reg_class((co)->aenv, irn, -1) == (co)->cls)
+
+#define MIN(a,b) ((a<b)?(a):(b))
+#define MAX(a,b) ((a<b)?(b):(a))
+
+#define list_entry_units(lh) list_entry(lh, unit_t, units)
+
+#define is_Reg_Phi(irn) (is_Phi(irn) && mode_is_data(get_irn_mode(irn)))
+
+#define get_Perm_src(irn) (get_irn_n(get_Proj_pred(irn), get_Proj_proj(irn)))
+#define is_Perm(arch_env, irn) (arch_irn_classify(arch_env, irn) == arch_irn_class_perm)
+#define is_Perm_Proj(arch_env, irn) (is_Proj(irn) && is_Perm(arch_env, get_Proj_pred(irn)))
+
+#define is_2addr_code(arch_env, irn, req) (arch_get_register_req(arch_env, req, irn, -1)->type == arch_register_req_type_should_be_same)
+
+
+/******************************************************************************
+ ____ _ _ _ _ _ _____ _
+ / __ \ | | | | | | (_) | / ____| |
+ | | | |_ __ | |_| | | |_ __ _| |_ ___ | (___ | |_ ___ _ __ __ _ __ _ ___
+ | | | | '_ \| __| | | | '_ \| | __/ __| \___ \| __/ _ \| '__/ _` |/ _` |/ _ \
+ | |__| | |_) | |_| |__| | | | | | |_\__ \ ____) | || (_) | | | (_| | (_| | __/
+ \____/| .__/ \__|\____/|_| |_|_|\__|___/ |_____/ \__\___/|_| \__,_|\__, |\___|
+ | | __/ |
+ |_| |___/
+ ******************************************************************************/
+
+#define MIS_HEUR_TRIGGER 8
+
typedef struct _unit_t {
struct list_head units; /**< chain for all units */
copy_opt_t *co; /**< the copy_opt this unit belongs to */
struct list_head queue; /**< list of qn's sorted by weight of qn-mis */
} unit_t;
-/* Helpers */
-#define get_irn_col(co, irn) arch_register_get_index(arch_get_irn_register((co)->aenv, irn))
-#define set_irn_col(co, irn, col) arch_set_irn_register((co)->aenv, irn, arch_register_for_index((co)->cls, col))
-#define is_curr_reg_class(co, irn) (arch_get_irn_reg_class((co)->aenv, irn, -1) == (co)->cls)
-
-#define MIN(a,b) ((a<b)?(a):(b))
-#define MAX(a,b) ((a<b)?(b):(a))
-
-#define list_entry_units(lh) list_entry(lh, unit_t, units)
-
-#define get_Copy_src(irn) (get_irn_n(get_Proj_pred(irn), get_Proj_proj(irn)))
-#define is_Perm(arch_env, irn) (arch_irn_classify(arch_env, irn) == arch_irn_class_perm)
-#define is_Reg_Phi(irn) (is_Phi(irn) && mode_is_data(get_irn_mode(irn)))
-#define is_Perm_Proj(arch_env, irn) (is_Proj(irn) && is_Perm(arch_env, get_Proj_pred(irn)))
-#define is_2addr_code(arch_env, irn, req) (arch_get_register_req(arch_env, req, irn, -1)->type == arch_register_req_type_should_be_same)
-/**
- * Checks if a node is optimizable, viz. has somthing to do with coalescing
- * @param arch The architecture environment
- * @param irn The irn to check
- * @param req A register_requirement structure (used to check for 2-addr-code)
- */
-#define co_is_optimizable(arch, irn, req) (!arch_irn_is_ignore(arch, irn) && (is_Reg_Phi(irn) || is_Perm_Proj(arch, irn) || is_2addr_code(arch, irn, req)))
-/**
- * Checks if the irn is a non-interfering argument of a node which 'is_optimizable'
- */
-int co_is_optimizable_arg(const copy_opt_t *co, ir_node *irn);
-
-/**
- * Returns the maximal costs possible, i.e. the costs if all
- * pairs would be assigned different registers.
- */
-int co_get_max_copy_costs(const copy_opt_t *co);
+/******************************************************************************
+ _____ _ _____ _
+ / ____| | | / ____| |
+ | | __ _ __ __ _ _ __ | |__ | (___ | |_ ___ _ __ __ _ __ _ ___
+ | | |_ | '__/ _` | '_ \| '_ \ \___ \| __/ _ \| '__/ _` |/ _` |/ _ \
+ | |__| | | | (_| | |_) | | | | ____) | || (_) | | | (_| | (_| | __/
+ \_____|_| \__,_| .__/|_| |_| |_____/ \__\___/|_| \__,_|\__, |\___|
+ | | __/ |
+ |_| |___/
+ ******************************************************************************/
-/**
- * Returns the inevitable costs, i.e. the costs of
- * all copy pairs which interfere.
- */
-int co_get_inevit_copy_costs(const copy_opt_t *co);
+typedef struct _neighb_t neighb_t;
-/**
- * Returns the current costs the copies are causing.
- * The result includes inevitable costs and the costs
- * of the copies regarding the current register allocation
- */
-int co_get_copy_costs(const copy_opt_t *co);
+struct _neighb_t {
+ neighb_t *next; /** the next neighbour entry*/
+ ir_node *irn; /** the neighbour itself */
+ int costs; /** the costs of the edge (node_t->irn, neighb_t->irn) */
+};
-/**
- * Returns a lower bound for the costs of copies in this ou.
- * The result includes inevitable costs and the costs of a
- * minimal costs caused by the nodes of the ou.
- */
-int co_get_lower_bound(const copy_opt_t *co);
+typedef struct _node_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 */
+} node_t;
#endif
#ifdef COPYOPT_STAT
+#define DO_HEUR
+#undef DO_ILP1
+#define DO_ILP2
+
#define DEBUG_LVL SET_LEVEL_1
static firm_dbg_module_t *dbg = NULL;
static void stat_copy_node(be_chordal_env_t *chordal_env, ir_node *root) {
curr_vals[I_CPY_CNT]++;
curr_vals[I_COPIES_MAX]++;
- if (nodes_interfere(chordal_env, root, get_Copy_src(root))) {
+ if (nodes_interfere(chordal_env, root, get_Perm_src(root))) {
curr_vals[I_COPIES_IF]++;
assert(0 && "A Perm pair (in/out) should never interfere!");
}
color_save_t saver;
int costs_inevit, costs_init, costs_heur, costs_ilp1, costs_ilp2, lower_bound;
+ phi_class_compute(chordal_env->irg);
+
co = new_copy_opt(chordal_env, co_get_costs_loop_depth);
+ co_build_ou_structure(co);
+ co_build_graph_structure(co);
DBG((dbg, LEVEL_1, "----> CO: %s\n", co->name));
- phi_class_compute(chordal_env->irg);
/* save colors */
saver.arch_env = chordal_env->birg->main_env->arch_env;
#endif /* DO_ILP2 */
pmap_destroy(saver.saved_colors);
+ co_free_graph_structure(co);
+ co_free_ou_structure(co);
free_copy_opt(co);
}
#ifdef COPYOPT_STAT
-#define DO_HEUR
-#define DO_ILP1
-#define DO_ILP2
-
#include "irgraph.h"
#include "bearch.h"
#include "bechordal_t.h"