dead node elimination now handles all anchors equaly
[libfirm] / ir / ir / iredges.c
1 /**
2  * Always available outs.
3  * @author Sebastian Hack
4  * @date 14.1.2005
5  */
6
7 #ifdef HAVE_CONFIG_H
8 #include "config.h"
9 #endif
10
11 #ifdef HAVE_ALLOCA_H
12 #include <alloca.h>
13 #endif
14 #ifdef HAVE_MALLOC_H
15 #include <malloc.h>
16 #endif
17
18 #include "irnode_t.h"
19 #include "iredges_t.h"
20 #include "irgwalk.h"
21 #include "irdump_t.h"
22 #include "irprintf.h"
23 #include "irhooks.h"
24 #include "debug.h"
25 #include "set.h"
26
27 DEBUG_ONLY(static firm_dbg_module_t *dbg;)
28
29 #if FIRM_EDGES_INPLACE
30
31 /**
32  * This flag is set to 1, if the edges get initialized for an irg.
33  * Then register additional data is forbidden.
34  */
35 static int edges_used = 0;
36
37 static int edges_private_size = 0;
38
39 int edges_register_private_data(size_t n)
40 {
41         int res = edges_private_size;
42
43         assert(!edges_used && "you cannot register private edge data, if edges have been initialized");
44
45         edges_private_size += n;
46         return res;
47 }
48
49 #define TIMES37(x) (((x) << 5) + ((x) << 2) + (x))
50
51 #define get_irn_out_list_head(irn) (&get_irn_out_info(irn)->outs)
52
53 static int edge_cmp(const void *p1, const void *p2, size_t len)
54 {
55         const ir_edge_t *e1 = p1;
56         const ir_edge_t *e2 = p2;
57         int res = e1->src == e2->src && e1->pos == e2->pos;
58
59         return !res;
60 }
61
62 #define edge_hash(edge) (TIMES37((edge)->pos) + HASH_PTR((edge)->src))
63
64 /**
65  * Initialize the out information for a graph.
66  * @note Dead node elim can call this on an already initialized graph.
67  */
68 void edges_init_graph(ir_graph *irg)
69 {
70         if(edges_activated(irg)) {
71                 irg_edge_info_t *info = _get_irg_edge_info(irg);
72                 int amount = 2048;
73
74                 edges_used = 1;
75
76                 if(info->edges) {
77                         amount = set_count(info->edges);
78                         del_set(info->edges);
79                 }
80
81                 info->edges = new_set(edge_cmp, amount);
82         }
83 }
84
85 #define EDGE_SIZE(src) \
86     (edges_private_size + (is_Block(src) ? sizeof(ir_block_edge_t) : sizeof(ir_edge_t)))
87
88
89 /**
90  * Get the edge object of an outgoing edge at a node.
91  * @param   irg The graph, the node is in.
92  * @param   src The node at which the edge originates.
93  * @param   pos The position of the edge.
94  * @return      The corresponding edge object or NULL,
95  *              if no such edge exists.
96  */
97 const ir_edge_t *get_irn_edge(ir_graph *irg, const ir_node *src, int pos)
98 {
99         if(edges_activated(irg)) {
100                 irg_edge_info_t *info = _get_irg_edge_info(irg);
101                 size_t size           = EDGE_SIZE(src);
102                 ir_edge_t key;
103
104                 key.src = (ir_node *) src;
105                 key.pos = pos;
106                 return set_find(info->edges, &key, size, edge_hash(&key));
107         }
108
109         return NULL;
110 }
111
112 /**
113  * Change the out count
114  */
115 static INLINE void edge_change_cnt(ir_node *tgt, int ofs) {
116         irn_edge_info_t *info = _get_irn_edge_info(tgt);
117         info->out_count += ofs;
118 }
119
120 /* The edge from (src, pos) -> old_tgt is redirected to tgt */
121 void edges_notify_edge(ir_node *src, int pos, ir_node *tgt, ir_node *old_tgt, ir_graph *irg)
122 {
123         const char *msg = "";
124
125         if(!edges_activated(irg))
126                 return;
127
128 #if 0
129         assert(node_is_in_irgs_storage(irg, src) && "source not in irg");
130 #endif
131
132         /*
133          * Only do something, if the old and new target differ.
134          */
135         if(tgt != old_tgt) {
136                 int is_block_edge = is_Block(src);
137                 set *edges = _get_irg_edge_info(irg)->edges;
138                 ir_edge_t *edge;
139
140                 /*
141                  * This is scary, but:
142                  * If two entries in a set do not have the same size, they are
143                  * treated as unequal, ignoring the comparison function.
144                  * So, edges from blocks have extra storage (they are
145                  * ir_block_edge_t's).
146                  *
147                  * Also add the amount of registered private data to the
148                  * size of the edge.
149                  */
150                 size_t size      = EDGE_SIZE(src);
151                 ir_edge_t *templ = alloca(size);
152
153                 /* Initialize the edge template to search in the set. */
154                 memset(templ, 0, size);
155                 templ->src = src;
156                 templ->pos = pos;
157                 templ->invalid = 0;
158                 templ->present = 0;
159                 DEBUG_ONLY(templ->src_nr = get_irn_node_nr(src));
160
161                 /*
162                  * If the target is NULL, the edge shall be deleted.
163                  */
164                 if (tgt == NULL) {
165                         /* search the edge in the set. */
166                         edge = set_find(edges, templ, size, edge_hash(templ));
167
168                         /* mark the edge invalid if it was found */
169                         if(edge) {
170                                 ir_block_edge_t *block_edge = (ir_block_edge_t *) edge;
171
172                                 msg = "deleting";
173                                 list_del(&edge->list);
174                                 edge->invalid = 1;
175                                 edge->pos = -2;
176                                 edge->src = NULL;
177
178                                 /*
179                                  * If the edge is a cf edge, we delete it also
180                                  * from the list of all block successor edges.
181                                  */
182                                 if(is_block_edge) {
183                                         list_del(&block_edge->succ_list);
184                                         edge_change_cnt(old_tgt,  -1);
185                                 }
186                         }
187
188                         /* If the edge was not found issue a warning on the debug stream */
189                         else {
190                                 msg = "edge to delete not found!\n";
191                         }
192                 } /* if */
193
194                 /*
195                  * The target is not NULL and the old target differs
196                  * from the new target, the edge shall be moved (if the
197                  * old target was != NULL) or added (if the old target was
198                  * NULL).
199                  */
200                 else {
201                         struct list_head *head = _get_irn_outs_head(tgt);
202
203                         /*
204                          * The list head in the block of the edges target.
205                          * Therein all control flow edges directed at that block
206                          * are recorded.
207                          */
208                         struct list_head *succ_head =
209                                 is_block_edge ? _get_block_succ_head(get_nodes_block(tgt)) : NULL;
210
211                         ir_block_edge_t *block_edge;
212
213 #if 0
214                         if(!node_is_in_irgs_storage(irg, tgt))
215                                 return;
216 #endif
217                         assert(head->next && head->prev &&
218                                         "target list head must have been initialized");
219
220                         /*
221                          * insert the edge, if it is not yet in the set or return
222                          * the instance in the set.
223                          */
224                         edge = set_insert(edges, templ, size, edge_hash(templ));
225                         block_edge = (ir_block_edge_t *) edge;
226
227 #ifdef DEBUG_libfirm
228                         assert(!edge->invalid && "Invalid edge encountered");
229 #endif
230
231                         /* If the old target is not null, the edge is moved. */
232                         if(old_tgt) {
233                                 msg = "redirecting";
234                                 list_move(&edge->list, head);
235
236                                 /* If the edge is a cf edge, move it from the successor list. */
237                                 if(is_block_edge)
238                                         list_move(&block_edge->succ_list, succ_head);
239
240                                 edge_change_cnt(old_tgt,  -1);
241                         }
242
243                         /* The old target was null, thus, the edge is newly created. */
244                         else {
245                                 msg = "adding";
246                                 list_add(&edge->list, head);
247
248                                 /*
249                                  * If the edge is cf edge, enter it into the successor list
250                                  * of the target node's block.
251                                  */
252                                 if(is_block_edge)
253                                         list_add(&block_edge->succ_list, succ_head);
254                         }
255
256                         edge_change_cnt(tgt,  +1);
257                 } /* else */
258         }
259
260         /* If the target and the old target are equal, nothing is done. */
261         DBG((dbg, LEVEL_5, "announce out edge: %n[%p] %d-> %n[%p](%n[%p]): %s\n",
262                                 src, src, pos, tgt, tgt, old_tgt, old_tgt, msg));
263 }
264
265 void edges_node_deleted(ir_node *old, ir_graph *irg)
266 {
267         if(edges_activated(irg)) {
268                 int not_a_block = !is_Block(old);
269                 int i, n;
270
271                 DBG((dbg, LEVEL_5, "node deleted: %n\n", old));
272
273                 /* Change to get_irn_n */
274                 for(i = -not_a_block, n = get_irn_arity(old); i < n; ++i) {
275                         ir_node *old_tgt = get_irn_n(old, i);
276                         DBG((dbg, LEVEL_5, "\tdelete to old target %n\n", old_tgt));
277                         edges_notify_edge(old, i, NULL, old_tgt, irg);
278                 }
279
280         }
281 }
282
283 void edges_invalidate(ir_node *irn, ir_graph *irg)
284 {
285         edges_node_deleted(irn, irg);
286 }
287
288 /**
289  * Post-Walker: notify all edges
290  */
291 static void build_edges_walker(ir_node *irn, void *data)
292 {
293         ir_graph *irg = data;
294         int not_a_block = !is_Block(irn);
295         int i, n;
296
297         for(i = -not_a_block, n = get_irn_arity(irn); i < n; ++i)
298                 edges_notify_edge(irn, i, get_irn_n(irn, i), NULL, irg);
299 }
300
301 /**
302  * Pre-Walker: initializes the list-heads and set the out-count
303  * of all nodes to 0.
304  */
305 static void init_lh_walker(ir_node *irn, void *data)
306 {
307         INIT_LIST_HEAD(_get_irn_outs_head(irn));
308         if(is_Block(irn))
309                 INIT_LIST_HEAD(_get_block_succ_head(irn));
310         _get_irn_edge_info(irn)->out_count = 0;
311 }
312
313 void edges_activate(ir_graph *irg)
314 {
315         irg_edge_info_t *info = _get_irg_edge_info(irg);
316
317         info->activated = 1;
318         edges_init_graph(irg);
319         irg_walk_graph(irg, init_lh_walker, build_edges_walker, irg);
320 }
321
322 void edges_deactivate(ir_graph *irg)
323 {
324         irg_edge_info_t *info = _get_irg_edge_info(irg);
325
326         info->activated = 0;
327         if(info->edges) {
328                 del_set(info->edges);
329     info->edges = NULL;
330   }
331 }
332
333 int (edges_activated)(const ir_graph *irg)
334 {
335         return _edges_activated(irg);
336 }
337
338
339 /**
340  * Reroute all use-edges from a node to another.
341  * @param from The node whose use-edges shall be withdrawn.
342  * @param to The node to which all the use-edges of @p from shall be
343  * sent to.
344  */
345 void edges_reroute(ir_node *from, ir_node *to, ir_graph *irg)
346 {
347         if(edges_activated(irg)) {
348                 struct list_head *head = _get_irn_outs_head(from);
349
350                 DBG((dbg, LEVEL_5,
351                                         "reroute from %n to %n\n", from, to));
352
353                 while(head != head->next) {
354                         ir_edge_t *edge = list_entry(head->next, ir_edge_t, list);
355                         // DBG((dbg, LEVEL_5, "\t%n %d\n", edge->src, edge->pos));
356                         assert(edge->pos >= -1);
357                         set_irn_n(edge->src, edge->pos, to);
358                 }
359         }
360 }
361
362 static void verify_set_presence(ir_node *irn, void *data)
363 {
364         ir_graph *irg = data;
365         set *edges = _get_irg_edge_info(irg)->edges;
366         int not_a_block = !is_Block(irn);
367         int i, n;
368
369         for(i = 0, n = get_irn_arity(irn) + not_a_block; i < n; ++i) {
370                 ir_block_edge_t space;
371                 ir_edge_t *templ = (ir_edge_t *) &space;
372                 ir_edge_t *e;
373                 size_t size = not_a_block ? sizeof(ir_edge_t) : sizeof(ir_block_edge_t);
374
375                 templ->src = irn;
376                 templ->pos = i - not_a_block;
377
378                 e = set_find(edges, templ, size, edge_hash(templ));
379                 if(e != NULL)
380                         e->present = 1;
381                 else
382                         DBG((dbg, LEVEL_DEFAULT, "edge %n,%d is missing\n", irn, templ->pos));
383         }
384 }
385
386 static void verify_list_presence(ir_node *irn, void *data)
387 {
388         const ir_edge_t *e;
389
390         foreach_out_edge(irn, e) {
391                 ir_node *tgt = get_irn_n(e->src, e->pos);
392                 if(irn != tgt)
393                         DBG((dbg, LEVEL_DEFAULT, "edge %n,%d is no out edge of %n but of %n\n",
394                                         e->src, e->pos, irn, tgt));
395         }
396
397 }
398
399 void edges_verify(ir_graph *irg)
400 {
401         set *edges = _get_irg_edge_info(irg)->edges;
402         ir_edge_t *e;
403
404         /* Clear the present bit in all edges available. */
405         for(e = set_first(edges); e; e = set_next(edges))
406                 e->present = 0;
407
408         irg_walk_graph(irg, verify_set_presence, verify_list_presence, irg);
409
410         /*
411          * Dump all edges which are not invalid and not present.
412          * These edges are superfluous and their presence in the
413          * edge set is wrong.
414          */
415         for(e = set_first(edges); e; e = set_next(edges)) {
416                 if(!e->invalid && !e->present)
417                         DBG((dbg, LEVEL_DEFAULT, "edge %n,%d is superfluous\n", e->src, e->pos));
418         }
419 }
420
421 void init_edges(void)
422 {
423         FIRM_DBG_REGISTER(dbg, DBG_EDGES);
424         /* firm_dbg_set_mask(dbg, -1); */
425 }
426
427
428 const ir_edge_t *(get_irn_out_edge_first)(const ir_node *irn)
429 {
430         return _get_irn_out_edge_first(irn);
431 }
432
433 const ir_edge_t *(get_irn_out_edge_next)(const ir_node *irn, const ir_edge_t *last)
434 {
435         return _get_irn_out_edge_next(irn, last);
436 }
437
438 ir_node *(get_edge_src_irn)(const ir_edge_t *edge)
439 {
440         return _get_edge_src_irn(edge);
441 }
442
443 int (get_edge_src_pos)(const ir_edge_t *edge)
444 {
445         return _get_edge_src_pos(edge);
446 }
447
448 int (get_irn_n_edges)(const ir_node *irn)
449 {
450         return _get_irn_n_edges(irn);
451 }
452
453
454 #endif /* FIRM_EDGES_INPLACE */