some unnecessary comments removed
[libfirm] / ir / be / becopypbqp.c
1 /*
2  * becopypbqp.c
3  *
4  *  Created on: Aug 28, 2009
5  *      Author: bersch
6  */
7 #include "config.h"
8
9 #ifdef FIRM_KAPS
10
11 #include "becopypbqp.h"
12
13 #include "kaps.h"
14 #include "pbqp_t.h"
15 #include "vector.h"
16 #include "matrix.h"
17 #include "html_dumper.h"
18 #include "heuristical.h"
19 #include "pbqp_node_t.h"
20
21 #include "becopyopt_t.h"
22 #include "beifg.h"
23 #include "beifg_t.h"
24 #include "bemodule.h"
25 #include "irprintf_t.h"
26
27 #include "besched.h"
28 #include "bearch.h"
29 #include "irdom.h"
30 #include "iredges.h"
31
32 #include "error.h"
33 #include "bitset.h"
34 #include "pmap.h"
35 #include "plist.h"
36 #include "pqueue.h"
37
38 #if KAPS_DUMP
39 static FILE *my_open(const be_chordal_env_t *env, const char *prefix, const char *suffix)
40 {
41         FILE *result;
42         char buf[1024];
43         size_t i, n;
44         char *tu_name;
45
46         n = strlen(env->birg->main_env->cup_name);
47         tu_name = XMALLOCN(char, n + 1);
48         strcpy(tu_name, env->birg->main_env->cup_name);
49         for (i = 0; i < n; ++i)
50                 if (tu_name[i] == '.')
51                         tu_name[i] = '_';
52
53         ir_snprintf(buf, sizeof(buf), "%s%s_%F_%s%s", prefix, tu_name, env->irg, env->cls->name, suffix);
54         xfree(tu_name);
55         result = fopen(buf, "wt");
56         if(result == NULL) {
57                 panic("Couldn't open '%s' for writing.", buf);
58         }
59
60         return result;
61 }
62 #endif
63
64 static void insert_into_reverse_peo(ir_node *block, void *data) {
65         pqueue_t  *queue = new_pqueue();
66         pbqp_co_t *pbqp_co = data;
67         ir_node   *irn;
68
69         sched_foreach(block, irn) {
70                 pbqp_node *node;
71
72                 if (get_irn_mode(irn) == mode_T) {
73                         const ir_edge_t *edge;
74
75                         foreach_out_edge(irn, edge) {
76                                 ir_node *proj = get_edge_src_irn(edge);
77                                 if (!arch_irn_consider_in_reg_alloc(pbqp_co->cls, proj))
78                                         continue;
79
80                                 // get related pbqp_node and insert into reverse peo
81                                 assert(node && "No corresponding PBQP-Node found!");
82
83                                 // insert proj node into priority queue (descending by their degree in ifg)
84                                 pqueue_put(queue,proj, be_ifg_degree(pbqp_co->ifg,proj));
85                         }
86
87                         /* insert proj nodes into reverse perfect elimination order (descending by their degree in ifg) */
88                         while(!pqueue_empty(queue)) {
89
90                                 plist_insert_back(pbqp_co->rpeo, get_node(pbqp_co->pbqp, get_irn_idx(pqueue_pop_front(queue))));
91                         }
92                 } else {
93                         if (!arch_irn_consider_in_reg_alloc(pbqp_co->cls, irn))
94                                 continue;
95
96                         /* get related pbqp_node and insert into reverse peo */
97                         assert(node && "No corresponding PBQP-Node found!");
98                         plist_insert_back(pbqp_co->rpeo, get_node(pbqp_co->pbqp, get_irn_idx(irn)));
99                 }
100         }
101
102         /* free priority queue */
103         del_pqueue(queue);
104 }
105
106 static int co_solve_heuristic_pbqp(copy_opt_t *co) {
107         void *nodes_it  = be_ifg_nodes_iter_alloca(co->cenv->ifg);
108         void *neigh_it  = be_ifg_neighbours_iter_alloca(co->cenv->ifg);
109         ir_node *ifg_node;
110         ir_node *if_neighb_node;
111
112         pbqp_co_t pbqp_co;
113
114         unsigned number_registers = co->cls->n_regs;
115         unsigned number_nodes = get_irg_last_idx(co->irg);
116
117         /* create and initialize data structure for pbqp copy minimization optimization */
118         pbqp_co.cls = co->cls;
119         pbqp_co.rpeo = plist_new();;
120         pbqp_co.map = pmap_create_ex(number_nodes);
121         pbqp_co.pbqp = alloc_pbqp(number_nodes);
122         pbqp_co.ignore_reg = bitset_malloc(number_registers);
123         pbqp_co.ifg = co->cenv->ifg;
124
125         /* get ignored registers */
126         be_put_ignore_regs(co->cenv->birg, co->cls, pbqp_co.ignore_reg);
127
128         /* add costs vector to nodes */
129         be_ifg_foreach_node(co->cenv->ifg, nodes_it, ifg_node) {
130                 /* create costs vector */
131                 struct vector *costs_vector = vector_alloc(pbqp_co.pbqp, number_registers);
132
133                 /* set costs */
134                 unsigned int cnt;
135                 for(cnt = 0; cnt < costs_vector->len; cnt++) {
136                         if (bitset_is_set(pbqp_co.ignore_reg,cnt)) {
137                                 vector_set(costs_vector, cnt, INF_COSTS);
138                         }
139                         else {
140                                 if (!arch_reg_out_is_allocatable(ifg_node, arch_register_for_index(co->cls, cnt)))
141                                 {
142                                         vector_set(costs_vector, cnt, INF_COSTS);
143                                 }
144                                 else {
145                                         vector_set(costs_vector, cnt, 0);
146                                 }
147                         }
148 #if KAPS_ENABLE_VECTOR_NAMES
149                         /* add description */
150                         vector_set_description(costs_vector, cnt, arch_register_for_index(co->cls, cnt)->name);
151 #endif
152                 }
153
154                 /* add costs vector to node */
155                 add_node_costs(pbqp_co.pbqp, get_irn_idx(ifg_node), costs_vector);
156
157                 /* insert ir_node and pbqp_node into map */
158                 pmap_insert(pbqp_co.map, ifg_node, get_node(pbqp_co.pbqp, get_irn_idx(ifg_node)));
159         }
160
161         /* add pbqp edges and cost matrix */
162         be_ifg_foreach_node(co->cenv->ifg, nodes_it, ifg_node) {
163                 /* add costs matrix between nodes (interference edge) */
164                 be_ifg_foreach_neighbour(co->cenv->ifg, neigh_it, ifg_node, if_neighb_node) {
165                         if(get_edge(pbqp_co.pbqp,get_irn_idx(ifg_node), get_irn_idx(if_neighb_node)) == NULL) {
166                                 /* create costs matrix */
167                                 struct pbqp_matrix *matrix = pbqp_matrix_alloc(pbqp_co.pbqp, number_registers, number_registers);
168
169                                 /* set costs */
170                                 unsigned row, col;
171                                 for(row = 0; row < number_registers; row++) {
172                                         for(col = 0; col < number_registers; col++) {
173                                                 if(row == col) {
174                                                         pbqp_matrix_set(matrix, row, col, INF_COSTS);
175                                                 }
176                                                 else {
177                                                         pbqp_matrix_set(matrix, row, col, 0);
178                                                 }
179                                         }
180                                 }
181
182                                 /* add costs matrix to interference edge */
183                                 add_edge_costs(pbqp_co.pbqp, get_irn_idx(ifg_node), get_irn_idx(if_neighb_node) , matrix);
184                         }
185                 }
186
187                 /* add costs matrix between nodes (affinity edge) */
188                 affinity_node_t *aff_node = get_affinity_info(co, ifg_node);
189                 neighb_t *aff_neighb_node;
190                 if(aff_node != NULL) {
191                         co_gs_foreach_neighb(aff_node, aff_neighb_node) {
192                                 pmap_entry *ptr_pbqp_node = pmap_find(pbqp_co.map,aff_neighb_node->irn);
193
194                                 /* ignore Unknowns */
195                                 if(ptr_pbqp_node == NULL) {
196                                         continue;
197                                 }
198
199                                 if(get_edge(pbqp_co.pbqp, get_irn_idx(aff_node->irn), get_irn_idx(aff_neighb_node->irn)) == NULL) {
200                                         /* create costs matrix */
201                                         struct pbqp_matrix *matrix = pbqp_matrix_alloc(pbqp_co.pbqp, number_registers, number_registers);
202
203                                         /* set costs */
204                                         unsigned row, col;
205                                         for(row = 0; row < number_registers; row++) {
206                                                 for(col = 0; col < number_registers; col++) {
207                                                         if(row == col) {
208                                                                 pbqp_matrix_set(matrix, row, col, 0);
209                                                         }
210                                                         else {
211                                                                 pbqp_matrix_set(matrix, row, col, 2);
212                                                         }
213                                                 }
214                                         }
215
216                                         /* add costs matrix to affinity edge */
217                                         add_edge_costs(pbqp_co.pbqp, get_irn_idx(aff_node->irn), get_irn_idx(aff_neighb_node->irn) , matrix);
218                                 }
219                         }
220                 }
221         }
222
223         /* create reverse perfect elimination order */
224         assure_doms(co->irg);
225         dom_tree_walk_irg(co->irg, insert_into_reverse_peo, NULL, &pbqp_co);
226
227 #if KAPS_DUMP
228         // dump graph before solving pbqp
229         FILE *file_before = my_open(co->cenv, "", "-before.html");
230         set_dumpfile(pbqp_co.pbqp, file_before);
231         pbqp_dump_input(pbqp_co.pbqp);
232 #endif
233
234
235         /* solve pbqp problem using a reverse perfect elimination order */
236         solve_pbqp_heuristical_co(pbqp_co.pbqp, pbqp_co.rpeo);
237     num solution = get_solution(pbqp_co.pbqp);
238
239     assert(solution != INF_COSTS && "No PBQP solution found");
240
241
242 #if KAPS_DUMP
243         /* dump graph after solving pbqp */
244         FILE *file_after = my_open(co->cenv, "", "-after.html");
245         set_dumpfile(pbqp_co.pbqp, file_after);
246         pbqp_dump_input(pbqp_co.pbqp);
247 #endif
248
249         /* coloring ifg */
250         be_ifg_foreach_node(co->cenv->ifg, nodes_it, ifg_node) {
251                 num index = get_node_solution(pbqp_co.pbqp, get_irn_idx(ifg_node));
252                 const arch_register_t *reg = arch_register_for_index(co->cls, index);
253                 arch_set_irn_register(ifg_node, reg);
254         }
255
256         /* free pbqp resources */
257 #if KAPS_DUMP
258         fclose(file_before);
259         fclose(file_after);
260 #endif
261         bitset_free(pbqp_co.ignore_reg);
262         pmap_destroy(pbqp_co.map);
263         plist_free(pbqp_co.rpeo);
264         free_pbqp(pbqp_co.pbqp);
265
266         return 0;
267 }
268
269 void be_init_copypbqp(void)
270 {
271         static co_algo_info copyheur = {
272                 co_solve_heuristic_pbqp, 0
273         };
274
275         be_register_copyopt("pbqp", &copyheur);
276 }
277
278 BE_REGISTER_MODULE_CONSTRUCTOR(be_init_copypbqp);
279
280 #endif