fixed set_irn_n hook
[libfirm] / ir / debug / firm_ycomp.c
1 /*
2  * Project:     libFIRM
3  * File name:   ir/debug/firm_ycomp.c
4  * Purpose:     Connect firm to ycomp
5  * Author:      Christian Wuerdig
6  * Modified by:
7  * Created:     16.11.2006
8  * CVS-ID:      $Id$
9  * Copyright:   (c) 2001-2006 Universität Karlsruhe
10  * Licence:     This file protected by GPL -  GNU GENERAL PUBLIC LICENSE.
11  */
12 #ifdef HAVE_CONFIG_H
13 #include "config.h"
14 #endif /* HAVE_CONFIG_H */
15
16 #include "assert.h"
17 #include "irhooks.h"
18 #include "firmnet.h"
19 #include "irnode.h"
20 #include "irgraph.h"
21 #include "irprintf.h"
22 #include "irprog.h"
23 #include "iredges.h"
24 #include "pset.h"
25 #include "obst.h"
26
27 #define SEND_BUF_SIZE 256
28 #define HASH_EDGE(edge) \
29         ((get_irn_node_nr((edge)->src) << 17)          | \
30         ((get_irn_node_nr((edge)->tgt) & 0xEFFF) << 2) | \
31         ((edge)->pos & 0x2))
32
33 typedef struct _exchange_node_outs_assoc_t {
34         int     n_out_edges;
35         ir_node *irn;
36 } exchange_node_outs_assoc_t;
37
38 typedef struct _ycomp_edge_t {
39         ir_node *src;
40         ir_node *tgt;
41         int     pos;
42 } ycomp_edge_t;
43
44 enum _firm_ycomp_node_realizer_values {
45         NODE_REALIZER_NORMAL,
46         NODE_REALIZER_PROJ,
47         NODE_REALIZER_BLOCK,
48         NODE_REALIZER_MEM,
49         NODE_REALIZER_PHI,
50         NODE_REALIZER_STARTEND,
51         NODE_REALIZER_LAST
52 };
53
54 typedef struct _firm_ycomp_node_realizer_t {
55         unsigned   id;
56         const char *linecolor;
57         const char *fillcolor;
58         const char *shape;
59 } firm_ycomp_node_realizer_t;
60
61 static firm_ycomp_node_realizer_t node_realizer[NODE_REALIZER_LAST] = {
62         { NODE_REALIZER_NORMAL,   "black", "white",  "box" },
63         { NODE_REALIZER_PROJ,     "black", "yellow", "box" },
64         { NODE_REALIZER_BLOCK,    "black", "yellow", "box" },
65         { NODE_REALIZER_MEM,      "black", "blue",   "box" },
66         { NODE_REALIZER_PHI,      "black", "green",  "box" },
67         { NODE_REALIZER_STARTEND, "black", "blue",   "box" },
68 };
69
70 enum _firm_ycomp_edge_realizer_values {
71         EDGE_REALIZER_DATA,
72         EDGE_REALIZER_MEM,
73         EDGE_REALIZER_DEP,
74         EDGE_REALIZER_CFG,
75         EDGE_REALIZER_LAST
76 };
77
78 typedef struct _firm_ycomp_edge_realizer_t {
79         unsigned   id;
80         const char *linecolor;
81         unsigned   thickness;
82         const char *style;
83 } firm_ycomp_edge_realizer_t;
84
85 static firm_ycomp_edge_realizer_t edge_realizer[EDGE_REALIZER_LAST] = {
86         { EDGE_REALIZER_DATA, "black", 1, "continuous" },
87         { EDGE_REALIZER_MEM,  "blue",  1, "continuous" },
88         { EDGE_REALIZER_DEP,  "green", 1, "continuous" },
89         { EDGE_REALIZER_CFG,  "red",   1, "continuous" },
90 };
91
92 typedef struct _firm_ycomp_dbg_t {
93         int            fd;
94         int            has_data;
95         pset           *exchanged_nodes;
96         pset           *edges;
97         struct obstack obst;
98         hook_entry_t   hook_new_irg;
99         hook_entry_t   hook_new_irn;
100         hook_entry_t   hook_set_edge;
101         hook_entry_t   hook_exchange;
102 } firm_ycomp_dbg_t;
103
104 static firm_ycomp_dbg_t yy_dbg;
105
106 static int cmp_edges(const void *a, const void *b) {
107         ycomp_edge_t *e1 = (ycomp_edge_t *)a;
108         ycomp_edge_t *e2 = (ycomp_edge_t *)b;
109
110         return (e1->src != e2->src) || (e1->tgt != e2->tgt) || (e1->pos != e2->pos);
111 }
112
113 static int cmp_nodes(const void *a, const void *b) {
114         exchange_node_outs_assoc_t *n1 = (exchange_node_outs_assoc_t *)a;
115         exchange_node_outs_assoc_t *n2 = (exchange_node_outs_assoc_t *)b;
116
117         return n1->irn != n2->irn;
118 }
119
120 static INLINE void send_cmd(const char *buf) {
121         ssize_t res, len;
122
123         fprintf(stderr, "'%s'\n", buf);
124         len = strlen(buf);
125         res = firmnet_send(yy_dbg.fd, (const void *)buf, len);
126         assert(res == len);
127 }
128
129 static void wait_for_sync(void) {
130         char buf[6];
131
132         firmnet_recv(yy_dbg.fd, buf, 6, 5);
133 }
134
135 static void firm_ycomp_debug_init_realizer(void) {
136         int  i;
137         char buf[SEND_BUF_SIZE];
138
139         for (i = 0; i < NODE_REALIZER_LAST; ++i) {
140                 snprintf(buf, sizeof(buf), "addNodeRealizer \"%u\" \"%s\" \"%s\" \"%s\"\n",
141                         node_realizer[i].id,
142                         node_realizer[i].linecolor,
143                         node_realizer[i].fillcolor,
144                         node_realizer[i].shape);
145                 send_cmd(buf);
146         }
147
148         for (i = 0; i < EDGE_REALIZER_LAST; ++i) {
149                 snprintf(buf, sizeof(buf), "addEdgeRealizer \"%u\" \"%s\" \"%u\" \"%s\"\n",
150                         edge_realizer[i].id,
151                         edge_realizer[i].linecolor,
152                         edge_realizer[i].thickness,
153                         edge_realizer[i].style);
154                 send_cmd(buf);
155         }
156 }
157
158 static INLINE unsigned get_node_realizer(ir_node *node) {
159         unsigned realizer;
160         opcode   opc = get_irn_opcode(node);
161
162         switch (opc) {
163                 case iro_Block:
164                         realizer = NODE_REALIZER_BLOCK;
165                         break;
166                 case iro_Phi:
167                         realizer = NODE_REALIZER_PHI;
168                         break;
169                 case iro_Proj:
170                         if (get_irn_mode(node) == mode_M)
171                                 realizer = NODE_REALIZER_MEM;
172                         else
173                                 realizer = NODE_REALIZER_PROJ;
174                         break;
175                 case iro_Start:
176                 case iro_End:
177                         realizer = NODE_REALIZER_STARTEND;
178                         break;
179                 default:
180                         realizer = NODE_REALIZER_NORMAL;
181         };
182
183         return realizer;
184 }
185
186 static INLINE unsigned get_edge_realizer(ir_node *src, ir_node *tgt) {
187         unsigned realizer;
188         ir_mode  *mode;
189
190         assert(! is_Block(tgt));
191
192         mode = get_irn_mode(tgt);
193
194         if (mode == mode_M)
195                 realizer = EDGE_REALIZER_MEM;
196         else if (mode == mode_X)
197                 realizer = EDGE_REALIZER_CFG;
198         else
199                 realizer = EDGE_REALIZER_DATA;
200
201         return realizer;
202 }
203
204 static void firm_ycomp_debug_new_node(void *context, ir_graph *graph, ir_node *node) {
205         firm_ycomp_dbg_t *dbg = context;
206         char     buf[SEND_BUF_SIZE];
207         int      i;
208         unsigned src_idx = get_irn_node_nr(node);
209
210         if (get_const_code_irg() == graph)
211                 return;
212
213         dbg->has_data = 1;
214
215         /* add node */
216         ir_snprintf(buf, sizeof(buf), "addNode \"%u\" \"%u\" \"%+F\"\n",
217                 src_idx,                    /* node id */
218                 get_node_realizer(node),    /* realizerId */
219                 node);                      /* label */
220         send_cmd(buf);
221
222         /* add edges */
223         for (i = get_irn_arity(node) - 1; i >= 0; --i) {
224                 ir_node      *pred   = get_irn_n(node, i);
225                 unsigned     tgt_idx = get_irn_node_nr(pred);
226                 ycomp_edge_t key, *entry;
227
228                 ir_snprintf(buf, sizeof(buf), "addEdge \"n%un%up%d\" \"%u\" \"%u\" \"%u\" \"%d\"\n",
229                         src_idx, tgt_idx, i,            /* edge id */
230                         src_idx,                        /* source node id */
231                         tgt_idx,                        /* target node id */
232                         get_edge_realizer(node, pred),  /* realizer id */
233                         i);                             /* title */
234                 send_cmd(buf);
235
236                 /* insert edge */
237                 key.src = node;
238                 key.tgt = pred;
239                 key.pos = i;
240                 entry   = pset_find(dbg->edges, &key, HASH_EDGE(&key));
241                 if (! entry) {
242                         entry = obstack_alloc(&dbg->obst, sizeof(*entry));
243                         entry->src = node;
244                         entry->tgt = pred;
245                         entry->pos = i;
246                         pset_insert(dbg->edges, entry, HASH_EDGE(entry));
247                 }
248         }
249
250         send_cmd("show\n");
251         send_cmd("sync\n");
252         wait_for_sync();
253 }
254
255 static void firm_ycomp_debug_new_irg(void *context, ir_graph *irg, entity *ent) {
256         if (yy_dbg.has_data) {
257                 send_cmd("deleteGraph\n");
258                 send_cmd("show\n");
259         }
260         yy_dbg.has_data = 0;
261         send_cmd("sync\n");
262         wait_for_sync();
263 }
264
265 static void firm_ycomp_debug_set_edge(void *context, ir_node *src, int pos, ir_node *tgt, ir_node *old_tgt) {
266         firm_ycomp_dbg_t           *dbg = context;
267         exchange_node_outs_assoc_t *entry, key;
268         ycomp_edge_t               *old_edge, *new_edge, edge_key;
269         char                       buf[SEND_BUF_SIZE];
270         unsigned                   src_idx, tgt_idx, old_tgt_idx;
271
272         /* ignore block edges for now */
273         if (pos < 0)
274                 return;
275
276         /* check if the new edge exists */
277         edge_key.src = src;
278         edge_key.tgt = tgt;
279         edge_key.pos = pos;
280         new_edge     = pset_find(dbg->edges, &edge_key, HASH_EDGE(&edge_key));
281
282         /* if the new edge already exists and the old target is the new target -> ignore */
283         if (new_edge && tgt == old_tgt)
284                 return;
285
286         /* check if the old edge exists */
287         edge_key.src = src;
288         edge_key.tgt = old_tgt;
289         edge_key.pos = pos;
290         old_edge     = pset_find(dbg->edges, &edge_key, HASH_EDGE(&edge_key));
291
292         /* check if old target is marked for exchange */
293         key.irn = old_tgt;
294         entry   = pset_find(dbg->exchanged_nodes, &key, HASH_PTR(old_tgt));
295
296         if (entry) {
297                 /* we are called from exchange() */
298                 entry->n_out_edges--;
299         }
300
301         src_idx     = get_irn_node_nr(src);
302         tgt_idx     = get_irn_node_nr(tgt);
303         old_tgt_idx = get_irn_node_nr(old_tgt);
304
305         if (old_edge) {
306                 /* delete the old edge if it exists */
307                 snprintf(buf, sizeof(buf), "deleteEdge \"n%un%up%d\"\n", src_idx, old_tgt_idx, pos);
308                 send_cmd(buf);
309                 pset_remove(dbg->edges, old_edge, HASH_EDGE(old_edge));
310         }
311
312         if (! new_edge) {
313                 /* add the new edge if it doesn't exist */
314                 snprintf(buf, sizeof(buf), "addEdge \"n%un%up%d\" \"%u\" \"%u\" \"%u\" \"%d\"\n",
315                         src_idx, tgt_idx, pos,          /* edge id */
316                         src_idx,                        /* source node id */
317                         tgt_idx,                        /* target node id */
318                         get_edge_realizer(src, tgt),    /* realizer id */
319                         pos);                           /* title */
320                 send_cmd(buf);
321
322                 /* insert the new edge */
323                 new_edge      = obstack_alloc(&dbg->obst, sizeof(*new_edge));
324                 new_edge->src = src;
325                 new_edge->tgt = tgt;
326                 new_edge->pos = pos;
327                 pset_insert(dbg->edges, new_edge, HASH_EDGE(new_edge));
328         }
329
330         /* show and sync if all edges are rerouted or if it's a normal set_irn_n */
331         if (! entry || entry->n_out_edges == 0) {
332                 send_cmd("show\n");
333                 send_cmd("sync\n");
334                 wait_for_sync();
335         }
336 }
337
338 static void firm_ycomp_debug_exchange(void *context, ir_node *old_node, ir_node *new_node) {
339         firm_ycomp_dbg_t           *dbg = context;
340         exchange_node_outs_assoc_t key, *entry;
341
342         key.irn = old_node;
343         entry   = pset_find(dbg->exchanged_nodes, &key, HASH_PTR(old_node));
344         if (entry) {
345                 entry->n_out_edges = get_irn_n_edges(old_node);
346         }
347         else {
348                 entry              = obstack_alloc(&dbg->obst, sizeof(*entry));
349                 entry->irn         = old_node;
350                 entry->n_out_edges = get_irn_n_edges(old_node);
351                 pset_insert(dbg->exchanged_nodes, entry, HASH_PTR(old_node));
352         }
353 }
354
355 void firm_init_ycomp_debugger(const char *host, uint16_t port) {
356         static int init_once = 0;
357
358         if (init_once)
359                 return;
360
361         memset(&yy_dbg, 0, sizeof(yy_dbg));
362         yy_dbg.fd = -1;
363
364         host = "localhost";
365         port = 4242;
366
367         yy_dbg.fd = firmnet_connect_tcp(host, port);
368
369         if (yy_dbg.fd > -1) {
370                 /* We could establish a connection to ycomp -> register hooks */
371                 firm_ycomp_debug_init_realizer();
372                 yy_dbg.exchanged_nodes = new_pset(cmp_nodes, 20);
373                 yy_dbg.edges           = new_pset(cmp_edges, 20);
374                 obstack_init(&yy_dbg.obst);
375
376                 /* new node hook */
377                 yy_dbg.hook_new_irn.context             = &yy_dbg;
378                 yy_dbg.hook_new_irn.hook._hook_new_node = firm_ycomp_debug_new_node;
379                 register_hook(hook_new_node, &yy_dbg.hook_new_irn);
380
381                 /* new irg hook */
382                 yy_dbg.hook_new_irg.context              = &yy_dbg;
383                 yy_dbg.hook_new_irg.hook._hook_new_graph = firm_ycomp_debug_new_irg;
384                 register_hook(hook_new_graph, &yy_dbg.hook_new_irg);
385
386                 /* set irn n hook */
387                 yy_dbg.hook_set_edge.context              = &yy_dbg;
388                 yy_dbg.hook_set_edge.hook._hook_set_irn_n = firm_ycomp_debug_set_edge;
389                 register_hook(hook_set_irn_n, &yy_dbg.hook_set_edge);
390
391                 /* replace (exchange) hook */
392                 yy_dbg.hook_exchange.context            = &yy_dbg;
393                 yy_dbg.hook_exchange.hook._hook_replace = firm_ycomp_debug_exchange;
394                 register_hook(hook_replace, &yy_dbg.hook_exchange);
395         }
396
397         init_once = 1;
398 }
399
400 void firm_finish_ycomp_debugger(void) {
401         if (yy_dbg.fd > -1) {
402                 firmnet_close_socket(yy_dbg.fd);
403                 unregister_hook(hook_new_graph, &yy_dbg.hook_new_irg);
404                 unregister_hook(hook_new_node, &yy_dbg.hook_new_irn);
405                 unregister_hook(hook_set_irn_n, &yy_dbg.hook_set_edge);
406                 unregister_hook(hook_replace, &yy_dbg.hook_exchange);
407                 del_pset(yy_dbg.exchanged_nodes);
408                 del_pset(yy_dbg.edges);
409                 yy_dbg.exchanged_nodes = NULL;
410                 obstack_free(&yy_dbg.obst, NULL);
411         }
412 }