Timer for time measurement added
[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 #include "timing.h"
32
33 #include "error.h"
34 #include "bitset.h"
35 #include "pmap.h"
36 #include "plist.h"
37 #include "pqueue.h"
38
39 #if KAPS_DUMP
40 static FILE *my_open(const be_chordal_env_t *env, const char *prefix, const char *suffix)
41 {
42         FILE *result;
43         char buf[1024];
44         size_t i, n;
45         char *tu_name;
46
47         n = strlen(env->birg->main_env->cup_name);
48         tu_name = XMALLOCN(char, n + 1);
49         strcpy(tu_name, env->birg->main_env->cup_name);
50         for (i = 0; i < n; ++i)
51                 if (tu_name[i] == '.')
52                         tu_name[i] = '_';
53
54         ir_snprintf(buf, sizeof(buf), "%s%s_%F_%s%s", prefix, tu_name, env->irg, env->cls->name, suffix);
55         xfree(tu_name);
56         result = fopen(buf, "wt");
57         if(result == NULL) {
58                 panic("Couldn't open '%s' for writing.", buf);
59         }
60
61         return result;
62 }
63 #endif
64
65 static void insert_into_reverse_peo(ir_node *block, void *data) {
66         pqueue_t  *queue = new_pqueue();
67         pqueue_t  *constatQueue = new_pqueue();
68         pbqp_co_t *pbqp_co = data;
69         ir_node   *irn;
70
71         sched_foreach(block, irn) {
72                 pbqp_node *node;
73
74                 if (get_irn_mode(irn) == mode_T) {
75                         const ir_edge_t *edge;
76
77                         foreach_out_edge(irn, edge) {
78                                 ir_node *proj = get_edge_src_irn(edge);
79                                 if (!arch_irn_consider_in_reg_alloc(pbqp_co->cls, proj))
80                                         continue;
81
82                                 // get related pbqp_node and insert into reverse peo
83                                 assert(node && "No corresponding PBQP-Node found!");
84
85                                 // insert proj node into priority queue (descending by their degree in ifg)
86                                 if(bitset_is_set(pbqp_co->restricted_nodes, get_irn_idx(proj))) {
87                                         pqueue_put(constatQueue,proj, be_ifg_degree(pbqp_co->ifg,proj));
88                                 }
89                                 else {
90                                         pqueue_put(queue,proj, be_ifg_degree(pbqp_co->ifg,proj));
91                                 }
92                         }
93
94                         /* first insert all restricted nodes */
95                         while(!pqueue_empty(constatQueue)) {
96                                 plist_insert_back(pbqp_co->rpeo, get_node(pbqp_co->pbqp, get_irn_idx(pqueue_pop_front(constatQueue))));
97                         }
98
99                         /* insert proj nodes into reverse perfect elimination order (descending by their degree in ifg) */
100                         while(!pqueue_empty(queue)) {
101                                 plist_insert_back(pbqp_co->rpeo, get_node(pbqp_co->pbqp, get_irn_idx(pqueue_pop_front(queue))));
102                         }
103
104                 } else {
105                         if (!arch_irn_consider_in_reg_alloc(pbqp_co->cls, irn))
106                                 continue;
107
108                         /* get related pbqp_node and insert into reverse peo */
109                         assert(node && "No corresponding PBQP-Node found!");
110                         plist_insert_back(pbqp_co->rpeo, get_node(pbqp_co->pbqp, get_irn_idx(irn)));
111                 }
112         }
113
114         /* free priority queues */
115         del_pqueue(queue);
116         del_pqueue(constatQueue);
117 }
118
119 static int co_solve_heuristic_pbqp(copy_opt_t *co) {
120         void *nodes_it                       = be_ifg_nodes_iter_alloca(co->cenv->ifg);
121         void *neigh_it                       = be_ifg_neighbours_iter_alloca(co->cenv->ifg);
122         unsigned number_registers            = co->cls->n_regs;
123         unsigned number_nodes                = get_irg_last_idx(co->irg);
124         ir_timer_t *t_ra_copymin_pbqp_create = ir_timer_register("be_co_pbqp_create", "copy minimization pbqp create");
125         ir_timer_t *t_ra_copymin_pbqp_solve  = ir_timer_register("be_co_pbqp_solve", "copy minimization pbqp solve");
126         ir_node *ifg_node;
127         ir_node *if_neighb_node;
128         pbqp_co_t pbqp_co;
129
130         #if KAPS_STATISTIC
131         printf("==>> IRG %s <<==\n", get_entity_name(get_irg_entity(co->irg)));
132         #endif
133
134         /* start timer */
135         ir_timer_start(t_ra_copymin_pbqp_create);
136
137         /* create and initialize data structure for pbqp copy minimization optimization */
138         pbqp_co.cls = co->cls;
139         pbqp_co.rpeo = plist_new();;
140         pbqp_co.map = pmap_create_ex(number_nodes);
141         pbqp_co.pbqp = alloc_pbqp(number_nodes);
142         pbqp_co.ignore_reg = bitset_malloc(number_registers);
143         pbqp_co.restricted_nodes = bitset_malloc(number_nodes);
144         pbqp_co.ifg = co->cenv->ifg;
145
146         /* get ignored registers */
147         be_put_ignore_regs(co->cenv->birg, co->cls, pbqp_co.ignore_reg);
148
149         /* add costs vector to nodes */
150         be_ifg_foreach_node(co->cenv->ifg, nodes_it, ifg_node) {
151                 int cntFreeChoosableRegs = 0;
152
153                 /* create costs vector */
154                 struct vector *costs_vector = vector_alloc(pbqp_co.pbqp, number_registers);
155
156                 /* set costs */
157                 unsigned int cnt;
158                 for(cnt = 0; cnt < costs_vector->len; cnt++) {
159                         if (bitset_is_set(pbqp_co.ignore_reg,cnt)) {
160                                 vector_set(costs_vector, cnt, INF_COSTS);
161                         }
162                         else {
163                                 if (!arch_reg_out_is_allocatable(ifg_node, arch_register_for_index(co->cls, cnt)))
164                                 {
165                                         vector_set(costs_vector, cnt, INF_COSTS);
166                                 }
167                                 else {
168                                         vector_set(costs_vector, cnt, 0);
169                                         cntFreeChoosableRegs++;
170                                 }
171                         }
172
173                         #if KAPS_ENABLE_VECTOR_NAMES
174                         /* add description */
175                         vector_set_description(costs_vector, cnt, arch_register_for_index(co->cls, cnt)->name);
176                         #endif
177                 }
178
179                 /* add costs vector to node */
180                 add_node_costs(pbqp_co.pbqp, get_irn_idx(ifg_node), costs_vector);
181
182                 /* insert ir_node and pbqp_node into map */
183                 pmap_insert(pbqp_co.map, ifg_node, get_node(pbqp_co.pbqp, get_irn_idx(ifg_node)));
184
185                 if(cntFreeChoosableRegs <= 4) {
186                         /* node is restricted */
187                         bitset_set(pbqp_co.restricted_nodes, get_irn_idx(ifg_node));
188                 }
189                 else
190                 {
191                         /* node is not restricted */
192                         bitset_clear(pbqp_co.restricted_nodes, get_irn_idx(ifg_node));
193                 }
194
195         }
196
197         /* add pbqp edges and cost matrix */
198         be_ifg_foreach_node(co->cenv->ifg, nodes_it, ifg_node) {
199                 /* add costs matrix between nodes (interference edge) */
200                 be_ifg_foreach_neighbour(co->cenv->ifg, neigh_it, ifg_node, if_neighb_node) {
201                         if(get_edge(pbqp_co.pbqp,get_irn_idx(ifg_node), get_irn_idx(if_neighb_node)) == NULL) {
202                                 /* create costs matrix */
203                                 struct pbqp_matrix *matrix = pbqp_matrix_alloc(pbqp_co.pbqp, number_registers, number_registers);
204
205                                 /* set costs */
206                                 unsigned row, col;
207                                 for(row = 0; row < number_registers; row++) {
208                                         for(col = 0; col < number_registers; col++) {
209                                                 if(row == col) {
210                                                         pbqp_matrix_set(matrix, row, col, INF_COSTS);
211                                                 }
212                                                 else {
213                                                         pbqp_matrix_set(matrix, row, col, 0);
214                                                 }
215                                         }
216                                 }
217
218                                 /* add costs matrix to interference edge */
219                                 add_edge_costs(pbqp_co.pbqp, get_irn_idx(ifg_node), get_irn_idx(if_neighb_node) , matrix);
220                         }
221                 }
222
223                 /* add costs matrix between nodes (affinity edge) */
224                 affinity_node_t *aff_node = get_affinity_info(co, ifg_node);
225                 neighb_t *aff_neighb_node;
226                 if(aff_node != NULL) {
227                         co_gs_foreach_neighb(aff_node, aff_neighb_node) {
228                                 pmap_entry *ptr_pbqp_node = pmap_find(pbqp_co.map,aff_neighb_node->irn);
229
230                                 /* ignore Unknowns */
231                                 if(ptr_pbqp_node == NULL) {
232                                         continue;
233                                 }
234
235                                 if(get_edge(pbqp_co.pbqp, get_irn_idx(aff_node->irn), get_irn_idx(aff_neighb_node->irn)) == NULL) {
236                                         /* create costs matrix */
237                                         struct pbqp_matrix *matrix = pbqp_matrix_alloc(pbqp_co.pbqp, number_registers, number_registers);
238
239                                         /* set costs */
240                                         unsigned row, col;
241                                         for(row = 0; row < number_registers; row++) {
242                                                 for(col = 0; col < number_registers; col++) {
243                                                         if(row == col) {
244                                                                 pbqp_matrix_set(matrix, row, col, 0);
245                                                         }
246                                                         else {
247                                                                 pbqp_matrix_set(matrix, row, col, 2);
248                                                         }
249                                                 }
250                                         }
251
252                                         /* add costs matrix to affinity edge */
253                                         add_edge_costs(pbqp_co.pbqp, get_irn_idx(aff_node->irn), get_irn_idx(aff_neighb_node->irn) , matrix);
254                                 }
255                         }
256                 }
257         }
258
259         /* create reverse perfect elimination order */
260         assure_doms(co->irg);
261         dom_tree_walk_irg(co->irg, insert_into_reverse_peo, NULL, &pbqp_co);
262
263         /* stop timer */
264         ir_timer_stop(t_ra_copymin_pbqp_create);
265
266         #if KAPS_DUMP
267         // dump graph before solving pbqp
268         FILE *file_before = my_open(co->cenv, "", "-before.html");
269         set_dumpfile(pbqp_co.pbqp, file_before);
270         pbqp_dump_input(pbqp_co.pbqp);
271         #endif
272
273         /* start timer */
274         ir_timer_start(t_ra_copymin_pbqp_solve);
275
276         /* solve pbqp problem using a reverse perfect elimination order */
277         solve_pbqp_heuristical_co(pbqp_co.pbqp, pbqp_co.rpeo);
278     num solution = get_solution(pbqp_co.pbqp);
279
280     /* stop time */
281     ir_timer_stop(t_ra_copymin_pbqp_solve);
282
283         #if KAPS_STATISTIC
284     printf("Number of independent edges   : %d\n", pbqp_co.pbqp->num_edges);
285     printf("Number of trivial solved nodes: %d\n", pbqp_co.pbqp->num_r0);
286     printf("Number of R1 reductions       : %d\n", pbqp_co.pbqp->num_r1);
287     printf("Number of R2 reductions       : %d\n", pbqp_co.pbqp->num_r2);
288     printf("Number of RN reductions       : %d\n", pbqp_co.pbqp->num_rn);
289         #endif
290
291     assert(solution != INF_COSTS && "No PBQP solution found");
292
293         #if KAPS_DUMP
294         /* dump graph after solving pbqp */
295         FILE *file_after = my_open(co->cenv, "", "-after.html");
296         set_dumpfile(pbqp_co.pbqp, file_after);
297         pbqp_dump_input(pbqp_co.pbqp);
298         #endif
299
300         /* coloring ifg */
301         be_ifg_foreach_node(co->cenv->ifg, nodes_it, ifg_node) {
302                 num index = get_node_solution(pbqp_co.pbqp, get_irn_idx(ifg_node));
303                 const arch_register_t *reg = arch_register_for_index(co->cls, index);
304                 arch_set_irn_register(ifg_node, reg);
305         }
306
307         /* free pbqp resources */
308         #if KAPS_DUMP
309         fclose(file_before);
310         fclose(file_after);
311         #endif
312         bitset_free(pbqp_co.ignore_reg);
313         bitset_free(pbqp_co.restricted_nodes);
314         pmap_destroy(pbqp_co.map);
315         plist_free(pbqp_co.rpeo);
316         free_pbqp(pbqp_co.pbqp);
317
318         return 0;
319 }
320
321 void be_init_copypbqp(void)
322 {
323         static co_algo_info copyheur = {
324                 co_solve_heuristic_pbqp, 0
325         };
326
327         be_register_copyopt("pbqp", &copyheur);
328 }
329
330 BE_REGISTER_MODULE_CONSTRUCTOR(be_init_copypbqp);
331
332 #endif