1 /*****************************************************************************
2 * Program: grgen_dumper.c
3 * Function: Dumps parts of a firm graph (those which have to be extracted
4 * as search and replace patterns) as a grGen rule.
5 * Depends on: Needs the analysis info generated by the pattern creator
6 * Author: Andreas Schoesser
8 *****************************************************************************/
11 // ---------------------------- INCLUDES --------------------------------
17 #include "simd_presets.h"
19 #include "firm_types.h"
24 #include "grgen_dumper__t.h"
25 #include "create_pattern_t.h"
26 #include "firm_node_ext.h"
28 // ----------------------------- GLOABALS --------------------------------
30 // Saves the current indent value and keeps spaces in a string
31 #define MAX_INDENT 100
32 static char indent[MAX_INDENT] = "";
33 static int current_indent = 0;
35 // Saves the current node number to generate node names
36 static int node_counter;
37 static int edge_counter;
42 /************************************************************************
43 * Initializes the grgen_dumper module and dumps the GrGen File header
44 * Returns: An environment to be passed to all functions of the GrGen
46 * Parameters: file: filename of the file to dump to
47 * append: 1 if the previous file content should be
49 ************************************************************************/
51 grgen_dumper_env_t *init_grgen_dumper(char *file, int append)
53 grgen_dumper_env_t *grgen_dumper_env = malloc(sizeof(grgen_dumper_env_t));
57 fp = fopen(file, "at");
60 fp = fopen(file, "wt");
63 fprintf(fp, "%susing Firm;\n\n", indent);
66 grgen_dumper_env -> output_file = fp;
67 return(grgen_dumper_env);
72 /************************************************************************
73 * Frees information used by the grgen_dumper and closes the output file
74 ************************************************************************/
76 void deinit_grgen_dumper(grgen_dumper_env_t *grgen_dumper_env)
78 fclose(grgen_dumper_env->output_file);
79 free(grgen_dumper_env);
85 /************************************************************************
88 * 1 if the complex operation uses the memory edge
89 * 0 if no memory edge is used.
90 ************************************************************************/
92 int dump_irgraph_grgen(grgen_dumper_env_t *grgen_dumper_env, graph_ana_info_t *graph_ana_info)
94 FILE *fp = grgen_dumper_env -> output_file;
95 dump_info_t dump_info;
99 get_rule_name(graph_ana_info, irg_name);
102 dump_info.irg = graph_ana_info->irg; // Basically copy the graph_ana_struct, ugly
103 dump_info.destroyed_regs = graph_ana_info->destroyed_regs; // Should have used a pointer to the
104 dump_info.register_access = graph_ana_info->register_access; // graph_ana_info struct here
105 dump_info.memory_access = graph_ana_info->memory_access;
106 dump_info.nodes_to_dump = graph_ana_info->nodes_to_dump;
107 dump_info.argument_nodes = graph_ana_info->argument_nodes;
108 dump_info.complex_operation_block = graph_ana_info->complex_operation_block;
109 dump_info.node_to_match_block = graph_ana_info->node_to_match_block;
110 dump_info.has_result = graph_ana_info->has_result;
111 dump_info.priority = graph_ana_info->priority;
112 dump_info.mode_edge_map = pmap_create(); // Create some additional pmaps to hold
113 dump_info.edge_name_map = pmap_create(); // node and edge name information etc.
114 dump_info.node_name_map = pmap_create();
115 dump_info.mode_name_map = pmap_create();
116 dump_info.dump_condition = pmap_create(); // pmaps "misused" as lists here...
117 dump_info.retyped_nodes = pmap_create();
118 dump_info.eval_statements = pmap_create();
119 dump_info.dump_everything = graph_ana_info->dump_everything;
121 // Node and egde count start at 0 for each pattern to be dumped.
124 obstack_init(&(dump_info.node_names));
125 obstack_init(&(dump_info.mode_names));
129 fprintf(fp, "\n\n%srule %s\n%s{\n", indent, irg_name, indent);
131 if(!dump_info.dump_everything)
132 fprintf(fp, "%spattern\n%s{\n", indent, indent);
135 fprintf(fp, "%spattern { }\n", indent);
136 fprintf(fp, "%sreplace\n%s{\n", indent, indent);
140 // *** Dump the left side of the rule
141 uses_memory = dump_pattern(&dump_info, fp);
143 // *** Dump the right side of the rule
144 if(!dump_info.dump_everything) // Hack: If a whole graph is dumped, the pattern part will raise errors since no complex operations etc. are there
146 dump_replacement(&dump_info, uses_memory, fp);
148 // *** Dump the eval part of the rule
149 fprintf(fp, "\n%seval {\n", indent);
151 dump_mandatory_evals(&dump_info, uses_memory, fp);
152 dump_vproj_nr(&dump_info, fp); // Dumps all vproj_nr attribute assignments
154 fprintf(fp, "%s} /* Eval */\n", indent);
156 // *** Close the replacement part
159 fprintf(fp, "%s} /* Replacement */\n", indent);
164 fprintf(fp, "%s}\n", indent);
167 pmap_destroy(dump_info.mode_edge_map);
168 pmap_destroy(dump_info.edge_name_map);
169 pmap_destroy(dump_info.node_name_map);
170 pmap_destroy(dump_info.mode_name_map);
171 pmap_destroy(dump_info.dump_condition);
172 pmap_destroy(dump_info.retyped_nodes);
173 pmap_destroy(dump_info.eval_statements);
174 obstack_free(&(dump_info.node_names), NULL);
175 obstack_finish(&(dump_info.node_names));
176 obstack_free(&(dump_info.mode_names), NULL);
177 obstack_finish(&(dump_info.mode_names));
183 /************************************************************************
184 * Dumps the left hand side of the rule
185 ************************************************************************/
187 static int dump_pattern(dump_info_t *dump_info, FILE *fp)
189 struct pmap *nodes_to_dump = dump_info->nodes_to_dump;
194 pmap_foreach(nodes_to_dump, entry)
196 ir_node *n = (ir_node *) entry->key;
200 if(get_irn_opcode(n) == iro_Proj && get_irn_modecode(n) == irm_M)
202 dump_grgen_node(n, dump_info, fp);
203 dump_grgen_mode(n, dump_info, fp, NULL);
204 //dump_grgen_block(n, dump_info, fp);
207 // If a condition has to be dumped afterwards: Save the node for later
208 code = get_irn_opcode(n);
209 if(code == iro_MultipleAdd ||
214 pmap_insert(dump_info -> dump_condition, n, NULL);
218 pmap_foreach(nodes_to_dump, entry)
220 ir_node *n = (ir_node *) entry->key;
224 for(i = -1; i < get_irn_arity(n); i++)
225 dump_grgen_edge(n, i, dump_info, fp);
228 // Dump the edge from a special pattern node to it's block. This block will later be the block
229 // of the complex operation
230 //dump_complex_operation_block_match(dump_info, fp);
232 if(!dump_info->dump_everything)
235 fprintf(fp, "\n%sif\n%s{\n", indent, indent);
238 pmap_foreach(dump_info->dump_condition, entry)
240 ir_node *n = (ir_node *) entry->key;
241 dump_grgen_condition(n, dump_info, fp);
244 fprintf(fp, "%s} /* Conditions */\n", indent);
248 fprintf(fp, "%s} /* Pattern */\n", indent);
254 /************************************************************************
255 * Dumps the right hand side of the rule
256 ************************************************************************/
258 static void dump_replacement(dump_info_t *dump_info, int uses_memory, FILE *fp)
261 register_access_descr_t *register_access_descr;
262 memory_access_descr_t *memory_access_descr;
264 // dump grGen "replace" statement
265 fprintf(fp, "\n%smodify {\n", indent);
268 // Dump the complex operation node with it's projs and vprojs
269 dump_complex_operation(dump_info, fp, uses_memory);
271 // Dump the rest of the replacement nodes. Do retyping to VProj if necessary
274 // First dump all nodes.
275 pmap_foreach(dump_info->nodes_to_dump, entry)
277 ir_node *n = (ir_node *) entry->key;
279 if((register_access_descr = pmap_get(dump_info->register_access, n)) != NULL)
281 // Nodes that represent a result in a register have to be retyped
282 if(register_access_descr -> load_store == REGISTER_STORE)
284 // Find out, if this store is a component of a vector or a standalone scalar
285 argument_descr_t *arg_descr;
287 arg_descr = pmap_get(dump_info->argument_nodes, register_access_descr->pointer_base);
288 assert(arg_descr && "No argument information available! Should have been created during analysis!");
290 // Treat SCALAR and VECTOR_COMPONENT differently
291 // A vector component has to be retyped to VProj
292 // A scalar has to be retyped to a Proj
293 switch(arg_descr->argument_type)
295 case ARGUMENT_VECTOR:
297 // assert(get_irn_opcode(n) != iro_VProj); // An existing VProj would be a register LOAD
299 // Node is a vector result to be stored in a register:
300 // Retype the node to VProj
301 // Connect it with the Data Proj of the complex operation
302 dump_retyping_to_vproj(n, NULL, dump_info, VECTOR_OP_PROJDATA_NAME, fp);
303 //dump_grgen_block(n, dump_info, fp);
306 case ARGUMENT_SCALAR:
307 // Retype the scalar result to proj
308 // Connect it directly with the operation
309 dump_retyping_to_proj(n, NULL, dump_info, VECTOR_OP_NAME, fp);
310 //dump_grgen_block(n, dump_info, fp);
311 //assert(0 && "// TODO: retype_to_proj, if the result is a scalar");
315 assert(0 && "Argument Type not implemented!");
322 if((memory_access_descr = pmap_get(dump_info->memory_access, n)) != NULL)
324 if(memory_access_descr->load_store == MEMORY_STORE)
326 // Node is part of a memory store, that is STORE or PROJM node.
328 // Trick to keep the M-edge predecessor of the Store node as
329 // the predecessor of the Id Node without actually matching the predecessor:
330 // Since we don't dump the M-Edge of the STORE but the Adr and Value edges and
331 // we can just "not dump" the 2 matched edges. The Adr and Value edges are therefore
332 // killed by the graph rewriting system. The M-Edge is not specified at all and the
333 // GRS is supposed to leave the edge as it was. M-Edges of Stores are at position 0,
334 // so the kept edge is also at position 0, which is correct.
335 dump_grgen_retyped_node(n, op_Sync, dump_info, fp);
336 dump_grgen_delete_incoming_edges(n, dump_info, fp); // Only the M edge (not matched) will persist
337 change_mode(n, mode_M, dump_info, fp);
342 // Same for the STORE PROJ M
343 if(get_irn_opcode(n) == iro_Proj && (memory_access_descr = pmap_get(dump_info->memory_access, get_irn_n(n, 0))) != NULL)
345 if(memory_access_descr->load_store == MEMORY_STORE)
347 dump_grgen_retyped_node(n, op_Sync, dump_info, fp);
348 change_mode(n, mode_M, dump_info, fp);
355 // Now dump the edges of the replaced nodes, that could not be dumped before:
356 // - Eliminated STOREs and ProjMs
357 pmap_foreach(dump_info->retyped_nodes, entry)
359 const ir_node *n = entry->key;
360 if(pmap_contains(dump_info->memory_access, n))
362 memory_access_descr_t *memory_access_descr = pmap_get(dump_info->memory_access, n);
363 assert(memory_access_descr->load_store == MEMORY_STORE);
365 if(get_irn_opcode(n) == iro_Proj)
367 // dump in edge of the retyped ProjM
368 fprintf(fp, "%s%s -:df-> %s;\n", indent, pmap_get(dump_info->node_name_map, n), pmap_get(dump_info->node_name_map, get_irn_n(n, 0)));
372 //dump_complex_operation_block_match(dump_info, fp);
374 /* Don't close the replacement since evals have moved into the replacement part */
377 fprintf(fp, "%s} /* Replacement */\n", indent);
383 /************************************************************************
384 * Dumps the new complex operation node and it's Projs and Vprojs
385 ************************************************************************/
387 void dump_complex_operation(dump_info_t *dump_info, FILE *fp, int uses_memory)
390 int i, mem_slot = (uses_memory) ? 1 : 0, max_argument;
391 char *mode_node_name, eval[100];
393 // Generate Vector operation
394 fprintf(fp, "%s%s : Complex;\n", indent, VECTOR_OP_NAME);
396 // Dump the mode of the Complex op (mode T).
397 mode_node_name = dump_grgen_mode_node(mode_T, dump_info, fp);
398 fprintf(fp, "%s%s -:has_mode-> %s;\n", indent, VECTOR_OP_NAME, mode_node_name);
400 // Connect the complex operation to it's block
401 assert(pmap_contains(dump_info->node_name_map, dump_info->complex_operation_block) && "Complex operation's block predecessor must have already been dumped in the positive pattern!");
402 fprintf(fp, "%s%s -pos0_%d:df-> %s;\n", indent, VECTOR_OP_NAME, edge_counter++, pmap_get(dump_info->node_name_map, dump_info->complex_operation_block));
404 if(dump_info->has_result)
406 // Dump the res proj node projecting the complete vector out of the complex operation
407 fprintf(fp, "%s%s : Proj;\n", indent, VECTOR_OP_PROJDATA_NAME);
408 mode_node_name = dump_grgen_mode_node(mode_LLu, dump_info, fp);
409 fprintf(fp, "%s%s -:has_mode-> %s;\n", indent, VECTOR_OP_PROJDATA_NAME, mode_node_name);
410 fprintf(fp, "%s%s -pos0_%d:df-> %s;\n", indent, VECTOR_OP_PROJDATA_NAME, edge_counter++, pmap_get(dump_info->node_name_map, dump_info->complex_operation_block));
411 fprintf(fp, "%s%s -pos1_%d:df-> %s;\n", indent, VECTOR_OP_PROJDATA_NAME, edge_counter++, VECTOR_OP_NAME);
412 sprintf(eval, "%s.proj = %d;", VECTOR_OP_PROJDATA_NAME, 0);
413 add_eval(dump_info, eval);
417 // Connect the complex operation to it's arguments
418 // Caution: The argument-nodes must have not been retyped!
420 max_argument = -1000;
421 pmap_foreach(dump_info->argument_nodes, entry)
423 ir_node *n = (ir_node *) entry->key;
425 argument_descr_t *argument_descr = entry -> value;
426 int arg_nr = argument_descr->arg_nr;
430 assert(pmap_contains(dump_info->node_name_map, n) && "The pointer base node must have already been dumped in the positive pattern!");
432 if(argument_descr->argument_location == ARGUMENT_SIMD_REGISTER)
435 argument = argument_descr->vec_op_input;
437 fprintf(fp, "%s%s -pos%d_%d:df-> %s;\n", indent, VECTOR_OP_NAME, arg_nr + 1, edge_counter++, pmap_get(dump_info->node_name_map, argument));
438 if(max_argument < arg_nr)
439 max_argument = arg_nr;
442 // Do preparations to connect the memory edge to the complex operation
445 // Dump a dummy in-edge used to connect the memory in manually later
446 fprintf(fp, "%s%s -pos%d_%d:df-> Bad%d : Bad;\n", indent, VECTOR_OP_NAME, max_argument + 2, edge_counter++, node_counter);
448 // Generate ProjM node to connect the rest of the replace pattern with
449 fprintf(fp, "%s%s : Proj;\n", indent, VECTOR_OP_PROJM_NAME);
450 fprintf(fp, "%s%s -:has_mode-> mode_M_node;\n", indent, VECTOR_OP_PROJM_NAME);
451 fprintf(fp, "%s%s -pos1_%d:df-> %s;\n", indent, VECTOR_OP_PROJM_NAME, edge_counter++, VECTOR_OP_NAME);
452 fprintf(fp, "%s%s -pos0_%d:df-> %s;\n", indent, VECTOR_OP_PROJM_NAME, edge_counter++, pmap_get(dump_info->node_name_map, dump_info->complex_operation_block));
454 // Add eval to set the proj nr
455 sprintf(eval, "%s.proj = %d;", VECTOR_OP_PROJM_NAME, (dump_info->has_result) ? 1 : 0);
456 add_eval(dump_info, eval);
460 pmap_foreach(dump_info->destroyed_regs, entry)
462 //ir_node *end_node = get_irg_end(dump_info->irg);
463 //char *end_name = pmap_get(dump_info->node_name_map, end_node);
464 char proj_name[255], keep_name[255];
466 // assert(end_name && "End node has to be already dumped in positive pattern!");
468 sprintf(proj_name, "Proj%d", node_counter++);
469 sprintf(keep_name, "IR_Keep%d", i);
470 fprintf(fp, "%s%s : Proj;\n", indent, proj_name);
471 fprintf(fp, "%s%s -:has_mode-> mode_LLu_node;\n", indent, proj_name);
472 fprintf(fp, "%s%s -pos0_%d:df-> %s;\n", indent, proj_name, edge_counter++, pmap_get(dump_info->node_name_map, dump_info->complex_operation_block));
473 fprintf(fp, "%s%s -pos1_%d:df-> %s;\n", indent, proj_name, edge_counter++, VECTOR_OP_NAME);
474 fprintf(fp, "%s%s : IR_Keep;\n", indent, keep_name);
475 fprintf(fp, "%s%s -pos%d_%d:df-> %s;\n", indent, keep_name, i + 1, edge_counter++, proj_name);
476 fprintf(fp, "%s%s -pos0_%d:df-> %s;\n", indent, keep_name, edge_counter++, pmap_get(dump_info->node_name_map, dump_info->complex_operation_block));
477 //fprintf(fp, "%s%s -:df-> %s;\n", indent, end_name, keep_name);
478 sprintf(eval, "%s.proj = %d;", proj_name, (dump_info->has_result + uses_memory + i));
479 add_eval(dump_info, eval);
486 /************************************************************************
487 * Dumps a node in GrGen Format
488 ************************************************************************/
490 static void dump_grgen_node(ir_node *n, dump_info_t *dump_info, FILE *fp)
494 // Already dumped the node? Then do nothing
495 if(pmap_contains(dump_info -> node_name_map, n))
498 // Else generate new node name and dump the node
500 node_name = obstack_alloc(&(dump_info -> node_names), MAX_NODENAME_LEN);
502 if(!pmap_contains(dump_info->argument_nodes, n))
504 register_access_descr_t *register_access_descr = pmap_get(dump_info->register_access, n);
506 if(n == dump_info->complex_operation_block)
507 sprintf(node_name, "%s", COMPLEX_OPERATION_BLOCK_NAME);
508 else if(register_access_descr != NULL && register_access_descr -> load_store == REGISTER_STORE) // Register STORE nodes get a special name to be fao
509 sprintf(node_name, "%s%d_%s%d", VECTOR_RESULT_NAME, register_access_descr->array_index, get_op_name(get_irn_op(n)), get_irn_node_nr(n));
511 sprintf(node_name, "%s%d", get_op_name(get_irn_op(n)), get_irn_node_nr(n));
513 if(get_irn_opcode(n) == iro_Bad) // A bad node that comes out of specification is a generic IR_node
514 fprintf(fp, "%s%s : %s;\n", indent, node_name, "IR_node");
516 fprintf(fp, "%s%s : %s;\n", indent, node_name, get_op_name(get_irn_op(n)));
520 // Argument nodes get a special name, so that they can be found after
521 // matching to test if their position is legal
522 argument_descr_t *arg_descr = pmap_get(dump_info->argument_nodes, n);
523 if(arg_descr->arg_nr != -1)
524 sprintf(node_name, "Arg_%d", arg_descr->arg_nr);
526 sprintf(node_name, "Result"); /// ???? What did I do here?
527 fprintf(fp, "%s%s : %s;\n", indent, node_name, VECTOR_BASE_TYPE);
531 pmap_insert(dump_info -> node_name_map, n, node_name);
537 /************************************************************************
538 * Dump grGen code for retyping a node to a new opCode.
539 * The mode stays the same.
540 * Changes also the already saved node_name in node_name_map
541 * Returns the node name generated for the retyped node.
542 ************************************************************************/
544 static char *dump_grgen_retyped_node(ir_node *n, ir_op *new_op, dump_info_t *dump_info, FILE *fp)
548 // A retyped node should have already been dumped.
549 assert(pmap_contains(dump_info->node_name_map, n));
551 // Else generate new node name and dump the retyped node
552 node_name = obstack_alloc(&(dump_info -> node_names), MAX_NODENAME_LEN);
553 sprintf(node_name, "%s%d", get_op_name(new_op), node_counter);
554 fprintf(fp, "%s%s : %s<%s>;\n", indent, node_name, get_op_name(new_op), pmap_get(dump_info->node_name_map, n));
555 pmap_insert(dump_info -> node_name_map, n, node_name);
557 // Save the retyped op
558 pmap_insert(dump_info -> retyped_nodes, n, (void *) new_op);
561 // Dump the block of the original node had one.
562 // dump_grgen_edge(n, -1, dump_info, fp);
569 /*************************************************************************
570 * Dumps 'delete' statements for all incoming egdes that have been matched
571 * except for the bock edge and the mode edge
572 * This is useful for nodes that were retyped to VProj or Sync and
573 * needing new incoming edges now;
574 *************************************************************************/
576 void dump_grgen_delete_incoming_edges(ir_node *n, dump_info_t *dump_info, FILE *fp)
578 char **nodes_edge_names;
581 // Delete all incoming edges of the original node since a retyped node
582 // will get new in edges (except the block edge and mode egde)
584 if(get_irn_arity(n) > 0)
586 fprintf(fp, "%sdelete(", indent);
587 nodes_edge_names = pmap_get(dump_info->edge_name_map, n);
588 assert(nodes_edge_names != NULL);
590 for(i = get_irn_arity(n); i > 0; i--)
591 if(nodes_edge_names[i] != NULL)
593 fprintf(fp, "%c%s", (deleted == 0) ? ' ' : ',', nodes_edge_names[i]);
603 /************************************************************************
605 * - The Block node of a ir_node if it has not been dumped before
606 * - The edge to the block node if n is not an argument or Const
607 ************************************************************************/
609 static void dump_grgen_block(ir_node *n, dump_info_t *dump_info, FILE *fp)
614 if(get_irn_opcode(n) == iro_Block) // A block has no block predecessor
617 if(get_irn_opcode(n) == iro_Const || pmap_contains(dump_info->argument_nodes, n))
620 if(get_irn_opcode(n) == iro_VProj)
623 block = get_nodes_block(n);
624 // Dump the block node if necessary
625 if(!pmap_contains(dump_info->node_name_map, block))
627 dump_grgen_node(block, dump_info, fp);
628 dump_grgen_mode(block, dump_info, fp, NULL);
631 // Dump the edge to the block node
632 dump_grgen_edge(n, -1, dump_info, fp);
637 /************************************************************************
638 * Dumps an edge in GrGen format
639 ************************************************************************/
641 static void dump_grgen_edge(ir_node *n, int n_edge, dump_info_t *dump_info, FILE *fp)
644 char *from_node_name, *to_node_name;
645 char **nodes_edge_names;
647 // Don't dump a block edge if n is a block or n is a const or n is an argument for the complex
648 // operation which can be in a random block in the host graph
649 if(!dump_info->dump_everything)
650 if(n_edge == -1 && n != dump_info->node_to_match_block && (is_Block(n) || (get_irn_opcode(n) == iro_VProj && dump_info->priority != PRIORITY_CLEANUP /* HACK!!! */ ) ||
651 get_irn_opcode(n) == iro_Const || get_irn_opcode(n) == iro_Cmp ||
652 (get_irn_opcode(n) == iro_Proj && get_irn_modecode(n) != irm_M) ||
653 get_irn_opcode(n) == iro_MultipleAdd ||
654 get_irn_opcode(n) == iro_Load ||
655 get_irn_opcode(n) == iro_Proj ||
656 get_irn_opcode(n) == iro_Conv ||
657 get_irn_op(n) == op_IrNode ||
658 pmap_contains(dump_info->argument_nodes, n)))
662 // Check if to_node has also to be dumped. If not, skip this edge
663 // We have to dump to_node here, because to_node has to be known by grgen before
664 // connecting an edge to it.
665 to_node = get_irn_n(n, n_edge);
666 if(!pmap_contains(dump_info -> nodes_to_dump, to_node))
669 if((nodes_edge_names = pmap_get(dump_info -> edge_name_map, n)) == NULL)
671 nodes_edge_names = (char **) obstack_alloc(&(dump_info->node_names), (get_irn_arity(n) + 1) * sizeof(char *));
672 memset(nodes_edge_names, 0, (get_irn_arity(n) + 1) * sizeof(char *));
673 pmap_insert(dump_info->edge_name_map, n, nodes_edge_names);
677 // Is the target node a node with memory mode?
678 if(dump_info->dump_everything || get_mode_modecode(get_irn_mode(to_node)) != irm_M)
680 // No, we can dump the edge since it's no memory edge:
682 // Dumps node only when it was not dumped before
683 // dump_grgen_node(to_node, node_name_map, node_names, mode_name_map, mode_names, fp);
684 // dump_grgen_node(to_node, dump_info, fp);
686 assert(pmap_contains(dump_info -> node_name_map, n));
687 assert(pmap_contains(dump_info -> node_name_map, to_node));
688 from_node_name = (char *) pmap_get(dump_info -> node_name_map, n);
689 to_node_name = (char *) pmap_get(dump_info -> node_name_map, to_node);
691 // Don't dump edge number for certain nodes that are commutative (like ADD operation)
692 if(!dump_info->dump_everything && (n_edge != -1 && (get_irn_opcode(n) == iro_Add ||
693 get_irn_opcode(n) == iro_MultipleAdd ||
694 get_irn_opcode(n) == iro_Mul) ||
695 get_irn_opcode(n) == iro_Block ||
696 get_irn_opcode(n) == iro_Phi))
698 char edge_name[50], *edge_name_obst;
700 sprintf(edge_name, "e%d", edge_counter++);
701 edge_name_obst = obstack_alloc(&(dump_info->node_names), strlen(edge_name) + 1);
702 strcpy(edge_name_obst, edge_name);
703 nodes_edge_names[n_edge + 1] = edge_name_obst;
705 fprintf(fp, "%s%s -%s:df-> %s;\n", indent, from_node_name, edge_name_obst, to_node_name);
709 char edge_name[50], *edge_name_obst;
711 sprintf(edge_name, "pos%d_%d", n_edge + 1, edge_counter++);
712 edge_name_obst = obstack_alloc(&(dump_info->node_names), strlen(edge_name) + 1);
713 strcpy(edge_name_obst, edge_name);
714 nodes_edge_names[n_edge + 1] = edge_name_obst;
716 fprintf(fp, "%s%s -%s:df-> %s;\n", indent, from_node_name, edge_name_obst, to_node_name);
719 switch(get_irn_opcode(n))
722 case iro_MultipleAdd:
727 fprintf(fp, "%s%s -pos%d_%d:df-> %s;\n", indent, from_node_name, n_edge + 1, edge_counter++, to_node_name);
736 /************************************************************************
737 * Dumps an FIRM Mode as GrGen Code
738 * If source_node_name == NULL, that name of n that was already
740 * If source_node_name != NULL, this given source will be used
741 * (useful for retyped nodes)
742 ************************************************************************/
744 static void dump_grgen_mode(ir_node *n, dump_info_t *dump_info, FILE *fp, ir_mode *alt_mode)
746 char *node_name = (char *) pmap_get(dump_info -> node_name_map, n);
747 ir_mode *irn_mode = (alt_mode != NULL) ? alt_mode : get_irn_mode(n);
749 char *mode_node_name;
751 if(pmap_contains(dump_info->argument_nodes, n))
753 mode_node_name = dump_grgen_mode_node(irn_mode, dump_info, fp);
755 //mode_code = get_mode_modecode(irn_mode);
756 //mode_name = get_mode_name(irn_mode);
761 // Check if the mode node has already been created
762 if(!pmap_contains(dump_info -> mode_name_map, (void *) mode_code))
764 // No, create a new mode-node
765 mode_node_name = obstack_alloc(&(dump_info -> mode_names), MAX_NODENAME_LEN);
766 sprintf(mode_node_name, "mode_%s_node", mode_name);
767 pmap_insert(dump_info -> mode_name_map, (int *) mode_code, mode_node_name);
768 // Dump the edge from the current node to it's mode node
769 fprintf(fp, "%s%s -:has_mode-> %s : Mode_%s;\n", indent, node_name, mode_node_name, mode_name);
774 // Yes, use the given mode-node
775 //mode_node_name = pmap_get(dump_info -> mode_name_map, (void *) mode_code);
776 sprintf(edge_name, "m%d", edge_counter++);
779 if(pmap_get(dump_info->mode_edge_map, n) == NULL)
781 char *edge_name_obst = obstack_alloc(&(dump_info->node_names), strlen(edge_name) + 1);
782 strcpy(edge_name_obst, edge_name);
783 pmap_insert(dump_info->mode_edge_map, n, edge_name_obst);
786 // Dump the edge from the current node to it's mode node
787 fprintf(fp, "%s%s -%s:has_mode-> %s;\n", indent, node_name, edge_name, mode_node_name);
795 /************************************************************************
796 * Dumps a node representing a node
797 ************************************************************************/
799 char *dump_grgen_mode_node(ir_mode *irn_mode, dump_info_t *dump_info, FILE *fp)
801 modecode mode_code = get_mode_modecode(irn_mode);
802 const char *mode_name = get_mode_name(irn_mode);
803 char *mode_node_name;
805 if(!pmap_contains(dump_info -> mode_name_map, (void *) mode_code))
807 // No, create a new mode-node
808 mode_node_name = obstack_alloc(&(dump_info -> mode_names), MAX_NODENAME_LEN);
809 sprintf(mode_node_name, "mode_%s_node", mode_name);
810 pmap_insert(dump_info -> mode_name_map, (void *) mode_code, mode_node_name);
811 fprintf(fp, "%s%s : Mode_%s;\n", indent, mode_node_name, mode_name);
812 return(mode_node_name);
816 return((char *) pmap_get(dump_info -> mode_name_map, (void *) mode_code));
823 /************************************************************************
824 * Dumps the condition for the given node, depending on the node's
825 * attributes and the node's opcode
826 ************************************************************************/
828 static void dump_grgen_condition(ir_node *n, dump_info_t *dump_info, FILE *fp)
831 ir_opcode code = get_irn_opcode(n);
833 if(code == iro_MultipleAdd)
835 node_name = pmap_get(dump_info->node_name_map, n);
836 fprintf(fp, "%s%s.arity == %d;\n", indent, node_name, get_irn_arity(n));
840 if(code == iro_Const)
842 node_name = pmap_get(dump_info->node_name_map, n);
843 fprintf(fp, "%s%s.value == \"%d\";\n", indent, node_name, get_tarval_long(get_Const_tarval(n)));
847 if(code == iro_VProj)
849 node_name = pmap_get(dump_info->node_name_map, n);
850 fprintf(fp, "%s%s.proj == %d;\n", indent, node_name, get_VProj_proj(n));
856 if(!pmap_contains(dump_info->argument_nodes, n))
858 node_name = pmap_get(dump_info->node_name_map, n);
859 fprintf(fp, "%s%s.proj == %d;\n", indent, node_name, get_Proj_proj(n));
867 ir_node *phi_block = get_nodes_block(n);
868 char **edge_names_phi, **edge_names_block;
871 assert((get_irn_arity(n) == get_irn_arity(phi_block)) && "Phi has other arity than it's block! Pattern seems to be broken.");
873 // Load the edge names that have been saved
874 edge_names_phi = pmap_get(dump_info->edge_name_map, n);
875 edge_names_block = pmap_get(dump_info->edge_name_map, phi_block);
876 assert(edge_names_phi && edge_names_block && "Some edge names have not been dumped!");
878 // Correlate the matched phi edges with the matched block edges
879 // Caution: Position 0 in the edge_names array is the block edge, so start at 1
880 for(i = 1; i < get_irn_arity(n) + 1; i++)
882 assert(edge_names_phi[i] != NULL && edge_names_block[i] != NULL && "Some edges have not been dumped!");
884 fprintf(fp, "%s%s.pos == %s.pos;\n", indent, edge_names_phi[i], edge_names_block[i]);
889 assert(0 && "Nodes attributes not supported");
895 /************************************************************************
896 * Dump grGen code for retyping a special node
897 ************************************************************************/
899 static void dump_retyping_to_vproj(ir_node *n, ir_node *complex_operation, dump_info_t *dump_info, char *vector_op_node_name, FILE *fp)
901 // Dump the grGen code for retyping
902 register_access_descr_t *register_access_descr;
905 /*char *node_name = obstack_alloc(&(dump_info->node_names), MAX_NODENAME_LEN);
907 // A node that should be retyped must be already there in the pattern part.
908 assert(pmap_contains(dump_info->node_name_map, n));
909 // Generate a node name for that VProj
910 sprintf(node_name, "VProj%d", node_counter);
911 fprintf(fp, "%s%s : VProj<%s>;\n", indent, node_name, pmap_get(dump_info->node_name_map, n));
912 dump_grgen_mode(n, dump_info, fp, node_name); */
914 node_name = dump_grgen_retyped_node(n, op_VProj, dump_info, fp);
915 dump_grgen_delete_incoming_edges(n, dump_info, fp);
917 // Dump the edge to the complex operation
918 fprintf(fp, "%s%s -pos1_%d:df-> %s;\n", indent, node_name, edge_counter++, vector_op_node_name);
921 // Save generated VProj Node name for later usage
922 register_access_descr = pmap_get(dump_info->register_access, n);
923 register_access_descr->replace_node_name = node_name;
928 /************************************************************************
929 * Dump grGen code for retyping a special node
930 ************************************************************************/
932 static void dump_retyping_to_proj(ir_node *n, ir_node *complex_operation, dump_info_t *dump_info, char *vector_op_node_name, FILE *fp)
934 // Dump the grGen code for retyping
935 register_access_descr_t *register_access_descr;
939 node_name = dump_grgen_retyped_node(n, op_Proj, dump_info, fp);
940 dump_grgen_delete_incoming_edges(n, dump_info, fp); // Will get a new edge to the complex op
941 dump_grgen_mode(n, dump_info, fp, NULL);
943 // Dump the edge to the complex operation
944 fprintf(fp, "%s%s -pos1_%d:df-> %s;\n", indent, node_name, edge_counter++, vector_op_node_name);
947 // Save generated VProj Node name for later usage
948 register_access_descr = pmap_get(dump_info->register_access, n);
949 register_access_descr->replace_node_name = node_name;
954 /************************************************************************
955 * Dump grGen Code to add the VProj Nr to VProj nodes after replacement
956 ************************************************************************/
958 static void dump_vproj_nr(dump_info_t *dump_info, FILE *fp)
962 pmap_foreach(dump_info -> register_access, entry)
964 ir_node *n = (ir_node *) entry->key;
965 register_access_descr_t *register_access_descr = entry->value;
967 // Only VProjs that represent a store have to be changed
968 if(register_access_descr->load_store == REGISTER_STORE)
969 fprintf(fp, "%s%s.proj = %d;\n", indent, pmap_get(dump_info->node_name_map, n) /*register_access_descr->replace_node_name*/, register_access_descr->array_index);
974 /************************************************************************
975 * Sets current indent
976 ************************************************************************/
978 void set_indent(int i)
982 // Generate a string containing i blank characters
983 if(i < MAX_INDENT - 1)
985 for(j = 0; j < i; j++)
994 /************************************************************************
995 * Gets current indent value
996 ************************************************************************/
1000 return(current_indent);
1003 void dump_complex_operation_block_match(dump_info_t *dump_info, FILE *fp)
1005 fprintf(fp, "%s%s -:df-> %s;\n", indent, pmap_get(dump_info->node_name_map, dump_info->node_to_match_block), pmap_get(dump_info->node_name_map, dump_info->complex_operation_block));
1009 /************************************************************************
1010 * Dumps some evals which are mandatory
1011 ************************************************************************/
1013 void dump_mandatory_evals(dump_info_t *dump_info, int uses_memory, FILE *fp)
1017 pmap_foreach(dump_info->eval_statements, entry)
1019 char *statement = (char *) entry->key;
1020 fprintf(fp, "%s%s\n", indent, statement);
1025 /************************************************************************
1026 * Adds an eval to the list that has to be dumped at the end
1027 ************************************************************************/
1029 void add_eval(dump_info_t *dump_info, char *eval)
1031 char *eval_obst = obstack_alloc(&(dump_info->node_names), strlen(eval) + 5);
1033 strcpy(eval_obst, eval);
1034 pmap_insert(dump_info->eval_statements, eval_obst, NULL);
1039 /*************************************************************************
1040 * Changes the mode of an already dumped node. Deletes the old mode edge
1041 * and inserts a new one. To be used e.g. in the replacement graph.
1042 *************************************************************************/
1044 void change_mode(ir_node *n, ir_mode *m, dump_info_t *dump_info, FILE *fp)
1046 char *mode_edge_name = pmap_get(dump_info->mode_edge_map, n);
1048 if(mode_edge_name != NULL)
1050 fprintf(fp, "%sdelete(%s);\n", indent, mode_edge_name);
1051 pmap_insert(dump_info->mode_edge_map, n, NULL);
1052 dump_grgen_mode(n, dump_info, fp, m);
1057 /************************************************************************
1058 * Sets up "fake" graph analysis information to just dump all nodes of
1059 * an ir graph. Used for the AGTIVE workshop.
1060 * Parameters: irg: The irg to dump
1063 ************************************************************************/
1065 void dump_irgraph_complete_grgen(ir_graph *irg, char *filename, int append)
1067 graph_ana_info_t graph_ana_info;
1068 struct obstack obst;
1069 grgen_dumper_env_t *gd_env;
1071 obstack_init(&obst);
1073 graph_ana_info.irg = irg;
1074 graph_ana_info.nodes_to_dump = pmap_create();
1075 graph_ana_info.register_access = pmap_create(); // Those pmaps are not filled here, but needed by the dumper
1076 graph_ana_info.memory_access = pmap_create();
1077 graph_ana_info.argument_nodes = pmap_create();
1078 graph_ana_info.destroyed_regs = pmap_create();
1079 graph_ana_info.obst = &obst;
1080 graph_ana_info.num_simd_arguments = 0;
1081 graph_ana_info.complex_operation_block = NULL;
1082 graph_ana_info.node_to_match_block = NULL;
1083 graph_ana_info.emit_statement = NULL;
1084 graph_ana_info.has_result = 0;
1085 graph_ana_info.variant_nr = 0;
1086 graph_ana_info.priority = 0;
1087 graph_ana_info.dump_everything = 1;
1089 gd_env = init_grgen_dumper(filename, append);
1090 irg_walk_graph(graph_ana_info.irg, collect_nodes, NULL, &graph_ana_info);
1091 dump_irgraph_grgen(gd_env, &graph_ana_info);
1092 deinit_grgen_dumper(gd_env);
1094 pmap_destroy(graph_ana_info.nodes_to_dump);
1095 pmap_destroy(graph_ana_info.destroyed_regs);
1096 pmap_destroy(graph_ana_info.register_access);
1097 pmap_destroy(graph_ana_info.memory_access);
1098 pmap_destroy(graph_ana_info.argument_nodes);
1099 obstack_free(&obst, NULL);
1100 obstack_finish(&obst);
1105 /************************************************************************
1106 * Collects all nodes of a ir graph, so that the ir graph can be
1108 ************************************************************************/
1111 static void collect_nodes(ir_node *n, void * env)
1113 graph_ana_info_t *graph_ana_info = (graph_ana_info_t *) env;
1115 pmap_insert(graph_ana_info->nodes_to_dump, n, NULL);