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