Commit cf1b80f0 authored by Daniel Grund's avatar Daniel Grund
Browse files

Changed many things in copy opt. 1st part of refactoring.

parent ce7d5bb2
......@@ -23,8 +23,9 @@
#include <malloc.h>
#endif
#include "debug.h"
#include "xmalloc.h"
#include "becopyopt.h"
#include "becopyopt_t.h"
#include "becopystat.h"
#include "bitset.h"
#include "bearch.h"
......@@ -104,7 +105,7 @@ static INLINE void qnode_add_conflict(const qnode_t *qn, const ir_node *n1, cons
static INLINE int qnode_are_conflicting(const qnode_t *qn, const ir_node *n1, const ir_node *n2) {
conflict_t c;
/* search for live range interference */
if (n1!=n2 && nodes_interfere(qn->ou->co->chordal_env, n1, n2))
if (n1!=n2 && nodes_interfere(qn->ou->co->cenv, n1, n2))
return 1;
/* search for recoloring conflicts */
if ((int)n1 < (int)n2) {
......@@ -213,9 +214,10 @@ static INLINE void qnode_pin_local(const qnode_t *qn, ir_node *irn) {
*
*/
static ir_node *qnode_color_irn(const qnode_t *qn, ir_node *irn, int col, const ir_node *trigger) {
const be_chordal_env_t *chordal_env = qn->ou->co->chordal_env;
const arch_register_class_t *cls = chordal_env->cls;
const arch_env_t *arch_env = chordal_env->main_env->arch_env;
copy_opt_t *co = qn->ou->co;
const be_chordal_env_t *chordal_env = co->cenv;
const arch_register_class_t *cls = co->cls;
const arch_env_t *arch_env = co->aenv;
int irn_col = qnode_get_new_color(qn, irn);
ir_node *sub_res, *curr;
be_ifg_t *ifg = chordal_env->ifg;
......@@ -507,8 +509,8 @@ static INLINE void ou_insert_qnode(unit_t *ou, qnode_t *qn) {
static void ou_optimize(unit_t *ou) {
int i;
qnode_t *curr = NULL, *tmp;
arch_env_t *aenv = get_arch_env(ou->co);
const arch_register_class_t *cls = ou->co->chordal_env->cls;
const arch_env_t *aenv = ou->co->aenv;
const arch_register_class_t *cls = ou->co->cls;
bitset_t *pos_regs = bitset_alloca(cls->n_regs);
bitset_t *ign_regs = bitset_alloca(cls->n_regs);
......@@ -576,7 +578,7 @@ static void ou_optimize(unit_t *ou) {
free_qnode(curr);
}
void co_heur_opt(copy_opt_t *co) {
int co_solve_heuristic(copy_opt_t *co) {
unit_t *curr;
dbg = firm_dbg_register("ir.be.copyoptheur");
......@@ -586,4 +588,6 @@ void co_heur_opt(copy_opt_t *co) {
ou_optimize(curr);
del_pset(pinned_global);
return 0;
}
This diff is collapsed.
This diff is collapsed.
/**
* Author: Daniel Grund
* Date: 28.02.2006
* 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
* - Path constraints
* - Clique path constraints
*
*
* \min \sum_{ (i,j) \in Q } w_ij y_ij
*
* y_ij = 1 (i,j) \in E
*
* \sum_c y_nc = |C| - 1 n \in N, c \in C
*
* y_nc = 1 n \in N, c \not\in C(n)
*
* \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
*
* y_ij \in N, w_ij \in R^+
*/
#include "becopyilp_t.h"
int co_solve_ilp2(copy_opt_t *co, double time_limit) {
int res = 1;
return res;
}
/**
* Author: Daniel Grund
* Date: 28.02.2006
* Copyright: (c) Universitaet Karlsruhe
* Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
*
* Common stuff used by all ILP fomulations.
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_ALLOCA_H
#include <alloca.h>
#endif
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
#include <lpp/lpp.h>
#include <lpp/lpp_net.h>
#include <lpp/lpp_cplex.h>
#include <lpp/lpp_remote.h>
#include "xmalloc.h"
#include "pset.h"
#include "irprog.h"
#include "irdom_t.h"
#include "iredges_t.h"
#include "bechordal_t.h"
#include "becopyopt_t.h"
#include "becopystat.h"
#include "besched_t.h"
#include "phiclass.h"
#define LPP_HOST "i44pc52"
#define LPP_SOLVER "cplex"
#define MAX(a,b) ((a<b)?(b):(a))
#define MIN(a,b) ((a<b)?(a):(b))
#define EPSILON 0.00001
......@@ -14,31 +14,33 @@
#include <malloc.h>
#endif
#include <libcore/lc_timing.h>
#include "xmalloc.h"
#include "debug.h"
#include "pmap.h"
#include "irgraph.h"
#include "irgwalk.h"
#include "irprog.h"
#include "irloop_t.h"
#include "iredges_t.h"
#include "phiclass.h"
#include "xmalloc.h"
#include "bearch.h"
#include "beutil.h"
#include "bechordal_t.h"
#include "becopyopt.h"
#include "becopyopt_t.h"
#include "becopystat.h"
static firm_dbg_module_t *dbg = NULL;
#define is_curr_reg_class(irn) \
(arch_get_irn_reg_class(get_arch_env(co), \
irn, -1) == co->chordal_env->cls)
#define MIN(a,b) ((a<b)?(a):(b))
#define MAX(a,b) ((a<b)?(b):(a))
static firm_dbg_module_t *dbg = NULL;
/**
* Determines a maximum weighted independent set with respect to
* the interference and conflict edges of all nodes in a qnode.
*/
static int ou_max_ind_set_costs(unit_t *ou) {
be_chordal_env_t *chordal_env = ou->co->chordal_env;
be_chordal_env_t *chordal_env = ou->co->cenv;
ir_node **safe, **unsafe;
int i, o, safe_count, safe_costs, unsafe_count, *unsafe_costs;
bitset_t *curr;
......@@ -124,11 +126,10 @@ static void co_collect_units(ir_node *irn, void *env) {
copy_opt_t *co = env;
unit_t *unit;
arch_register_req_t req;
arch_env_t *aenv = co->chordal_env->main_env->arch_env;
if (!is_curr_reg_class(irn))
if (!is_curr_reg_class(co, irn))
return;
if (!is_optimizable(get_arch_env(co), irn, &req))
if (!co_is_optimizable(co->aenv, irn, &req))
return;
/* Init a new unit */
......@@ -152,10 +153,10 @@ static void co_collect_units(ir_node *irn, void *env) {
int o, arg_pos;
ir_node *arg = get_irn_n(irn, i);
assert(is_curr_reg_class(arg) && "Argument not in same register class.");
assert(is_curr_reg_class(co, arg) && "Argument not in same register class.");
if (arg == irn)
continue;
if (nodes_interfere(co->chordal_env, irn, arg)) {
if (nodes_interfere(co->cenv, irn, arg)) {
unit->inevitable_costs += co->get_costs(irn, arg, i);
continue;
}
......@@ -186,8 +187,8 @@ static void co_collect_units(ir_node *irn, void *env) {
} else
/* Proj of a perm with corresponding arg */
if (is_Perm_Proj(get_arch_env(co), irn)) {
assert(!nodes_interfere(co->chordal_env, irn, get_Copy_src(irn)));
if (is_Perm_Proj(co->aenv, irn)) {
assert(!nodes_interfere(co->cenv, irn, get_Copy_src(irn)));
unit->nodes = xmalloc(2 * sizeof(*unit->nodes));
unit->costs = xmalloc(2 * sizeof(*unit->costs));
unit->node_count = 2;
......@@ -197,9 +198,9 @@ static void co_collect_units(ir_node *irn, void *env) {
} else
/* Src == Tgt of a 2-addr-code instruction */
if (is_2addr_code(get_arch_env(co), irn, &req)) {
if (is_2addr_code(co->aenv, irn, &req)) {
ir_node *other = req.other_same;
if (!nodes_interfere(co->chordal_env, irn, other)) {
if (!nodes_interfere(co->cenv, irn, other)) {
unit->nodes = xmalloc(2 * sizeof(*unit->nodes));
unit->costs = xmalloc(2 * sizeof(*unit->costs));
unit->node_count = 2;
......@@ -234,6 +235,10 @@ static void co_collect_units(ir_node *irn, void *env) {
}
}
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;
......@@ -242,11 +247,14 @@ copy_opt_t *new_copy_opt(be_chordal_env_t *chordal_env, int (*get_costs)(ir_node
dbg = firm_dbg_register("ir.be.copyopt");
co = xcalloc(1, sizeof(*co));
co->chordal_env = chordal_env;
co->cenv = chordal_env;
co->aenv = chordal_env->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(get_irg(co)));
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);
......@@ -254,7 +262,7 @@ copy_opt_t *new_copy_opt(be_chordal_env_t *chordal_env, int (*get_costs)(ir_node
DBG((dbg, LEVEL_1, "\tCollecting optimization units\n"));
INIT_LIST_HEAD(&co->units);
irg_walk_graph(get_irg(co), co_collect_units, NULL, co);
irg_walk_graph(co->irg, co_collect_units, NULL, co);
return co;
}
......@@ -269,21 +277,20 @@ void free_copy_opt(copy_opt_t *co) {
}
int is_optimizable_arg(const copy_opt_t *co, ir_node *irn) {
arch_env_t *aenv = get_arch_env(co);
const ir_edge_t *edge;
if (arch_irn_is_ignore(aenv, irn))
if (arch_irn_is_ignore(co->aenv, irn))
return 0;
foreach_out_edge(irn, edge) {
ir_node *n = edge->src;
if (!nodes_interfere(co->chordal_env, irn, n) || irn == n) {
if (!nodes_interfere(co->cenv, irn, n) || irn == n) {
arch_register_req_t req;
arch_get_register_req(aenv, &req, n, -1);
arch_get_register_req(co->aenv, &req, n, -1);
if(is_Reg_Phi(n) ||
is_Perm(aenv, n) ||
is_Perm(co->aenv, n) ||
(arch_register_req_is(&req, should_be_same) && req.other_same == irn)
)
return 1;
......@@ -363,3 +370,155 @@ int co_get_lower_bound(const copy_opt_t *co) {
res += curr->inevitable_costs + curr->min_nodes_costs;
return res;
}
#define DO_HEUR
#undef DO_CLASSES
#undef DO_ILP
/**
* Helpers for saving and restoring colors of nodes.
* Used to get dependable and comparable benchmark results.
*/
#if (defined(DO_HEUR) && defined(DO_BETTER)) || (defined(DO_HEUR) && defined(DO_ILP)) || (defined(DO_BETTER) && defined(DO_ILP))
typedef struct color_saver {
arch_env_t *arch_env;
be_chordal_env_t *chordal_env;
pmap *saved_colors;
int flag; /* 0 save, 1 load */
} color_save_t;
static void save_load(ir_node *irn, void *env) {
color_save_t *saver = env;
if (saver->chordal_env->cls == arch_get_irn_reg_class(saver->arch_env, irn, -1)) {
if (saver->flag == 0) { /* save */
const arch_register_t *reg = arch_get_irn_register(saver->arch_env, irn);
pmap_insert(saver->saved_colors, irn, (void *) reg);
} else { /*load */
arch_register_t *reg = pmap_get(saver->saved_colors, irn);
arch_set_irn_register(saver->arch_env, irn, reg);
}
}
}
static void save_colors(color_save_t *color_saver) {
color_saver->flag = 0;
irg_walk_graph(color_saver->chordal_env->irg, save_load, NULL, color_saver);
}
static void load_colors(color_save_t *color_saver) {
color_saver->flag = 1;
irg_walk_graph(color_saver->chordal_env->irg, save_load, NULL, color_saver);
}
#endif /* Need save/load stuff */
void co_compare_solvers(be_chordal_env_t *chordal_env) {
copy_opt_t *co;
#ifdef DO_STAT
lc_timer_t *timer;
color_save_t saver;
int costs, costs_inevit, costs_init, costs_heur, costs_classes, costs_ilp, lower_bound;
#endif
co = new_copy_opt(chordal_env, get_costs_loop_depth);
DBG((dbg, LEVEL_1, "----> CO: %s\n", co->name));
phi_class_compute(chordal_env->irg);
#ifdef DO_STAT
#if (defined(DO_HEUR) && defined(DO_BETTER)) || (defined(DO_HEUR) && defined(DO_ILP)) || (defined(DO_BETTER) && defined(DO_ILP))
saver.arch_env = chordal_env->main_env->arch_env;
saver.chordal_env = chordal_env;
saver.saved_colors = pmap_create();
save_colors(&saver);
#endif
costs_inevit = co_get_inevit_copy_costs(co);
lower_bound = co_get_lower_bound(co);
costs_init = co_get_copy_costs(co);
DBG((dbg, LEVEL_1, "Inevit Costs: %3d\n", costs_inevit));
DBG((dbg, LEVEL_1, "Lower Bound: %3d\n", lower_bound));
DBG((dbg, LEVEL_1, "Init costs: %3d\n", costs_init));
copystat_add_inevit_costs(costs_inevit);
copystat_add_init_costs(costs_init);
copystat_add_max_costs(co_get_max_copy_costs(co));
#endif
#ifdef DO_HEUR
#ifdef DO_STAT
timer = lc_timer_register("heur", NULL);
lc_timer_reset_and_start(timer);
#endif
co_solve_heuristic(co);
#ifdef DO_STAT
lc_timer_stop(timer);
costs_heur = co_get_copy_costs(co);
DBG((dbg, LEVEL_1, "Heur costs: %3d\n", costs_heur));
copystat_add_heur_time(lc_timer_elapsed_msec(timer));
copystat_add_heur_costs(costs_heur);
assert(lower_bound <= costs_heur);
#endif
#endif /* DO_HEUR */
#ifdef DO_CLASSES
#ifdef DO_STAT
#ifdef DO_HEUR
load_colors(&saver);
#endif
timer = lc_timer_register("classes", NULL);
lc_timer_reset_and_start(timer);
#endif
co_classes_opt(co);
#ifdef DO_STAT
lc_timer_stop(timer);
costs_classes = co_get_copy_costs(co);
DBG((dbg, LEVEL_1, "Classes costs: %3d\n", costs_classes));
copystat_add_classes_time(lc_timer_elapsed_msec(timer));
copystat_add_classes_costs(costs_heur);
assert(lower_bound <= costs_classes);
#endif
#endif /* DO_CLASSES */
#ifdef DO_ILP
#ifdef DO_STAT
#if defined(DO_HEUR) || defined(DO_CLASSES)
load_colors(&saver);
#endif
#endif
co_solve_ilp1(co, 60.0);
#ifdef DO_STAT
costs_ilp = co_get_copy_costs(co);
DBG((dbg, LEVEL_1, "Opt costs: %3d\n", costs_ilp));
copystat_add_opt_costs(costs_ilp);
assert(lower_bound <= costs_ilp);
#endif
#endif /* DO_ILP */
#ifdef DO_STAT
#if (defined(DO_HEUR) && defined(DO_BETTER)) || (defined(DO_HEUR) && defined(DO_ILP)) || (defined(DO_BETTER) && defined(DO_ILP))
pmap_destroy(saver.saved_colors);
#endif
#endif
free_copy_opt(co);
}
/**
* Author: Daniel Grund
* Date: 12.04.2005
* Date: 11.04.2005
* Copyright: (c) Universitaet Karlsruhe
* Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
*
* Header for copy optimization problem. Analysis and set up of the problem.
* Main file for the optimization reducing the copies needed for:
* - Phi coalescing
* - Register-constrained nodes
* - Two-address code instructions
*/
#ifndef _BECOPYOPT_H
#define _BECOPYOPT_H
#include "debug.h"
#include "obst.h"
#include "list.h"
#include "set.h"
#include "pset.h"
#include "bitset.h"
#include "irgraph.h"
#include "irgwalk.h"
#include "irnode.h"
#include "irdom.h"
#include "irouts.h"
#include "beutil.h"
#include "benumb_t.h"
#include "belive_t.h"
#include "bechordal_t.h"
#include "bearch.h"
#include "bechordal.h"
#define MIS_HEUR_TRIGGER 8
typedef int(*cost_fct_t)(ir_node*, ir_node*, int);
/**
* Data representing the problem of copy minimization.
*/
typedef struct _copy_opt_t {
be_chordal_env_t *chordal_env;
char *name; /**< ProgName__IrgName__RegClass */
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;
} copy_opt_t;
typedef struct _copy_opt_t copy_opt_t;
/**
* A single unit of optimization. Lots of these form a copy-opt problem
* Has to be called during the firm init phase
*/
typedef struct _unit_t {
struct list_head units; /**< chain for all units */
copy_opt_t *co; /**< the copy_opt this unit belongs to */
int node_count; /**< size of the nodes array */
ir_node **nodes; /**< [0] is the root-node, others are non interfering args of it. */
int *costs; /**< costs[i] are arising, if nodes[i] has a different color */
int inevitable_costs; /**< sum of costs of all args interfering with root */
int all_nodes_costs; /**< sum of all costs[i] */
int min_nodes_costs; /**< a lower bound for the costs in costs[], determined by a max indep. set */
int sort_key; /**< maximum costs. controls the order of ou's in the struct list_head units. */
/* for heuristic */
struct list_head queue; /**< list of qn's sorted by weight of qn-mis */
} unit_t;
/* Helpers */
#define get_arch_env(co) ((co)->chordal_env->main_env->arch_env)
#define get_irg(co) ((co)->chordal_env->irg)
#define get_irn_col(co, irn) \
arch_register_get_index(arch_get_irn_register(get_arch_env(co), irn))
#define set_irn_col(co, irn, col) \
arch_set_irn_register(get_arch_env(co), irn, arch_register_for_index(co->chordal_env->cls, col))
#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)
void be_copy_opt_init(void);
/**
* Generate the problem. Collect all infos and optimizable nodes.
* Generate the problem. Collect all information and optimizable nodes.
*/
copy_opt_t *new_copy_opt(be_chordal_env_t *chordal_env, int (*get_costs)(ir_node*, ir_node*, int));
copy_opt_t *new_copy_opt(be_chordal_env_t *chordal_env, cost_fct_t get_costs);
/**
* Free the space...
* Free the space used...
*/
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)
*/
#define 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 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
* @return Must be >= 0 in all cases.
*/
int get_costs_loop_depth(ir_node *root, ir_node* arg, int pos);
int co_get_costs_loop_depth(ir_node *root, ir_node* arg, int pos);
/**
* All costs equal 1. Using this will reduce the number of copies.
* @return Must be >= 0 in all cases.
*/
int get_costs_all_one(ir_node *root, ir_node* arg, int pos);
/**
* 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);
int co_get_costs_all_one(ir_node *root, ir_node* arg, int pos);
/**
* 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
* Solves the problem using a heuristic approach
*/
int co_get_copy_costs(const copy_opt_t *co);
int co_solve_heuristic(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.
* Solves the problem using mixed integer programming
* @returns 1 iff solution state was optimal
*/
int co_get_lower_bound(const copy_opt_t *co);
int co_solve_ilp1(copy_opt_t *co, double time_limit);
/**
* Solves the problem using a heuristic approach
* Solves the problem using mixed integer programming
* @returns 1 iff solution state was optimal
*/
void co_heur_opt(copy_opt_t *co);
int co_solve_ilp2(copy_opt_t *co, double time_limit);
/**
* Solves the problem using mixed integer programming
* @returns 1 iff solution state was optimal
* Compares different solutions of the same problem
*/
int co_ilp_opt(copy_opt_t *co, double time_limit);
void co_compare_solvers(be_chordal_env_t *chordal_env);