X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;ds=sidebyside;f=ir%2Fbe%2Fbecopyopt.c;h=1b9ccd4a7eba2a2666ba3729b0bd2ebaab44ab0c;hb=8535fe8732b0acf822be252812a7158ce5b8134a;hp=0bf32f14860da5a4f74b67317fb37557cb383e16;hpb=48f893878b07f6e334389ff52abda5cc2adbf179;p=libfirm diff --git a/ir/be/becopyopt.c b/ir/be/becopyopt.c index 0bf32f148..1b9ccd4a7 100644 --- a/ir/be/becopyopt.c +++ b/ir/be/becopyopt.c @@ -5,8 +5,9 @@ * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE. */ #ifdef HAVE_CONFIG_H -#include "config.h" +#include #endif + #ifdef HAVE_ALLOCA_H #include #endif @@ -18,6 +19,7 @@ #include "xmalloc.h" #include "debug.h" #include "pmap.h" +#include "raw_bitset.h" #include "irgraph.h" #include "irgwalk.h" #include "irprog.h" @@ -26,7 +28,9 @@ #include "phiclass.h" #include "irbitset.h" #include "irphase_t.h" +#include "irprintf_t.h" +#include "bemodule.h" #include "bearch.h" #include "benode_t.h" #include "beutil.h" @@ -36,23 +40,125 @@ #include "belive_t.h" #include "beinsn_t.h" #include "besched_t.h" - -#ifdef WITH_LIBCORE +#include "benodesets.h" +#include "bejavacoal.h" +#include "bestatevent.h" +#include "beirg_t.h" +#include "error.h" + +#include +#include +#include + +#define DUMP_BEFORE 1 +#define DUMP_AFTER 2 +#define DUMP_APPEL 4 +#define DUMP_ALL 2 * DUMP_APPEL - 1 + +#define COST_FUNC_FREQ 1 +#define COST_FUNC_LOOP 2 +#define COST_FUNC_ALL_ONE 3 + +static unsigned dump_flags = 0; +static unsigned style_flags = 0; +static unsigned do_stats = 0; +static cost_fct_t cost_func = co_get_costs_exec_freq; +static unsigned algo = CO_ALGO_HEUR2; +static int improve = 1; + +static const lc_opt_enum_mask_items_t dump_items[] = { + { "before", DUMP_BEFORE }, + { "after", DUMP_AFTER }, + { "appel", DUMP_APPEL }, + { "all", DUMP_ALL }, + { NULL, 0 } +}; + +static const lc_opt_enum_mask_items_t style_items[] = { + { "color", CO_IFG_DUMP_COLORS }, + { "labels", CO_IFG_DUMP_LABELS }, + { "constr", CO_IFG_DUMP_CONSTR }, + { "shape", CO_IFG_DUMP_SHAPE }, + { "full", 2 * CO_IFG_DUMP_SHAPE - 1 }, + { NULL, 0 } +}; + +static const lc_opt_enum_mask_items_t algo_items[] = { + { "none", CO_ALGO_NONE }, + { "heur", CO_ALGO_HEUR }, + { "heur2", CO_ALGO_HEUR2 }, +#ifdef WITH_JVM + { "heur3", CO_ALGO_HEUR3 }, +#endif /* WITH_JVM */ +#ifdef WITH_ILP + { "ilp", CO_ALGO_ILP }, +#endif /* WITH_ILP */ + { NULL, 0 } +}; + +typedef int (*opt_funcptr)(void); + +static const lc_opt_enum_func_ptr_items_t cost_func_items[] = { + { "freq", (opt_funcptr) co_get_costs_exec_freq }, + { "loop", (opt_funcptr) co_get_costs_loop_depth }, + { "one", (opt_funcptr) co_get_costs_all_one }, + { NULL, NULL } +}; + +static lc_opt_enum_mask_var_t dump_var = { + &dump_flags, dump_items +}; + +static lc_opt_enum_mask_var_t style_var = { + &style_flags, style_items +}; + +static lc_opt_enum_mask_var_t algo_var = { + &algo, algo_items +}; + +static lc_opt_enum_func_ptr_var_t cost_func_var = { + (opt_funcptr*) &cost_func, cost_func_items +}; + +static const lc_opt_table_entry_t options[] = { + LC_OPT_ENT_ENUM_INT ("algo", "select copy optimization algo", &algo_var), + LC_OPT_ENT_ENUM_FUNC_PTR ("cost", "select a cost function", &cost_func_var), + LC_OPT_ENT_ENUM_MASK ("dump", "dump ifg before or after copy optimization", &dump_var), + LC_OPT_ENT_ENUM_MASK ("style", "dump style for ifg dumping", &style_var), + LC_OPT_ENT_BOOL ("stats", "dump statistics after each optimization", &do_stats), + LC_OPT_ENT_BOOL ("improve", "run heur3 before if algo can exploit start solutions", &improve), + { NULL } +}; /* Insert additional options registration functions here. */ +extern void be_co_ilp_register_options(lc_opt_entry_t *grp); extern void be_co2_register_options(lc_opt_entry_t *grp); extern void be_co3_register_options(lc_opt_entry_t *grp); -void co_register_options(lc_opt_entry_t *grp) +void be_init_copycoal(void) { - be_co2_register_options(grp); - be_co3_register_options(grp); + lc_opt_entry_t *be_grp = lc_opt_get_grp(firm_opt_get_root(), "be"); + lc_opt_entry_t *ra_grp = lc_opt_get_grp(be_grp, "ra"); + lc_opt_entry_t *chordal_grp = lc_opt_get_grp(ra_grp, "chordal"); + lc_opt_entry_t *co_grp = lc_opt_get_grp(chordal_grp, "co"); + + lc_opt_add_table(co_grp, options); } -#endif +BE_REGISTER_MODULE_CONSTRUCTOR(be_init_copycoal); #undef QUICK_AND_DIRTY_HACK +static int nodes_interfere(const be_chordal_env_t *env, const ir_node *a, const ir_node *b) +{ + if(env->ifg) + return be_ifg_connected(env->ifg, a, b); + else + return values_interfere(env->birg->lv, a, b); +} + + /****************************************************************************** _____ _ / ____| | | @@ -65,8 +171,6 @@ void co_register_options(lc_opt_entry_t *grp) DEBUG_ONLY(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, cost_fct_t get_costs) { @@ -99,7 +203,7 @@ void free_copy_opt(copy_opt_t *co) { } int co_is_optimizable_root(const copy_opt_t *co, ir_node *irn) { - arch_register_req_t req; + const arch_register_req_t *req; const arch_register_t *reg; if (arch_irn_is(co->aenv, irn, ignore)) @@ -109,7 +213,8 @@ int co_is_optimizable_root(const copy_opt_t *co, ir_node *irn) { if (arch_register_type_is(reg, ignore)) return 0; - if (is_Reg_Phi(irn) || is_Perm_Proj(co->aenv, irn) || is_2addr_code(co->aenv, irn, &req)) + req = arch_get_register_req(co->aenv, irn, -1); + if (is_Reg_Phi(irn) || is_Perm_Proj(co->aenv, irn) || is_2addr_code(req)) return 1; return 0; @@ -132,14 +237,16 @@ int co_is_optimizable_arg(const copy_opt_t *co, ir_node *irn) { 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); + const arch_register_req_t *req; + req = arch_get_register_req(co->aenv, 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; + (arch_register_req_is(req, should_be_same))) { + ir_node *other = get_irn_n(irn, req->other_same); + if(other == irn) + return 1; + } } } @@ -162,18 +269,21 @@ int co_get_costs_loop_depth(const copy_opt_t *co, ir_node *root, ir_node* arg, i int d = get_loop_depth(loop); cost = d*d; } - return cost+1; + return 1+cost; } int co_get_costs_exec_freq(const copy_opt_t *co, ir_node *root, ir_node* arg, int pos) { + int res; ir_node *root_bl = get_nodes_block(root); ir_node *copy_bl = is_Phi(root) ? get_Block_cfgpred_block(root_bl, pos) : root_bl; - unsigned long freq = get_block_execfreq_ulong(co->cenv->exec_freq, copy_bl); - return freq > 0 ? (int) freq : 1; + res = get_block_execfreq_ulong(co->cenv->birg->exec_freq, copy_bl); + + /* don't allow values smaller than one. */ + return res < 1 ? 1 : res; } -int co_get_costs_all_one(const copy_opt_t *co, ir_node *root, ir_node* arg, int pos) { +int co_get_costs_all_one(const copy_opt_t *co, ir_node *root, ir_node *arg, int pos) { return 1; } @@ -278,7 +388,6 @@ static int ou_max_ind_set_costs(unit_t *ou) { static void co_collect_units(ir_node *irn, void *env) { copy_opt_t *co = env; unit_t *unit; - arch_register_req_t req; if (!is_curr_reg_class(co, irn)) return; @@ -348,21 +457,25 @@ static void co_collect_units(ir_node *irn, void *env) { unit->nodes[0] = irn; unit->nodes[1] = get_Perm_src(irn); unit->costs[1] = co->get_costs(co, irn, unit->nodes[1], -1); - } else - - /* Src == Tgt of a 2-addr-code instruction */ - if (is_2addr_code(co->aenv, irn, &req)) { - ir_node *other = req.other_same; - 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; - unit->nodes[0] = irn; - unit->nodes[1] = other; - unit->costs[1] = co->get_costs(co, irn, other, -1); + } else { + const arch_register_req_t *req = + arch_get_register_req(co->aenv, irn, -1); + + /* Src == Tgt of a 2-addr-code instruction */ + if (is_2addr_code(req)) { + ir_node *other = get_irn_n(irn, req->other_same); + 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; + unit->nodes[0] = irn; + unit->nodes[1] = other; + unit->costs[1] = co->get_costs(co, irn, other, -1); + } + } else { + assert(0 && "This is not an optimizable node!"); } - } else - assert(0 && "This is not an optimizable node!"); + } /* Insert the new unit at a position according to its costs */ if (unit->node_count > 1) { @@ -549,6 +662,40 @@ int co_get_lower_bound(const copy_opt_t *co) { return res; } +void co_complete_stats(const copy_opt_t *co, co_complete_stats_t *stat) +{ + bitset_t *seen = bitset_irg_malloc(co->irg); + affinity_node_t *an; + + memset(stat, 0, sizeof(stat[0])); + + /* count affinity edges. */ + co_gs_foreach_aff_node(co, an) { + neighb_t *neigh; + stat->aff_nodes += 1; + bitset_add_irn(seen, an->irn); + co_gs_foreach_neighb(an, neigh) { + if(!bitset_contains_irn(seen, neigh->irn)) { + stat->aff_edges += 1; + stat->max_costs += neigh->costs; + + if(get_irn_col(co, an->irn) != get_irn_col(co, neigh->irn)) { + stat->costs += neigh->costs; + stat->unsatisfied_edges += 1; + } + + if(nodes_interfere(co->cenv, an->irn, neigh->irn)) { + stat->aff_int += 1; + stat->inevit_costs += neigh->costs; + } + + } + } + } + + bitset_free(seen); +} + /****************************************************************************** _____ _ _____ _ / ____| | | / ____| | @@ -575,7 +722,7 @@ static void add_edge(copy_opt_t *co, ir_node *n1, ir_node *n2, int costs) { new_node.irn = n1; new_node.degree = 0; new_node.neighbours = NULL; - node = set_insert(co->nodes, &new_node, sizeof(new_node), HASH_PTR(new_node.irn)); + node = set_insert(co->nodes, &new_node, sizeof(new_node), nodeset_hash(new_node.irn)); allocnew = 1; for (nbr = node->neighbours; nbr; nbr = nbr->next) @@ -609,7 +756,6 @@ static INLINE void add_edges(copy_opt_t *co, ir_node *n1, ir_node *n2, int costs static void build_graph_walker(ir_node *irn, void *env) { copy_opt_t *co = env; int pos, max; - arch_register_req_t req; const arch_register_t *reg; if (!is_curr_reg_class(co, irn) || arch_irn_is(co->aenv, irn, ignore)) @@ -633,8 +779,14 @@ static void build_graph_walker(ir_node *irn, void *env) { } /* 2-address code */ - else if (is_2addr_code(co->aenv, irn, &req)) - add_edges(co, irn, req.other_same, co->get_costs(co, irn, req.other_same, 0)); + else { + const arch_register_req_t *req = + arch_get_register_req(co->aenv, irn, -1); + if (is_2addr_code(req)) { + ir_node *other = get_irn_n(irn, req->other_same); + add_edges(co, irn, other, co->get_costs(co, irn, other, 0)); + } + } } void co_build_graph_structure(copy_opt_t *co) { @@ -660,7 +812,7 @@ int co_gs_is_optimizable(copy_opt_t *co, ir_node *irn) { ASSERT_GS_AVAIL(co); new_node.irn = irn; - n = set_find(co->nodes, &new_node, sizeof(new_node), HASH_PTR(new_node.irn)); + n = set_find(co->nodes, &new_node, sizeof(new_node), nodeset_hash(new_node.irn)); if (n) { return (n->degree > 0); } else @@ -671,7 +823,6 @@ void co_dump_appel_graph(const copy_opt_t *co, FILE *f) { be_ifg_t *ifg = co->cenv->ifg; int *color_map = alloca(co->cls->n_regs * sizeof(color_map[0])); - bitset_t *adm = bitset_alloca(co->cls->n_regs); ir_node *irn; void *it, *nit; @@ -704,17 +855,15 @@ void co_dump_appel_graph(const copy_opt_t *co, FILE *f) int idx = PTR_TO_INT(get_irn_link(irn)); affinity_node_t *a = get_affinity_info(co, irn); - arch_register_req_t req; + const arch_register_req_t *req; ir_node *adj; - arch_get_register_req(co->aenv, &req, irn, BE_OUT_POS(0)); - if(arch_register_req_is(&req, limited)) { - bitset_clear_all(adm); - req.limited(req.limited_env, adm); - for(i = 0; i < co->cls->n_regs; ++i) - if(!bitset_is_set(adm, i) && color_map[i] >= 0) + req = arch_get_register_req(co->aenv, irn, BE_OUT_POS(0)); + if(arch_register_req_is(req, limited)) { + for(i = 0; i < co->cls->n_regs; ++i) { + if(!rbitset_is_set(req->limited, i) && color_map[i] >= 0) fprintf(f, "%d %d -1\n", color_map[i], idx); - + } } @@ -733,7 +882,7 @@ void co_dump_appel_graph(const copy_opt_t *co, FILE *f) if(!arch_irn_is(co->aenv, n->irn, ignore)) { int n_idx = PTR_TO_INT(get_irn_link(n->irn)); if(idx < n_idx) - fprintf(f, "%d %d %d\n", idx, n_idx, n->costs); + fprintf(f, "%d %d %d\n", idx, n_idx, (int) n->costs); } } } @@ -866,6 +1015,7 @@ static void appel_walker(ir_node *bl, void *data) struct obstack *obst = &env->obst; void *base = obstack_base(obst); pset *live = pset_new_ptr_default(); + be_lv_t *lv = env->co->cenv->birg->lv; int n_insns = 0; int n_nodes = 0; @@ -899,7 +1049,7 @@ static void appel_walker(ir_node *bl, void *data) } DBG((env->co->cenv->dbg, LEVEL_2, "%+F\n", bl)); - be_liveness_end_of_block(env->co->cenv->lv, env->co->aenv, env->co->cls, bl, live); + be_liveness_end_of_block(lv, env->co->aenv, env->co->cls, bl, live); /* Generate the bad and ugly. */ for(i = n_insns - 1; i >= 0; --i) { @@ -993,7 +1143,6 @@ static void appel_inter_block_aff(ir_node *bl, void *data) for(j = 0, n = get_Block_n_cfgpreds(bl); j < n; ++j) { ir_node *pred = get_Block_cfgpred_block(bl, j); - appel_block_info_t *pred_bli = phase_get_irn_data(&env->ph, pred); int nr = appel_get_live_end_nr(env, pred, irn); assert(nr >= 0); @@ -1006,7 +1155,6 @@ static void appel_inter_block_aff(ir_node *bl, void *data) for(j = 0, n = get_Block_n_cfgpreds(bl); j < n; ++j) { ir_node *pred = get_Block_cfgpred_block(bl, j); - appel_block_info_t *pred_bli = phase_get_irn_data(&env->ph, pred); ir_node *op = get_irn_n(irn, j); int nr = appel_get_live_end_nr(env, pred, op); @@ -1023,8 +1171,9 @@ void co_dump_appel_graph_cliques(const copy_opt_t *co, FILE *f) int n_colors; appel_clique_walker_t env; bitset_t *adm = bitset_alloca(co->cls->n_regs); + be_lv_t *lv = co->cenv->birg->lv; - be_liveness_recompute(co->cenv->lv); + be_liveness_recompute(lv); obstack_init(&env.obst); phase_init(&env.ph, "appel_clique_dumper", co->irg, PHASE_DEFAULT_GROWTH, appel_clique_walker_irn_init); env.curr_nr = co->cls->n_regs; @@ -1064,8 +1213,306 @@ void co_dump_appel_graph_cliques(const copy_opt_t *co, FILE *f) obstack_free(&env.obst, NULL); } +/* + ___ _____ ____ ____ ___ _____ ____ _ + |_ _| ___/ ___| | _ \ / _ \_ _| | _ \ _ _ _ __ ___ _ __ (_)_ __ __ _ + | || |_ | | _ | | | | | | || | | | | | | | | '_ ` _ \| '_ \| | '_ \ / _` | + | || _|| |_| | | |_| | |_| || | | |_| | |_| | | | | | | |_) | | | | | (_| | + |___|_| \____| |____/ \___/ |_| |____/ \__,_|_| |_| |_| .__/|_|_| |_|\__, | + |_| |___/ +*/ + +static const char *get_dot_color_name(int col) +{ + static const char *names[] = { + "blue", + "red", + "green", + "yellow", + "cyan", + "magenta", + "orange", + "chocolate", + "beige", + "navy", + "darkgreen", + "darkred", + "lightPink", + "chartreuse", + "lightskyblue", + "linen", + "pink", + "lightslateblue", + "mintcream", + "red", + "darkolivegreen", + "mediumblue", + "mistyrose", + "salmon", + "darkseagreen", + "mediumslateblue" + "moccasin", + "tomato", + "forestgreen", + "darkturquoise", + "palevioletred" + }; + + return col < sizeof(names)/sizeof(names[0]) ? names[col] : "white"; +} + +typedef struct _co_ifg_dump_t { + const copy_opt_t *co; + unsigned flags; +} co_ifg_dump_t; + +static void ifg_dump_graph_attr(FILE *f, void *self) +{ + fprintf(f, "overlap=scale"); +} + +static int ifg_is_dump_node(void *self, ir_node *irn) +{ + co_ifg_dump_t *cod = self; + return !arch_irn_is(cod->co->aenv, irn, ignore); +} + +static void ifg_dump_node_attr(FILE *f, void *self, ir_node *irn) +{ + co_ifg_dump_t *env = self; + const arch_register_t *reg = arch_get_irn_register(env->co->aenv, irn); + const arch_register_req_t *req; + int limited; + + req = arch_get_register_req(env->co->aenv, irn, BE_OUT_POS(0)); + limited = arch_register_req_is(req, limited); + + if(env->flags & CO_IFG_DUMP_LABELS) { + ir_fprintf(f, "label=\"%+F", irn); + +#if 0 + // TODO fix this... + if((env->flags & CO_IFG_DUMP_CONSTR) && limited) { + bitset_t *bs = bitset_alloca(env->co->cls->n_regs); + req.limited(req.limited_env, bs); + ir_fprintf(f, "\\n%B", bs); + } +#endif + ir_fprintf(f, "\" "); + } else { + fprintf(f, "label=\"\" shape=point " ); + } + + if(env->flags & CO_IFG_DUMP_SHAPE) + fprintf(f, "shape=%s ", limited ? "diamond" : "ellipse"); + + if(env->flags & CO_IFG_DUMP_COLORS) + fprintf(f, "style=filled color=%s ", get_dot_color_name(reg->index)); +} + +static void ifg_dump_at_end(FILE *file, void *self) +{ + co_ifg_dump_t *env = self; + affinity_node_t *a; + + co_gs_foreach_aff_node(env->co, a) { + const arch_register_t *ar = arch_get_irn_register(env->co->aenv, a->irn); + unsigned aidx = get_irn_idx(a->irn); + neighb_t *n; + + co_gs_foreach_neighb(a, n) { + const arch_register_t *nr = arch_get_irn_register(env->co->aenv, n->irn); + unsigned nidx = get_irn_idx(n->irn); + + if(aidx < nidx) { + const char *color = nr == ar ? "blue" : "red"; + fprintf(file, "\tn%d -- n%d [weight=0.01 ", aidx, nidx); + if(env->flags & CO_IFG_DUMP_LABELS) + fprintf(file, "label=\"%d\" ", n->costs); + if(env->flags & CO_IFG_DUMP_COLORS) + fprintf(file, "color=%s ", color); + else + fprintf(file, "style=dotted"); + fprintf(file, "];\n"); + } + } + } +} + + +static be_ifg_dump_dot_cb_t ifg_dot_cb = { + ifg_is_dump_node, + ifg_dump_graph_attr, + ifg_dump_node_attr, + NULL, + NULL, + ifg_dump_at_end +}; + + + +void co_dump_ifg_dot(const copy_opt_t *co, FILE *f, unsigned flags) +{ + co_ifg_dump_t cod; + + cod.co = co; + cod.flags = flags; + be_ifg_dump_dot(co->cenv->ifg, co->irg, f, &ifg_dot_cb, &cod); +} + void co_solve_park_moon(copy_opt_t *opt) { } + +static int void_algo(copy_opt_t *co) +{ + return 0; +} + +/* + _ _ _ _ _ + / \ | | __ _ ___ _ __(_) |_| |__ _ __ ___ ___ + / _ \ | |/ _` |/ _ \| '__| | __| '_ \| '_ ` _ \/ __| + / ___ \| | (_| | (_) | | | | |_| | | | | | | | \__ \ + /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_|___/ + |___/ +*/ + +typedef struct { + co_algo_t *algo; + const char *name; + int can_improve_existing; +} co_algo_info_t; + +static co_algo_info_t algos[] = { + { void_algo, "none", 0 }, + { co_solve_heuristic, "heur1", 0 }, + { co_solve_heuristic_new, "heur2", 0 }, + { co_solve_heuristic_java, "heur3", 0 }, +#ifdef WITH_ILP + { co_solve_ilp2, "ilp", 1 }, +#endif + { NULL, "", 0 } +}; + +/* + __ __ _ ____ _ + | \/ | __ _(_)_ __ | _ \ _ __(_)_ _____ _ __ + | |\/| |/ _` | | '_ \ | | | | '__| \ \ / / _ \ '__| + | | | | (_| | | | | | | |_| | | | |\ V / __/ | + |_| |_|\__,_|_|_| |_| |____/|_| |_| \_/ \___|_| + +*/ + +static FILE *my_open(const be_chordal_env_t *env, const char *prefix, const char *suffix) +{ + FILE *result; + char buf[1024]; + + ir_snprintf(buf, sizeof(buf), "%s%F_%s%s", prefix, env->irg, env->cls->name, suffix); + result = fopen(buf, "wt"); + if(result == NULL) { + panic("Couldn't open '%s' for writing.", buf); + } + + return result; +} + +void co_driver(be_chordal_env_t *cenv) +{ + lc_timer_t *timer = lc_timer_register("firm.be.copyopt", "runtime"); + co_complete_stats_t before, after; + copy_opt_t *co; + co_algo_t *algo_func; + int was_optimal = 0; + + if(algo < 0 || algo >= CO_ALGO_LAST) + return; + + co = new_copy_opt(cenv, cost_func); + co_build_ou_structure(co); + co_build_graph_structure(co); + + co_complete_stats(co, &before); + + be_stat_ev_ull("co_aff_nodes", before.aff_nodes); + be_stat_ev_ull("co_aff_edges", before.aff_edges); + be_stat_ev_ull("co_max_costs", before.max_costs); + be_stat_ev_ull("co_inevit_costs", before.inevit_costs); + be_stat_ev_ull("co_aff_int", before.aff_int); + + be_stat_ev_ull("co_init_costs", before.costs); + be_stat_ev_ull("co_init_unsat", before.unsatisfied_edges); + + /* Dump the interference graph in Appel's format. */ + if(dump_flags & DUMP_APPEL) { + FILE *f = my_open(cenv, "", ".apl"); + co_dump_appel_graph(co, f); + fclose(f); + } + + if(dump_flags & DUMP_BEFORE) { + FILE *f = my_open(cenv, "", "-before.dot"); + co_dump_ifg_dot(co, f, style_flags); + fclose(f); + } + + /* if the algo can improve results, provide an initial solution with heur3 */ + if(improve && algos[algo].can_improve_existing) { + co_complete_stats_t stats; + + /* produce a heuristical solution */ + co_solve_heuristic_java(co); + + /* do the stats and provide the current costs */ + co_complete_stats(co, &stats); + be_stat_ev_ull("co_prepare_costs", stats.costs); + } + +#ifdef WITH_JVM + /* start the JVM here so that it does not tamper the timing. */ + if(algo == CO_ALGO_HEUR3) + be_java_coal_start_jvm(); +#endif + + algo_func = algos[algo].algo; + + lc_timer_reset_and_start(timer); + + was_optimal = algo_func(co); + + lc_timer_stop(timer); + be_stat_ev("co_time", lc_timer_elapsed_msec(timer)); + + be_stat_ev_ull("co_optimal", was_optimal); + + if(dump_flags & DUMP_AFTER) { + FILE *f = my_open(cenv, "", "-after.dot"); + co_dump_ifg_dot(co, f, style_flags); + fclose(f); + } + + co_complete_stats(co, &after); + + if(do_stats) { + ulong64 optimizable_costs = after.max_costs - after.inevit_costs; + ulong64 evitable = after.costs - after.inevit_costs; + + ir_printf("%30F ", cenv->irg); + printf("%10s %10" ULL_FMT "%10" ULL_FMT "%10" ULL_FMT, cenv->cls->name, after.max_costs, before.costs, after.inevit_costs); + + if(optimizable_costs > 0) + printf("%10" ULL_FMT " %5.2f\n", after.costs, (evitable * 100.0) / optimizable_costs); + else + printf("%10" ULL_FMT " %5s\n", after.costs, "-"); + } + + be_stat_ev_ull("co_after_costs", after.costs); + be_stat_ev_ull("co_after_unsat", after.unsatisfied_edges); + + co_free_graph_structure(co); + co_free_ou_structure(co); + free_copy_opt(co); +}