some workaround to avoid condeval creating Phibs which not all backends like
[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 "irnodeset.h"
20 #include "irgraph_t.h"
21 #include "irgwalk.h"
22
23 #include "be_t.h"
24 #include "belive_t.h"
25 #include "bera.h"
26 #include "beifg_t.h"
27 #include "bechordal_t.h"
28
29 #define MAX(x, y) ((x) > (y) ? (x) : (y))
30
31 typedef struct _ifg_std_t ifg_std_t;
32
33 struct _ifg_std_t {
34         const be_ifg_impl_t *impl;
35         const be_chordal_env_t *env;
36 };
37
38 static void ifg_std_free(void *self)
39 {
40         free(self);
41 }
42
43 static int ifg_std_connected(const void *self, const ir_node *a, const ir_node *b)
44 {
45         const ifg_std_t *ifg = self;
46         be_lv_t *lv = ifg->env->birg->lv;
47         return values_interfere(lv, a, b);
48 }
49
50 typedef struct _nodes_iter_t {
51         const be_chordal_env_t *env;
52         struct obstack obst;
53         int n;
54         int curr;
55         ir_node **nodes;
56 } nodes_iter_t;
57
58 static void nodes_walker(ir_node *bl, void *data)
59 {
60         nodes_iter_t *it = data;
61         struct list_head *head = get_block_border_head(it->env, bl);
62
63         border_t *b;
64
65         foreach_border_head(head, b) {
66                 if(b->is_def && b->is_real) {
67                         obstack_ptr_grow(&it->obst, b->irn);
68                         it->n++;
69                 }
70         }
71 }
72
73 static void find_nodes(const void *self, void *iter) {
74         const ifg_std_t *ifg = self;
75         nodes_iter_t *it = iter;
76
77         obstack_init(&it->obst);
78         it->n     = 0;
79         it->curr  = 0;
80         it->env   = ifg->env;
81
82         irg_block_walk_graph(ifg->env->irg, nodes_walker, NULL, iter);
83         obstack_ptr_grow(&it->obst, NULL);
84         it->nodes = obstack_finish(&it->obst);
85 }
86
87 static INLINE void node_break(nodes_iter_t *it, int force)
88 {
89         if((it->curr >= it->n || force) && it->nodes) {
90                 obstack_free(&it->obst, NULL);
91                 it->nodes = NULL;
92         }
93 }
94
95 static ir_node *get_next_node(void *iter)
96 {
97         nodes_iter_t *it = iter;
98         ir_node *res     = NULL;
99
100         if(it->curr < it->n)
101                 res = it->nodes[it->curr++];
102
103         node_break(it, 0);
104
105         return res;
106 }
107
108 static ir_node *ifg_std_nodes_begin(const void *self, void *iter)
109 {
110         find_nodes(self, iter);
111         return get_next_node(iter);
112 }
113
114 static ir_node *ifg_std_nodes_next(const void *self, void *iter)
115 {
116         return get_next_node(iter);
117 }
118
119 static void ifg_std_nodes_break(const void *self, void *iter)
120 {
121         node_break(iter, 1);
122 }
123
124 typedef struct _adj_iter_t {
125         const be_chordal_env_t *env;
126         const ir_node        *irn;
127         int                   valid;
128         ir_nodeset_t          neighbours;
129         ir_nodeset_iterator_t iter;
130 } adj_iter_t;
131
132 static void find_neighbour_walker(ir_node *block, void *data)
133 {
134         adj_iter_t *it          = data;
135         struct list_head *head  = get_block_border_head(it->env, block);
136
137         border_t *b;
138         int has_started = 0;
139
140         if(!be_is_live_in(it->env->birg->lv, block, it->irn) && block != get_nodes_block(it->irn))
141                 return;
142
143         foreach_border_head(head, b) {
144                 ir_node *irn = b->irn;
145
146                 if(irn == it->irn) {
147                         if(b->is_def)
148                                 has_started = 1;
149                         else
150                                 break; /* if we reached the end of the node's lifetime we can safely break */
151                 }
152                 else if(b->is_def) {
153                         /* if any other node than the one in question starts living, add it to the set */
154                         ir_nodeset_insert(&it->neighbours, irn);
155                 }
156                 else if(!has_started) {
157                         /* we only delete, if the live range in question has not yet started */
158                         ir_nodeset_remove(&it->neighbours, irn);
159                 }
160
161         }
162 }
163
164 static void find_neighbours(const ifg_std_t *ifg, adj_iter_t *it, const ir_node *irn)
165 {
166         it->env         = ifg->env;
167         it->irn         = irn;
168         it->valid       = 1;
169         ir_nodeset_init(&it->neighbours);
170
171         dom_tree_walk(get_nodes_block(irn), find_neighbour_walker, NULL, it);
172
173         ir_nodeset_iterator_init(&it->iter, &it->neighbours);
174 }
175
176 static INLINE void neighbours_break(adj_iter_t *it, int force)
177 {
178         assert(it->valid == 1);
179         ir_nodeset_destroy(&it->neighbours);
180         it->valid = 0;
181 }
182
183 static ir_node *get_next_neighbour(adj_iter_t *it) {
184         ir_node *res = ir_nodeset_iterator_next(&it->iter);
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 ir_nodeset_iterator_next(&it->iter);
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 = ir_nodeset_size(&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 }