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