3 * File name: ir/debug/firm_ycomp.c
4 * Purpose: Connect firm to ycomp
5 * Author: Christian Wuerdig
9 * Copyright: (c) 2001-2006 Universität Karlsruhe
10 * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
14 #endif /* HAVE_CONFIG_H */
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) | \
33 typedef struct _exchange_node_outs_assoc_t {
37 } exchange_node_outs_assoc_t;
39 typedef struct _ycomp_edge_t {
45 enum _firm_ycomp_node_realizer_values {
51 NODE_REALIZER_STARTEND,
57 typedef struct _firm_ycomp_node_realizer_t {
59 const char *linecolor;
60 const char *fillcolor;
62 } firm_ycomp_node_realizer_t;
64 static firm_ycomp_node_realizer_t node_realizer[NODE_REALIZER_LAST] = {
65 { NODE_REALIZER_NORMAL, "black", "white", "box" },
66 { NODE_REALIZER_PROJ, "black", "yellow", "box" },
67 { NODE_REALIZER_BLOCK, "black", "yellow", "box" },
68 { NODE_REALIZER_MEM, "black", "blue", "box" },
69 { NODE_REALIZER_PHI, "black", "green", "box" },
70 { NODE_REALIZER_STARTEND, "black", "blue", "box" },
71 { NODE_REALIZER_IRG, "black", "white", "box" },
72 { NODE_REALIZER_ID, "black", "darkgrey", "box" },
75 enum _firm_ycomp_edge_realizer_values {
83 typedef struct _firm_ycomp_edge_realizer_t {
85 const char *linecolor;
88 } firm_ycomp_edge_realizer_t;
90 static firm_ycomp_edge_realizer_t edge_realizer[EDGE_REALIZER_LAST] = {
91 { EDGE_REALIZER_DATA, "black", 1, "continuous" },
92 { EDGE_REALIZER_MEM, "blue", 1, "continuous" },
93 { EDGE_REALIZER_DEP, "green", 1, "continuous" },
94 { EDGE_REALIZER_CFG, "red", 1, "continuous" },
97 typedef struct _firm_ycomp_dbg_t {
100 pset *exchanged_nodes;
102 unsigned in_dead_node_elim : 1;
104 hook_entry_t hook_new_irn;
105 hook_entry_t hook_new_irg;
106 hook_entry_t hook_set_edge;
107 hook_entry_t hook_exchange;
108 hook_entry_t hook_into_id;
109 hook_entry_t hook_dead_node;
112 static firm_ycomp_dbg_t yy_dbg;
114 static int cmp_edges(const void *a, const void *b) {
115 ycomp_edge_t *e1 = (ycomp_edge_t *)a;
116 ycomp_edge_t *e2 = (ycomp_edge_t *)b;
118 return (e1->src != e2->src) || (e1->tgt != e2->tgt) || (e1->pos != e2->pos);
121 static int cmp_nodes(const void *a, const void *b) {
122 exchange_node_outs_assoc_t *n1 = (exchange_node_outs_assoc_t *)a;
123 exchange_node_outs_assoc_t *n2 = (exchange_node_outs_assoc_t *)b;
125 return n1->irn != n2->irn;
128 static INLINE void send_cmd(firm_ycomp_dbg_t *dbg, const char *buf) {
132 res = firmnet_send(dbg->fd, (const void *)buf, len);
136 static void wait_for_sync(firm_ycomp_dbg_t *dbg) {
138 firmnet_recv(dbg->fd, buf, 6, 5);
141 static void show_and_sync(firm_ycomp_dbg_t *dbg) {
142 send_cmd(dbg, "show\n");
143 send_cmd(dbg, "sync\n");
148 * Register the edge and node realizer in yComp.
150 static void firm_ycomp_debug_init_realizer(firm_ycomp_dbg_t *dbg) {
152 char buf[SEND_BUF_SIZE];
154 for (i = 0; i < NODE_REALIZER_LAST; ++i) {
155 snprintf(buf, sizeof(buf), "addNodeRealizer \"%u\" \"%s\" \"%s\" \"%s\"\n",
157 node_realizer[i].linecolor,
158 node_realizer[i].fillcolor,
159 node_realizer[i].shape);
163 for (i = 0; i < EDGE_REALIZER_LAST; ++i) {
164 snprintf(buf, sizeof(buf), "addEdgeRealizer \"%u\" \"%s\" \"%u\" \"%s\"\n",
166 edge_realizer[i].linecolor,
167 edge_realizer[i].thickness,
168 edge_realizer[i].style);
174 * Retrieve the appropriate realizer for given node.
176 static INLINE unsigned get_node_realizer(ir_node *node) {
178 opcode opc = get_irn_opcode(node);
182 realizer = NODE_REALIZER_BLOCK;
185 realizer = NODE_REALIZER_PHI;
188 if (get_irn_mode(node) == mode_M)
189 realizer = NODE_REALIZER_MEM;
191 realizer = NODE_REALIZER_PROJ;
195 realizer = NODE_REALIZER_STARTEND;
198 realizer = NODE_REALIZER_NORMAL;
205 * Retrieve the appropriate realizer for given edge.
207 static INLINE unsigned get_edge_realizer(ir_node *src, ir_node *tgt) {
209 ir_mode *tgt_mode, *src_mode;
211 assert(! is_Block(tgt));
213 tgt_mode = get_irn_mode(tgt);
214 src_mode = is_Block(src) ? NULL : get_irn_mode(src);
216 if (tgt_mode == mode_M || src_mode)
217 realizer = EDGE_REALIZER_MEM;
218 else if (tgt_mode == mode_X)
219 realizer = EDGE_REALIZER_CFG;
221 realizer = EDGE_REALIZER_DATA;
227 * Add new nodes, resp. new blocks in yComp and add input edges.
229 static void firm_ycomp_debug_new_node(void *context, ir_graph *graph, ir_node *node) {
230 firm_ycomp_dbg_t *dbg = context;
231 char buf[SEND_BUF_SIZE];
235 if (get_const_code_irg() == graph || dbg->in_dead_node_elim)
238 src_idx = get_irn_node_nr(node);
241 if (is_Block(node)) {
242 /* add block (subgraph) */
243 ir_snprintf(buf, sizeof(buf), "addSubgraphNode \"%d\" \"%d\" \"%u\" \"%+F\"\n",
245 get_irn_node_nr(node), /* graph id */
246 NODE_REALIZER_BLOCK, /* realizer id */
251 ir_snprintf(buf, sizeof(buf), "addNode \"%d\" \"%u\" \"%u\" \"%+F\"\n",
252 get_irn_node_nr(get_nodes_block(node)), /* parent id */
253 src_idx, /* node id */
254 get_node_realizer(node), /* realizer id */
260 for (i = get_irn_arity(node) - 1; i >= 0; --i) {
261 ir_node *pred = get_irn_n(node, i);
262 unsigned tgt_idx = get_irn_node_nr(pred);
263 ycomp_edge_t key, *entry;
265 ir_snprintf(buf, sizeof(buf), "addEdge \"n%un%up%d\" \"%u\" \"%u\" \"%u\" \"%d\"\n",
266 src_idx, tgt_idx, i, /* edge id */
267 src_idx, /* source node id */
268 tgt_idx, /* target node id */
269 get_edge_realizer(node, pred), /* realizer id */
277 entry = pset_find(dbg->edges, &key, HASH_EDGE(&key));
279 entry = obstack_alloc(&dbg->obst, sizeof(*entry));
283 pset_insert(dbg->edges, entry, HASH_EDGE(entry));
291 * Clear the old irg if it has some data and create a new one.
293 static void firm_ycomp_debug_new_irg(void *context, ir_graph *irg, entity *ent) {
294 firm_ycomp_dbg_t *dbg = context;
295 char buf[SEND_BUF_SIZE];
297 if (yy_dbg.has_data) {
298 send_cmd(dbg, "deleteGraph\n");
299 send_cmd(dbg, "show\n");
303 ir_snprintf(buf, sizeof(buf), "addSubgraphNode \"-1\" \"0\" \"%u\" \"%s\"\n",
304 NODE_REALIZER_IRG, get_entity_name(ent));
306 send_cmd(dbg, "sync\n");
311 * Handle set_irn_n calls.
313 * - remove old edge and add new one
315 static void firm_ycomp_debug_set_edge(void *context, ir_node *src, int pos, ir_node *tgt, ir_node *old_tgt) {
316 firm_ycomp_dbg_t *dbg = context;
317 exchange_node_outs_assoc_t *entry, key;
318 ycomp_edge_t *old_edge, *new_edge, edge_key;
319 char buf[SEND_BUF_SIZE];
320 unsigned src_idx, tgt_idx, old_tgt_idx;
322 if (dbg->in_dead_node_elim)
325 src_idx = get_irn_node_nr(src);
326 tgt_idx = get_irn_node_nr(tgt);
327 old_tgt_idx = get_irn_node_nr(old_tgt);
329 /* set_irn_n with pos -1 means: node moves to new block */
331 if (tgt != old_tgt) {
332 snprintf(buf, sizeof(buf), "moveNode \"%d\" \"%d\"\n", src_idx, tgt_idx);
339 /* check if the new edge exists */
343 new_edge = pset_find(dbg->edges, &edge_key, HASH_EDGE(&edge_key));
345 /* if the new edge already exists and the old target is the new target -> ignore */
346 if (new_edge && tgt == old_tgt)
349 /* check if the old edge exists */
351 edge_key.tgt = old_tgt;
353 old_edge = pset_find(dbg->edges, &edge_key, HASH_EDGE(&edge_key));
355 /* check if old target is marked for exchange */
357 entry = pset_find(dbg->exchanged_nodes, &key, HASH_PTR(old_tgt));
360 /* we are called from exchange() */
361 entry->n_out_edges--;
364 /* delete the old edge if it exists */
366 snprintf(buf, sizeof(buf), "deleteEdge \"n%un%up%d\"\n", src_idx, old_tgt_idx, pos);
368 pset_remove(dbg->edges, old_edge, HASH_EDGE(old_edge));
372 /* add the new edge if it doesn't exist */
373 snprintf(buf, sizeof(buf), "addEdge \"n%un%up%d\" \"%u\" \"%u\" \"%u\" \"%d\"\n",
374 src_idx, tgt_idx, pos, /* edge id */
375 src_idx, /* source node id */
376 tgt_idx, /* target node id */
377 get_edge_realizer(src, tgt), /* realizer id */
381 /* insert the new edge */
382 new_edge = obstack_alloc(&dbg->obst, sizeof(*new_edge));
386 pset_insert(dbg->edges, new_edge, HASH_EDGE(new_edge));
389 /* show and sync if all edges are rerouted or if it's a normal set_irn_n */
390 if (! entry || entry->n_out_edges == 0) {
396 * Put nodes, about to be exchanged into a set.
398 static void firm_ycomp_debug_exchange(void *context, ir_node *old_node, ir_node *new_node) {
399 firm_ycomp_dbg_t *dbg = context;
400 exchange_node_outs_assoc_t key, *entry;
402 /* put nodes, which are about to be exchanged into a set */
405 entry = pset_find(dbg->exchanged_nodes, &key, HASH_PTR(old_node));
407 entry->n_out_edges = get_irn_n_edges(old_node);
408 entry->nw = new_node;
411 entry = obstack_alloc(&dbg->obst, sizeof(*entry));
412 entry->irn = old_node;
413 entry->nw = new_node;
414 entry->n_out_edges = get_irn_n_edges(old_node);
415 pset_insert(dbg->exchanged_nodes, entry, HASH_PTR(old_node));
420 * Remove all old in edges, turn node into id node, add new input edge.
422 static void firm_ycomp_debug_turn_into_id(void *context, ir_node *old_node) {
423 firm_ycomp_dbg_t *dbg = context;
424 exchange_node_outs_assoc_t key, *entry;
426 char buf[SEND_BUF_SIZE];
427 unsigned src_idx, tgt_idx;
428 ycomp_edge_t edge_key, *new_edge;
431 entry = pset_find(dbg->exchanged_nodes, &key, HASH_PTR(old_node));
433 assert(entry != NULL && "Exchange entry missing");
435 src_idx = get_irn_node_nr(old_node);
436 tgt_idx = get_irn_node_nr(entry->nw);
438 /* remove all old edges */
439 for (i = get_irn_arity(old_node) - 1; i >= 0; --i) {
440 ycomp_edge_t *old_edge;
441 unsigned old_tgt_idx;
443 /* check if the old edge exists */
444 edge_key.src = old_node;
445 edge_key.tgt = get_irn_n(old_node, i);
447 old_edge = pset_find(dbg->edges, &edge_key, HASH_EDGE(&edge_key));
449 old_tgt_idx = get_irn_node_nr(edge_key.tgt);
451 /* remove the old edge */
453 snprintf(buf, sizeof(buf), "deleteEdge \"n%un%up%d\"\n", src_idx, old_tgt_idx, i);
455 pset_remove(dbg->edges, old_edge, HASH_EDGE(old_edge));
459 /* change the old node into an id node */
460 snprintf(buf, sizeof(buf), "changeNode \"%ld\" \"%u\"\n", get_irn_node_nr(old_node), NODE_REALIZER_ID);
463 /* add new Id input */
464 snprintf(buf, sizeof(buf), "addEdge \"n%un%up%d\" \"%u\" \"%u\" \"%u\" \"%d\"\n",
465 src_idx, tgt_idx, 0, /* edge id */
466 src_idx, /* source node id */
467 tgt_idx, /* target node id */
468 get_edge_realizer(old_node, entry->nw), /* realizer id */
475 /* add the new edge to our pset */
476 new_edge = obstack_alloc(&dbg->obst, sizeof(*new_edge));
477 new_edge->src = old_node;
478 new_edge->tgt = entry->nw;
480 pset_insert(dbg->edges, new_edge, HASH_EDGE(new_edge));
484 * Just mark start/end of dead node elimination.
486 static void firm_ycomp_debug_dead_node_elim(void *context, ir_graph *irg, int start) {
487 firm_ycomp_dbg_t *dbg = context;
488 dbg->in_dead_node_elim = start != 0;
492 * Establish connection to yComp and register all hooks.
494 void firm_init_ycomp_debugger(const char *host, uint16_t port) {
495 static int init_once = 0;
500 memset(&yy_dbg, 0, sizeof(yy_dbg));
503 fprintf(stderr, "connecting to %s:%u\n", host, port);
504 yy_dbg.fd = firmnet_connect_tcp(host, port);
506 if (yy_dbg.fd > -1) {
507 /* We could establish a connection to ycomp -> register hooks */
508 firm_ycomp_debug_init_realizer(&yy_dbg);
509 yy_dbg.exchanged_nodes = new_pset(cmp_nodes, 20);
510 yy_dbg.edges = new_pset(cmp_edges, 20);
511 obstack_init(&yy_dbg.obst);
513 #define REGISTER_HOOK(ycomp_hook, firm_hook, func) \
515 yy_dbg.ycomp_hook.context = &yy_dbg; \
516 yy_dbg.ycomp_hook.hook._##firm_hook = func; \
517 register_hook(firm_hook, &yy_dbg.ycomp_hook); \
520 REGISTER_HOOK(hook_new_irn, hook_new_node, firm_ycomp_debug_new_node);
521 REGISTER_HOOK(hook_new_irg, hook_new_graph, firm_ycomp_debug_new_irg);
522 REGISTER_HOOK(hook_set_edge, hook_set_irn_n, firm_ycomp_debug_set_edge);
523 REGISTER_HOOK(hook_exchange, hook_replace, firm_ycomp_debug_exchange);
524 REGISTER_HOOK(hook_into_id, hook_turn_into_id, firm_ycomp_debug_turn_into_id);
525 REGISTER_HOOK(hook_dead_node, hook_dead_node_elim, firm_ycomp_debug_dead_node_elim);
534 * Close connection to yComp, unregister all hooks and free memory.
536 void firm_finish_ycomp_debugger(void) {
537 if (yy_dbg.fd > -1) {
538 /* close connection */
539 firmnet_close_socket(yy_dbg.fd);
542 /* unregister all hooks */
543 unregister_hook(hook_new_graph, &yy_dbg.hook_new_irg);
544 unregister_hook(hook_new_node, &yy_dbg.hook_new_irn);
545 unregister_hook(hook_set_irn_n, &yy_dbg.hook_set_edge);
546 unregister_hook(hook_replace, &yy_dbg.hook_exchange);
547 unregister_hook(hook_dead_node_elim, &yy_dbg.hook_dead_node);
548 unregister_hook(hook_turn_into_id, &yy_dbg.hook_into_id);
551 del_pset(yy_dbg.exchanged_nodes);
552 del_pset(yy_dbg.edges);
554 /* free data obstack */
555 obstack_free(&yy_dbg.obst, NULL);