adapted to new callback
[libfirm] / ir / be / becopyopt.c
1 /**
2  * Author:      Daniel Grund
3  * Date:                12.04.2005
4  * Copyright:   (c) Universitaet Karlsruhe
5  * Licence:     This file protected by GPL -  GNU GENERAL PUBLIC LICENSE.
6  */
7 #ifdef HAVE_CONFIG_H
8 #include "config.h"
9 #endif
10 #ifdef HAVE_ALLOCA_H
11 #include <alloca.h>
12 #endif
13 #ifdef HAVE_MALLOC_H
14 #include <malloc.h>
15 #endif
16
17 #include "execfreq.h"
18 #include "xmalloc.h"
19 #include "debug.h"
20 #include "pmap.h"
21 #include "irgraph.h"
22 #include "irgwalk.h"
23 #include "irprog.h"
24 #include "irloop_t.h"
25 #include "iredges_t.h"
26 #include "phiclass.h"
27 #include "irbitset.h"
28 #include "irphase_t.h"
29 #include "irprintf_t.h"
30
31
32 #include "bearch.h"
33 #include "benode_t.h"
34 #include "beutil.h"
35 #include "beifg_t.h"
36 #include "becopyopt_t.h"
37 #include "becopystat.h"
38 #include "belive_t.h"
39 #include "beinsn_t.h"
40 #include "besched_t.h"
41 #include "benodesets.h"
42
43 #define DUMP_BEFORE 1
44 #define DUMP_AFTER  2
45 #define DUMP_APPEL  4
46 #define DUMP_ALL    2 * DUMP_APPEL - 1
47
48 #define COST_FUNC_FREQ     1
49 #define COST_FUNC_LOOP     2
50 #define COST_FUNC_ALL_ONE  3
51
52 static int dump_flags         = 0;
53 static int style_flags        = 0;
54 static int do_stats           = 0;
55 static cost_fct_t cost_func   = co_get_costs_exec_freq;
56 static int algo               = CO_ALGO_HEUR2;
57
58 #ifdef WITH_LIBCORE
59 static const lc_opt_enum_mask_items_t dump_items[] = {
60         { "before",  DUMP_BEFORE },
61         { "after",   DUMP_AFTER  },
62         { "appel",   DUMP_APPEL  },
63         { "all",     DUMP_ALL    },
64         { NULL,      0 }
65 };
66
67 static const lc_opt_enum_mask_items_t style_items[] = {
68         { "color",   CO_IFG_DUMP_COLORS },
69         { "labels",  CO_IFG_DUMP_LABELS },
70         { "constr",  CO_IFG_DUMP_CONSTR },
71         { "shape",   CO_IFG_DUMP_SHAPE  },
72         { "full",    2 * CO_IFG_DUMP_SHAPE - 1 },
73         { NULL,      0 }
74 };
75
76 static const lc_opt_enum_mask_items_t algo_items[] = {
77         { "none",   CO_ALGO_NONE  },
78         { "heur",   CO_ALGO_HEUR  },
79         { "heur2",  CO_ALGO_HEUR2 },
80         { "heur3",  CO_ALGO_HEUR3 },
81         { "ilp",    CO_ALGO_ILP   },
82         { NULL,     0 }
83 };
84
85 static const lc_opt_enum_func_ptr_items_t cost_func_items[] = {
86         { "freq",   co_get_costs_exec_freq },
87         { "loop",   co_get_costs_loop_depth },
88         { "one",    co_get_costs_all_one },
89         { NULL,     0 }
90 };
91
92 static lc_opt_enum_mask_var_t dump_var = {
93         &dump_flags, dump_items
94 };
95
96 static lc_opt_enum_mask_var_t style_var = {
97         &style_flags, style_items
98 };
99
100 static lc_opt_enum_mask_var_t algo_var = {
101         &algo, algo_items
102 };
103
104 static lc_opt_enum_func_ptr_var_t cost_func_var = {
105         &cost_func, cost_func_items
106 };
107
108 static const lc_opt_table_entry_t options[] = {
109         LC_OPT_ENT_ENUM_INT      ("algo",  "select copy optimization algo (heur, heur2, heur3, ilp)", &algo_var),
110         LC_OPT_ENT_ENUM_FUNC_PTR ("cost",  "select a cost function (freq, loop, one)",    &cost_func_var),
111         LC_OPT_ENT_ENUM_MASK     ("dump",  "dump ifg before or after copy optimization",  &dump_var),
112         LC_OPT_ENT_ENUM_MASK     ("style", "dump style for ifg dumping",                  &style_var),
113         LC_OPT_ENT_BOOL          ("stats", "dump statistics after each optimization",     &do_stats),
114         { NULL }
115 };
116
117 /* Insert additional options registration functions here. */
118 extern void be_co_ilp_register_options(lc_opt_entry_t *grp);
119 extern void be_co2_register_options(lc_opt_entry_t *grp);
120 extern void be_co3_register_options(lc_opt_entry_t *grp);
121
122 void co_register_options(lc_opt_entry_t *grp)
123 {
124         lc_opt_entry_t *co_grp = lc_opt_get_grp(grp, "co");
125         lc_opt_add_table(co_grp, options);
126
127         be_co2_register_options(co_grp);
128         be_co3_register_options(co_grp);
129 #ifdef WITH_ILP
130         be_co_ilp_register_options(co_grp);
131 #endif
132 }
133 #endif
134
135
136 #undef QUICK_AND_DIRTY_HACK
137
138 /******************************************************************************
139     _____                           _
140    / ____|                         | |
141   | |  __  ___ _ __   ___ _ __ __ _| |
142   | | |_ |/ _ \ '_ \ / _ \ '__/ _` | |
143   | |__| |  __/ | | |  __/ | | (_| | |
144    \_____|\___|_| |_|\___|_|  \__,_|_|
145
146  ******************************************************************************/
147
148 DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
149
150 void be_copy_opt_init(void) {
151 }
152
153 copy_opt_t *new_copy_opt(be_chordal_env_t *chordal_env, cost_fct_t get_costs)
154 {
155         const char *s1, *s2, *s3;
156         int len;
157         copy_opt_t *co;
158
159         FIRM_DBG_REGISTER(dbg, "ir.be.copyopt");
160
161         co = xcalloc(1, sizeof(*co));
162         co->cenv      = chordal_env;
163         co->aenv      = chordal_env->birg->main_env->arch_env;
164         co->irg       = chordal_env->irg;
165         co->cls       = chordal_env->cls;
166         co->get_costs = get_costs;
167
168         s1 = get_irp_prog_name();
169         s2 = get_entity_name(get_irg_entity(co->irg));
170         s3 = chordal_env->cls->name;
171         len = strlen(s1) + strlen(s2) + strlen(s3) + 5;
172         co->name = xmalloc(len);
173         snprintf(co->name, len, "%s__%s__%s", s1, s2, s3);
174
175         return co;
176 }
177
178 void free_copy_opt(copy_opt_t *co) {
179         xfree(co->name);
180         free(co);
181 }
182
183 int co_is_optimizable_root(const copy_opt_t *co, ir_node *irn) {
184         arch_register_req_t req;
185         const arch_register_t *reg;
186
187         if (arch_irn_is(co->aenv, irn, ignore))
188                 return 0;
189
190         reg = arch_get_irn_register(co->aenv, irn);
191         if (arch_register_type_is(reg, ignore))
192                 return 0;
193
194         if (is_Reg_Phi(irn) || is_Perm_Proj(co->aenv, irn) || is_2addr_code(co->aenv, irn, &req))
195                 return 1;
196
197         return 0;
198 }
199
200 int co_is_optimizable_arg(const copy_opt_t *co, ir_node *irn) {
201         const ir_edge_t *edge;
202         const arch_register_t *reg;
203
204         assert(0 && "Is buggy and obsolete. Do not use");
205
206         if (arch_irn_is(co->aenv, irn, ignore))
207                 return 0;
208
209         reg = arch_get_irn_register(co->aenv, irn);
210         if (arch_register_type_is(reg, ignore))
211                 return 0;
212
213         foreach_out_edge(irn, edge) {
214                 ir_node *n = edge->src;
215
216                 if (!nodes_interfere(co->cenv, irn, n) || irn == n) {
217                         arch_register_req_t req;
218                         arch_get_register_req(co->aenv, &req, n, -1);
219
220                         if(is_Reg_Phi(n) ||
221                            is_Perm(co->aenv, n) ||
222                            (arch_register_req_is(&req, should_be_same) && req.other_same == irn)
223                           )
224                                 return 1;
225                 }
226         }
227
228         return 0;
229 }
230
231 int co_get_costs_loop_depth(const copy_opt_t *co, ir_node *root, ir_node* arg, int pos) {
232         int cost = 0;
233         ir_loop *loop;
234         ir_node *root_block = get_nodes_block(root);
235
236         if (is_Phi(root)) {
237                 /* for phis the copies are placed in the corresponding pred-block */
238                 loop = get_irn_loop(get_Block_cfgpred_block(root_block, pos));
239         } else {
240                 /* a perm places the copy in the same block as it resides */
241                 loop = get_irn_loop(root_block);
242         }
243         if (loop) {
244                 int d = get_loop_depth(loop);
245                 cost = d*d;
246         }
247         return cost+1;
248 }
249
250 int co_get_costs_exec_freq(const copy_opt_t *co, ir_node *root, ir_node* arg, int pos) {
251         ir_node *root_bl = get_nodes_block(root);
252         ir_node *copy_bl = is_Phi(root) ? get_Block_cfgpred_block(root_bl, pos) : root_bl;
253         unsigned long freq = get_block_execfreq_ulong(co->cenv->exec_freq, copy_bl);
254         return freq > 0 ? (int) freq : 1;
255 }
256
257
258 int co_get_costs_all_one(const copy_opt_t *co, ir_node *root, ir_node* arg, int pos) {
259         return 1;
260 }
261
262 /******************************************************************************
263    ____        _   _    _       _ _          _____ _
264   / __ \      | | | |  | |     (_) |        / ____| |
265  | |  | |_ __ | |_| |  | |_ __  _| |_ ___  | (___ | |_ ___  _ __ __ _  __ _  ___
266  | |  | | '_ \| __| |  | | '_ \| | __/ __|  \___ \| __/ _ \| '__/ _` |/ _` |/ _ \
267  | |__| | |_) | |_| |__| | | | | | |_\__ \  ____) | || (_) | | | (_| | (_| |  __/
268   \____/| .__/ \__|\____/|_| |_|_|\__|___/ |_____/ \__\___/|_|  \__,_|\__, |\___|
269         | |                                                            __/ |
270         |_|                                                           |___/
271  ******************************************************************************/
272
273 /**
274  * Determines a maximum weighted independent set with respect to
275  * the interference and conflict edges of all nodes in a qnode.
276  */
277 static int ou_max_ind_set_costs(unit_t *ou) {
278         be_chordal_env_t *chordal_env = ou->co->cenv;
279         ir_node **safe, **unsafe;
280         int i, o, safe_count, safe_costs, unsafe_count, *unsafe_costs;
281         bitset_t *curr;
282         int max, pos, curr_weight, best_weight = 0;
283
284         /* assign the nodes into two groups.
285          * safe: node has no interference, hence it is in every max stable set.
286          * unsafe: node has an interference
287          */
288         safe = alloca((ou->node_count-1) * sizeof(*safe));
289         safe_costs = 0;
290         safe_count = 0;
291         unsafe = alloca((ou->node_count-1) * sizeof(*unsafe));
292         unsafe_costs = alloca((ou->node_count-1) * sizeof(*unsafe_costs));
293         unsafe_count = 0;
294         for(i=1; i<ou->node_count; ++i) {
295                 int is_safe = 1;
296                 for(o=1; o<ou->node_count; ++o) {
297                         if (i==o)
298                                 continue;
299                         if (nodes_interfere(chordal_env, ou->nodes[i], ou->nodes[o])) {
300                                 unsafe_costs[unsafe_count] = ou->costs[i];
301                                 unsafe[unsafe_count] = ou->nodes[i];
302                                 ++unsafe_count;
303                                 is_safe = 0;
304                                 break;
305                         }
306                 }
307                 if (is_safe) {
308                         safe_costs += ou->costs[i];
309                         safe[safe_count++] = ou->nodes[i];
310                 }
311         }
312
313
314         /* now compute the best set out of the unsafe nodes*/
315         if (unsafe_count > MIS_HEUR_TRIGGER) {
316                 bitset_t *best = bitset_alloca(unsafe_count);
317                 /* Heuristik: Greedy trial and error form index 0 to unsafe_count-1 */
318                 for (i=0; i<unsafe_count; ++i) {
319                         bitset_set(best, i);
320                         /* check if it is a stable set */
321                         for (o=bitset_next_set(best, 0); o!=-1 && o<i; o=bitset_next_set(best, o+1))
322                                 if (nodes_interfere(chordal_env, unsafe[i], unsafe[o])) {
323                                         bitset_clear(best, i); /* clear the bit and try next one */
324                                         break;
325                                 }
326                 }
327                 /* compute the weight */
328                 bitset_foreach(best, pos)
329                         best_weight += unsafe_costs[pos];
330         } else {
331                 /* Exact Algorithm: Brute force */
332                 curr = bitset_alloca(unsafe_count);
333                 bitset_set_all(curr);
334                 while ((max = bitset_popcnt(curr)) != 0) {
335                         /* check if curr is a stable set */
336                         for (i=bitset_next_set(curr, 0); i!=-1; i=bitset_next_set(curr, i+1))
337                                 for (o=bitset_next_set(curr, i+1); o!=-1; o=bitset_next_set(curr, o+1)) /* !!!!! difference to qnode_max_ind_set(): NOT (curr, i) */
338                                                 if (nodes_interfere(chordal_env, unsafe[i], unsafe[o]))
339                                                         goto no_stable_set;
340
341                         /* if we arrive here, we have a stable set */
342                         /* compute the weigth of the stable set*/
343                         curr_weight = 0;
344                         bitset_foreach(curr, pos)
345                                 curr_weight += unsafe_costs[pos];
346
347                         /* any better ? */
348                         if (curr_weight > best_weight) {
349                                 best_weight = curr_weight;
350                         }
351
352         no_stable_set:
353                         bitset_minus1(curr);
354                 }
355         }
356
357         return safe_costs+best_weight;
358 }
359
360 static void co_collect_units(ir_node *irn, void *env) {
361         copy_opt_t *co = env;
362         unit_t *unit;
363         arch_register_req_t req;
364
365         if (!is_curr_reg_class(co, irn))
366                 return;
367         if (!co_is_optimizable_root(co, irn))
368                 return;
369
370         /* Init a new unit */
371         unit = xcalloc(1, sizeof(*unit));
372         unit->co = co;
373         unit->node_count = 1;
374         INIT_LIST_HEAD(&unit->queue);
375
376         /* Phi with some/all of its arguments */
377         if (is_Reg_Phi(irn)) {
378                 int i, arity;
379
380                 /* init */
381                 arity = get_irn_arity(irn);
382                 unit->nodes = xmalloc((arity+1) * sizeof(*unit->nodes));
383                 unit->costs = xmalloc((arity+1) * sizeof(*unit->costs));
384                 unit->nodes[0] = irn;
385
386                 /* fill */
387                 for (i=0; i<arity; ++i) {
388                         int o, arg_pos;
389                         ir_node *arg = get_irn_n(irn, i);
390
391                         assert(is_curr_reg_class(co, arg) && "Argument not in same register class.");
392                         if (arg == irn)
393                                 continue;
394                         if (nodes_interfere(co->cenv, irn, arg)) {
395                                 unit->inevitable_costs += co->get_costs(co, irn, arg, i);
396                                 continue;
397                         }
398
399                         /* Else insert the argument of the phi to the members of this ou */
400                         DBG((dbg, LEVEL_1, "\t   Member: %+F\n", arg));
401
402                         /* Check if arg has occurred at a prior position in the arg/list */
403                         arg_pos = 0;
404                         for (o=0; o<unit->node_count; ++o)
405                                 if (unit->nodes[o] == arg) {
406                                         arg_pos = o;
407                                         break;
408                                 }
409
410                         if (!arg_pos) { /* a new argument */
411                                 /* insert node, set costs */
412                                 unit->nodes[unit->node_count] = arg;
413                                 unit->costs[unit->node_count] = co->get_costs(co, irn, arg, i);
414                                 unit->node_count++;
415                         } else { /* arg has occured before in same phi */
416                                 /* increase costs for existing arg */
417                                 unit->costs[arg_pos] += co->get_costs(co, irn, arg, i);
418                         }
419                 }
420                 unit->nodes = xrealloc(unit->nodes, unit->node_count * sizeof(*unit->nodes));
421                 unit->costs = xrealloc(unit->costs, unit->node_count * sizeof(*unit->costs));
422         } else
423
424         /* Proj of a perm with corresponding arg */
425         if (is_Perm_Proj(co->aenv, irn)) {
426                 assert(!nodes_interfere(co->cenv, irn, get_Perm_src(irn)));
427                 unit->nodes = xmalloc(2 * sizeof(*unit->nodes));
428                 unit->costs = xmalloc(2 * sizeof(*unit->costs));
429                 unit->node_count = 2;
430                 unit->nodes[0] = irn;
431                 unit->nodes[1] = get_Perm_src(irn);
432                 unit->costs[1] = co->get_costs(co, irn, unit->nodes[1], -1);
433         } else
434
435         /* Src == Tgt of a 2-addr-code instruction */
436         if (is_2addr_code(co->aenv, irn, &req)) {
437                 ir_node *other = req.other_same;
438                 if (!nodes_interfere(co->cenv, irn, other)) {
439                         unit->nodes = xmalloc(2 * sizeof(*unit->nodes));
440                         unit->costs = xmalloc(2 * sizeof(*unit->costs));
441                         unit->node_count = 2;
442                         unit->nodes[0] = irn;
443                         unit->nodes[1] = other;
444                         unit->costs[1] = co->get_costs(co, irn, other, -1);
445                 }
446         } else
447                 assert(0 && "This is not an optimizable node!");
448
449         /* Insert the new unit at a position according to its costs */
450         if (unit->node_count > 1) {
451                 int i;
452                 struct list_head *tmp;
453
454                 /* Determine the maximum costs this unit can cause: all_nodes_cost */
455                 for(i=1; i<unit->node_count; ++i) {
456                         unit->sort_key = MAX(unit->sort_key, unit->costs[i]);
457                         unit->all_nodes_costs += unit->costs[i];
458                 }
459
460                 /* Determine the minimal costs this unit will cause: min_nodes_costs */
461                 unit->min_nodes_costs += unit->all_nodes_costs - ou_max_ind_set_costs(unit);
462                 /* Insert the new ou according to its sort_key */
463                 tmp = &co->units;
464                 while (tmp->next != &co->units && list_entry_units(tmp->next)->sort_key > unit->sort_key)
465                         tmp = tmp->next;
466                 list_add(&unit->units, tmp);
467         } else {
468                 free(unit);
469         }
470 }
471
472 #ifdef QUICK_AND_DIRTY_HACK
473
474 static int compare_ous(const void *k1, const void *k2) {
475         const unit_t *u1 = *((const unit_t **) k1);
476         const unit_t *u2 = *((const unit_t **) k2);
477         int i, o, u1_has_constr, u2_has_constr;
478         arch_register_req_t req;
479         const arch_env_t *aenv = u1->co->aenv;
480
481         /* Units with constraints come first */
482         u1_has_constr = 0;
483         for (i=0; i<u1->node_count; ++i) {
484                 arch_get_register_req(aenv, &req, u1->nodes[i], -1);
485                 if (arch_register_req_is(&req, limited)) {
486                         u1_has_constr = 1;
487                         break;
488                 }
489         }
490
491         u2_has_constr = 0;
492         for (i=0; i<u2->node_count; ++i) {
493                 arch_get_register_req(aenv, &req, u2->nodes[i], -1);
494                 if (arch_register_req_is(&req, limited)) {
495                         u2_has_constr = 1;
496                         break;
497                 }
498         }
499
500         if (u1_has_constr != u2_has_constr)
501                 return u2_has_constr - u1_has_constr;
502
503         /* Now check, whether the two units are connected */
504 #if 0
505         for (i=0; i<u1->node_count; ++i)
506                 for (o=0; o<u2->node_count; ++o)
507                         if (u1->nodes[i] == u2->nodes[o])
508                                 return 0;
509 #endif
510
511         /* After all, the sort key decides. Greater keys come first. */
512         return u2->sort_key - u1->sort_key;
513
514 }
515
516 /**
517  * Sort the ou's according to constraints and their sort_key
518  */
519 static void co_sort_units(copy_opt_t *co) {
520         int i, count = 0, costs;
521         unit_t *ou, **ous;
522
523         /* get the number of ous, remove them form the list and fill the array */
524         list_for_each_entry(unit_t, ou, &co->units, units)
525                 count++;
526         ous = alloca(count * sizeof(*ous));
527
528         costs = co_get_max_copy_costs(co);
529
530         i = 0;
531         list_for_each_entry(unit_t, ou, &co->units, units)
532                 ous[i++] = ou;
533
534         INIT_LIST_HEAD(&co->units);
535
536         assert(count == i && list_empty(&co->units));
537
538         for (i=0; i<count; ++i)
539                 ir_printf("%+F\n", ous[i]->nodes[0]);
540
541         qsort(ous, count, sizeof(*ous), compare_ous);
542
543         ir_printf("\n\n");
544         for (i=0; i<count; ++i)
545                 ir_printf("%+F\n", ous[i]->nodes[0]);
546
547         /* reinsert into list in correct order */
548         for (i=0; i<count; ++i)
549                 list_add_tail(&ous[i]->units, &co->units);
550
551         assert(costs == co_get_max_copy_costs(co));
552 }
553 #endif
554
555 void co_build_ou_structure(copy_opt_t *co) {
556         DBG((dbg, LEVEL_1, "\tCollecting optimization units\n"));
557         INIT_LIST_HEAD(&co->units);
558         irg_walk_graph(co->irg, co_collect_units, NULL, co);
559 #ifdef QUICK_AND_DIRTY_HACK
560         co_sort_units(co);
561 #endif
562 }
563
564 void co_free_ou_structure(copy_opt_t *co) {
565         unit_t *curr, *tmp;
566         ASSERT_OU_AVAIL(co);
567         list_for_each_entry_safe(unit_t, curr, tmp, &co->units, units) {
568                 xfree(curr->nodes);
569                 xfree(curr->costs);
570                 xfree(curr);
571         }
572         co->units.next = NULL;
573 }
574
575 /* co_solve_heuristic() is implemented in becopyheur.c */
576
577 int co_get_max_copy_costs(const copy_opt_t *co) {
578         int i, res = 0;
579         unit_t *curr;
580
581         ASSERT_OU_AVAIL(co);
582
583         list_for_each_entry(unit_t, curr, &co->units, units) {
584                 res += curr->inevitable_costs;
585                 for (i=1; i<curr->node_count; ++i)
586                         res += curr->costs[i];
587         }
588         return res;
589 }
590
591 int co_get_inevit_copy_costs(const copy_opt_t *co) {
592         int res = 0;
593         unit_t *curr;
594
595         ASSERT_OU_AVAIL(co);
596
597         list_for_each_entry(unit_t, curr, &co->units, units)
598                 res += curr->inevitable_costs;
599         return res;
600 }
601
602 int co_get_copy_costs(const copy_opt_t *co) {
603         int i, res = 0;
604         unit_t *curr;
605
606         ASSERT_OU_AVAIL(co);
607
608         list_for_each_entry(unit_t, curr, &co->units, units) {
609                 int root_col = get_irn_col(co, curr->nodes[0]);
610                 DBG((dbg, LEVEL_1, "  %3d costs for root %+F color %d\n", curr->inevitable_costs, curr->nodes[0], root_col));
611                 res += curr->inevitable_costs;
612                 for (i=1; i<curr->node_count; ++i) {
613                         int arg_col = get_irn_col(co, curr->nodes[i]);
614                         if (root_col != arg_col) {
615                                 DBG((dbg, LEVEL_1, "  %3d for arg %+F color %d\n", curr->costs[i], curr->nodes[i], arg_col));
616                                 res += curr->costs[i];
617                         }
618                 }
619         }
620         return res;
621 }
622
623 int co_get_lower_bound(const copy_opt_t *co) {
624         int res = 0;
625         unit_t *curr;
626
627         ASSERT_OU_AVAIL(co);
628
629         list_for_each_entry(unit_t, curr, &co->units, units)
630                 res += curr->inevitable_costs + curr->min_nodes_costs;
631         return res;
632 }
633
634 /******************************************************************************
635    _____                 _        _____ _
636   / ____|               | |      / ____| |
637  | |  __ _ __ __ _ _ __ | |__   | (___ | |_ ___  _ __ __ _  __ _  ___
638  | | |_ | '__/ _` | '_ \| '_ \   \___ \| __/ _ \| '__/ _` |/ _` |/ _ \
639  | |__| | | | (_| | |_) | | | |  ____) | || (_) | | | (_| | (_| |  __/
640   \_____|_|  \__,_| .__/|_| |_| |_____/ \__\___/|_|  \__,_|\__, |\___|
641                   | |                                       __/ |
642                   |_|                                      |___/
643  ******************************************************************************/
644
645 static int compare_affinity_node_t(const void *k1, const void *k2, size_t size) {
646         const affinity_node_t *n1 = k1;
647         const affinity_node_t *n2 = k2;
648
649         return (n1->irn != n2->irn);
650 }
651
652 static void add_edge(copy_opt_t *co, ir_node *n1, ir_node *n2, int costs) {
653         affinity_node_t new_node, *node;
654         neighb_t new_nbr, *nbr;
655         int allocnew;
656
657         new_node.irn        = n1;
658         new_node.degree     = 0;
659         new_node.neighbours = NULL;
660         node = set_insert(co->nodes, &new_node, sizeof(new_node), nodeset_hash(new_node.irn));
661
662         allocnew = 1;
663         for (nbr = node->neighbours; nbr; nbr = nbr->next)
664                 if (nbr->irn == n2) {
665                         allocnew = 0;
666                         break;
667                 }
668
669         /* if we did not find n2 in n1's neighbourhood insert it */
670         if (allocnew) {
671                 obstack_grow(&co->obst, &new_nbr, sizeof(new_nbr));
672                 nbr = obstack_finish(&co->obst);
673                 nbr->irn   = n2;
674                 nbr->costs = 0;
675                 nbr->next  = node->neighbours;
676                 node->neighbours = nbr;
677                 node->degree++;
678         }
679
680         /* now nbr points to n1's neighbour-entry of n2 */
681         nbr->costs += costs;
682 }
683
684 static INLINE void add_edges(copy_opt_t *co, ir_node *n1, ir_node *n2, int costs) {
685         if (! be_ifg_connected(co->cenv->ifg, n1, n2)) {
686                 add_edge(co, n1, n2, costs);
687                 add_edge(co, n2, n1, costs);
688         }
689 }
690
691 static void build_graph_walker(ir_node *irn, void *env) {
692         copy_opt_t *co = env;
693         int pos, max;
694         arch_register_req_t req;
695         const arch_register_t *reg;
696
697         if (!is_curr_reg_class(co, irn) || arch_irn_is(co->aenv, irn, ignore))
698                 return;
699
700         reg = arch_get_irn_register(co->aenv, irn);
701         if (arch_register_type_is(reg, ignore))
702                 return;
703
704         /* Phis */
705         if (is_Reg_Phi(irn))
706                 for (pos=0, max=get_irn_arity(irn); pos<max; ++pos) {
707                         ir_node *arg = get_irn_n(irn, pos);
708                         add_edges(co, irn, arg, co->get_costs(co, irn, arg, pos));
709                 }
710
711         /* Perms */
712         else if (is_Perm_Proj(co->aenv, irn)) {
713                 ir_node *arg = get_Perm_src(irn);
714                 add_edges(co, irn, arg, co->get_costs(co, irn, arg, 0));
715         }
716
717         /* 2-address code */
718         else if (is_2addr_code(co->aenv, irn, &req))
719                 add_edges(co, irn, req.other_same, co->get_costs(co, irn, req.other_same, 0));
720 }
721
722 void co_build_graph_structure(copy_opt_t *co) {
723         obstack_init(&co->obst);
724         co->nodes = new_set(compare_affinity_node_t, 32);
725
726         irg_walk_graph(co->irg, build_graph_walker, NULL, co);
727 }
728
729 void co_free_graph_structure(copy_opt_t *co) {
730         ASSERT_GS_AVAIL(co);
731
732         del_set(co->nodes);
733         obstack_free(&co->obst, NULL);
734         co->nodes = NULL;
735 }
736
737 /* co_solve_ilp1() co_solve_ilp2() are implemented in becopyilpX.c */
738
739 int co_gs_is_optimizable(copy_opt_t *co, ir_node *irn) {
740         affinity_node_t new_node, *n;
741
742         ASSERT_GS_AVAIL(co);
743
744         new_node.irn = irn;
745         n = set_find(co->nodes, &new_node, sizeof(new_node), nodeset_hash(new_node.irn));
746         if (n) {
747                 return (n->degree > 0);
748         } else
749                 return 0;
750 }
751
752 void co_dump_appel_graph(const copy_opt_t *co, FILE *f)
753 {
754         be_ifg_t *ifg  = co->cenv->ifg;
755         int *color_map = alloca(co->cls->n_regs * sizeof(color_map[0]));
756         bitset_t *adm  = bitset_alloca(co->cls->n_regs);
757
758         ir_node *irn;
759         void *it, *nit;
760         int i, n, n_regs;
761
762         n_regs = 0;
763         for(i = 0; i < co->cls->n_regs; ++i) {
764                 const arch_register_t *reg = &co->cls->regs[i];
765                 color_map[i] = arch_register_type_is(reg, ignore) ? -1 : n_regs++;
766         }
767
768         /*
769          * n contains the first node number.
770          * the values below n are the pre-colored register nodes
771          */
772
773         it  = be_ifg_nodes_iter_alloca(ifg);
774         nit = be_ifg_neighbours_iter_alloca(ifg);
775
776         n = n_regs;
777         be_ifg_foreach_node(ifg, it, irn) {
778                 if(!arch_irn_is(co->aenv, irn, ignore))
779                         set_irn_link(irn, INT_TO_PTR(n++));
780         }
781
782         fprintf(f, "%d %d\n", n, n_regs);
783
784         be_ifg_foreach_node(ifg, it, irn) {
785                 if(!arch_irn_is(co->aenv, irn, ignore)) {
786                         int idx            = PTR_TO_INT(get_irn_link(irn));
787                         affinity_node_t *a = get_affinity_info(co, irn);
788
789                         arch_register_req_t req;
790                         ir_node *adj;
791
792                         arch_get_register_req(co->aenv, &req, irn, BE_OUT_POS(0));
793                         if(arch_register_req_is(&req, limited)) {
794                                 bitset_clear_all(adm);
795                                 req.limited(req.limited_env, adm);
796                                 for(i = 0; i < co->cls->n_regs; ++i)
797                                         if(!bitset_is_set(adm, i) && color_map[i] >= 0)
798                                                 fprintf(f, "%d %d -1\n", color_map[i], idx);
799
800                         }
801
802
803                         be_ifg_foreach_neighbour(ifg, nit, irn, adj) {
804                                 if(!arch_irn_is(co->aenv, adj, ignore)) {
805                                         int adj_idx = PTR_TO_INT(get_irn_link(adj));
806                                         if(idx < adj_idx)
807                                                 fprintf(f, "%d %d -1\n", idx, adj_idx);
808                                 }
809                         }
810
811                         if(a) {
812                                 neighb_t *n;
813
814                                 co_gs_foreach_neighb(a, n) {
815                                         if(!arch_irn_is(co->aenv, n->irn, ignore)) {
816                                                 int n_idx = PTR_TO_INT(get_irn_link(n->irn));
817                                                 if(idx < n_idx)
818                                                         fprintf(f, "%d %d %d\n", idx, n_idx, n->costs);
819                                         }
820                                 }
821                         }
822                 }
823         }
824 }
825
826 typedef struct _appel_clique_walker_t {
827         phase_t ph;
828         const copy_opt_t *co;
829         int curr_nr;
830         int node_count;
831         FILE *f;
832         int dumb;
833         int *color_map;
834         struct obstack obst;
835 } appel_clique_walker_t;
836
837 typedef struct _appel_block_info_t {
838         int *live_end_nr;
839         int *live_in_nr;
840         int *phi_nr;
841         ir_node **live_end;
842         ir_node **live_in;
843         ir_node **phi;
844         int n_live_end;
845         int n_live_in;
846         int n_phi;
847 } appel_block_info_t;
848
849 static int appel_aff_weight(const appel_clique_walker_t *env, ir_node *bl)
850 {
851 #if 0
852         double freq = get_block_execfreq(env->co->cenv->execfreq, bl);
853         int res = (int) freq;
854         return res == 0 ? 1 : res;
855 #else
856         ir_loop *loop = get_irn_loop(bl);
857         if(loop) {
858                 int d = get_loop_depth(loop);
859                 return 1 + d * d;
860         }
861         return 1;
862 #endif
863 }
864
865 static void *appel_clique_walker_irn_init(phase_t *phase, ir_node *irn, void *old)
866 {
867         appel_block_info_t *res = NULL;
868
869         if(is_Block(irn)) {
870                 appel_clique_walker_t *d = (void *) phase;
871                 res = phase_alloc(phase, sizeof(res[0]));
872                 res->phi_nr      = phase_alloc(phase, d->co->cls->n_regs * sizeof(res->live_end_nr));
873                 res->live_end_nr = phase_alloc(phase, d->co->cls->n_regs * sizeof(res->live_end_nr));
874                 res->live_in_nr  = phase_alloc(phase, d->co->cls->n_regs * sizeof(res->live_in_nr));
875                 res->live_end    = phase_alloc(phase, d->co->cls->n_regs * sizeof(res->live_end));
876                 res->live_in     = phase_alloc(phase, d->co->cls->n_regs * sizeof(res->live_in));
877                 res->phi         = phase_alloc(phase, d->co->cls->n_regs * sizeof(res->live_in));
878         }
879
880         return res;
881 }
882
883 typedef struct _insn_list_t {
884         be_insn_t *insn;
885         struct list_head list;
886 } insn_list_t;
887
888 static int appel_get_live_end_nr(appel_clique_walker_t *env, ir_node *bl, ir_node *irn)
889 {
890         appel_block_info_t *bli = phase_get_irn_data(&env->ph, bl);
891         int i;
892
893         for(i = 0; i < bli->n_live_end; ++i)
894                 if(bli->live_end[i] == irn)
895                         return bli->live_end_nr[i];
896
897         return -1;
898 }
899
900 static int appel_dump_clique(appel_clique_walker_t *env, pset *live, ir_node *bl, int curr_nr, int start_nr)
901 {
902         ir_node **live_arr = alloca(env->co->cls->n_regs * sizeof(live_arr[0]));
903         ir_node *irn;
904         int n_live;
905         int j;
906
907         n_live = 0;
908         foreach_pset(live, irn)
909                 live_arr[n_live++] = irn;
910
911         /* dump the live after clique */
912         if(!env->dumb) {
913                 for(j = 0; j < n_live; ++j) {
914                         int k;
915
916                         for(k = j + 1; k < n_live; ++k) {
917                                 fprintf(env->f, "%d %d -1 ", curr_nr + j, curr_nr + k);
918                         }
919                         fprintf(env->f, "\n");
920                 }
921         }
922
923         /* dump the affinities */
924         for(j = 0; !env->dumb && j < n_live; ++j) {
925                 ir_node *irn = live_arr[j];
926                 int old_nr = PTR_TO_INT(get_irn_link(irn));
927
928                 /* if the node was already live in the last insn dump the affinity */
929                 if(old_nr > start_nr) {
930                         int weight = appel_aff_weight(env, bl);
931                         fprintf(env->f, "%d %d %d\n", old_nr, curr_nr + j, weight);
932                 }
933         }
934
935         /* set the current numbers into the link field. */
936         for(j = 0; j < n_live; ++j) {
937                 ir_node *irn = live_arr[j];
938                 set_irn_link(irn, INT_TO_PTR(curr_nr + j));
939         }
940
941         return curr_nr + n_live;
942 }
943
944 static void appel_walker(ir_node *bl, void *data)
945 {
946         appel_clique_walker_t *env = data;
947         appel_block_info_t *bli    = phase_get_or_set_irn_data(&env->ph, bl);
948         struct obstack *obst       = &env->obst;
949         void *base                 = obstack_base(obst);
950         pset *live                 = pset_new_ptr_default();
951
952         int n_insns  = 0;
953         int n_nodes  = 0;
954         int start_nr = env->curr_nr;
955         int curr_nr  = start_nr;
956
957         be_insn_env_t insn_env;
958         int i, j;
959         ir_node *irn;
960         be_insn_t **insns;
961
962         insn_env.aenv = env->co->aenv;
963         insn_env.cls  = env->co->cls;
964         insn_env.obst = obst;
965         insn_env.ignore_colors = env->co->cenv->ignore_colors;
966
967         /* Guess how many insns will be in this block. */
968         sched_foreach(bl, irn)
969                 n_nodes++;
970
971         bli->n_phi = 0;
972         insns = malloc(n_nodes * sizeof(insns[0]));
973
974         /* Put all insns in an array. */
975         irn = sched_first(bl);
976         while(!sched_is_end(irn)) {
977                 be_insn_t *insn;
978                 insn = be_scan_insn(&insn_env, irn);
979                 insns[n_insns++] = insn;
980                 irn = insn->next_insn;
981         }
982
983         DBG((env->co->cenv->dbg, LEVEL_2, "%+F\n", bl));
984         be_liveness_end_of_block(env->co->cenv->lv, env->co->aenv, env->co->cls, bl, live);
985
986         /* Generate the bad and ugly. */
987         for(i = n_insns - 1; i >= 0; --i) {
988                 be_insn_t *insn = insns[i];
989
990                 /* The first live set has to be saved in the block border set. */
991                 if(i == n_insns - 1) {
992                         j = 0;
993                         foreach_pset(live, irn) {
994                                 bli->live_end[j]    = irn;
995                                 bli->live_end_nr[j] = curr_nr + j;
996                                 ++j;
997                         }
998                         bli->n_live_end = j;
999                 }
1000
1001                 if(!env->dumb) {
1002                         for(j = 0; j < insn->use_start; ++j) {
1003                                 ir_node *op   = insn->ops[j].carrier;
1004                                 bitset_t *adm = insn->ops[j].regs;
1005                                 int k;
1006                                 int nr;
1007
1008                                 if(!insn->ops[j].has_constraints)
1009                                         continue;
1010
1011                                 nr = 0;
1012                                 foreach_pset(live, irn) {
1013                                         if(irn == op) {
1014                                                 pset_break(live);
1015                                                 break;
1016                                         }
1017                                         ++nr;
1018                                 }
1019
1020                                 assert(nr < pset_count(live));
1021
1022                                 for(k = 0; k < env->co->cls->n_regs; ++k) {
1023                                         int mapped_col = env->color_map[k];
1024                                         if(mapped_col >= 0 && !bitset_is_set(adm, k) && !bitset_is_set(env->co->cenv->ignore_colors, k))
1025                                                 fprintf(env->f, "%d %d -1\n", curr_nr + nr, mapped_col);
1026                                 }
1027                         }
1028                 }
1029
1030                 /* dump the clique and update the stuff. */
1031                 curr_nr = appel_dump_clique(env, live, bl, curr_nr, start_nr);
1032
1033                 /* remove all defs. */
1034                 for(j = 0; j < insn->use_start; ++j)
1035                         pset_remove_ptr(live, insn->ops[j].carrier);
1036
1037                 if(is_Phi(insn->irn) && arch_irn_consider_in_reg_alloc(env->co->aenv, env->co->cls, insn->irn)) {
1038                         bli->phi[bli->n_phi]    = insn->irn;
1039                         bli->phi_nr[bli->n_phi] = PTR_TO_INT(get_irn_link(insn->irn));
1040                         bli->n_phi++;
1041                 }
1042
1043                 /* add all uses */
1044                 else
1045                         for(j = insn->use_start; j < insn->n_ops; ++j)
1046                                 pset_insert_ptr(live, insn->ops[j].carrier);
1047         }
1048
1049         /* print the start clique. */
1050         curr_nr = appel_dump_clique(env, live, bl, curr_nr, start_nr);
1051
1052         i = 0;
1053         foreach_pset(live, irn) {
1054                 bli->live_in[i]    = irn;
1055                 bli->live_in_nr[i] = PTR_TO_INT(get_irn_link(irn));
1056                 ++i;
1057         }
1058         bli->n_live_in = i;
1059
1060         del_pset(live);
1061         free(insns);
1062         obstack_free(obst, base);
1063         env->curr_nr = curr_nr;
1064 }
1065
1066 static void appel_inter_block_aff(ir_node *bl, void *data)
1067 {
1068         appel_clique_walker_t *env = data;
1069         appel_block_info_t *bli    = phase_get_irn_data(&env->ph, bl);
1070
1071         int i, j, n;
1072
1073         for(i = 0; i < bli->n_live_in; ++i) {
1074                 ir_node *irn = bli->live_in[i];
1075
1076                 for(j = 0, n = get_Block_n_cfgpreds(bl); j < n; ++j) {
1077                         ir_node *pred  = get_Block_cfgpred_block(bl, j);
1078
1079                         int nr = appel_get_live_end_nr(env, pred, irn);
1080                         assert(nr >= 0);
1081                         fprintf(env->f, "%d %d 1\n", bli->live_in_nr[i], nr);
1082                 }
1083         }
1084
1085         for(i = 0; i < bli->n_phi; ++i) {
1086                 ir_node *irn = bli->phi[i];
1087
1088                 for(j = 0, n = get_Block_n_cfgpreds(bl); j < n; ++j) {
1089                         ir_node *pred  = get_Block_cfgpred_block(bl, j);
1090                         ir_node *op = get_irn_n(irn, j);
1091
1092                         int nr = appel_get_live_end_nr(env, pred, op);
1093                         assert(nr >= 0);
1094                         fprintf(env->f, "%d %d 1\n", bli->phi_nr[i], nr);
1095                 }
1096         }
1097
1098 }
1099
1100 void co_dump_appel_graph_cliques(const copy_opt_t *co, FILE *f)
1101 {
1102         int i;
1103         int n_colors;
1104         appel_clique_walker_t env;
1105         bitset_t *adm = bitset_alloca(co->cls->n_regs);
1106
1107         be_liveness_recompute(co->cenv->lv);
1108         obstack_init(&env.obst);
1109         phase_init(&env.ph, "appel_clique_dumper", co->irg, PHASE_DEFAULT_GROWTH, appel_clique_walker_irn_init);
1110         env.curr_nr = co->cls->n_regs;
1111         env.co = co;
1112         env.f = f;
1113
1114         bitset_copy(adm, co->cenv->ignore_colors);
1115         bitset_flip_all(adm);
1116
1117         /* Make color map. */
1118         env.color_map = alloca(co->cls->n_regs * sizeof(env.color_map[0]));
1119         for(i = 0, n_colors = 0; i < co->cls->n_regs; ++i) {
1120                 const arch_register_t *reg = &co->cls->regs[i];
1121                 env.color_map[i] = arch_register_type_is(reg, ignore) ? -1 : n_colors++;
1122         }
1123
1124         env.dumb = 1;
1125         env.curr_nr = n_colors;
1126         irg_block_walk_graph(co->irg, firm_clear_link, NULL, NULL);
1127         irg_block_walk_graph(co->irg, appel_walker, NULL, &env);
1128
1129         fprintf(f, "%d %d\n", env.curr_nr, n_colors);
1130
1131         /* make the first k nodes interfere */
1132         for(i = 0; i < n_colors; ++i) {
1133                 int j;
1134                 for(j = i + 1; j < n_colors; ++j)
1135                         fprintf(f, "%d %d -1 ", i, j);
1136                 fprintf(f, "\n");
1137         }
1138
1139         env.dumb = 0;
1140         env.curr_nr = n_colors;
1141         irg_block_walk_graph(co->irg, firm_clear_link, NULL, NULL);
1142         irg_block_walk_graph(co->irg, appel_walker, NULL, &env);
1143         irg_block_walk_graph(co->irg, appel_inter_block_aff, NULL, &env);
1144         obstack_free(&env.obst, NULL);
1145 }
1146
1147 /*
1148          ___ _____ ____   ____   ___ _____   ____                        _
1149         |_ _|  ___/ ___| |  _ \ / _ \_   _| |  _ \ _   _ _ __ ___  _ __ (_)_ __   __ _
1150          | || |_ | |  _  | | | | | | || |   | | | | | | | '_ ` _ \| '_ \| | '_ \ / _` |
1151          | ||  _|| |_| | | |_| | |_| || |   | |_| | |_| | | | | | | |_) | | | | | (_| |
1152         |___|_|   \____| |____/ \___/ |_|   |____/ \__,_|_| |_| |_| .__/|_|_| |_|\__, |
1153                                                                   |_|            |___/
1154 */
1155
1156 static const char *get_dot_color_name(int col)
1157 {
1158         static const char *names[] = {
1159                 "blue",
1160                 "red",
1161                 "green",
1162                 "yellow",
1163                 "cyan",
1164                 "magenta",
1165                 "orange",
1166                 "chocolate",
1167                 "beige",
1168                 "navy",
1169                 "darkgreen",
1170                 "darkred",
1171                 "lightPink",
1172                 "chartreuse",
1173                 "lightskyblue",
1174                 "linen",
1175                 "pink",
1176                 "lightslateblue",
1177                 "mintcream",
1178                 "red",
1179                 "darkolivegreen",
1180                 "mediumblue",
1181                 "mistyrose",
1182                 "salmon",
1183                 "darkseagreen",
1184                 "mediumslateblue"
1185                 "moccasin",
1186                 "tomato",
1187                 "forestgreen",
1188                 "darkturquoise",
1189                 "palevioletred"
1190         };
1191
1192         return col < sizeof(names)/sizeof(names[0]) ? names[col] : "white";
1193 }
1194
1195 typedef struct _co_ifg_dump_t {
1196         const copy_opt_t *co;
1197         unsigned flags;
1198 } co_ifg_dump_t;
1199
1200 static void ifg_dump_graph_attr(FILE *f, void *self)
1201 {
1202         fprintf(f, "overlap=scale");
1203 }
1204
1205 static int ifg_is_dump_node(void *self, ir_node *irn)
1206 {
1207         co_ifg_dump_t *cod = self;
1208         return !arch_irn_is(cod->co->aenv, irn, ignore);
1209 }
1210
1211 static void ifg_dump_node_attr(FILE *f, void *self, ir_node *irn)
1212 {
1213         co_ifg_dump_t *env         = self;
1214         const arch_register_t *reg = arch_get_irn_register(env->co->aenv, irn);
1215         arch_register_req_t req;
1216         int limited;
1217
1218         arch_get_register_req(env->co->aenv, &req, irn, BE_OUT_POS(0));
1219         limited = arch_register_req_is(&req, limited);
1220
1221         if(env->flags & CO_IFG_DUMP_LABELS) {
1222                 ir_fprintf(f, "label=\"%+F", irn);
1223
1224                 if((env->flags & CO_IFG_DUMP_CONSTR) && limited) {
1225                         bitset_t *bs = bitset_alloca(env->co->cls->n_regs);
1226                         req.limited(req.limited_env, bs);
1227                         ir_fprintf(f, "\\n%B", bs);
1228                 }
1229                 ir_fprintf(f, "\" ");
1230         }
1231
1232         else
1233                 fprintf(f, "label=\"\" shape=point " );
1234
1235         if(env->flags & CO_IFG_DUMP_SHAPE)
1236                 fprintf(f, "shape=%s ", limited ? "diamond" : "ellipse");
1237
1238         if(env->flags & CO_IFG_DUMP_COLORS)
1239                 fprintf(f, "style=filled color=%s ", get_dot_color_name(reg->index));
1240 }
1241
1242 static void ifg_dump_at_end(FILE *file, void *self)
1243 {
1244         co_ifg_dump_t *env = self;
1245         affinity_node_t *a;
1246
1247         co_gs_foreach_aff_node(env->co, a) {
1248                 const arch_register_t *ar = arch_get_irn_register(env->co->aenv, a->irn);
1249                 unsigned aidx = get_irn_idx(a->irn);
1250                 neighb_t *n;
1251
1252                 co_gs_foreach_neighb(a, n) {
1253                         const arch_register_t *nr = arch_get_irn_register(env->co->aenv, n->irn);
1254                         unsigned nidx = get_irn_idx(n->irn);
1255
1256                         if(aidx < nidx) {
1257                                 const char *color = nr == ar ? "blue" : "red";
1258                                 fprintf(file, "\tn%d -- n%d [weight=0.01 ", aidx, nidx);
1259                                 if(env->flags & CO_IFG_DUMP_LABELS)
1260                                         fprintf(file, "label=\"%d\" ", n->costs);
1261                                 if(env->flags & CO_IFG_DUMP_COLORS)
1262                                         fprintf(file, "color=%s ", color);
1263                                 else
1264                                         fprintf(file, "style=dashed");
1265                                 fprintf(file, "];\n");
1266                         }
1267                 }
1268         }
1269 }
1270
1271
1272 static be_ifg_dump_dot_cb_t ifg_dot_cb = {
1273         ifg_is_dump_node,
1274         ifg_dump_graph_attr,
1275         ifg_dump_node_attr,
1276         NULL,
1277         NULL,
1278         ifg_dump_at_end
1279 };
1280
1281
1282
1283 void co_dump_ifg_dot(const copy_opt_t *co, FILE *f, unsigned flags)
1284 {
1285         co_ifg_dump_t cod;
1286
1287         cod.co    = co;
1288         cod.flags = flags;
1289         be_ifg_dump_dot(co->cenv->ifg, co->irg, f, &ifg_dot_cb, &cod);
1290 }
1291
1292
1293 void co_solve_park_moon(copy_opt_t *opt)
1294 {
1295
1296 }
1297
1298 static int void_algo(copy_opt_t *co)
1299 {
1300         return 0;
1301 }
1302
1303 /*
1304                 _    _                  _ _   _
1305            / \  | | __ _  ___  _ __(_) |_| |__  _ __ ___  ___
1306           / _ \ | |/ _` |/ _ \| '__| | __| '_ \| '_ ` _ \/ __|
1307          / ___ \| | (_| | (_) | |  | | |_| | | | | | | | \__ \
1308         /_/   \_\_|\__, |\___/|_|  |_|\__|_| |_|_| |_| |_|___/
1309                            |___/
1310 */
1311
1312 static co_algo_t *algos[] = {
1313         void_algo,
1314         co_solve_heuristic,
1315         co_solve_heuristic_new,
1316         co_solve_heuristic_java,
1317 #ifdef WITH_ILP
1318         co_solve_ilp2
1319 #endif
1320 };
1321
1322 /*
1323     __  __       _         ____       _
1324    |  \/  | __ _(_)_ __   |  _ \ _ __(_)_   _____ _ __
1325    | |\/| |/ _` | | '_ \  | | | | '__| \ \ / / _ \ '__|
1326    | |  | | (_| | | | | | | |_| | |  | |\ V /  __/ |
1327    |_|  |_|\__,_|_|_| |_| |____/|_|  |_| \_/ \___|_|
1328
1329 */
1330
1331 void co_driver(be_chordal_env_t *cenv)
1332 {
1333         copy_opt_t *co;
1334         co_algo_t  *algo_func;
1335         int init_costs;
1336
1337         if(algo < 0 || algo >= CO_ALGO_LAST)
1338                 return;
1339
1340         co = new_copy_opt(cenv, cost_func);
1341         co_build_ou_structure(co);
1342         co_build_graph_structure(co);
1343         init_costs = co_get_copy_costs(co);
1344
1345         /* Dump the interference graph in Appel's format. */
1346         if(dump_flags & DUMP_APPEL) {
1347                 FILE *f = be_chordal_open(cenv, "", ".apl");
1348                 co_dump_appel_graph(co, f);
1349                 fclose(f);
1350         }
1351
1352         if(dump_flags & DUMP_BEFORE) {
1353                 FILE *f = be_chordal_open(cenv, "", "-before.dot");
1354                 co_dump_ifg_dot(co, f, style_flags);
1355                 fclose(f);
1356         }
1357
1358         algo_func = algos[algo];
1359         algo_func(co);
1360
1361         if(dump_flags & DUMP_AFTER) {
1362                 FILE *f = be_chordal_open(cenv, "", "-after.dot");
1363                 co_dump_ifg_dot(co, f, style_flags);
1364                 fclose(f);
1365         }
1366
1367         if(do_stats) {
1368                 int optimizable_costs = co_get_max_copy_costs(co) - co_get_lower_bound(co);
1369                 int remaining         = co_get_copy_costs(co);
1370                 int evitable          = remaining - co_get_lower_bound(co);
1371
1372                 ir_printf("%30F %10s %10d%10d%10d%10d", cenv->irg, cenv->cls->name,
1373                                 co_get_max_copy_costs(co), init_costs,
1374                                 co_get_inevit_copy_costs(co), co_get_lower_bound(co));
1375
1376                 if(optimizable_costs > 0)
1377                         printf("%10d %5.2f\n", remaining, (evitable * 100.0) / optimizable_costs);
1378                 else
1379                         printf("%10d %5s\n", remaining, "-");
1380         }
1381
1382         co_free_graph_structure(co);
1383         co_free_ou_structure(co);
1384         free_copy_opt(co);
1385 }