move is_liveness_node to irlivechk header and share it with belive
[libfirm] / ir / ana / irouts.c
1 /*
2  * Copyright (C) 1995-2011 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    Compute and access out edges (also called def-use edges).
23  * @author   Goetz Lindenmaier, Michael Beck
24  * @date     1.2002
25  */
26 #include "config.h"
27
28 #include <string.h>
29
30 #include "xmalloc.h"
31 #include "irouts.h"
32 #include "irnode_t.h"
33 #include "irgraph_t.h"
34 #include "irprog_t.h"
35 #include "irgwalk.h"
36 #include "util.h"
37 #include "irprintf.h"
38 #include "error.h"
39 #include "ircons.h"
40
41 unsigned get_irn_n_outs(const ir_node *node)
42 {
43         return node->o.out->n_edges;
44 }
45
46 ir_node *get_irn_out(const ir_node *def, unsigned pos)
47 {
48         assert(pos < get_irn_n_outs(def));
49         return def->o.out->edges[pos].use;
50 }
51
52 ir_node *get_irn_out_ex(const ir_node *def, unsigned pos, int *in_pos)
53 {
54         assert(pos < get_irn_n_outs(def));
55         *in_pos = def->o.out->edges[pos].pos;
56         return def->o.out->edges[pos].use;
57 }
58
59 void set_irn_out(ir_node *def, unsigned pos, ir_node *use, int in_pos)
60 {
61         assert(use != NULL);
62         assert(pos < get_irn_n_outs(def));
63         def->o.out->edges[pos].use = use;
64         def->o.out->edges[pos].pos = in_pos;
65 }
66
67 unsigned get_Block_n_cfg_outs(const ir_node *bl)
68 {
69         assert(is_Block(bl));
70         unsigned n_cfg_outs = 0;
71         for (unsigned i = 0; i < get_irn_n_outs(bl); ++i) {
72                 const ir_node *succ = get_irn_out(bl, i);
73                 if (get_irn_mode(succ) != mode_X)
74                         continue;
75                 if (is_End(succ) || is_Bad(succ))
76                         continue;
77                 n_cfg_outs += get_irn_n_outs(succ);
78         }
79         return n_cfg_outs;
80 }
81
82 unsigned get_Block_n_cfg_outs_ka(const ir_node *bl)
83 {
84         assert(is_Block(bl));
85         unsigned n_cfg_outs = 0;
86         for (unsigned i = 0; i < get_irn_n_outs(bl); ++i) {
87                 const ir_node *succ = get_irn_out(bl, i);
88                 if (get_irn_mode(succ) != mode_X)
89                         continue;
90                 if (is_Bad(succ))
91                         continue;
92                 if (is_End(succ)) {
93                         ir_node *end_bl = get_nodes_block(succ);
94                         if (end_bl == bl)
95                                 continue;
96                         ++n_cfg_outs;
97                         continue;
98                 }
99                 n_cfg_outs += get_irn_n_outs(succ);
100         }
101         return n_cfg_outs;
102 }
103
104 ir_node *get_Block_cfg_out(const ir_node *bl, unsigned pos)
105 {
106         assert(is_Block(bl));
107         for (unsigned i = 0; i < get_irn_n_outs(bl); ++i) {
108                 const ir_node *succ = get_irn_out(bl, i);
109                 if (get_irn_mode(succ) != mode_X)
110                         continue;
111                 if (is_End(succ) || is_Bad(succ))
112                         continue;
113
114                 unsigned n_outs = get_irn_n_outs(succ);
115                 if (pos < n_outs)
116                         return get_irn_out(succ, pos);
117                 else
118                         pos -= n_outs;
119         }
120         return NULL;
121 }
122
123 ir_node *get_Block_cfg_out_ka(const ir_node *bl, unsigned pos)
124 {
125         assert(is_Block(bl));
126         for (unsigned i = 0; i < get_irn_n_outs(bl); ++i) {
127                 const ir_node *succ = get_irn_out(bl, i);
128                 if (get_irn_mode(succ) != mode_X)
129                         continue;
130                 if (is_Bad(succ))
131                         continue;
132
133                 if (is_End(succ)) {
134                         ir_node *end_bl = get_nodes_block(succ);
135                         if (end_bl == bl) {
136                                 /* ignore End if we are in the Endblock */
137                                 continue;
138                         }
139                         if (pos == 0) {
140                                 /* handle keep-alive here: return the Endblock instead of the End node */
141                                 return end_bl;
142                         } else {
143                                 --pos;
144                                 continue;
145                         }
146                 }
147                 unsigned n_outs = get_irn_n_outs(succ);
148                 if (pos < n_outs)
149                         return get_irn_out(succ, pos);
150                 else
151                         pos -= n_outs;
152         }
153         return NULL;
154 }
155
156 static void irg_out_walk_2(ir_node *node, irg_walk_func *pre,
157                            irg_walk_func *post, void *env)
158 {
159         assert(get_irn_visited(node) < get_irg_visited(current_ir_graph));
160
161         set_irn_visited(node, get_irg_visited(current_ir_graph));
162
163         if (pre) pre(node, env);
164
165         int n = get_irn_n_outs(node);
166         for (int i = 0; i < n; ++i) {
167                 ir_node *succ = get_irn_out(node, i);
168                 if (get_irn_visited(succ) < get_irg_visited(current_ir_graph))
169                         irg_out_walk_2(succ, pre, post, env);
170         }
171
172         if (post) post(node, env);
173 }
174
175 void irg_out_walk(ir_node *node, irg_walk_func *pre, irg_walk_func *post,
176                   void *env)
177 {
178         assert(node);
179         ir_graph *irg = get_irn_irg(node);
180         if (irg_has_properties(irg, IR_GRAPH_PROPERTY_CONSISTENT_OUTS)) {
181                 inc_irg_visited(irg);
182                 irg_out_walk_2(node, pre, post, env);
183         }
184 }
185
186 static void irg_out_block_walk2(ir_node *bl, irg_walk_func *pre,
187                                 irg_walk_func *post, void *env)
188 {
189         if (Block_block_visited(bl))
190                 return;
191
192         mark_Block_block_visited(bl);
193
194         if (pre)
195                 pre(bl, env);
196
197         int n = get_Block_n_cfg_outs(bl);
198         for (int i = 0; i < n; ++i) {
199                 /* find the corresponding predecessor block. */
200                 ir_node *pred = get_Block_cfg_out(bl, i);
201                 /* recursion */
202                 irg_out_block_walk2(pred, pre, post, env);
203         }
204
205         if (post)
206                 post(bl, env);
207 }
208
209 void irg_out_block_walk(ir_node *node, irg_walk_func *pre, irg_walk_func *post,
210                         void *env)
211 {
212         ir_graph *irg = get_irn_irg(node);
213         assert(is_Block(node) || (get_irn_mode(node) == mode_X));
214
215         ir_graph *rem = current_ir_graph;
216         current_ir_graph = irg;
217
218         inc_irg_block_visited(irg);
219
220         if (get_irn_mode(node) == mode_X) {
221                 int n = get_irn_n_outs(node);
222                 for (int i = 0; i < n; ++i) {
223                         ir_node *succ = get_irn_out(node, i);
224                         irg_out_block_walk2(succ, pre, post, env);
225                 }
226         } else {
227                 irg_out_block_walk2(node, pre, post, env);
228         }
229
230         current_ir_graph = rem;
231 }
232
233 /*--------------------------------------------------------------------*/
234 /** Building and Removing the out datastructure                      **/
235 /**                                                                  **/
236 /** The outs of a graph are allocated in a single, large array.      **/
237 /** This allows to allocate and deallocate the memory for the outs   **/
238 /** on demand.  The large array is separated into many small ones    **/
239 /** for each node.  Only a single field to reference the out array   **/
240 /** is stored in each node and a field referencing the large out     **/
241 /** array in irgraph.  The 0 field of each out array contains the    **/
242 /** size of this array.  This saves memory in the irnodes themselves.**/
243 /** The construction does two passes over the graph.  The first pass **/
244 /** counts the overall number of outs and the outs of each node.  It **/
245 /** stores the outs of each node in the out reference of the node.   **/
246 /** Then the large array is allocated.  The second iteration chops   **/
247 /** the large array into smaller parts, sets the out edges and       **/
248 /** recounts the out edges.                                          **/
249 /** Removes Tuple nodes!                                             **/
250 /*--------------------------------------------------------------------*/
251
252
253 /** Returns the amount of out edges for not yet visited successors. */
254 static void count_outs_node(ir_node *n)
255 {
256         if (irn_visited_else_mark(n))
257                 return;
258
259         /* initialize our counter */
260         n->o.n_outs = 0;
261
262         int start     = is_Block(n) ? 0 : -1;
263         int irn_arity = get_irn_arity(n);
264         for (int i = start; i < irn_arity; ++i) {
265                 ir_node *def = get_irn_n(n, i);
266                 /* optimize Tuples */
267                 ir_node *skipped = skip_Tuple(def);
268                 if (skipped != def)
269                         set_irn_n(n, i, skipped);
270
271                 count_outs_node(skipped);
272                 ++skipped->o.n_outs;
273         }
274 }
275
276
277 /** Returns the amount of out edges for not yet visited successors.
278  *  This version handles some special nodes like irg_frame, irg_args etc. */
279 static void count_outs(ir_graph *irg)
280 {
281         inc_irg_visited(irg);
282         count_outs_node(get_irg_end(irg));
283         for (int i = anchor_first; i <= anchor_last; ++i) {
284                 ir_node *n = get_irg_anchor(irg, i);
285                 if (irn_visited_else_mark(n))
286                         continue;
287                 n->o.n_outs = 0;
288         }
289 }
290
291 static void set_out_edges_node(ir_node *node, struct obstack *obst)
292 {
293         if (irn_visited_else_mark(node))
294                 return;
295
296         /* Allocate my array */
297         unsigned n_outs = node->o.n_outs;
298         node->o.out          = OALLOCF(obst, ir_def_use_edges, edges, n_outs);
299         node->o.out->n_edges = 0;
300
301         /* add def->use edges from my predecessors to me */
302         int start     = is_Block(node) ? 0 : -1;
303         int irn_arity = get_irn_arity(node);
304         for (int i = start; i < irn_arity; ++i) {
305                 ir_node *def = get_irn_n(node, i);
306
307                 /* recurse, ensures that out array of pred is already allocated */
308                 set_out_edges_node(def, obst);
309
310                 /* Remember this Def-Use edge */
311                 unsigned pos = def->o.out->n_edges++;
312                 def->o.out->edges[pos].use = node;
313                 def->o.out->edges[pos].pos = i;
314         }
315 }
316
317 static void set_out_edges(ir_graph *irg)
318 {
319         struct obstack *obst = &irg->out_obst;
320
321         obstack_init(obst);
322         irg->out_obst_allocated = true;
323
324         inc_irg_visited(irg);
325         set_out_edges_node(get_irg_end(irg), obst);
326         for (int i = anchor_first; i <= anchor_last; ++i) {
327                 ir_node *n = get_irg_anchor(irg, i);
328                 if (irn_visited_else_mark(n))
329                         continue;
330                 n->o.out          = OALLOCF(obst, ir_def_use_edges, edges, 0);
331                 n->o.out->n_edges = 0;
332         }
333 }
334
335 void compute_irg_outs(ir_graph *irg)
336 {
337         free_irg_outs(irg);
338
339         /* This first iteration counts the overall number of out edges and the
340            number of out edges for each node. */
341         count_outs(irg);
342
343         /* The second iteration splits the irg->outs array into smaller arrays
344            for each node and writes the back edges into this array. */
345         set_out_edges(irg);
346
347         add_irg_properties(irg, IR_GRAPH_PROPERTY_CONSISTENT_OUTS
348                               | IR_GRAPH_PROPERTY_NO_TUPLES);
349 }
350
351 void assure_irg_outs(ir_graph *irg)
352 {
353         if (!irg_has_properties(irg, IR_GRAPH_PROPERTY_CONSISTENT_OUTS))
354                 compute_irg_outs(irg);
355 }
356
357 #ifdef DEBUG_libfirm
358 /** Clear the outs of a node */
359 static void reset_outs(ir_node *node, void *unused)
360 {
361         (void) unused;
362         node->o.out = NULL;
363 }
364 #endif
365
366 void free_irg_outs(ir_graph *irg)
367 {
368         if (irg->out_obst_allocated) {
369                 obstack_free(&irg->out_obst, NULL);
370                 irg->out_obst_allocated = false;
371         }
372
373 #ifdef DEBUG_libfirm
374         /* when debugging, *always* reset all nodes' outs!  irg->outs might
375            have been lying to us */
376         irg_walk_graph (irg, reset_outs, NULL, NULL);
377 #endif
378 }