5a607d618727f200c191cc14f6ef2ff0027be58e
[libfirm] / ir / be / becopypbqp.c
1 /*
2  * becopypbqp.c
3  *
4  *  Created on: Aug 28, 2009
5  *      Author: bersch
6  */
7
8 #include "kaps.h"
9 #include "pbqp_t.h"
10 #include "vector.h"
11 #include "matrix.h"
12 #include "html_dumper.h"
13 #include "heuristical.h"
14 #include "pbqp_node_t.h"
15
16 #include "becopyopt_t.h"
17 #include "beifg.h"
18 #include "beifg_t.h"
19 #include "irprintf_t.h"
20
21 #include "error.h"
22 #include "bitset.h"
23 #include "pmap.h"
24
25 static FILE *my_open(const be_chordal_env_t *env, const char *prefix, const char *suffix)
26 {
27         FILE *result;
28         char buf[1024];
29         size_t i, n;
30         char *tu_name;
31
32         n = strlen(env->birg->main_env->cup_name);
33         tu_name = XMALLOCN(char, n + 1);
34         strcpy(tu_name, env->birg->main_env->cup_name);
35         for (i = 0; i < n; ++i)
36                 if (tu_name[i] == '.')
37                         tu_name[i] = '_';
38
39         ir_snprintf(buf, sizeof(buf), "%s%s_%F_%s%s", prefix, tu_name, env->irg, env->cls->name, suffix);
40         xfree(tu_name);
41         result = fopen(buf, "wt");
42         if(result == NULL) {
43                 panic("Couldn't open '%s' for writing.", buf);
44         }
45
46         return result;
47 }
48
49 int co_solve_heuristic_pbqp(copy_opt_t *co) {
50         void *nodes_it  = be_ifg_nodes_iter_alloca(co->cenv->ifg);
51         void *neigh_it  = be_ifg_neighbours_iter_alloca(co->cenv->ifg);
52         ir_node *ifg_node, *if_neighb_node;
53
54         pbqp *pbqp_problem;
55         unsigned number_registers = co->cls->n_regs;
56         unsigned number_nodes = 0;
57         unsigned int nodeIdx = 0;
58
59         bitset_t *ignore_registers;
60         pmap *map;
61
62         // count nodes in ifg
63         be_ifg_foreach_node(co->cenv->ifg, nodes_it, ifg_node) {
64                 number_nodes++;
65         }
66
67         // create empty PBQP instance
68         pbqp_problem = alloc_pbqp(number_nodes);
69
70         //
71         ignore_registers = bitset_malloc(number_registers);
72         be_put_ignore_regs(co->cenv->birg, co->cls, ignore_registers);
73
74         // create map
75         map = pmap_create_ex(number_nodes);
76
77         // add costs vector to nodes
78         nodeIdx = 0;
79         be_ifg_foreach_node(co->cenv->ifg, nodes_it, ifg_node) {
80                 // create costs vector
81                 struct vector *costs_vector = vector_alloc(pbqp_problem, number_registers);
82
83                 // set costs
84                 unsigned int cnt;
85                 for(cnt = 0; cnt < costs_vector->len; cnt++) {
86                         if (bitset_is_set(ignore_registers,cnt)) {
87                                 vector_set(costs_vector, cnt, INF_COSTS);
88                         }
89                         else {
90                                 if (!arch_reg_out_is_allocatable(ifg_node, arch_register_for_index(co->cls, cnt)))
91                                 {
92                                         vector_set(costs_vector, cnt, INF_COSTS);
93                                 }
94                                 else {
95                                         vector_set(costs_vector, cnt, 0);
96                                 }
97                         }
98
99                         // add description
100                         vector_set_description(costs_vector, cnt, arch_register_for_index(co->cls, cnt)->name);
101                 }
102
103                 // add costs vector to node
104                 add_node_costs(pbqp_problem, nodeIdx, costs_vector);
105
106                 // insert ir_node and pbqp_node into map
107                 pmap_insert(map, ifg_node, get_node(pbqp_problem,nodeIdx));
108
109                 // increment nodeIndex
110                 nodeIdx++;
111         }
112
113         be_ifg_foreach_node(co->cenv->ifg, nodes_it, ifg_node) {
114                 pbqp_node *src_node = pmap_find(map,ifg_node)->value;
115                 unsigned int srcNodeIdx = src_node->index;
116
117                 // add costs matrix between nodes (interference edge)
118                 be_ifg_foreach_neighbour(co->cenv->ifg, neigh_it, ifg_node, if_neighb_node) {
119                         pbqp_node *trg_node = pmap_find(map,if_neighb_node)->value;
120                         if(get_edge(pbqp_problem, srcNodeIdx, trg_node->index) == NULL) {
121                                 // create costs matrix
122                                 struct pbqp_matrix *matrix = pbqp_matrix_alloc(pbqp_problem, number_registers, number_registers);
123
124                                 // set costs
125                                 unsigned row, col;
126                                 for(row = 0; row < number_registers; row++) {
127                                         for(col = 0; col < number_registers; col++) {
128                                                 if(row == col) {
129                                                         pbqp_matrix_set(matrix, row, col, INF_COSTS);
130                                                 }
131                                                 else {
132                                                         pbqp_matrix_set(matrix, row, col, 2);
133                                                 }
134                                         }
135                                 }
136
137                                 // add costs matrix to interference edge
138                                 add_edge_costs(pbqp_problem, srcNodeIdx, trg_node->index , matrix);
139                         }
140                 }
141
142                 // add costs matrix between nodes (affinety edge)
143                 affinity_node_t *aff_node = get_affinity_info(co, ifg_node);
144                 neighb_t *aff_neighb_node;
145                 if(aff_node != NULL) {
146                         co_gs_foreach_neighb(aff_node, aff_neighb_node) {
147                                 pbqp_node *trg_node = pmap_find(map,aff_neighb_node->irn)->value;
148                                 if(get_edge(pbqp_problem, srcNodeIdx, trg_node->index) == NULL) {
149                                         // create costs matrix
150                                         struct pbqp_matrix *matrix = pbqp_matrix_alloc(pbqp_problem, number_registers, number_registers);
151
152                                         // set costs
153                                         unsigned row, col;
154                                         for(row = 0; row < number_registers; row++) {
155                                                 for(col = 0; col < number_registers; col++) {
156                                                         if(row == col) {
157                                                                 pbqp_matrix_set(matrix, row, col, 0);
158                                                         }
159                                                         else {
160                                                                 pbqp_matrix_set(matrix, row, col, 2);
161                                                         }
162                                                 }
163                                         }
164
165                                         // add costs matrix to interference edge
166                                         add_edge_costs(pbqp_problem, srcNodeIdx, trg_node->index , matrix);
167                                 }
168                         }
169                 }
170         }
171
172 #if KAPS_DUMP
173         // dump graph before solving pbqp
174         FILE *file_before = my_open(co->cenv, "", "-before.html");
175         set_dumpfile(pbqp_problem, file_before);
176         pbqp_dump_input(pbqp_problem);
177 #endif
178
179
180         // solve pbqp problem
181         solve_pbqp_heuristical(pbqp_problem);
182         //solve_pbqp_brute_force(pbqp_problem);
183         num solution = get_solution(pbqp_problem);
184
185         printf("Solution (%s): %d\n",co->name, (int)solution);
186
187         // coloring ifg
188         be_ifg_foreach_node(co->cenv->ifg, nodes_it, ifg_node) {
189                 pbqp_node *node = pmap_find(map,ifg_node)->value;
190                 num index = get_node_solution(pbqp_problem, node->index);
191                 const arch_register_t *reg = arch_register_for_index(co->cls, index);
192                 arch_set_irn_register(ifg_node, reg);
193         }
194
195 #if KAPS_DUMP
196         // dump graph after solving pbqp
197         FILE *file_after = my_open(co->cenv, "", "-after.html");
198         set_dumpfile(pbqp_problem, file_after);
199         pbqp_dump_input(pbqp_problem);
200 #endif
201
202
203         // free pbqp resources
204 #if KAPS_DUMP
205         fclose(file_before);
206         fclose(file_after);
207 #endif
208         bitset_free(ignore_registers);
209         pmap_destroy(map);
210         free_pbqp(pbqp_problem);
211
212         return 0;
213 }