fix the type of the graph number
[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 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 *templ      = alloca(size);
103
104                 memset(templ, 0, size);
105                 templ->src = (ir_node *) src;
106                 templ->pos = pos;
107                 return set_find(info->edges, templ, size, edge_hash(templ));
108         }
109
110         return NULL;
111 }
112
113 void edges_notify_edge(ir_node *src, int pos, ir_node *tgt, ir_node *old_tgt, ir_graph *irg)
114 {
115         const char *msg = "";
116
117         if(!edges_activated(irg))
118                 return;
119
120 #if 0
121         assert(node_is_in_irgs_storage(irg, src) && "source not in irg");
122 #endif
123
124         /*
125          * Only do something, if the old and new target differ.
126          */
127         if(tgt != old_tgt) {
128                 int is_block_edge = is_Block(src);
129                 set *edges = _get_irg_edge_info(irg)->edges;
130                 ir_edge_t *edge;
131
132                 /*
133                  * This is scray, but:
134                  * If two entries in a set do not have the same size, they are
135                  * treated as unequal, ignoring the comparison function.
136                  * So, edges from blocks have extra storage (they are
137                  * ir_block_edge_t's).
138                  *
139                  * Also add the amount of registered private data to the
140                  * size of the edge.
141                  */
142                 size_t size      = EDGE_SIZE(src);
143                 ir_edge_t *templ = alloca(size);
144
145                 /* Initialize the edge template to search in the set. */
146                 memset(templ, 0, size);
147 #ifdef DEBUG_libfirm
148                 templ->src_nr = get_irn_node_nr(src);
149 #endif
150                 templ->src = src;
151                 templ->pos = pos;
152                 templ->invalid = 0;
153                 templ->present = 0;
154
155                 /*
156                  * If the target is NULL, the edge shall be deleted.
157                  */
158                 if(tgt == NULL) {
159                         /* search the edge in the set. */
160                         edge = set_find(edges, templ, size, edge_hash(templ));
161
162                         /* mark the edge invalid if it was found */
163                         if(edge) {
164                                 ir_block_edge_t *block_edge = (ir_block_edge_t *) edge;
165
166                                 msg = "deleting";
167                                 list_del(&edge->list);
168                                 edge->invalid = 1;
169                                 edge->pos = -2;
170                                 edge->src = NULL;
171
172                                 /*
173                                  * If the edge is a cf edge, we delete it also
174                                  * from the list of all block successor edges.
175                                  */
176                                 if(is_block_edge)
177                                         list_del(&block_edge->succ_list);
178                         }
179
180                         /* If the edge was not found issue a warning on the debug stream */
181                         else {
182                                 msg = "edge to delete not found!\n";
183                         }
184                 } /* if */
185
186                 /*
187                  * The target is not NULL and the old target differs
188                  * from the new target, the edge shall be moved (if the
189                  * old target was != NULL) or added (if the old target was
190                  * NULL).
191                  */
192                 else {
193                         struct list_head *head = _get_irn_outs_head(tgt);
194
195                         /*
196                          * The list head in the block of the edges target.
197                          * Therein all control flow edges directed at that block
198                          * are recorded.
199                          */
200                         struct list_head *succ_head =
201                                 is_block_edge ? _get_block_succ_head(get_nodes_block(tgt)) : NULL;
202
203                         ir_block_edge_t *block_edge;
204
205 #if 0
206                         if(!node_is_in_irgs_storage(irg, tgt))
207                                 return;
208 #endif
209                         assert(head->next && head->prev &&
210                                         "target list head must have been initialized");
211
212                         /*
213                          * insert the edge, if it is not yet in the set or return
214                          * the instance in the set.
215                          */
216                         edge = set_insert(edges, templ, size, edge_hash(templ));
217                         block_edge = (ir_block_edge_t *) edge;
218
219 #ifdef DEBUG_libfirm
220                         assert(!edge->invalid && "Invalid edge encountered");
221 #endif
222
223                         /* If the old target is not null, the edge is moved. */
224                         if(old_tgt) {
225                                 msg = "redirecting";
226                                 list_move(&edge->list, head);
227
228                                 /* If the edge is a cf edge, move it from the successor list. */
229                                 if(is_block_edge)
230                                         list_move(&block_edge->succ_list, succ_head);
231
232                                 _get_irn_edge_info(old_tgt)->out_count -= 1;
233                         }
234
235                         /* The old target was null, thus, the edge is newly created. */
236                         else {
237                                 msg = "adding";
238                                 list_add(&edge->list, head);
239
240                                 /*
241                                  * If the edge is cf edge, enter it into the successor list
242                                  * of the target node's block.
243                                  */
244                                 if(is_block_edge)
245                                         list_add(&block_edge->succ_list, succ_head);
246                         }
247
248                         _get_irn_edge_info(tgt)->out_count += 1;
249                 } /* else */
250         }
251
252         /* If the target and the old target are equal, nothing is done. */
253         DBG((dbg, LEVEL_5, "announce out edge: %n[%p] %d-> %n[%p](%n[%p]): %s\n",
254                                 src, src, pos, tgt, tgt, old_tgt, old_tgt, msg));
255 }
256
257 void edges_node_deleted(ir_node *old, ir_graph *irg)
258 {
259         if(edges_activated(irg)) {
260                 int not_a_block = !is_Block(old);
261                 ir_edge_t templ;
262                 int i, n;
263
264                 templ.src = old;
265                 DBG((dbg, LEVEL_5, "node deleted: %n\n", old));
266
267                 /* Change to get_irn_n */
268                 for(i = -not_a_block, n = get_irn_arity(old); i < n; ++i) {
269                         ir_node *old_tgt = get_irn_n(old, i);
270                         DBG((dbg, LEVEL_5, "\tdelete to old target %n\n", old_tgt));
271                         edges_notify_edge(old, i, NULL, old_tgt, irg);
272                 }
273
274         }
275 }
276
277 void edges_invalidate(ir_node *irn, ir_graph *irg)
278 {
279         edges_node_deleted(irn, irg);
280 }
281
282 static void build_edges_walker(ir_node *irn, void *data)
283 {
284         ir_graph *irg = data;
285         int not_a_block = !is_Block(irn);
286         int i, n;
287
288         for(i = -not_a_block, n = get_irn_arity(irn); i < n; ++i)
289                 edges_notify_edge(irn, i, get_irn_n(irn, i), NULL, irg);
290 }
291
292 static void init_lh_walker(ir_node *irn, void *data)
293 {
294         INIT_LIST_HEAD(_get_irn_outs_head(irn));
295         if(is_Block(irn))
296                 INIT_LIST_HEAD(_get_block_succ_head(irn));
297 }
298
299 void edges_activate(ir_graph *irg)
300 {
301         irg_edge_info_t *info = _get_irg_edge_info(irg);
302
303         info->activated = 1;
304         edges_init_graph(irg);
305         irg_walk_graph(irg, init_lh_walker, build_edges_walker, irg);
306 }
307
308 void edges_deactivate(ir_graph *irg)
309 {
310         irg_edge_info_t *info = _get_irg_edge_info(irg);
311
312         info->activated = 0;
313         if(info->edges) {
314                 del_set(info->edges);
315     info->edges = NULL;
316   }
317 }
318
319 int (edges_activated)(const ir_graph *irg)
320 {
321         return _edges_activated(irg);
322 }
323
324
325 /**
326  * Reroute all use-edges from a node to another.
327  * @param from The node whose use-edges shall be withdrawn.
328  * @param to The node to which all the use-edges of @p from shall be
329  * sent to.
330  */
331 void edges_reroute(ir_node *from, ir_node *to, ir_graph *irg)
332 {
333         if(edges_activated(irg)) {
334                 struct list_head *head = _get_irn_outs_head(from);
335
336                 DBG((firm_dbg_register(DBG_EDGES), LEVEL_5,
337                                         "reroute from %n to %n\n", from, to));
338
339                 while(head != head->next) {
340                         ir_edge_t *edge = list_entry(head->next, ir_edge_t, list);
341                         // DBG((dbg, LEVEL_5, "\t%n %d\n", edge->src, edge->pos));
342                         assert(edge->pos >= -1);
343                         set_irn_n(edge->src, edge->pos, to);
344                 }
345         }
346 }
347
348 static void verify_set_presence(ir_node *irn, void *data)
349 {
350         ir_graph *irg = data;
351         set *edges = _get_irg_edge_info(irg)->edges;
352         int not_a_block = !is_Block(irn);
353         int i, n;
354
355         for(i = 0, n = get_irn_arity(irn) + not_a_block; i < n; ++i) {
356     ir_block_edge_t space;
357                 ir_edge_t *templ = (ir_edge_t *) &space;
358                 ir_edge_t *e;
359     size_t size = not_a_block ? sizeof(ir_edge_t) : sizeof(ir_block_edge_t);
360
361                 templ->src = irn;
362                 templ->pos = i - not_a_block;
363
364                 e = set_find(edges, templ, size, edge_hash(templ));
365                 if(e != NULL)
366                         e->present = 1;
367                 else
368                         DBG((dbg, LEVEL_DEFAULT, "edge %n,%d is missing\n", irn, templ->pos));
369         }
370 }
371
372 static void verify_list_presence(ir_node *irn, void *data)
373 {
374         const ir_edge_t *e;
375
376         foreach_out_edge(irn, e) {
377                 ir_node *tgt = get_irn_n(e->src, e->pos);
378                 if(irn != tgt)
379                         DBG((dbg, LEVEL_DEFAULT, "edge %n,%d is no out edge of %n but of %n\n",
380                                         e->src, e->pos, irn, tgt));
381         }
382
383 }
384
385 void edges_verify(ir_graph *irg)
386 {
387         set *edges = _get_irg_edge_info(irg)->edges;
388         ir_edge_t *e;
389
390         /* Clear the present bit in all edges available. */
391         for(e = set_first(edges); e; e = set_next(edges))
392                 e->present = 0;
393
394         irg_walk_graph(irg, verify_set_presence, verify_list_presence, irg);
395
396         /*
397          * Dump all edges which are not invalid and not present.
398          * These edges are superfluous and their presence in the
399          * edge set is wrong.
400          */
401         for(e = set_first(edges); e; e = set_next(edges)) {
402                 if(!e->invalid && !e->present)
403                         DBG((dbg, LEVEL_DEFAULT, "edge %n,%d is superfluous\n", e->src, e->pos));
404         }
405 }
406
407 void init_edges(void)
408 {
409         dbg = firm_dbg_register(DBG_EDGES);
410         /* firm_dbg_set_mask(dbg, -1); */
411 }
412
413
414 const ir_edge_t *(get_irn_out_edge_first)(const ir_node *irn)
415 {
416         return _get_irn_out_edge_first(irn);
417 }
418
419 const ir_edge_t *(get_irn_out_edge_next)(const ir_node *irn, const ir_edge_t *last)
420 {
421         return _get_irn_out_edge_next(irn, last);
422 }
423
424 ir_node *(get_edge_src_irn)(const ir_edge_t *edge)
425 {
426         return _get_edge_src_irn(edge);
427 }
428
429 int (get_edge_src_pos)(const ir_edge_t *edge)
430 {
431         return _get_edge_src_pos(edge);
432 }
433
434 int (get_irn_n_edges)(const ir_node *irn)
435 {
436   return _get_irn_n_edges(irn);
437 }
438
439
440 #endif /* FIRM_EDGES_INPLACE */