b323464e583a203689bea22c8bfcdd1957c02b20
[libfirm] / ir / be / becopyilp2.c
1 /**
2  * Author:      Daniel Grund
3  * Date:                28.02.2006
4  * Copyright:   (c) Universitaet Karlsruhe
5  * Licence:     This file protected by GPL -  GNU GENERAL PUBLIC LICENSE.
6  *
7  *
8  * ILP formalization using G=(V, E, Q):
9  *  - 2 class of variables: coloring vars x_ic   and   equal color vars y_ij
10  *  - Path constraints
11  *  - Clique-star constraints
12  *
13  *
14  *      \min \sum_{ (i,j) \in Q }  w_ij y_ij
15  *
16  *              \sum_c x_nc                     =  1                    n \in N, c \in C
17  *
18  *              x_nc                            =  0                    n \in N, c \not\in C(n)
19  *
20  *              \sum x_nc                       <= 1                    x_nc \in Clique \in AllCliques,  c \in C
21  *
22  *              \sum_{e \in p} y_e      >= 1                    p \in P         path constraints
23  *
24  *              \sum_{e \in cs} y_e     >= |cs| - 1             cs \in CP       clique-star constraints
25  *
26  *              x_nc, y_ij \in N,   w_ij \in R^+
27  */
28
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif /* HAVE_CONFIG_H */
32
33 #ifdef WITH_ILP
34
35 #include "irtools.h"
36 #include "irgwalk.h"
37 #include "becopyilp_t.h"
38 #include "beifg_t.h"
39 #include "besched_t.h"
40
41 #define DEBUG_LVL 1
42
43 typedef struct _local_env_t {
44         firm_dbg_module_t *dbg;
45         double time_limit;
46         int first_x_var, last_x_var;
47         pmap *nr_2_irn;
48 } local_env_t;
49
50 static void build_coloring_cstr(ilp_env_t *ienv) {
51         be_ifg_t *ifg = ienv->co->cenv->ifg;
52         void *iter = be_ifg_nodes_iter_alloca(ifg);
53         bitset_t *colors;
54         ir_node *irn;
55         char buf[16];
56
57         colors = bitset_alloca(arch_register_class_n_regs(ienv->co->cls));
58
59         be_ifg_foreach_node(ifg, iter, irn)
60                 if (!sr_is_removed(ienv->sr, irn)) {
61                         int col, cst_idx;
62                         arch_register_req_t req;
63                         int curr_node_color = get_irn_col(ienv->co, irn);
64                         int node_nr = (int)get_irn_node_nr(irn);
65                         local_env_t *lenv = ienv->env;
66
67                         pmap_insert(lenv->nr_2_irn, INT_TO_PTR(node_nr), irn);
68
69                         arch_get_register_req(ienv->co->aenv, &req, irn, -1);
70
71                         /* get assignable colors */
72                         if (arch_register_req_is(&req, limited))
73                                 req.limited(req.limited_env, colors);
74                         else
75                                 arch_put_non_ignore_regs(ienv->co->aenv, req.cls, colors);
76
77                         /* add the coloring constraint */
78                         cst_idx = lpp_add_cst(ienv->lp, NULL, lpp_equal, 1.0);
79
80                         bitset_foreach(colors, col) {
81                                 int var_idx = lpp_add_var(ienv->lp, name_cdd(buf, 'x', node_nr, col), lpp_binary, 0.0);
82                                 lpp_set_start_value(ienv->lp, var_idx, (col == curr_node_color) ? 1.0 : 0.0);
83                                 lpp_set_factor_fast(ienv->lp, cst_idx, var_idx, 1);
84
85                                 lenv->last_x_var = var_idx;
86                                 if (lenv->first_x_var == -1)
87                                         lenv->first_x_var = var_idx;
88                         }
89
90                         /* add register constraint constraints */
91                         bitset_foreach_clear(colors, col) {
92                                 int cst_idx = lpp_add_cst(ienv->lp, NULL, lpp_equal, 0.0);
93                                 int var_idx = lpp_add_var(ienv->lp, name_cdd(buf, 'x', node_nr, col), lpp_binary, 0.0);
94                                 lpp_set_start_value(ienv->lp, var_idx, 0.0);
95                                 lpp_set_factor_fast(ienv->lp, cst_idx, var_idx, 1);
96
97                                 lenv->last_x_var = var_idx;
98                         }
99                 }
100 }
101
102 static void build_interference_cstr(ilp_env_t *ienv) {
103         lpp_t *lpp = ienv->lp;
104         be_ifg_t *ifg = ienv->co->cenv->ifg;
105         int n_colors = arch_register_class_n_regs(ienv->co->cls);
106         int i, col;
107
108         void *iter = be_ifg_cliques_iter_alloca(ifg);
109         ir_node **clique = alloca(sizeof(*clique) * n_colors);
110         int size;
111
112         char buf[16];
113
114         /* for each maximal clique */
115         be_ifg_foreach_clique(ifg, iter, clique, &size) {
116
117                 if (size < 2)
118                         continue;
119
120                 /* for all colors */
121                 for (col=0; col<n_colors; ++col) {
122                         int cst_idx = lpp_add_cst(lpp, NULL, lpp_less, 1.0);
123
124                         /* for each member of this clique */
125                         for (i=0; i<size; ++i) {
126                                 ir_node *irn = clique[i];
127
128                                 if (!sr_is_removed(ienv->sr, irn)) {
129                                         int var_idx = lpp_get_var_idx(lpp, name_cdd(buf, 'x', (int)get_irn_node_nr(irn), col));
130                                         lpp_set_factor_fast(lpp, cst_idx, var_idx, 1);
131                                 }
132                         }
133                 }
134         }
135 }
136
137 static void build_affinity_cstr(ilp_env_t *ienv) {
138         unit_t *curr;
139         int n_colors = arch_register_class_n_regs(ienv->co->cls);
140
141         /* for all optimization units */
142         list_for_each_entry(unit_t, curr, &ienv->co->units, units) {
143                 ir_node *root, *arg;
144                 int root_nr, arg_nr, i, col, y_idx, root_idx, arg_idx;
145                 char buf[16];
146                 int root_col, arg_col;
147
148                 root = curr->nodes[0];
149                 root_nr = (int) get_irn_node_nr(root);
150                 root_col = get_irn_col(ienv->co, root);
151
152                 for (i = 1; i < curr->node_count; ++i) {
153                         arg = curr->nodes[i];
154                         arg_nr = (int) get_irn_node_nr(arg);
155                         arg_col = get_irn_col(ienv->co, arg);
156
157                         /* add a new affinity variable */
158                         y_idx = lpp_add_var(ienv->lp, name_cdd_sorted(buf, 'y', root_nr, arg_nr), lpp_binary, curr->costs[i]);
159                         lpp_set_start_value(ienv->lp, y_idx, (root_col==arg_col) ? 0.0 : 1.0);
160
161                         /* add constraints relating the affinity var to the color vars */
162                         for (col=0; col<n_colors; ++col) {
163                                 int cst_idx = lpp_add_cst(ienv->lp, NULL, lpp_less, 0.0);
164                                 root_idx = lpp_get_var_idx(ienv->lp, name_cdd(buf, 'x', root_nr, col));
165                                 arg_idx  = lpp_get_var_idx(ienv->lp, name_cdd(buf, 'x', arg_nr,  col));
166
167                                 lpp_set_factor_fast(ienv->lp, cst_idx, root_idx,  1.0);
168                                 lpp_set_factor_fast(ienv->lp, cst_idx, arg_idx,  -1.0);
169                                 lpp_set_factor_fast(ienv->lp, cst_idx, root_idx, -1.0);
170                         }
171                 }
172         }
173 }
174
175 /**
176  * Helping stuff for build_clique_star_cstr
177  */
178 typedef struct _edge_t {
179         ir_node *n1, *n2;
180 } edge_t;
181
182 static int compare_edge_t(const void *k1, const void *k2, size_t size) {
183         const edge_t *e1 = k1;
184         const edge_t *e2 = k2;
185
186         return ! (e1->n1 == e2->n1   &&   e1->n2 == e2->n2);
187 }
188
189 #define HASH_EDGE(e) (HASH_PTR((e)->n1) ^ HASH_PTR((e)->n2))
190
191 static INLINE edge_t *add_edge(set *edges, ir_node *n1, ir_node *n2, int *counter) {
192         edge_t new_edge;
193
194         if (PTR_TO_INT(n1) < PTR_TO_INT(n2)) {
195                 new_edge.n1 = n1;
196                 new_edge.n2 = n2;
197         } else {
198                 new_edge.n1 = n2;
199                 new_edge.n2 = n1;
200         }
201         *counter++;
202         return set_insert(edges, &new_edge, sizeof(new_edge), HASH_EDGE(&new_edge));
203 }
204
205 static INLINE edge_t *find_edge(set *edges, ir_node *n1, ir_node *n2) {
206         edge_t new_edge;
207
208         if (PTR_TO_INT(n1) < PTR_TO_INT(n2)) {
209                 new_edge.n1 = n1;
210                 new_edge.n2 = n2;
211         } else {
212                 new_edge.n1 = n2;
213                 new_edge.n2 = n1;
214         }
215         return set_find(edges, &new_edge, sizeof(new_edge), HASH_EDGE(&new_edge));
216 }
217
218 static INLINE void remove_edge(set *edges, ir_node *n1, ir_node *n2, int *counter) {
219         edge_t new_edge, *e;
220
221         if (PTR_TO_INT(n1) < PTR_TO_INT(n2)) {
222                 new_edge.n1 = n1;
223                 new_edge.n2 = n2;
224         } else {
225                 new_edge.n1 = n2;
226                 new_edge.n2 = n1;
227         }
228         e = set_find(edges, &new_edge, sizeof(new_edge), HASH_EDGE(&new_edge));
229         if (e) {
230                 e->n1 = NULL;
231                 e->n2 = NULL;
232                 *counter--;
233         }
234 }
235
236 #define pset_foreach(pset, irn)  for(irn=pset_first(pset); irn; irn=pset_next(pset))
237
238 /**
239  * Search for an interference clique and an external node
240  * with affinity edges to all nodes of the clique.
241  * At most 1 node of the clique can be colored equally with the external node.
242  */
243 static void build_clique_star_cstr(ilp_env_t *ienv) {
244         node_t *node;
245
246         /* for each node with affinity edges */
247         co_gs_foreach_node(ienv->co, node) {
248                 struct obstack ob;
249                 neighb_t *nbr;
250                 ir_node *center = node->irn;
251                 ir_node **nodes;
252                 set *edges;
253                 int i, o, n_nodes, n_edges;
254
255                 obstack_init(&ob);
256                 edges = new_set(compare_edge_t, 8);
257
258                 /* get all affinity neighbours */
259                 n_nodes = 0;
260                 co_gs_foreach_neighb(node, nbr) {
261                         obstack_ptr_grow(&ob, nbr->irn);
262                         ++n_nodes;
263                 }
264                 nodes = obstack_finish(&ob);
265
266                 /* get all interference edges between these */
267                 n_edges = 0;
268                 for (i=0; i<n_nodes; ++i)
269                         for (o=0; o<i; ++o)
270                                 if (be_ifg_connected(ienv->co->cenv->ifg, nodes[i], nodes[o]))
271                                         add_edge(edges, nodes[i], nodes[o], &n_edges);
272
273                 /* cover all these interference edges with maximal cliques */
274                 while (n_edges) {
275                         edge_t *e;
276                         pset *clique = pset_new_ptr(8);
277                         int growed;
278
279                         /* get 2 starting nodes to form a clique */
280                         for (e=set_first(edges); !e->n1; e=set_next(edges))
281                                 /*nothing*/ ;
282
283                         remove_edge(edges, e->n1, e->n2, &n_edges);
284                         pset_insert_ptr(clique, e->n1);
285                         pset_insert_ptr(clique, e->n2);
286
287                         /* while the clique is growing */
288                         do {
289                                 growed = 0;
290
291                                 /* search for a candidate to extend the clique */
292                                 for (i=0; i<n_nodes; ++i) {
293                                         ir_node *member, *cand = nodes[i];
294                                         int is_cand;
295
296                                         /* if its already in the clique try the next */
297                                         if (pset_find_ptr(clique, cand))
298                                                 continue;
299
300                                         /* are there all necessary interferences? */
301                                         is_cand = 1;
302                                         pset_foreach(clique, member) {
303                                                 if (!find_edge(edges, cand, member)) {
304                                                         is_cand = 0;
305                                                         pset_break(clique);
306                                                         break;
307                                                 }
308                                         }
309
310                                         /* now we know if we have a clique extender */
311                                         if (is_cand) {
312                                                 /* first remove all covered edges */
313                                                 pset_foreach(clique, member)
314                                                         remove_edge(edges, cand, member, &n_edges);
315
316                                                 /* insert into clique */
317                                                 pset_insert_ptr(clique, cand);
318                                                 growed = 1;
319                                                 break;
320                                         }
321                                 }
322                         } while (growed);
323
324                         /* now the clique is maximal. Finally add the constraint */
325                         {
326                                 ir_node *member;
327                                 int var_idx, cst_idx, center_nr, member_nr;
328                                 char buf[16];
329
330                                 cst_idx = lpp_add_cst(ienv->lp, NULL, lpp_greater, pset_count(clique)-1);
331                                 center_nr = get_irn_node_nr(center);
332
333                                 pset_foreach(clique, member) {
334                                         member_nr = get_irn_node_nr(member);
335                                         var_idx = lpp_get_var_idx(ienv->lp, name_cdd_sorted(buf, 'y', center_nr, member_nr));
336                                         lpp_set_factor_fast(ienv->lp, cst_idx, var_idx, 1.0);
337                                 }
338                         }
339
340                         del_pset(clique);
341                 }
342
343                 del_set(edges);
344                 obstack_free(&ob, NULL);
345         }
346 }
347
348 /**
349  *
350  */
351 static void build_path_cstr(ilp_env_t *ienv) {
352
353 }
354
355 static void ilp2_build(ilp_env_t *ienv) {
356         local_env_t *lenv = ienv->env;
357         int lower_bound;
358
359         ienv->lp = new_lpp(ienv->co->name, lpp_minimize);
360         build_coloring_cstr(ienv);
361         build_interference_cstr(ienv);
362         build_affinity_cstr(ienv);
363         build_clique_star_cstr(ienv);
364         build_path_cstr(ienv);
365
366         lower_bound = co_get_lower_bound(ienv->co) - co_get_inevit_copy_costs(ienv->co);
367         lpp_set_bound(ienv->lp, lower_bound);
368         lpp_set_time_limit(ienv->lp, lenv->time_limit);
369 }
370
371 static void ilp2_apply(ilp_env_t *ienv) {
372         local_env_t *lenv = ienv->env;
373         double *sol;
374         lpp_sol_state_t state;
375         int i, count;
376
377         count = lenv->last_x_var - lenv->first_x_var + 1;
378         sol = xmalloc(count * sizeof(sol[0]));
379         state = lpp_get_solution(ienv->lp, sol, lenv->first_x_var, lenv->last_x_var);
380         if (state != lpp_optimal) {
381                 printf("WARNING %s: Solution state is not 'optimal': %d\n", ienv->co->name, state);
382                 assert(state >= lpp_feasible && "The solution should at least be feasible!");
383         }
384
385         for (i=0; i<count; ++i) {
386                 int nodenr, color;
387                 char var_name[16];
388
389                 if (sol[i] > 1-EPSILON) { /* split variable name into components */
390                         lpp_get_var_name(ienv->lp, lenv->first_x_var+i, var_name, sizeof(var_name));
391
392                         if (sscanf(var_name, "x_%d_%d", &nodenr, &color) == 2) {
393                                 ir_node *irn = pmap_get(lenv->nr_2_irn, INT_TO_PTR(nodenr));
394                                 assert(irn && "This node number must be present in the map");
395
396                                 set_irn_col(ienv->co, irn, color);
397                         } else
398                                 assert(0 && "This should be a x-var");
399                 }
400         }
401
402 #ifdef COPYOPT_STAT
403         /* TODO adapt to multiple possible ILPs */
404         copystat_add_ilp_time((int)(1000.0*lpp_get_sol_time(pi->curr_lp)));  //now we have ms
405         copystat_add_ilp_vars(lpp_get_var_count(pi->curr_lp));
406         copystat_add_ilp_csts(lpp_get_cst_count(pi->curr_lp));
407         copystat_add_ilp_iter(lpp_get_iter_cnt(pi->curr_lp));
408 #endif
409 }
410
411 int co_solve_ilp2(copy_opt_t *co, double time_limit) {
412         lpp_sol_state_t sol_state;
413         ilp_env_t *ienv;
414         local_env_t my;
415
416         my.time_limit  = time_limit;
417         my.first_x_var = -1;
418         my.last_x_var  = -1;
419         my.nr_2_irn    = pmap_create();
420         my.dbg         = firm_dbg_register("ir.be.coilp2");
421         firm_dbg_set_mask(my.dbg, DEBUG_LVL);
422
423         ienv = new_ilp_env(co, ilp2_build, ilp2_apply, &my);
424
425         sol_state = ilp_go(ienv);
426
427         pmap_destroy(my.nr_2_irn);
428         free_ilp_env(ienv);
429
430         return sol_state == lpp_optimal;
431 }
432
433 #else /* WITH_ILP */
434
435 static void only_that_you_can_compile_without_WITH_ILP_defined(void) {
436 }
437
438 #endif /* WITH_ILP */