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