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