- add support for statistics and merge debug info
[libfirm] / ir / ana / irextbb2.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     Alternative extended basic block computation
23  * @author    Matthias Braun
24  * @date      5.2005
25  * @version   $Id$
26  * @summary
27  *  Alternative algorithm for computing extended basic blocks (using out edges
28  *  and execution frequencies)
29  */
30 #include "config.h"
31
32 #include "irextbb_t.h"
33 #include "irgwalk.h"
34 #include "irnode_t.h"
35 #include "irgraph_t.h"
36 #include "iredges_t.h"
37 #include "irouts.h"
38 #include "xmalloc.h"
39 #include "irprintf.h"
40 #include "execfreq.h"
41
42 typedef struct _env {
43         struct obstack *obst;   /**< the obstack where allocations took place */
44         ir_extblk *head;        /**< head of the list of all extended blocks */
45         ir_exec_freq *execfreqs;
46 } env_t;
47
48 /**
49  * allocate a new extended block header.
50  */
51 static ir_extblk *allocate_extblk(ir_node *block, env_t *env)
52 {
53         ir_extblk *extblk = obstack_alloc(env->obst, sizeof(*extblk));
54
55         extblk->kind    = k_ir_extblk;
56         extblk->visited = 1;
57         extblk->blks    = (ir_node **)env->head;
58         extblk->link    = block;
59         env->head       = extblk;
60
61         set_Block_extbb(block, extblk);
62         set_irn_link(block, NULL);
63
64         return extblk;
65 }
66
67 /**
68  * add a block to an extended block
69  */
70 static void addto_extblk(ir_extblk *extblk, ir_node *block)
71 {
72         /* link all blocks belonging to this extended block */
73         set_irn_link(block, extblk->link);
74
75         extblk->link = block;
76         extblk->visited++;
77
78         set_Block_extbb(block, extblk);
79 }
80
81 /**
82  * Returns the number of block successors.
83  * we are interested only in 1, 2 and >2.
84  */
85 static int get_block_n_succs(ir_node *block) {
86         if (edges_activated(current_ir_graph)) {
87                 const ir_edge_t *edge;
88
89                 edge = get_block_succ_first(block);
90                 if (! edge)
91                         return 0;
92
93                 edge = get_block_succ_next(block, edge);
94                 if (! edge)
95                         return 1;
96
97                 edge = get_block_succ_next(block, edge);
98                 return edge ? 3 : 2;
99         }
100
101         return get_Block_n_cfg_outs(block);
102 }
103
104 static void pick_successor(ir_node *block, ir_extblk *extblk, env_t *env);
105
106 static void create_extblk(ir_node *block, env_t *env)
107 {
108         ir_extblk *extblk;
109
110         if (irn_visited_else_mark(block))
111                 return;
112
113         extblk = allocate_extblk(block, env);
114
115         pick_successor(block, extblk, env);
116 }
117
118 static void pick_successor(ir_node *block, ir_extblk *extblk, env_t *env)
119 {
120         const ir_edge_t *edge;
121         ir_node         *best_succ    = NULL;
122         double          best_execfreq = -1;
123
124         /*
125                 More than two successors means we have a jump table.
126                 we cannot include a jump target into the current extended
127                 basic block, so create a new one here.
128         */
129         if (get_block_n_succs(block) > 2) {
130                 const ir_edge_t *edge;
131
132                 foreach_block_succ(block, edge) {
133                         ir_node *succ = get_edge_src_irn(edge);
134                         create_extblk(succ, env);
135                 }
136
137                 return;
138         }
139
140         foreach_block_succ(block, edge) {
141                 ir_node *succ = get_edge_src_irn(edge);
142                 double execfreq;
143
144                 if(irn_visited(succ))
145                         continue;
146
147                 if(get_Block_n_cfgpreds(succ) > 1) {
148                         create_extblk(succ, env);
149                         continue;
150                 }
151
152                 execfreq = get_block_execfreq(env->execfreqs, succ);
153
154                 /*
155                         Remember best successor and make non best successor with only 1
156                         pred block to new extbb leaders.
157                 */
158                 if (execfreq > best_execfreq) {
159                         if (best_succ != NULL) {
160                                 create_extblk(best_succ, env);
161                         }
162
163                         best_execfreq = execfreq;
164                         best_succ = succ;
165                 }
166                 else {
167                         create_extblk(succ, env);
168                 }
169         }
170
171         /* add best successor and recursively try to pick more */
172         if(best_succ != NULL) {
173                 addto_extblk(extblk, best_succ);
174                 mark_irn_visited(best_succ);
175                 pick_successor(best_succ, extblk, env);
176         }
177 }
178
179 /*
180  * Compute the extended basic blocks for a graph
181  */
182 void compute_extbb_execfreqs(ir_graph *irg, ir_exec_freq *execfreqs) {
183         env_t     env;
184         ir_extblk *extbb, *next;
185         ir_node   *endblock;
186
187         if (irg->extbb_obst) {
188                 obstack_free(irg->extbb_obst, NULL);
189         }
190         else {
191                 irg->extbb_obst = XMALLOC(struct obstack);
192         }
193         obstack_init(irg->extbb_obst);
194
195         env.obst      = irg->extbb_obst;
196         env.head      = NULL;
197         env.execfreqs = execfreqs;
198
199         assure_irg_outs(irg);
200
201         /* we must mark nodes, so increase the visited flag */
202         inc_irg_visited(irg);
203         create_extblk(get_irg_start_block(irg), &env);
204
205         /* the end block needs a extbb assigned (even for endless loops) */
206         endblock = get_irg_end_block(irg);
207         create_extblk(endblock, &env);
208
209         /*
210                 Ok, we have now the list of all extended blocks starting with env.head
211                 every extended block "knowns" the number of blocks in visited and
212                 the blocks are linked in link.
213                 Now we can create arrays that hold the blocks, some kind of "out" edges
214                 for the extended block
215         */
216         for (extbb = env.head; extbb; extbb = next) {
217                 int i, len = (int)extbb->visited;
218                 ir_node *block;
219
220                 next = (ir_extblk *)extbb->blks;
221
222                 extbb->blks = NEW_ARR_D(ir_node *, env.obst, len);
223
224                 for (block = extbb->link, i = 0; i < len; ++i) {
225                         ir_node *nblock = get_irn_link(block);
226
227                         /* ensure that the leader is the first one */
228                         extbb->blks[len - 1 - i] = block;
229                         set_irn_link(block, NULL);
230                         block = nblock;
231                 }
232
233 #if 0
234                 for(i = 0; i < len; ++i) {
235                         if(i > 0)
236                                 printf(", ");
237                         ir_printf("%+F", extbb->blks[i]);
238                 }
239                 printf("\n");
240 #endif
241
242                 extbb->link    = NULL;
243                 extbb->visited = 0;
244         }
245
246         irg->extblk_state = extblk_valid;
247 }