start register allocator again, fix typo
[libfirm] / ir / be / beifg_std.c
1 /**
2  * @file   beifg_std.c
3  * @date   18.11.2005
4  * @author Sebastian Hack
5  *
6  * Copyright (C) 2005 Universitaet Karlsruhe
7  * Released under the GPL
8  */
9
10 #ifdef HAVE_CONFIG_H
11 #include "config.h"
12 #endif
13
14 #include <stdlib.h>
15
16 #include "list.h"
17
18 #include "irnode_t.h"
19 #include "irgraph_t.h"
20 #include "irgwalk.h"
21
22 #include "be_t.h"
23 #include "belive_t.h"
24 #include "bera.h"
25 #include "beifg_t.h"
26 #include "bechordal_t.h"
27
28 #define MAX(x, y) ((x) > (y) ? (x) : (y))
29
30 typedef struct _ifg_std_t ifg_std_t;
31
32 struct _ifg_std_t {
33         const be_ifg_impl_t *impl;
34         const be_chordal_env_t *env;
35 };
36
37 static void ifg_std_free(void *self)
38 {
39         free(self);
40 }
41
42 static int ifg_std_connected(const void *self, const ir_node *a, const ir_node *b)
43 {
44         const ifg_std_t *ifg = self;
45         be_lv_t *lv = ifg->env->birg->lv;
46         return values_interfere(lv, a, b);
47 }
48
49 typedef struct _nodes_iter_t {
50         const be_chordal_env_t *env;
51         struct obstack obst;
52         int n;
53         int curr;
54         ir_node **nodes;
55 } nodes_iter_t;
56
57 static void nodes_walker(ir_node *bl, void *data)
58 {
59         nodes_iter_t *it = data;
60         struct list_head *head = get_block_border_head(it->env, bl);
61
62         border_t *b;
63
64         foreach_border_head(head, b) {
65                 if(b->is_def && b->is_real) {
66                         obstack_ptr_grow(&it->obst, b->irn);
67                         it->n++;
68                 }
69         }
70 }
71
72 static void find_nodes(const void *self, void *iter) {
73         const ifg_std_t *ifg = self;
74         nodes_iter_t *it = iter;
75
76         obstack_init(&it->obst);
77         it->n     = 0;
78         it->curr  = 0;
79         it->env   = ifg->env;
80
81         irg_block_walk_graph(ifg->env->irg, nodes_walker, NULL, iter);
82         obstack_ptr_grow(&it->obst, NULL);
83         it->nodes = obstack_finish(&it->obst);
84 }
85
86 static INLINE void node_break(nodes_iter_t *it, int force)
87 {
88         if((it->curr >= it->n || force) && it->nodes) {
89                 obstack_free(&it->obst, NULL);
90                 it->nodes = NULL;
91         }
92 }
93
94 static ir_node *get_next_node(void *iter)
95 {
96         nodes_iter_t *it = iter;
97         ir_node *res     = NULL;
98
99         if(it->curr < it->n)
100                 res = it->nodes[it->curr++];
101
102         node_break(it, 0);
103
104         return res;
105 }
106
107 static ir_node *ifg_std_nodes_begin(const void *self, void *iter)
108 {
109         find_nodes(self, iter);
110         return get_next_node(iter);
111 }
112
113 static ir_node *ifg_std_nodes_next(const void *self, void *iter)
114 {
115         return get_next_node(iter);
116 }
117
118 static void ifg_std_nodes_break(const void *self, void *iter)
119 {
120         node_break(iter, 1);
121 }
122
123 typedef struct _adj_iter_t {
124         const be_chordal_env_t *env;
125         const ir_node *irn;
126         int reached_end;
127         pset *neighbours;
128 } adj_iter_t;
129
130 static void find_neighbour_walker(ir_node *block, void *data)
131 {
132         adj_iter_t *it          = data;
133         struct list_head *head  = get_block_border_head(it->env, block);
134
135         border_t *b;
136         int has_started = 0;
137
138         if(!be_is_live_in(it->env->birg->lv, block, it->irn) && block != get_nodes_block(it->irn))
139                 return;
140
141         foreach_border_head(head, b) {
142                 ir_node *irn = b->irn;
143
144                 if(irn == it->irn) {
145                         if(b->is_def)
146                                 has_started = 1;
147                         else
148                                 break; /* if we reached the end of the node's lifetime we can safely break */
149                 }
150                 else if(b->is_def) {
151                         /* if any other node than the one in question starts living, add it to the set */
152                         pset_insert_ptr(it->neighbours, irn);
153                 }
154                 else if(!has_started) {
155                         /* we only delete, if the live range in question has not yet started */
156                         pset_remove_ptr(it->neighbours, irn);
157                 }
158
159         }
160 }
161
162 static void find_neighbours(const ifg_std_t *ifg, adj_iter_t *it, const ir_node *irn)
163 {
164         it->env         = ifg->env;
165         it->irn         = irn;
166         it->neighbours  = pset_new_ptr(16);
167         it->reached_end = 0;
168
169         dom_tree_walk(get_nodes_block(irn), find_neighbour_walker, NULL, it);
170 }
171
172 static INLINE void neighbours_break(adj_iter_t *it, int force)
173 {
174         if((it->reached_end || force) && it->neighbours) {
175                 del_pset(it->neighbours);
176                 it->neighbours = NULL;
177         }
178 }
179
180 static ir_node *get_next_neighbour(adj_iter_t *it) {
181         ir_node *res = pset_next(it->neighbours);
182
183         it->reached_end = res == NULL;
184         neighbours_break(it, 0);
185
186         return res;
187 }
188
189 static ir_node *ifg_std_neighbours_begin(const void *self, void *iter, const ir_node *irn)
190 {
191         adj_iter_t *it = iter;
192         find_neighbours(self, iter, irn);
193         return pset_first(it->neighbours);
194 }
195
196 static ir_node *ifg_std_neighbours_next(const void *self, void *iter)
197 {
198         return get_next_neighbour(iter);
199 }
200
201 static void ifg_std_neighbours_break(const void *self, void *iter)
202 {
203         neighbours_break(iter, 1);
204 }
205
206 typedef struct _cliques_iter_t {
207         struct obstack ob;
208         const be_chordal_env_t *cenv;
209         ir_node **buf;
210         ir_node **blocks;
211         int n_blocks, blk;
212         struct list_head *bor;
213         pset *living;
214 } cliques_iter_t;
215
216 static INLINE void free_clique_iter(cliques_iter_t *it) {
217         it->n_blocks = -1;
218         obstack_free(&it->ob, NULL);
219         del_pset(it->living);
220 }
221
222 static void get_blocks_dom_order(ir_node *blk, void *env) {
223         cliques_iter_t *it = env;
224         obstack_ptr_grow(&it->ob, blk);
225 }
226
227 #define pset_foreach(pset, irn)  for(irn=pset_first(pset); irn; irn=pset_next(pset))
228
229
230 /**
231  * NOTE: Be careful when changing this function!
232  *       First understand the control flow of consecutive calls.
233  */
234 static INLINE int get_next_clique(cliques_iter_t *it) {
235
236         /* continue in the block we left the last time */
237         for (; it->blk < it->n_blocks; it->blk++) {
238                 int output_on_shrink = 0;
239                 struct list_head *head = get_block_border_head(it->cenv, it->blocks[it->blk]);
240
241                 /* on entry to a new block set the first border ... */
242                 if (!it->bor)
243                         it->bor = head->prev;
244
245                 /* ... otherwise continue with the border we left the last time */
246                 for (; it->bor != head; it->bor = it->bor->prev) {
247                         border_t *b = list_entry(it->bor, border_t, list);
248
249                         /* if its a definition irn starts living */
250                         if (b->is_def) {
251                                 pset_insert_ptr(it->living, b->irn);
252                                 if (b->is_real)
253                                         output_on_shrink = 1;
254                         } else
255
256                         /* if its the last usage the irn dies */
257                         {
258                                 /* before shrinking the set, return the current maximal clique */
259                                 if (output_on_shrink) {
260                                         int count = 0;
261                                         ir_node *irn;
262
263                                         /* fill the output buffer */
264                                         pset_foreach(it->living, irn)
265                                                 it->buf[count++] = irn;
266
267                                         assert(count > 0 && "We have a 'last usage', so there must be sth. in it->living");
268
269                                         return count;
270                                 }
271
272                                 pset_remove_ptr(it->living, b->irn);
273                         }
274                 }
275
276                 it->bor = NULL;
277                 assert(0 == pset_count(it->living) && "Something has survived! (At the end of the block it->living must be empty)");
278         }
279
280         if (it->n_blocks != -1)
281                 free_clique_iter(it);
282
283         return -1;
284 }
285
286 static int ifg_std_cliques_begin(const void *self, void *iter, ir_node **buf)
287 {
288         const ifg_std_t *ifg = self;
289         cliques_iter_t *it = iter;
290         ir_node *start_bl = get_irg_start_block(ifg->env->irg);
291
292         obstack_init(&it->ob);
293         dom_tree_walk(start_bl, get_blocks_dom_order, NULL, it);
294
295         it->cenv     = ifg->env;
296         it->buf      = buf;
297         it->n_blocks = obstack_object_size(&it->ob) / sizeof(void *);
298         it->blocks   = obstack_finish(&it->ob);
299         it->blk      = 0;
300         it->bor      = NULL;
301         it->living   = pset_new_ptr(2 * arch_register_class_n_regs(it->cenv->cls));
302
303         return get_next_clique(it);
304 }
305
306 static int ifg_std_cliques_next(const void *self, void *iter)
307 {
308         return get_next_clique(iter);
309 }
310
311 static void ifg_std_cliques_break(const void *self, void *iter)
312 {
313         free_clique_iter(iter);
314 }
315
316
317 static int ifg_std_degree(const void *self, const ir_node *irn)
318 {
319         adj_iter_t it;
320         int degree;
321         find_neighbours(self, &it, irn);
322         degree = pset_count(it.neighbours);
323         neighbours_break(&it, 1);
324         return degree;
325 }
326
327 static const be_ifg_impl_t ifg_std_impl = {
328         sizeof(nodes_iter_t),
329         sizeof(adj_iter_t),
330         sizeof(cliques_iter_t),
331
332         ifg_std_free,
333         ifg_std_connected,
334         ifg_std_neighbours_begin,
335         ifg_std_neighbours_next,
336         ifg_std_neighbours_break,
337         ifg_std_nodes_begin,
338         ifg_std_nodes_next,
339         ifg_std_nodes_break,
340         ifg_std_cliques_begin,
341         ifg_std_cliques_next,
342         ifg_std_cliques_break,
343         ifg_std_degree
344 };
345
346 be_ifg_t *be_ifg_std_new(const be_chordal_env_t *env)
347 {
348         ifg_std_t *ifg = xmalloc(sizeof(*ifg));
349
350         ifg->impl = &ifg_std_impl;
351         ifg->env  = env;
352
353         return (be_ifg_t *) ifg;
354 }