Added beirgmod and benode
[libfirm] / ir / be / becopyilp.c
1 /**
2  * Author:      Daniel Grund
3  * Date:                17.05.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
11 #ifdef HAVE_ALLOCA_H
12 #include <alloca.h>
13 #endif
14 #ifdef HAVE_MALLOC_H
15 #include <malloc.h>
16 #endif
17
18 #include "irprog.h"
19
20 #include "lpp.h"
21 #include "xmalloc.h"
22 #include "becopyopt.h"
23 #include "becopystat.h"
24
25 #define DEBUG_LVL SET_LEVEL_1
26 static firm_dbg_module_t *dbg = NULL;
27
28 #define SLOTS_LIVING 32
29
30 /**
31  * Represents the _costs_ if node n and m have different colors.
32  * Must be >=0.
33  **/
34 #define get_weight(n,m) 1
35
36 typedef struct _simpl_t {
37         struct list_head chain;
38         if_node_t *ifn;
39 } simpl_t;
40
41 typedef struct _problem_instance_t {
42         const copy_opt_t *co;                   /** the original copy_opt problem */
43         /* problem size reduction removing simple nodes */
44         struct list_head simplicials;   /**< holds all simpl_t's in right order to color*/
45         pset *removed;                                  /**< holds all removed simplicial irns */
46         /* lp problem */
47         lpp_t *dilp;                                    /**< problem formulation directly as milp */
48         /* overhead stuff */
49         lpp_t *curr_lp;                                 /**< points to the problem currently used */
50         int curr_color, cst_counter, last_x_var;
51         char buf[32];
52 } problem_instance_t;
53
54 #define is_removed(irn) pset_find_ptr(pi->removed, irn)
55 /*
56  * Some stuff for variable name handling.
57  */
58 #define mangle_cst(buf, prefix, nr) \
59                         snprintf((buf), sizeof(buf), "%c%d", (prefix), (nr))
60
61 #define mangle_var(buf, prefix, node_nr, color) \
62                         snprintf((buf), sizeof(buf), "%c%d_%d", (prefix), (node_nr), (color))
63
64 #define mangle_var_irn(buf, prefix, irn, color) \
65                         mangle_var((buf), (prefix), get_irn_graph_nr(irn), (color))
66
67 #define split_var(var, nnr, col) \
68                         sscanf(var, "x%d_%d", (nnr), (col))
69
70
71 /**
72  * Checks if a node is simplicial in the graph
73  * heeding the already removed nodes.
74  */
75 static INLINE int pi_is_simplicial(problem_instance_t *pi, const if_node_t *ifn) {
76         int i, o, size = 0;
77         if_node_t **all, *curr;
78         all = alloca(ifn_get_degree(ifn) * sizeof(*all));
79
80         /* get all non-removed neighbors */
81         foreach_neighb(ifn, curr)
82                 if (!is_removed(curr))
83                         all[size++] = curr;
84
85         /* check if these form a clique */
86         for (i=0; i<size; ++i)
87                 for (o=i+1; o<size; ++o)
88                         if (!ifg_has_edge(pi->co->chordal_env, all[i], all[o]))
89                                 return 0;
90
91         /* all edges exist so this is a clique */
92         return 1;
93 }
94
95 /**
96  * Iterative finds and 'removes' from the graph all nodes which are
97  * simplicial AND not member of a equal-color-wish
98  */
99 static void pi_find_simplicials(problem_instance_t *pi) {
100         set *if_nodes;
101         if_node_t *ifn;
102         int redo = 1;
103
104         if_nodes = be_ra_get_ifg_nodes(pi->co->chordal_env);
105         while (redo) {
106                 redo = 0;
107                 for (ifn = set_first(if_nodes); ifn; ifn = set_next(if_nodes)) {
108                         ir_node *irn = get_irn_for_graph_nr(pi->co->irg, ifn->nnr);
109                         if (!is_removed(irn) && !is_optimizable(irn) &&
110           !is_optimizable_arg(pi->co, irn) && pi_is_simplicial(pi, ifn)) {
111                                 simpl_t *s = xmalloc(sizeof(*s));
112                                 s->ifn = ifn;
113                                 list_add(&s->chain, &pi->simplicials);
114                                 pset_insert_ptr(pi->removed, irn);
115                                 redo = 1;
116                                 DBG((dbg, LEVEL_2, " Removed %n\n", irn));
117                         }
118                 }
119         }
120 }
121
122 /**
123  * Add coloring-force conditions
124  */
125 static void pi_add_constr_A(ir_node *block, void *env) {
126         problem_instance_t *pi = env;
127         struct list_head *head = get_block_border_head(pi->co->chordal_env, block);
128         border_t *curr;
129         bitset_t *pos_regs = bitset_alloca(pi->co->cls->n_regs);
130
131         list_for_each_entry_reverse(border_t, curr, head, list)
132                 if (curr->is_def && curr->is_real && !is_removed(curr->irn)) {
133                         int cst_idx, nnr, col;
134
135                         nnr = get_irn_graph_nr(curr->irn);
136                         mangle_cst(pi->buf, 'A', nnr);
137                         cst_idx = lpp_add_cst(pi->curr_lp, pi->buf, equal, 1);
138
139                         // iterate over all possible colors in order
140                         bitset_clear_all(pos_regs);
141                         arch_get_allocatable_regs(pi->co->env, curr->irn, arch_pos_make_out(0), pi->co->cls, pos_regs);
142                         bitset_foreach(pos_regs, col) {
143                                 int var_idx;
144                                 mangle_var(pi->buf, 'x', nnr, col);
145                                 var_idx = lpp_add_var(pi->curr_lp, pi->buf, binary, 0);
146                                 pi->last_x_var = var_idx;
147                                 lpp_set_factor_fast(pi->curr_lp, cst_idx, var_idx, 1);
148                         }
149                 }
150 }
151
152 /**
153  * Checks if all nodes in @p living are live in in block @p block.
154  * @return 1 if all are live in
155  *         0 else
156  */
157 static INLINE int all_live_in(ir_node *block, pset *living) {
158         ir_node *n;
159         for (n = pset_first(living); n; n = pset_next(living))
160                 if (!is_live_in(block, n)) {
161                         pset_break(living);
162                         return 0;
163                 }
164         return 1;
165 }
166
167 /**
168  * Finds cliques in the interference graph, considering only nodes
169  * for which the color pi->curr_color is possible. Finds only 'maximal-cliques',
170  * viz cliques which are not contained in another one.
171  * This is used for the matrix B.
172  * TODO check color
173  */
174 static void pi_add_constr_B(ir_node *block, void *env) {
175         problem_instance_t *pi = env;
176         enum phase_t {growing, shrinking} phase = growing;
177         struct list_head *head = get_block_border_head(pi->co->chordal_env, block);
178         border_t *b;
179         pset *living = pset_new_ptr(SLOTS_LIVING);
180
181         list_for_each_entry_reverse(border_t, b, head, list) {
182                 const ir_node *irn = b->irn;
183                 if (is_removed(irn))
184                         continue;
185
186                 if (b->is_def) {
187                         DBG((dbg, LEVEL_2, "Def %n\n", irn));
188                         pset_insert_ptr(living, irn);
189                         phase = growing;
190                 } else { /* is_use */
191                         DBG((dbg, LEVEL_2, "Use %n\n", irn));
192
193                         /* before shrinking the set, store the current 'maximum' clique;
194                          * do NOT if clique is a single node
195                          * do NOT if all values are live_in (in this case they were contained in a live-out clique elsewhere) */
196                         if (phase == growing && pset_count(living) >= 2 && !all_live_in(block, living)) {
197                                 int cst_idx;
198                                 ir_node *n;
199                                 mangle_cst(pi->buf, 'B', pi->cst_counter);
200                                 cst_idx = lpp_add_cst(pi->curr_lp, pi->buf, less, 1);
201                                 for (n = pset_first(living); n; n = pset_next(living)) {
202                                         int var_idx;
203                                         mangle_var_irn(pi->buf, 'x', n, pi->curr_color);
204                                         var_idx = lpp_get_var_idx(pi->curr_lp, pi->buf);
205                                         assert(var_idx>=1);
206                                         lpp_set_factor_fast(pi->curr_lp, cst_idx, var_idx, 1);
207                                 }
208                                 pi->cst_counter++;
209                         }
210                         pset_remove_ptr(living, irn);
211                         phase = shrinking;
212                 }
213         }
214
215         del_pset(living);
216 }
217
218 static void pi_add_constr_E(problem_instance_t *pi) {
219         unit_t *curr;
220         bitset_t *root_regs, *arg_regs;
221         root_regs = bitset_alloca(pi->co->cls->n_regs);
222         arg_regs = bitset_alloca(pi->co->cls->n_regs);
223
224         /* for all roots of optimization units */
225         list_for_each_entry(unit_t, curr, &pi->co->units, units) {
226                 const ir_node *root, *arg;
227                 int rootnr, argnr, color;
228                 int y_idx, i, cst_counter = 0;
229                 char buf[32];
230
231                 root = curr->nodes[0];
232                 rootnr = get_irn_graph_nr(root);
233                 bitset_clear_all(root_regs);
234                 arch_get_allocatable_regs(pi->co->env, root, arch_pos_make_out(0), pi->co->cls, root_regs);
235
236                 /* for all arguments of root */
237                 for (i = 1; i < curr->node_count; ++i) {
238                         arg = curr->nodes[i];
239                         argnr = get_irn_graph_nr(arg);
240                         bitset_clear_all(arg_regs);
241                         arch_get_allocatable_regs(pi->co->env, arg, arch_pos_make_out(0), pi->co->cls, arg_regs);
242
243                         /* Introduce new variable and set factor in objective function */
244                         y_idx = lpp_add_var(pi->curr_lp, NULL, real, get_weight(root, arg));
245
246                         /* For all colors root and arg have in common, add 2 constraints to E */
247                         bitset_and(arg_regs, root_regs);
248                         bitset_foreach(arg_regs, color) {
249                                 int root_idx, arg_idx, cst_idx;
250                                 mangle_var(buf, 'x', rootnr, color);
251                                 root_idx = lpp_get_var_idx(pi->curr_lp, buf);
252                                 mangle_var(buf, 'x', argnr, color);
253                                 arg_idx = lpp_get_var_idx(pi->curr_lp, buf);
254
255                                 /* add root-arg+y <= 1 */
256                                 mangle_cst(buf, 'E', cst_counter++);
257                                 cst_idx = lpp_add_cst(pi->curr_lp, buf, less, 0);
258                                 lpp_set_factor_fast(pi->curr_lp, cst_idx, root_idx, 1);
259                                 lpp_set_factor_fast(pi->curr_lp, cst_idx, arg_idx, -1);
260                                 lpp_set_factor_fast(pi->curr_lp, cst_idx, y_idx, -1);
261
262                                 /* add arg-root+y <= 1 */
263                                 mangle_cst(buf, 'E', cst_counter++);
264                                 cst_idx = lpp_add_cst(pi->curr_lp, buf, less, 0);
265                                 lpp_set_factor_fast(pi->curr_lp, cst_idx, root_idx, -1);
266                                 lpp_set_factor_fast(pi->curr_lp, cst_idx, arg_idx, 1);
267                                 lpp_set_factor_fast(pi->curr_lp, cst_idx, y_idx, -1);
268                         }
269                 }
270         }
271 }
272
273 /**
274  * Generate the initial problem matrices and vectors.
275  */
276 static problem_instance_t *new_pi(const copy_opt_t *co) {
277         problem_instance_t *pi;
278
279         DBG((dbg, LEVEL_1, "Generating new instance...\n"));
280         pi = xcalloc(1, sizeof(*pi));
281         pi->co = co;
282         pi->removed = pset_new_ptr_default();
283         INIT_LIST_HEAD(&pi->simplicials);
284         pi->dilp = new_lpp(co->name, minimize);
285
286         /* problem size reduction */
287         pi_find_simplicials(pi);
288         //TODO dump_ifg_w/o_removed
289
290         pi->curr_lp = pi->dilp;
291
292         /* Matrix A: knapsack constraint for each node */
293         dom_tree_walk_irg(co->irg, pi_add_constr_A, NULL, pi);
294         /* Matrix B: interference constraints using cliques */
295         for (pi->curr_color = 0; pi->curr_color < pi->co->cls->n_regs; ++pi->curr_color)
296                 dom_tree_walk_irg(co->irg, pi_add_constr_B, NULL, pi);
297         /* Matrix E weights for the 'same-color-optimization' target */
298         pi_add_constr_E(pi);
299         return pi;
300 }
301
302 /**
303  * Clean the problem instance
304  */
305 static void free_pi(problem_instance_t *pi) {
306         DBG((dbg, LEVEL_1, "Free instance...\n"));
307         /* pi->simplicials get freed during apply_solution */
308         free_lpp(pi->dilp);
309         del_pset(pi->removed);
310         free(pi);
311 }
312
313 /**
314  * Set starting values for the mip problem according
315  * to the current coloring of the graph.
316  */
317 static void pi_set_start_sol(problem_instance_t *pi) {
318         int i;
319         for (i=1; i<=pi->last_x_var; ++i) {
320                 int nnr, col;
321                 double val;
322                 /* get variable name */
323                 const char *var_name = lpp_get_var_name(pi->curr_lp, i);
324                 /* split into components */
325                 if (split_var(var_name, &nnr, &col) == 2) {
326                         assert(get_irn_col(pi->co, get_irn_for_graph_nr(pi->co->irg, nnr)) != -1);
327                         val = (get_irn_col(pi->co, get_irn_for_graph_nr(pi->co->irg, nnr)) == col) ? 1 : 0;
328                         lpp_set_start_value(pi->curr_lp, i, val);
329                 } else
330                         assert(0 && "x vars always look like this 'x123_45'");
331         }
332 }
333
334 /**
335  * Invoke a solver
336  */
337 static void pi_solve_ilp(problem_instance_t *pi) {
338         pi_set_start_sol(pi);
339         lpp_solve(pi->curr_lp, 1);
340 }
341
342 /**
343  * Set the color of all simplicial nodes removed form
344  * the graph before transforming it to an ilp.
345  */
346 static void pi_set_simplicials(problem_instance_t *pi) {
347         simpl_t *simpl, *tmp;
348         bitset_t *used_cols = bitset_alloca(arch_register_class_n_regs(pi->co->cls));
349
350         /* color the simplicial nodes in right order */
351         list_for_each_entry_safe(simpl_t, simpl, tmp, &pi->simplicials, chain) {
352                 int free_col;
353                 ir_node *other_irn, *irn;
354                 if_node_t *other, *ifn;
355
356                 /* get free color by inspecting all neighbors */
357                 ifn = simpl->ifn;
358                 irn = get_irn_for_graph_nr(pi->co->irg, ifn->nnr);
359                 bitset_clear_all(used_cols);
360                 foreach_neighb(ifn, other) {
361                         other_irn = get_irn_for_graph_nr(pi->co->irg, other->nnr);
362                         if (!is_removed(other_irn)) /* only inspect nodes which are in graph right now */
363                                 bitset_set(used_cols, get_irn_col(pi->co, other_irn));
364                 }
365
366                 /* now all bits not set are possible colors */
367                 free_col = bitset_next_clear(used_cols, 0);
368                 assert(free_col != -1 && "No free color found. This can not be.");
369                 set_irn_col(pi->co, irn, free_col);
370                 pset_remove_ptr(pi->removed, irn); /* irn is back in graph again */
371                 free(simpl);
372         }
373 }
374
375 /**
376  * Sets the colors of irns according to the values of variables
377  * provided by the solution of the solver.
378  */
379 static void pi_apply_solution(problem_instance_t *pi) {
380 //              else if (vars_section && sscanf(buf, "x%d_%d %d", &num, &col, &val) == 3 && val == 1) {
381 //                      set_irn_col(lpp, get_irn_for_graph_nr(lpp->irg, num), col);
382         int i;
383         double *sol;
384         DBG((dbg, LEVEL_1, "Applying solution...\n"));
385
386 #ifdef DO_STAT
387         //TODO
388 #endif
389
390         sol = xmalloc(pi->last_x_var * sizeof(*sol));
391         lpp_get_solution(pi->curr_lp, sol, 1, pi->last_x_var);
392         for (i=0; i<pi->last_x_var; ++i)
393                 if (sol[i] == 1) { /* split varibale name into components */
394                         int nnr, col;
395                         const char *var_name = lpp_get_var_name(pi->curr_lp, 1+i);
396                         if (split_var(var_name, &nnr, &col) == 2) {
397                                 DBG((dbg, LEVEL_2, " x%d = %d\n", nnr, col));
398                                 set_irn_col(pi->co, get_irn_for_graph_nr(pi->co->irg, nnr), col);
399                         } else
400                                 assert(0 && "this should be a x-var");
401         }
402         pi_set_simplicials(pi);
403 }
404
405 void co_ilp_opt(copy_opt_t *co) {
406         problem_instance_t *pi;
407         dbg = firm_dbg_register("ir.be.copyoptilp");
408         if (!strcmp(co->name, DEBUG_IRG))
409                 firm_dbg_set_mask(dbg, -1);
410         else
411                 firm_dbg_set_mask(dbg, DEBUG_LVL);
412
413         pi = new_pi(co);
414         pi_solve_ilp(pi);
415         pi_apply_solution(pi);
416         free_pi(pi);
417 }