ef5b0178ee756f29e63aa0da0f407adfc82e11c5
[libfirm] / ir / be / beifg_clique.c
1 /*
2  * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19
20 /**
21  * @file
22  * @brief       Clique calculation for chordal ifg.
23  * @author      Sebastian Hack
24  * @date        18.11.2005
25  * @version     $Id$
26  */
27 #include "config.h"
28
29 #include <stdlib.h>
30
31 #include "belive_t.h"
32 #include "list.h"
33
34 #include "irnode_t.h"
35 #include "irgraph_t.h"
36 #include "irgwalk.h"
37 #include "irbitset.h"
38
39 #include "bearch.h"
40 #include "be_t.h"
41 #include "beintlive_t.h"
42 #include "beifg_t.h"
43 #include "beifg_impl.h"
44 #include "bechordal_t.h"
45
46 typedef struct _cli_head_t {
47         struct list_head   list;
48         struct _cli_head_t *next_cli_head;
49         ir_node            *min;
50         ir_node            *max;
51 } cli_head_t;
52
53 typedef struct _ifg_clique_t {
54         const be_ifg_impl_t    *impl;
55         const be_chordal_env_t *env;
56         cli_head_t             *cli_root;
57         struct obstack         obst;
58         cli_head_t             *curr_cli_head;
59 } ifg_clique_t;
60
61 typedef struct _cli_element_t {
62         struct list_head list;
63         ir_node          *irn;
64 } cli_element_t;
65
66 typedef struct _cli_iter_t {
67         const ifg_clique_t *ifg;
68         cli_head_t         *curr_cli_head;
69         cli_element_t      *curr_cli_element;
70         const ir_node      *curr_irn;
71         bitset_t           *visited_neighbours;
72         bitset_t           *visited_nodes;
73 } cli_iter_t;
74
75 /* PRIVATE FUNCTIONS */
76 static cli_head_t *get_new_cli_head(ifg_clique_t *ifg)
77 {
78         cli_head_t *cli_head;
79         cli_head_t *new_cli_head;
80
81         if (ifg->cli_root == NULL)
82         {
83                 new_cli_head = OALLOC(&ifg->obst, cli_head_t);
84                 INIT_LIST_HEAD(&new_cli_head->list);
85                 ifg->cli_root = new_cli_head;
86         }
87         else
88         {
89                 cli_head = ifg->cli_root;
90                 while (!(cli_head->next_cli_head == NULL))
91                 {
92                         cli_head = cli_head->next_cli_head;
93                 }
94                 new_cli_head = OALLOC(&ifg->obst, cli_head_t);
95                 INIT_LIST_HEAD(&new_cli_head->list);
96                 cli_head->next_cli_head = new_cli_head;
97         }
98
99         new_cli_head->min = NULL;
100         new_cli_head->max = NULL;
101         new_cli_head->next_cli_head = NULL;
102         ifg->curr_cli_head = new_cli_head;
103
104         return new_cli_head;
105 }
106
107 static cli_element_t *get_new_cli_element(ifg_clique_t *ifg)
108 {
109         cli_element_t *cli_element;
110
111         cli_element = OALLOC(&ifg->obst, cli_element_t);
112         INIT_LIST_HEAD(&cli_element->list);
113
114         return cli_element;
115 }
116
117 static void write_clique(ir_nodeset_t *live_set, ifg_clique_t *ifg)
118 {
119         ir_node *live_irn;
120         ir_node *test_node;
121         int test_int = 0;
122         ir_node *max_node = NULL;
123         ir_node *min_node = NULL;
124         cli_element_t *new_element = NULL;
125         cli_element_t *element = NULL;
126         cli_head_t *cli_head = get_new_cli_head(ifg);
127         int is_element = 0;
128         ir_nodeset_iterator_t iter;
129
130         foreach_ir_nodeset(live_set, live_irn, iter)
131         {
132                 /* test if node is max or min dominator*/
133                 test_node = live_irn;
134                 if (max_node == NULL)
135                 {
136                         max_node = test_node;
137                         min_node = test_node;
138                 }
139                 else
140                 {
141                         test_int = value_dominates(test_node, max_node);
142                         if (test_int == 1)
143                         {
144                                 max_node = test_node;
145                         }
146                         test_int = value_dominates(min_node, test_node);
147                         if (test_int == 1)
148                         {
149                                 min_node = test_node;
150                         }
151                 }
152
153                 list_for_each_entry(cli_element_t, element, &cli_head->list, list){
154                         if (element->irn == live_irn){
155                                 is_element = 1;
156                                 break;
157                         }
158                 }
159
160                 if (!is_element){
161                         new_element = get_new_cli_element(ifg);
162                         new_element->irn = live_irn;
163                         list_add(&new_element->list, &cli_head->list) ;
164                 }
165         }
166
167         cli_head->min = min_node;
168         cli_head->max = max_node;
169 }
170
171 static cli_head_t *get_next_cli_head(const ir_node *irn, cli_iter_t *it) /* ...containing the node *irn */
172 {
173         cli_head_t *head;
174         cli_element_t *element;
175
176         int is_dominated_by_max;
177         //int dominates_min;
178
179         if (it->curr_cli_head == NULL || it->curr_cli_head->next_cli_head == NULL) /* way back of recursion or this is the last clique */
180         {
181                 it->curr_cli_head = NULL;
182                 return NULL;
183         }
184
185         head = it->curr_cli_head->next_cli_head;
186
187         is_dominated_by_max = value_dominates(head->max, irn);
188         //dominates_min = value_dominates(irn, head->min);
189
190         if ((is_dominated_by_max) || (irn == head->max)) /* node could be in clique */
191         {
192                 /* check if node is in clique */
193                 list_for_each_entry(cli_element_t, element, &head->list, list)
194                 {
195                         if (&element->list != &head->list)
196                         {
197                                 if (element->irn == irn)
198                                 {
199                                         /* node is in clique */
200                                         it->curr_cli_head    = head;
201                                         /* needed because the next element is searched with list.next of it->curr_cli_element */
202                                         it->curr_cli_element = (void *) head;
203                                         break;
204                                 }
205                         }
206                 }
207
208                 if (it->curr_cli_head != head) /*node was not in clique */
209                 {
210                         it->curr_cli_head = head;
211                         head = get_next_cli_head(irn, it);
212                 }
213         }
214         else
215         {
216                 it->curr_cli_head = head;
217                 head = get_next_cli_head(irn, it);
218         }
219         return head;
220 }
221
222 /* ... of the current clique, returns NULL if there were no more elements ..*/
223 static cli_element_t *get_next_element(const ir_node *irn, cli_iter_t *it)
224 {
225         cli_element_t *element = it->curr_cli_element;
226         cli_head_t    *head    = it->curr_cli_head;
227
228         if (!head || it->curr_cli_element == NULL) /* way back of recursion or there are no more heads */
229         {
230                 it->curr_cli_element = NULL;
231                 return NULL;
232         }
233         else
234         {
235                 element = list_entry(element->list.next, cli_element_t, list);
236
237                 if (&element->list == &head->list) /* Clique has no more elements */
238                 {
239                         head = get_next_cli_head(irn, it);
240                         element = get_next_element(irn, it);
241                 }
242
243                 if (element && element->irn == irn) /* the node you are searching neighbors for */
244                 {
245                         it->curr_cli_element = element;
246                         element = get_next_element(irn, it);
247                 }
248
249                 it->curr_cli_element = element;
250
251                 return element;
252         }
253 }
254
255 static void find_nodes(const ifg_clique_t *ifg, cli_iter_t *it)
256 {
257         cli_element_t *element;
258         cli_head_t *cli_head = ifg->cli_root;
259
260         bitset_t *bitset_visnodes = bitset_malloc(get_irg_last_idx(ifg->env->irg));
261
262         it->visited_nodes = bitset_visnodes;
263         it->curr_cli_head = cli_head;
264
265         assert(cli_head && "There is no root entry to work on!");
266
267         if (cli_head->list.next != &cli_head->list) /* if cli_head contains an element */
268         {
269                 element = list_entry(cli_head->list.next, cli_element_t, list);
270                 it->curr_cli_element = element;
271         }
272 }
273
274 static ir_node *get_next_node(cli_iter_t *it)
275 {
276         cli_head_t *cli_head = NULL;
277         cli_element_t *element = it->curr_cli_element;
278
279         ir_node *irn;
280
281         if (element == NULL)
282                 return NULL;
283
284         if (!(&it->curr_cli_head->list == element->list.next))
285         {
286                 irn = element->irn;
287                 element = list_entry(element->list.next, cli_element_t, list);
288                 it->curr_cli_element = element;
289         }
290         else /* reached end of clique */
291         {
292                 cli_head = it->curr_cli_head;
293                 if (!(cli_head->next_cli_head == NULL))
294                 {
295                         irn = element->irn;
296                         cli_head = cli_head->next_cli_head;
297                         it->curr_cli_head = cli_head;
298                         element = list_entry(cli_head->list.next, cli_element_t, list);
299                         it->curr_cli_element = element;
300                 }
301                 else
302                 {
303                         it->curr_cli_head = NULL;
304                         it->curr_cli_element = NULL;
305                         irn = element->irn;
306                 }
307         }
308         if (!(irn == NULL))
309         {
310                 if (bitset_is_set(it->visited_nodes, get_irn_idx(irn)))
311                 {
312                         irn = get_next_node(it);
313                 }
314                 if (!(irn == NULL))
315                 {
316                         bitset_set(it->visited_nodes, get_irn_idx(irn));
317                 }
318         }
319
320         return irn;
321 }
322
323 static void find_neighbour_walker(ir_node *bl, void *data)
324 {
325         ifg_clique_t     *ifg    = data;
326         struct list_head *head   = get_block_border_head(ifg->env, bl);
327         int               was_def = 0;
328         ir_nodeset_t      live;
329         border_t         *b;
330
331         ir_nodeset_init(&live);
332
333         assert(is_Block(bl) && "There is no block to work on.");
334
335         foreach_border_head(head, b) /* follow the borders of the block */
336         {
337                 ir_node *irn = b->irn;
338
339                 if (b->is_def) /* b is a new node */
340                 {
341                         ir_nodeset_insert(&live, irn);
342                         if (b->is_real)
343                         {
344                                 was_def = 1;
345                         }
346                 }
347                 else
348                 {
349                         if (was_def == 1) /* if there is a USE after a DEF... */
350                         {
351                                 write_clique(&live, ifg); /* ...add the clique. */
352                                 was_def = 0;
353                         }
354                         ir_nodeset_remove(&live, irn);
355                 }
356         }
357         ir_nodeset_destroy(&live);
358 }
359
360 static void find_first_neighbour(const ifg_clique_t *ifg, cli_iter_t *it, const ir_node *irn)
361 {
362         cli_head_t    *cli_head = ifg->cli_root;
363         cli_element_t *element;
364         bitset_t      *bitset_visneighbours = bitset_malloc(get_irg_last_idx(ifg->env->irg));
365
366         int is_dominated_by_max = 0;
367         int dominates_min = 0;
368         int is_in_clique = 0;
369
370         it->curr_cli_head = cli_head;
371         it->ifg = ifg;
372         it->visited_neighbours = bitset_visneighbours;
373
374         assert(cli_head && "There is no root entry for a cli_head.");
375
376         is_dominated_by_max = value_dominates(cli_head->max, irn);
377         dominates_min = value_dominates(irn, cli_head->min);
378
379         if ((is_dominated_by_max) || (irn == cli_head->max))  /* node could be in clique */
380         {
381                 /* check if node is in clique */
382                 list_for_each_entry(cli_element_t, element, &cli_head->list, list)
383                 {
384                         if (element->irn == irn) /* node is in clique */
385                         {
386                                 it->curr_cli_element = (void *) cli_head; /* needed because the next element is searched with list.next of it->curr_cli_element */
387                                 is_in_clique = 1;
388                                 element = get_next_element(irn, it);
389                                 break;
390                         }
391                 }
392         }
393         if (!is_in_clique)
394         {
395                 cli_head = get_next_cli_head(irn, it);
396                 element = get_next_element(irn, it);
397         }
398
399         it->curr_cli_element = element;
400         it->curr_irn = irn;
401 }
402
403 static ir_node *get_next_neighbour(cli_iter_t *it)
404 {
405         ir_node *res = NULL;
406         const ir_node *irn = it->curr_irn;
407
408         if (it->curr_cli_element != NULL)
409                 res = it->curr_cli_element->irn;
410         else
411                 return NULL;
412
413         it->curr_cli_element = get_next_element(irn, it);
414
415         if (res)
416         {
417                 if (bitset_contains_irn(it->visited_neighbours, res))
418                 {
419                         res = get_next_neighbour(it);
420                 }
421                 else
422                 {
423                         bitset_set(it->visited_neighbours, get_irn_idx(res));
424                 }
425         }
426
427         return res;
428 }
429
430
431 /* PUBLIC FUNCTIONS */
432
433 static void ifg_clique_free(void *self)
434 {
435         ifg_clique_t *ifg = self;
436         obstack_free(&ifg->obst, NULL);
437
438         free(self);
439 }
440
441 static int ifg_clique_connected(const void *self, const ir_node *a, const ir_node *b)
442 {
443         const ifg_clique_t *ifg = self;
444         cli_iter_t it;
445         int connected = -1;
446         ir_node *irn = NULL;
447
448         find_first_neighbour(ifg, &it, a);
449         connected = 0;
450         irn = get_next_neighbour(&it);
451         while (irn != NULL)
452         {
453                 if (irn == b)
454                 {
455                         connected = 1;
456                         break;
457                 }
458                 irn = get_next_neighbour(&it);
459         }
460
461         return connected;
462 }
463
464 static ir_node *ifg_clique_neighbours_begin(const void *self, void *iter, const ir_node *irn)
465 {
466         find_first_neighbour(self, iter, irn);
467         return get_next_neighbour(iter);
468 }
469
470 static ir_node *ifg_clique_neighbours_next(const void *self, void *iter)
471 {
472         (void) self;
473         return get_next_neighbour(iter);
474 }
475
476 static void ifg_clique_neighbours_break(const void *self, void *iter)
477 {
478         cli_iter_t *it = iter;
479         (void) self;
480
481         bitset_free(it->visited_neighbours);
482 }
483
484 static ir_node *ifg_clique_nodes_begin(const void *self, void *iter)
485 {
486         find_nodes(self, iter);
487         return get_next_node(iter);
488 }
489
490 static ir_node *ifg_clique_nodes_next(const void *self, void *iter)
491 {
492         (void) self;
493         return get_next_node(iter);
494 }
495
496 static void ifg_clique_nodes_break(const void *self, void *iter)
497 {
498         cli_iter_t *it = iter;
499         (void) self;
500
501         bitset_free(it->visited_nodes);
502 }
503
504 static int ifg_clique_degree(const void *self, const ir_node *irn)
505 {
506         int degree = -1;
507         cli_iter_t it;
508
509         find_first_neighbour(self, &it, irn);
510         degree = 0;
511         irn = get_next_neighbour(&it);
512         while (irn != NULL)
513         {
514                 degree++;
515                 irn = get_next_neighbour(&it);
516         }
517
518         return degree;
519 }
520
521 static const be_ifg_impl_t ifg_clique_impl = {
522         sizeof(cli_iter_t),
523         sizeof(cli_iter_t),
524         0,
525         ifg_clique_free,
526         ifg_clique_connected,
527         ifg_clique_neighbours_begin,
528         ifg_clique_neighbours_next,
529         ifg_clique_neighbours_break,
530         ifg_clique_nodes_begin,
531         ifg_clique_nodes_next,
532         ifg_clique_nodes_break,
533         NULL,
534         NULL,
535         NULL,
536         ifg_clique_degree
537 };
538
539 be_ifg_t *be_ifg_clique_new(const be_chordal_env_t *env)
540 {
541         ifg_clique_t *ifg       = XMALLOC(ifg_clique_t);
542
543         ifg->impl               = &ifg_clique_impl;
544         ifg->env                        = env;
545
546         ifg->cli_root           = NULL;
547         obstack_init(&ifg->obst);
548
549         dom_tree_walk_irg(env->irg, find_neighbour_walker, NULL, ifg);
550
551         obstack_finish(&ifg->obst);
552         return (be_ifg_t *) ifg;
553 }