added a #if FIRM_EDGES_INPLACE
[libfirm] / ir / ir / iredges.c
1 /**
2  * Always available outs.
3  * @author Sebastian Hack
4  * @date 14.1.2005
5  */
6
7 #include "irnode_t.h"
8 #include "iredges_t.h"
9 #include "irdump_t.h"
10 #include "irprintf.h"
11 #include "irhooks.h"
12 #include "debug.h"
13 #include "set.h"
14
15 static firm_dbg_module_t *dbg;
16
17 #if FIRM_EDGES_INPLACE
18
19 #define TIMES37(x) (((x) << 5) + ((x) << 2) + (x))
20
21 #define get_irn_out_list_head(irn) (&get_irn_out_info(irn)->outs)
22
23 static int edge_cmp(const void *p1, const void *p2, size_t len)
24 {
25         const ir_edge_t *e1 = p1;
26         const ir_edge_t *e2 = p2;
27         int res = e1->src == e2->src && e1->pos == e2->pos;
28
29         return !res;
30 }
31
32 static INLINE unsigned edge_hash(const ir_edge_t *edge)
33 {
34         unsigned result = HASH_PTR(edge->src);
35         result = TIMES37(result) + edge->pos;
36         return result;
37 }
38
39 /**
40  * Initialize the out information for a graph.
41  * @note Dead node elim can call this on an already initialized graph.
42  */
43 void edges_init_graph(ir_graph *irg)
44 {
45         if(edges_activated(irg)) {
46                 irg_edge_info_t *info = _get_irg_edge_info(irg);
47                 int amount = 2048;
48
49                 if(info->edges) {
50                         amount = set_count(info->edges);
51                         del_set(info->edges);
52                 }
53
54                 info->edges = new_set(edge_cmp, amount);
55         }
56 }
57
58 void edges_notify_edge(ir_node *src, int pos, ir_node *tgt, ir_node *old_tgt, ir_graph *irg)
59 {
60         const char *msg = "";
61
62         if(!edges_activated(irg))
63                 return;
64
65         assert(node_is_in_irgs_storage(irg, src) && "source not in irg");
66
67         /*
68          * Only do something, if the old and new target differ.
69          */
70         if(tgt != old_tgt) {
71                 set *edges = _get_irg_edge_info(irg)->edges;
72                 ir_edge_t templ;
73                 ir_edge_t *edge;
74
75                 /* Initialize the edge template to search in the set. */
76 #ifdef DEBUG_libfirm
77                 templ.src_nr = get_irn_node_nr(src);
78 #endif
79                 templ.src = src;
80                 templ.pos = pos;
81                 templ.invalid = 0;
82                 templ.present = 0;
83                 INIT_LIST_HEAD(&templ.list);
84
85                 /*
86                  * If the target is NULL, the edge shall be deleted.
87                  */
88                 if(tgt == NULL) {
89                         /* search the edge in the set. */
90                         edge = set_find(edges, &templ, sizeof(templ), edge_hash(&templ));
91
92                         /* mark the edge invalid if it was found */
93                         if(edge) {
94                                 msg = "deleting";
95                                 list_del(&edge->list);
96                                 edge->invalid = 1;
97                                 edge->pos = -2;
98                                 edge->src = NULL;
99                         }
100
101                         /* If the edge was not found issue a warning on the debug stream */
102                         else {
103                                 msg = "edge to delete not found!\n";
104                         }
105                 } /* if */
106
107                 /*
108                  * The target is not NULL and the old target differs
109                  * from the new target, the edge shall be moved (if the
110                  * old target was != NULL) or added (if the old target was
111                  * NULL).
112                  */
113                 else {
114                         struct list_head *head = _get_irn_outs_head(tgt);
115
116                         if(!node_is_in_irgs_storage(irg, tgt))
117                                 return;
118
119                         assert(head->next && head->prev &&
120                                         "target list head must have been initialized");
121
122                         /*
123                          * insert the edge, if it is not yet in the set or return
124                          * the instance in the set.
125                          */
126                         edge = set_insert(edges, &templ, sizeof(templ), edge_hash(&templ));
127
128 #ifdef DEBUG_libfirm
129                         assert(!edge->invalid && "Invalid edge encountered");
130 #endif
131
132                         /* If the old target is not null, the edge is moved. */
133                         if(old_tgt) {
134                                 msg = "redirecting";
135                                 list_move(&edge->list, head);
136                                 _get_irn_edge_info(old_tgt)->out_count -= 1;
137                         }
138
139                         /* The old target was null, thus, the edge is newly created. */
140                         else {
141                                 msg = "adding";
142                                 list_add(&edge->list, head);
143                         }
144
145                         _get_irn_edge_info(tgt)->out_count += 1;
146                 } /* else */
147         }
148
149         /* If the target and the old target are equal, nothing is done. */
150         DBG((dbg, LEVEL_5, "announce out edge: %n[%p] %d-> %n[%p](%n[%p]): %s\n",
151                                 src, src, pos, tgt, tgt, old_tgt, old_tgt, msg));
152 }
153
154 void edges_node_deleted(ir_node *old, ir_graph *irg)
155 {
156         if(edges_activated(irg)) {
157                 int not_a_block = !is_Block(old);
158                 ir_edge_t templ;
159                 int i, n;
160
161                 templ.src = old;
162                 DBG((dbg, LEVEL_5, "node deleted: %n\n", old));
163
164                 /* Change to get_irn_n */
165                 for(i = -not_a_block, n = get_irn_arity(old); i < n; ++i) {
166                         ir_node *old_tgt = get_irn_n(old, i);
167                         DBG((dbg, LEVEL_5, "\tdelete to old target %n\n", old_tgt));
168                         edges_notify_edge(old, i, NULL, old_tgt, irg);
169                 }
170
171         }
172 }
173
174 void edges_invalidate(ir_node *irn, ir_graph *irg)
175 {
176         edges_node_deleted(irn, irg);
177 }
178
179
180 static void build_edges_walker(ir_node *irn, void *data)
181 {
182         ir_graph *irg = data;
183         int not_a_block = !is_Block(irn);
184         int i, n;
185
186         for(i = -not_a_block, n = get_irn_arity(irn); i < n; ++i)
187                 edges_notify_edge(irn, i, get_irn_n(irn, i), NULL, irg);
188 }
189
190 void edges_activate(ir_graph *irg)
191 {
192         irg_edge_info_t *info = _get_irg_edge_info(irg);
193
194         info->activated = 1;
195         edges_init_graph(irg);
196         irg_walk_graph(irg, NULL, build_edges_walker, irg);
197 }
198
199 void edges_deactivate(ir_graph *irg)
200 {
201         irg_edge_info_t *info = _get_irg_edge_info(irg);
202
203         info->activated = 0;
204         if(info->edges)
205                 del_set(info->edges);
206 }
207
208 int (edges_activated)(const ir_graph *irg)
209 {
210         return _edges_activated(irg);
211 }
212
213
214 /**
215  * Reroute all use-edges from a node to another.
216  * @param from The node whose use-edges shall be withdrawn.
217  * @param to The node to which all the use-edges of @p from shall be
218  * sent to.
219  */
220 void edges_reroute(ir_node *from, ir_node *to, ir_graph *irg)
221 {
222         if(edges_activated(irg)) {
223                 struct list_head *head = _get_irn_outs_head(from);
224
225                 DBG((firm_dbg_register(DBG_EDGES), LEVEL_5,
226                                         "reroute from %n to %n\n", from, to));
227
228                 while(head != head->next) {
229                         ir_edge_t *edge = list_entry(head->next, ir_edge_t, list);
230                         // DBG((dbg, LEVEL_5, "\t%n %d\n", edge->src, edge->pos));
231                         assert(edge->pos >= -1);
232                         set_irn_n(edge->src, edge->pos, to);
233                 }
234         }
235 }
236
237 static void verify_set_presence(ir_node *irn, void *data)
238 {
239         ir_graph *irg = data;
240         set *edges = _get_irg_edge_info(irg)->edges;
241         int not_a_block = !is_Block(irn);
242         int i, n;
243
244         for(i = 0, n = get_irn_arity(irn) + not_a_block; i < n; ++i) {
245                 ir_edge_t templ;
246                 ir_edge_t *e;
247
248                 templ.src = irn;
249                 templ.pos = i - not_a_block;
250
251                 e = set_find(edges, &templ, sizeof(templ), edge_hash(&templ));
252                 if(e != NULL)
253                         e->present = 1;
254                 else
255                         ir_fprintf(stderr, "edge %n,%d is missing\n", irn, templ.pos);
256         }
257 }
258
259 static void verify_list_presence(ir_node *irn, void *data)
260 {
261         const ir_edge_t *e;
262
263         foreach_out_edge(irn, e) {
264                 ir_node *tgt = get_irn_n(e->src, e->pos);
265                 if(irn != tgt)
266                         ir_fprintf(stderr, "edge %n,%d is no out edge of %n but of %n\n",
267                                         e->src, e->pos, irn, tgt);
268         }
269
270 }
271
272 void edges_verify(ir_graph *irg)
273 {
274         set *edges = _get_irg_edge_info(irg)->edges;
275         ir_edge_t *e;
276
277         /* Clear the present bit in all edges available. */
278         for(e = set_first(edges); e; e = set_next(edges))
279                 e->present = 0;
280
281         irg_walk_graph(irg, verify_set_presence, verify_list_presence, irg);
282
283         /*
284          * Dump all edges which are not invalid and not present.
285          * These edges are superfluous and their presence in the
286          * edge set is wrong.
287          */
288         for(e = set_first(edges); e; e = set_next(edges)) {
289                 if(!e->invalid && !e->present)
290                         ir_fprintf(stderr, "edge %n,%d is superfluous\n", e->src, e->pos);
291         }
292 }
293
294 void init_edges(void)
295 {
296         dbg = firm_dbg_register(DBG_EDGES);
297         /* firm_dbg_set_mask(dbg, -1); */
298 }
299
300
301 const ir_edge_t *(get_irn_out_edge_first)(const ir_node *irn)
302 {
303         return _get_irn_out_edge_first(irn);
304 }
305
306 const ir_edge_t *(get_irn_out_edge_next)(const ir_node *irn, const ir_edge_t *last)
307 {
308         return _get_irn_out_edge_next(irn, last);
309 }
310
311 ir_node *(get_edge_src_irn)(const ir_edge_t *edge)
312 {
313         return _get_edge_src_irn(edge);
314 }
315
316 int (get_edge_src_pos)(const ir_edge_t *edge)
317 {
318         return _get_edge_src_pos(edge);
319 }
320
321 #endif /* FIRM_EDGES_INPLACE */