2 * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
4 * This file is part of libFirm.
6 * This file may be distributed and/or modified under the terms of the
7 * GNU General Public License version 2 as published by the Free Software
8 * Foundation and appearing in the file LICENSE.GPL included in the
9 * packaging of this file.
11 * Licensees holding valid libFirm Professional Edition licenses may use
12 * this file in accordance with the libFirm Commercial License.
13 * Agreement provided with the Software.
15 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * @brief Connect firm to ycomp
23 * @author Christian Wuerdig
29 #endif /* HAVE_CONFIG_H */
43 #define SEND_BUF_SIZE 256
44 #define HASH_EDGE(edge) \
45 ((get_irn_node_nr((edge)->src) << 17) | \
46 ((get_irn_node_nr((edge)->tgt) & 0xEFFF) << 2) | \
49 typedef struct _exchange_node_outs_assoc_t {
53 } exchange_node_outs_assoc_t;
55 typedef struct _ycomp_edge_t {
61 enum _firm_ycomp_node_realizer_values {
67 NODE_REALIZER_STARTEND,
73 typedef struct _firm_ycomp_node_realizer_t {
75 const char *linecolor;
76 const char *fillcolor;
77 const char *textcolor;
79 } firm_ycomp_node_realizer_t;
81 static firm_ycomp_node_realizer_t node_realizer[NODE_REALIZER_LAST] = {
82 { NODE_REALIZER_NORMAL, "black", "white", "black", "box" },
83 { NODE_REALIZER_PROJ, "black", "yellow", "black", "box" },
84 { NODE_REALIZER_BLOCK, "black", "yellow", "white", "box" },
85 { NODE_REALIZER_MEM, "black", "blue", "black", "box" },
86 { NODE_REALIZER_PHI, "black", "green", "black", "box" },
87 { NODE_REALIZER_STARTEND, "black", "blue", "black", "box" },
88 { NODE_REALIZER_IRG, "black", "white", "white", "box" },
89 { NODE_REALIZER_ID, "black", "darkgrey", "black", "box" },
92 enum _firm_ycomp_edge_realizer_values {
100 typedef struct _firm_ycomp_edge_realizer_t {
102 const char *linecolor;
103 const char *textcolor;
106 } firm_ycomp_edge_realizer_t;
108 static firm_ycomp_edge_realizer_t edge_realizer[EDGE_REALIZER_LAST] = {
109 { EDGE_REALIZER_DATA, "black", "black", 1, "continuous" },
110 { EDGE_REALIZER_MEM, "blue", "black", 1, "continuous" },
111 { EDGE_REALIZER_DEP, "green", "black", 1, "continuous" },
112 { EDGE_REALIZER_CFG, "red", "black", 1, "continuous" },
115 typedef struct _firm_ycomp_dbg_t {
118 pset *exchanged_nodes;
120 unsigned in_dead_node_elim : 1;
122 hook_entry_t hook_new_irn;
123 hook_entry_t hook_new_irg;
124 hook_entry_t hook_set_edge;
125 hook_entry_t hook_exchange;
126 hook_entry_t hook_into_id;
127 hook_entry_t hook_dead_node;
130 static firm_ycomp_dbg_t yy_dbg;
132 static int cmp_edges(const void *a, const void *b) {
133 ycomp_edge_t *e1 = (ycomp_edge_t *)a;
134 ycomp_edge_t *e2 = (ycomp_edge_t *)b;
136 return (e1->src != e2->src) || (e1->tgt != e2->tgt) || (e1->pos != e2->pos);
139 static int cmp_nodes(const void *a, const void *b) {
140 exchange_node_outs_assoc_t *n1 = (exchange_node_outs_assoc_t *)a;
141 exchange_node_outs_assoc_t *n2 = (exchange_node_outs_assoc_t *)b;
143 return n1->irn != n2->irn;
146 static INLINE void send_cmd(firm_ycomp_dbg_t *dbg, const char *buf) {
150 res = firmnet_send(dbg->fd, (const void *)buf, len);
154 static void wait_for_sync(firm_ycomp_dbg_t *dbg) {
156 firmnet_recv(dbg->fd, buf, 6, 5);
159 static void show_and_sync(firm_ycomp_dbg_t *dbg) {
160 send_cmd(dbg, "show\n");
161 send_cmd(dbg, "sync\n");
166 * Register the edge and node realizer in yComp.
168 static void firm_ycomp_debug_init_realizer(firm_ycomp_dbg_t *dbg) {
170 char buf[SEND_BUF_SIZE];
172 for (i = 0; i < NODE_REALIZER_LAST; ++i) {
173 snprintf(buf, sizeof(buf), "addNodeRealizer \"%u\" \"%s\" \"%s\" \"%s\" \"%s\"\n",
175 node_realizer[i].linecolor,
176 node_realizer[i].fillcolor,
177 node_realizer[i].textcolor,
178 node_realizer[i].shape);
182 for (i = 0; i < EDGE_REALIZER_LAST; ++i) {
183 snprintf(buf, sizeof(buf), "addEdgeRealizer \"%u\" \"%s\" \"%s\" \"%u\" \"%s\"\n",
185 edge_realizer[i].linecolor,
186 edge_realizer[i].textcolor,
187 edge_realizer[i].thickness,
188 edge_realizer[i].style);
194 * Retrieve the appropriate realizer for given node.
196 static INLINE unsigned get_node_realizer(ir_node *node) {
198 ir_opcode opc = get_irn_opcode(node);
202 realizer = NODE_REALIZER_BLOCK;
205 realizer = NODE_REALIZER_PHI;
208 if (get_irn_mode(node) == mode_M)
209 realizer = NODE_REALIZER_MEM;
211 realizer = NODE_REALIZER_PROJ;
215 realizer = NODE_REALIZER_STARTEND;
218 realizer = NODE_REALIZER_NORMAL;
225 * Retrieve the appropriate realizer for given edge.
227 static INLINE unsigned get_edge_realizer(ir_node *src, ir_node *tgt) {
229 ir_mode *tgt_mode, *src_mode;
231 if (is_Block(tgt) || is_Block(src))
232 return EDGE_REALIZER_CFG;
234 tgt_mode = get_irn_mode(tgt);
235 src_mode = is_Block(src) ? NULL : get_irn_mode(src);
237 if (tgt_mode == mode_M || (src_mode == mode_M && tgt_mode == mode_T))
238 realizer = EDGE_REALIZER_MEM;
239 else if (tgt_mode == mode_X)
240 realizer = EDGE_REALIZER_CFG;
242 realizer = EDGE_REALIZER_DATA;
248 * Hook: Add new nodes, resp. new blocks in yComp and add input edges.
250 static void firm_ycomp_debug_new_node(void *context, ir_graph *graph, ir_node *node) {
251 firm_ycomp_dbg_t *dbg = context;
252 char buf[SEND_BUF_SIZE];
256 if (get_const_code_irg() == graph || dbg->in_dead_node_elim)
259 src_idx = get_irn_node_nr(node);
262 if (is_Block(node)) {
263 /* add block (subgraph) */
264 ir_snprintf(buf, sizeof(buf), "addSubgraphNode \"%d\" \"%d\" \"%u\" \"%+F\"\n",
266 get_irn_node_nr(node), /* graph id */
267 NODE_REALIZER_BLOCK, /* realizer id */
272 ir_snprintf(buf, sizeof(buf), "addNode \"%d\" \"%u\" \"%u\" \"%+F\"\n",
273 get_irn_node_nr(get_nodes_block(node)), /* parent id */
274 src_idx, /* node id */
275 get_node_realizer(node), /* realizer id */
281 for (i = get_irn_arity(node) - 1; i >= 0; --i) {
282 ir_node *pred = get_irn_n(node, i);
283 unsigned tgt_idx = get_irn_node_nr(pred);
284 ycomp_edge_t key, *entry;
286 ir_snprintf(buf, sizeof(buf), "addEdge \"n%un%up%d\" \"%u\" \"%u\" \"%u\" \"%d\"\n",
287 src_idx, tgt_idx, i, /* edge id */
288 src_idx, /* source node id */
289 tgt_idx, /* target node id */
290 get_edge_realizer(node, pred), /* realizer id */
298 entry = pset_find(dbg->edges, &key, HASH_EDGE(&key));
300 entry = obstack_alloc(&dbg->obst, sizeof(*entry));
304 pset_insert(dbg->edges, entry, HASH_EDGE(entry));
312 * Clear the old irg if it has some data and create a new one.
314 static void firm_ycomp_debug_new_irg(void *context, ir_graph *irg,
317 firm_ycomp_dbg_t *dbg = context;
318 char buf[SEND_BUF_SIZE];
321 if (yy_dbg.has_data) {
322 send_cmd(dbg, "deleteGraph\n");
323 // send_cmd(dbg, "show\n");
327 ir_snprintf(buf, sizeof(buf), "addSubgraphNode \"-1\" \"0\" \"%u\" \"%s\"\n",
328 NODE_REALIZER_IRG, get_entity_name(ent));
330 send_cmd(dbg, "sync\n");
335 * Hook: Handle set_irn_n calls.
337 * - remove old edge and add new one
339 static void firm_ycomp_debug_set_edge(void *context, ir_node *src, int pos, ir_node *tgt, ir_node *old_tgt) {
340 firm_ycomp_dbg_t *dbg = context;
341 exchange_node_outs_assoc_t *entry = NULL;
342 exchange_node_outs_assoc_t key;
343 ycomp_edge_t *old_edge, *new_edge, edge_key;
344 char buf[SEND_BUF_SIZE];
345 unsigned src_idx, tgt_idx;
347 if (dbg->in_dead_node_elim)
350 src_idx = get_irn_node_nr(src);
351 tgt_idx = get_irn_node_nr(tgt);
353 /* set_irn_n with pos -1 means: node moves to new block */
355 if (tgt != old_tgt) {
356 snprintf(buf, sizeof(buf), "moveNode \"%d\" \"%d\"\n", src_idx, tgt_idx);
363 /* check if the new edge exists */
367 new_edge = pset_find(dbg->edges, &edge_key, HASH_EDGE(&edge_key));
369 /* if the new edge already exists and the old target is the new target -> ignore */
370 if (new_edge && tgt == old_tgt)
373 /* check if the old edge exists */
375 int old_tgt_idx = get_irn_node_nr(old_tgt);
378 edge_key.tgt = old_tgt;
380 old_edge = pset_find(dbg->edges, &edge_key, HASH_EDGE(&edge_key));
382 /* check if old target is marked for exchange */
384 entry = pset_find(dbg->exchanged_nodes, &key, HASH_PTR(old_tgt));
387 /* we are called from exchange() */
388 entry->n_out_edges--;
391 /* delete the old edge if it exists */
393 snprintf(buf, sizeof(buf), "deleteEdge \"n%un%up%d\"\n", src_idx, old_tgt_idx, pos);
395 pset_remove(dbg->edges, old_edge, HASH_EDGE(old_edge));
400 /* add the new edge if it doesn't exist */
401 snprintf(buf, sizeof(buf), "addEdge \"n%un%up%d\" \"%u\" \"%u\" \"%u\" \"%d\"\n",
402 src_idx, tgt_idx, pos, /* edge id */
403 src_idx, /* source node id */
404 tgt_idx, /* target node id */
405 get_edge_realizer(src, tgt), /* realizer id */
409 /* insert the new edge */
410 new_edge = obstack_alloc(&dbg->obst, sizeof(*new_edge));
414 pset_insert(dbg->edges, new_edge, HASH_EDGE(new_edge));
417 /* show and sync if all edges are rerouted or if it's a normal set_irn_n */
418 if (! entry || entry->n_out_edges == 0) {
424 * Hook: Put nodes, about to be exchanged into a set.
426 static void firm_ycomp_debug_exchange(void *context, ir_node *old_node, ir_node *new_node) {
427 firm_ycomp_dbg_t *dbg = context;
428 exchange_node_outs_assoc_t key, *entry;
430 /* put nodes, which are about to be exchanged into a set */
433 entry = pset_find(dbg->exchanged_nodes, &key, HASH_PTR(old_node));
435 entry->n_out_edges = get_irn_n_edges(old_node);
436 entry->nw = new_node;
439 entry = obstack_alloc(&dbg->obst, sizeof(*entry));
440 entry->irn = old_node;
441 entry->nw = new_node;
442 entry->n_out_edges = get_irn_n_edges(old_node);
443 pset_insert(dbg->exchanged_nodes, entry, HASH_PTR(old_node));
448 * Hook: Remove all old in edges, turn node into id node, add new input edge.
450 static void firm_ycomp_debug_turn_into_id(void *context, ir_node *old_node) {
451 firm_ycomp_dbg_t *dbg = context;
452 exchange_node_outs_assoc_t key, *entry;
454 char buf[SEND_BUF_SIZE];
455 unsigned src_idx, tgt_idx;
456 ycomp_edge_t edge_key, *new_edge;
459 entry = pset_find(dbg->exchanged_nodes, &key, HASH_PTR(old_node));
461 assert(entry != NULL && "Exchange entry missing");
463 src_idx = get_irn_node_nr(old_node);
464 tgt_idx = get_irn_node_nr(entry->nw);
466 /* remove all old edges */
467 for (i = get_irn_arity(old_node) - 1; i >= 0; --i) {
468 ycomp_edge_t *old_edge;
469 unsigned old_tgt_idx;
471 /* check if the old edge exists */
472 edge_key.src = old_node;
473 edge_key.tgt = get_irn_n(old_node, i);
475 old_edge = pset_find(dbg->edges, &edge_key, HASH_EDGE(&edge_key));
477 old_tgt_idx = get_irn_node_nr(edge_key.tgt);
479 /* remove the old edge */
481 snprintf(buf, sizeof(buf), "deleteEdge \"n%un%up%d\"\n", src_idx, old_tgt_idx, i);
483 pset_remove(dbg->edges, old_edge, HASH_EDGE(old_edge));
487 /* change the old node into an id node */
488 snprintf(buf, sizeof(buf), "changeNode \"%ld\" \"%u\"\n", get_irn_node_nr(old_node), NODE_REALIZER_ID);
491 /* add new Id input */
492 snprintf(buf, sizeof(buf), "addEdge \"n%un%up%d\" \"%u\" \"%u\" \"%u\" \"%d\"\n",
493 src_idx, tgt_idx, 0, /* edge id */
494 src_idx, /* source node id */
495 tgt_idx, /* target node id */
496 get_edge_realizer(old_node, entry->nw), /* realizer id */
503 /* add the new edge to our pset */
504 new_edge = obstack_alloc(&dbg->obst, sizeof(*new_edge));
505 new_edge->src = old_node;
506 new_edge->tgt = entry->nw;
508 pset_insert(dbg->edges, new_edge, HASH_EDGE(new_edge));
512 * Hook: Just mark start/end of dead node elimination.
514 static void firm_ycomp_debug_dead_node_elim(void *context, ir_graph *irg, int start) {
515 firm_ycomp_dbg_t *dbg = context;
517 dbg->in_dead_node_elim = start != 0;
521 * Establish connection to yComp and register all hooks.
523 void firm_init_ycomp_debugger(const char *host, unsigned port) {
524 static int init_once = 0;
529 memset(&yy_dbg, 0, sizeof(yy_dbg));
532 fprintf(stderr, "connecting to %s:%u\n", host, port);
533 yy_dbg.fd = firmnet_connect_tcp(host, port);
535 if (yy_dbg.fd > -1) {
536 /* We could establish a connection to ycomp -> register hooks */
537 firm_ycomp_debug_init_realizer(&yy_dbg);
538 yy_dbg.exchanged_nodes = new_pset(cmp_nodes, 20);
539 yy_dbg.edges = new_pset(cmp_edges, 20);
540 obstack_init(&yy_dbg.obst);
542 #define REGISTER_HOOK(ycomp_hook, firm_hook, func) \
544 yy_dbg.ycomp_hook.context = &yy_dbg; \
545 yy_dbg.ycomp_hook.hook._##firm_hook = func; \
546 register_hook(firm_hook, &yy_dbg.ycomp_hook); \
549 REGISTER_HOOK(hook_new_irn, hook_new_node, firm_ycomp_debug_new_node);
550 REGISTER_HOOK(hook_new_irg, hook_new_graph, firm_ycomp_debug_new_irg);
551 REGISTER_HOOK(hook_set_edge, hook_set_irn_n, firm_ycomp_debug_set_edge);
552 REGISTER_HOOK(hook_exchange, hook_replace, firm_ycomp_debug_exchange);
553 REGISTER_HOOK(hook_into_id, hook_turn_into_id, firm_ycomp_debug_turn_into_id);
554 REGISTER_HOOK(hook_dead_node, hook_dead_node_elim, firm_ycomp_debug_dead_node_elim);
563 * Close connection to yComp, unregister all hooks and free memory.
565 void firm_finish_ycomp_debugger(void) {
566 if (yy_dbg.fd > -1) {
567 /* close connection */
568 firmnet_close_socket(yy_dbg.fd);
571 /* unregister all hooks */
572 unregister_hook(hook_new_graph, &yy_dbg.hook_new_irg);
573 unregister_hook(hook_new_node, &yy_dbg.hook_new_irn);
574 unregister_hook(hook_set_irn_n, &yy_dbg.hook_set_edge);
575 unregister_hook(hook_replace, &yy_dbg.hook_exchange);
576 unregister_hook(hook_dead_node_elim, &yy_dbg.hook_dead_node);
577 unregister_hook(hook_turn_into_id, &yy_dbg.hook_into_id);
580 del_pset(yy_dbg.exchanged_nodes);
581 del_pset(yy_dbg.edges);
583 /* free data obstack */
584 obstack_free(&yy_dbg.obst, NULL);