moved firmext code into the backend dir
[libfirm] / ir / be / grgen / simd / grgen_dumper.c
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
7  * Date:                2006-12-07
8  *****************************************************************************/
9
10
11 // ---------------------------- INCLUDES --------------------------------
12
13 #include <assert.h>
14 #include <stdio.h>
15 #include <obst.h>
16
17 #include "simd_presets.h"
18
19 #include "firm_types.h"
20 #include "pmap.h"
21 #include "tv.h"
22 #include "irgwalk.h"
23
24 #include "grgen_dumper__t.h"
25 #include "create_pattern_t.h"
26 #include "firm_node_ext.h"
27
28 // ----------------------------- GLOABALS --------------------------------
29
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;
34
35 // Saves the current node number to generate node names
36 static int node_counter;
37 static int edge_counter;
38
39
40
41
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
45  *                              dumper.
46  * Parameters:  file:   filename of the file to dump to
47  *                              append: 1 if the previous file content should be
48  *                                              maintained.
49  ************************************************************************/
50
51 grgen_dumper_env_t *init_grgen_dumper(char *file, int append)
52 {
53         grgen_dumper_env_t *grgen_dumper_env = malloc(sizeof(grgen_dumper_env_t));
54         FILE *fp;
55
56         if(append)
57                 fp = fopen(file, "at");
58         else
59         {
60                 fp = fopen(file, "wt");
61
62                 // *** Dump header
63                 fprintf(fp, "%susing Firm;\n\n", indent);
64         }
65
66         grgen_dumper_env -> output_file = fp;
67         return(grgen_dumper_env);
68 }
69
70
71
72 /************************************************************************
73  * Frees information used by the grgen_dumper and closes the output file
74  ************************************************************************/
75
76 void deinit_grgen_dumper(grgen_dumper_env_t *grgen_dumper_env)
77 {
78         fclose(grgen_dumper_env->output_file);
79         free(grgen_dumper_env);
80 }
81
82
83
84
85 /************************************************************************
86  * Starts dumping
87  * Returns
88  * 1 if the complex operation uses the memory edge
89  * 0 if no memory edge is used.
90  ************************************************************************/
91
92 int dump_irgraph_grgen(grgen_dumper_env_t *grgen_dumper_env, graph_ana_info_t *graph_ana_info)
93 {
94         FILE *fp = grgen_dumper_env -> output_file;
95         dump_info_t dump_info;
96         int uses_memory = 0;
97         char irg_name[255];
98
99         get_rule_name(graph_ana_info, irg_name);
100
101         // Do initialization
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;
120
121         // Node and egde count start at 0 for each pattern to be dumped.
122         node_counter = 0;
123         edge_counter = 0;
124         obstack_init(&(dump_info.node_names));
125         obstack_init(&(dump_info.mode_names));
126
127         // Dump rule header
128         set_indent(0);
129         fprintf(fp, "\n\n%srule %s\n%s{\n", indent, irg_name, indent);
130         set_indent(2);
131         if(!dump_info.dump_everything)
132                 fprintf(fp, "%spattern\n%s{\n", indent, indent);
133         else
134         {
135                 fprintf(fp, "%spattern { }\n", indent);
136                 fprintf(fp, "%sreplace\n%s{\n", indent, indent);
137         }
138         set_indent(4);
139
140         // *** Dump the left side of the rule
141         uses_memory = dump_pattern(&dump_info, fp);
142
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
145         {
146                 dump_replacement(&dump_info, uses_memory, fp);
147
148                 // *** Dump the eval part of the rule
149                 fprintf(fp, "\n%seval {\n", indent);
150                 set_indent(6);
151                 dump_mandatory_evals(&dump_info, uses_memory, fp);
152                 dump_vproj_nr(&dump_info, fp);  // Dumps all vproj_nr attribute assignments
153                 set_indent(4);
154                 fprintf(fp, "%s} /* Eval */\n", indent);
155
156                 // *** Close the replacement part
157
158                 set_indent(2);
159                 fprintf(fp, "%s} /* Replacement */\n", indent);
160         }
161
162         // *** Dump footer
163         set_indent(0);
164         fprintf(fp, "%s}\n", indent);
165
166         // Clean up
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));
178
179         return(uses_memory);
180 }
181
182
183 /************************************************************************
184  * Dumps the left hand side of the rule
185  ************************************************************************/
186
187 static int dump_pattern(dump_info_t *dump_info, FILE *fp)
188 {
189         struct pmap *nodes_to_dump = dump_info->nodes_to_dump;
190         pmap_entry *entry;
191         int uses_memory = 0;
192
193         // Dump all nodes
194         pmap_foreach(nodes_to_dump, entry)
195         {
196                 ir_node *n = (ir_node *) entry->key;
197                 ir_opcode code;
198
199                 // Dump node
200                 if(get_irn_opcode(n) == iro_Proj && get_irn_modecode(n) == irm_M)
201                         uses_memory = 1;
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);
205
206
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 ||
210                    code == iro_VProj ||
211                    code == iro_Const ||
212                    code == iro_Proj ||
213                    code == iro_Phi)
214                         pmap_insert(dump_info -> dump_condition, n, NULL);
215         }
216
217         // Dump all edges
218         pmap_foreach(nodes_to_dump, entry)
219         {
220                 ir_node *n = (ir_node *) entry->key;
221                 int i;
222
223                 // Dump edges
224                 for(i = -1; i < get_irn_arity(n); i++)
225                         dump_grgen_edge(n, i, dump_info, fp);
226         }
227
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);
231
232         if(!dump_info->dump_everything)
233         {
234
235                 fprintf(fp, "\n%sif\n%s{\n", indent, indent);
236                 set_indent(6);
237
238                 pmap_foreach(dump_info->dump_condition, entry)
239                 {
240                         ir_node *n = (ir_node *) entry->key;
241                         dump_grgen_condition(n, dump_info, fp);
242                 }
243                 set_indent(4);
244                 fprintf(fp, "%s} /* Conditions */\n", indent);
245         }
246
247         set_indent(2);
248         fprintf(fp, "%s} /* Pattern */\n", indent);
249         return(uses_memory);
250 }
251
252
253
254 /************************************************************************
255  * Dumps the right hand side of the rule
256  ************************************************************************/
257
258 static void dump_replacement(dump_info_t *dump_info, int uses_memory, FILE *fp)
259 {
260         pmap_entry *entry;
261         register_access_descr_t *register_access_descr;
262         memory_access_descr_t *memory_access_descr;
263
264         // dump grGen "replace" statement
265         fprintf(fp, "\n%smodify {\n", indent);
266         set_indent(4);
267
268         // Dump the complex operation node with it's projs and vprojs
269         dump_complex_operation(dump_info, fp, uses_memory);
270
271         // Dump the rest of the replacement nodes. Do retyping to VProj if necessary
272         fprintf(fp, "\n");
273
274         // First dump all nodes.
275         pmap_foreach(dump_info->nodes_to_dump, entry)
276         {
277                 ir_node *n = (ir_node *) entry->key;
278
279                 if((register_access_descr = pmap_get(dump_info->register_access, n)) != NULL)
280                 {
281                         // Nodes that represent a result in a register have to be retyped
282                         if(register_access_descr -> load_store == REGISTER_STORE)
283                         {
284                                 // Find out, if this store is a component of a vector or a standalone scalar
285                                 argument_descr_t *arg_descr;
286
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!");
289
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)
294                                 {
295                                         case ARGUMENT_VECTOR:
296                                                         // Not needed:
297                                                         // assert(get_irn_opcode(n) != iro_VProj); // An existing VProj would be a register LOAD
298
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);
304                                                         break;
305
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");
312                                                         break;
313
314                                         default:
315                                                         assert(0 && "Argument Type not implemented!");
316                                 }
317
318                                 continue;
319                         }
320                 }
321
322                 if((memory_access_descr = pmap_get(dump_info->memory_access, n)) != NULL)
323                 {
324                         if(memory_access_descr->load_store == MEMORY_STORE)
325                         {
326                                         // Node is part of a memory store, that is STORE or PROJM node.
327                                         // Retype it to id.
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);
338                                         continue;
339                         }
340                 }
341
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)
344                 {
345                         if(memory_access_descr->load_store == MEMORY_STORE)
346                         {
347                                 dump_grgen_retyped_node(n, op_Sync, dump_info, fp);
348                                 change_mode(n, mode_M, dump_info, fp);
349                                 continue;
350                         }
351                 }
352         }
353
354
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)
358         {
359                 const ir_node *n = entry->key;
360                 if(pmap_contains(dump_info->memory_access, n))
361                 {
362                         memory_access_descr_t *memory_access_descr = pmap_get(dump_info->memory_access, n);
363                         assert(memory_access_descr->load_store == MEMORY_STORE);
364
365                         if(get_irn_opcode(n) == iro_Proj)
366                         {
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)));
369                         }
370                 }
371         }
372         //dump_complex_operation_block_match(dump_info, fp);
373
374         /* Don't close the replacement since evals have moved into the replacement part  */
375 #if 0
376         set_indent(2);
377         fprintf(fp, "%s} /* Replacement */\n", indent);
378 #endif
379 }
380
381
382
383 /************************************************************************
384  * Dumps the new complex operation node and it's Projs and Vprojs
385  ************************************************************************/
386
387 void dump_complex_operation(dump_info_t *dump_info, FILE *fp, int uses_memory)
388 {
389         pmap_entry *entry;
390         int i, mem_slot = (uses_memory) ? 1 : 0, max_argument;
391         char *mode_node_name, eval[100];
392
393         // Generate Vector operation
394         fprintf(fp, "%s%s : Complex;\n", indent, VECTOR_OP_NAME);
395
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);
399
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));
403
404         if(dump_info->has_result)
405         {
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);
414         }
415
416
417         // Connect the complex operation to it's arguments
418         // Caution: The argument-nodes must have not been retyped!
419         i = 0;
420         max_argument = -1000;
421         pmap_foreach(dump_info->argument_nodes, entry)
422         {
423                 ir_node *n = (ir_node *) entry->key;
424                 ir_node *argument;
425                 argument_descr_t *argument_descr = entry -> value;
426                 int arg_nr = argument_descr->arg_nr;
427
428                 if(arg_nr < 0)
429                         continue;
430                 assert(pmap_contains(dump_info->node_name_map, n) && "The pointer base node must have already been dumped in the positive pattern!");
431
432                 if(argument_descr->argument_location == ARGUMENT_SIMD_REGISTER)
433                         argument = n;
434                 else
435                         argument = argument_descr->vec_op_input;
436
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;
440         }
441
442         // Do preparations to connect the memory edge to the complex operation
443         if(uses_memory)
444         {
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);
447
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));
453
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);
457         }
458
459         i = 0;
460         pmap_foreach(dump_info->destroyed_regs, entry)
461         {
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];
465
466 //              assert(end_name && "End node has to be already dumped in positive pattern!");
467
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);
480                 i++;
481         }
482 }
483
484
485
486 /************************************************************************
487  * Dumps a node in GrGen Format
488  ************************************************************************/
489
490 static void dump_grgen_node(ir_node *n, dump_info_t *dump_info, FILE *fp)
491 {
492         char *node_name;
493
494         // Already dumped the node? Then do nothing
495         if(pmap_contains(dump_info -> node_name_map, n))
496                 return;
497
498         // Else generate new node name and dump the node
499
500         node_name = obstack_alloc(&(dump_info -> node_names), MAX_NODENAME_LEN);
501
502         if(!pmap_contains(dump_info->argument_nodes, n))
503         {
504                 register_access_descr_t *register_access_descr = pmap_get(dump_info->register_access, n);
505
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));
510                 else
511                         sprintf(node_name, "%s%d", get_op_name(get_irn_op(n)), get_irn_node_nr(n));
512
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");
515                 else
516                         fprintf(fp, "%s%s : %s;\n", indent, node_name, get_op_name(get_irn_op(n)));
517         }
518         else
519         {
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);
525                 else
526                         sprintf(node_name, "Result");  /// ???? What did I do here?
527                 fprintf(fp, "%s%s : %s;\n", indent, node_name, VECTOR_BASE_TYPE);
528
529         }
530
531         pmap_insert(dump_info -> node_name_map, n, node_name);
532         node_counter++;
533 }
534
535
536
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  ************************************************************************/
543
544 static char *dump_grgen_retyped_node(ir_node *n, ir_op *new_op, dump_info_t *dump_info, FILE *fp)
545 {
546         char *node_name;
547
548         // A retyped node should have already been dumped.
549         assert(pmap_contains(dump_info->node_name_map, n));
550
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);
556
557         // Save the retyped op
558         pmap_insert(dump_info -> retyped_nodes, n, (void *) new_op);
559         node_counter++;
560
561         // Dump the block of the original node had one.
562         // dump_grgen_edge(n, -1, dump_info, fp);
563
564         return(node_name);
565 }
566
567
568
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  *************************************************************************/
575
576 void dump_grgen_delete_incoming_edges(ir_node *n, dump_info_t *dump_info, FILE *fp)
577 {
578         char **nodes_edge_names;
579         int  i, deleted = 0;
580
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)
583
584         if(get_irn_arity(n) > 0)
585         {
586                 fprintf(fp, "%sdelete(", indent);
587                 nodes_edge_names = pmap_get(dump_info->edge_name_map, n);
588                 assert(nodes_edge_names != NULL);
589
590                 for(i = get_irn_arity(n); i > 0; i--)
591                         if(nodes_edge_names[i] != NULL)
592                         {
593                                 fprintf(fp, "%c%s", (deleted == 0) ? ' ' : ',', nodes_edge_names[i]);
594                                 deleted = 1;
595                         }
596
597                         fprintf(fp, ");\n");
598         }
599 }
600
601
602
603 /************************************************************************
604  * Dumps
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  ************************************************************************/
608
609 static void dump_grgen_block(ir_node *n, dump_info_t *dump_info, FILE *fp)
610 {
611         ir_node *block;
612         return;
613
614         if(get_irn_opcode(n) == iro_Block)  // A block has no block predecessor
615                 return;
616
617         if(get_irn_opcode(n) == iro_Const || pmap_contains(dump_info->argument_nodes, n))
618                 return;
619
620         if(get_irn_opcode(n) == iro_VProj)
621                 return;
622
623         block = get_nodes_block(n);
624         // Dump the block node if necessary
625         if(!pmap_contains(dump_info->node_name_map, block))
626         {
627                 dump_grgen_node(block, dump_info, fp);
628                 dump_grgen_mode(block, dump_info, fp, NULL);
629         }
630
631         // Dump the edge to the block node
632         dump_grgen_edge(n, -1, dump_info, fp);
633 }
634
635
636
637 /************************************************************************
638  * Dumps an edge in GrGen format
639  ************************************************************************/
640
641 static void dump_grgen_edge(ir_node *n, int n_edge, dump_info_t *dump_info, FILE *fp)
642 {
643         ir_node *to_node;
644         char *from_node_name, *to_node_name;
645         char **nodes_edge_names;
646
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)))
659                                 return;
660
661
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))
667                 return;
668
669         if((nodes_edge_names = pmap_get(dump_info -> edge_name_map, n)) == NULL)
670         {
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);
674         }
675
676
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)
679         {
680                 // No, we can dump the edge since it's no memory edge:
681
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);
685
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);
690
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))
697                 {
698                                 char edge_name[50], *edge_name_obst;
699
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;
704
705                                 fprintf(fp, "%s%s -%s:df-> %s;\n", indent, from_node_name, edge_name_obst, to_node_name);
706                 }
707                 else
708                 {
709                                 char edge_name[50], *edge_name_obst;
710
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;
715
716                                 fprintf(fp, "%s%s -%s:df-> %s;\n", indent, from_node_name, edge_name_obst, to_node_name);
717                 }
718                 /*
719                 switch(get_irn_opcode(n))
720                 {
721                         case iro_Add:
722                         case iro_MultipleAdd:
723                         case iro_Mul:
724
725                                 break;
726                         default:
727                                 fprintf(fp, "%s%s -pos%d_%d:df-> %s;\n", indent, from_node_name, n_edge + 1, edge_counter++, to_node_name);
728                                 break;
729                 }*/
730
731         }
732 }
733
734
735
736 /************************************************************************
737  * Dumps an FIRM Mode as GrGen Code
738  * If source_node_name == NULL, that name of n that was already
739  * generated is used.
740  * If source_node_name != NULL, this given source will be used
741  * (useful for retyped nodes)
742  ************************************************************************/
743
744 static void dump_grgen_mode(ir_node *n, dump_info_t *dump_info, FILE *fp, ir_mode *alt_mode)
745 {
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);
748         char edge_name[50];
749         char *mode_node_name;
750
751         if(pmap_contains(dump_info->argument_nodes, n))
752                 irn_mode = mode_ANY;
753         mode_node_name = dump_grgen_mode_node(irn_mode, dump_info, fp);
754
755         //mode_code =  get_mode_modecode(irn_mode);
756         //mode_name =  get_mode_name(irn_mode);
757
758
759
760 #if 0
761         // Check if the mode node has already been created
762         if(!pmap_contains(dump_info -> mode_name_map, (void *) mode_code))
763         {
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);
770         }
771         else
772         {
773 #endif
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++);
777
778
779                 if(pmap_get(dump_info->mode_edge_map, n) == NULL)
780                 {
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);
784                 }
785
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);
788 #if 0
789         }
790 #endif
791 }
792
793
794
795 /************************************************************************
796  * Dumps a node representing a node
797  ************************************************************************/
798
799 char *dump_grgen_mode_node(ir_mode *irn_mode, dump_info_t *dump_info, FILE *fp)
800 {
801         modecode mode_code = get_mode_modecode(irn_mode);
802         const char *mode_name =  get_mode_name(irn_mode);
803         char *mode_node_name;
804
805         if(!pmap_contains(dump_info -> mode_name_map, (void *) mode_code))
806         {
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);
813         }
814         else
815         {
816                 return((char *) pmap_get(dump_info -> mode_name_map, (void *) mode_code));
817         }
818
819 }
820
821
822
823 /************************************************************************
824  * Dumps the condition for the given node, depending on the node's
825  * attributes and the node's opcode
826  ************************************************************************/
827
828 static void dump_grgen_condition(ir_node *n, dump_info_t *dump_info, FILE *fp)
829 {
830         char *node_name;
831         ir_opcode code = get_irn_opcode(n);
832
833         if(code == iro_MultipleAdd)
834         {
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));
837                 return;
838         }
839
840         if(code == iro_Const)
841         {
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)));
844                 return;
845         }
846
847         if(code == iro_VProj)
848         {
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));
851                 return;
852         }
853
854         if(code == iro_Proj)
855         {
856                 if(!pmap_contains(dump_info->argument_nodes, n))
857                 {
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));
860                 }
861                 return;
862         }
863
864
865         if(code == iro_Phi)
866         {
867                 ir_node *phi_block = get_nodes_block(n);
868                 char **edge_names_phi, **edge_names_block;
869                 int i;
870
871                 assert((get_irn_arity(n) == get_irn_arity(phi_block)) && "Phi has other arity than it's block! Pattern seems to be broken.");
872
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!");
877
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++)
881                 {
882                                 assert(edge_names_phi[i] != NULL && edge_names_block[i] != NULL && "Some edges have not been dumped!");
883
884                                 fprintf(fp, "%s%s.pos == %s.pos;\n", indent, edge_names_phi[i], edge_names_block[i]);
885                 }
886                 return;
887         }
888
889         assert(0 && "Nodes attributes not supported");
890 }
891
892
893
894
895 /************************************************************************
896  * Dump grGen code for retyping a special node
897  ************************************************************************/
898
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)
900 {
901         // Dump the grGen code for retyping
902         register_access_descr_t *register_access_descr;
903         char *node_name;
904
905         /*char *node_name = obstack_alloc(&(dump_info->node_names), MAX_NODENAME_LEN);
906
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); */
913
914         node_name = dump_grgen_retyped_node(n, op_VProj, dump_info, fp);
915         dump_grgen_delete_incoming_edges(n, dump_info, fp);
916
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);
919         node_counter++;
920
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;
924 }
925
926
927
928 /************************************************************************
929  * Dump grGen code for retyping a special node
930  ************************************************************************/
931
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)
933 {
934         // Dump the grGen code for retyping
935         register_access_descr_t *register_access_descr;
936         char *node_name;
937
938
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);
942
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);
945         node_counter++;
946
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;
950 }
951
952
953
954 /************************************************************************
955  * Dump grGen Code to add the VProj Nr to VProj nodes after replacement
956  ************************************************************************/
957
958 static void dump_vproj_nr(dump_info_t *dump_info, FILE *fp)
959 {
960         pmap_entry *entry;
961
962         pmap_foreach(dump_info -> register_access, entry)
963         {
964                 ir_node *n = (ir_node *) entry->key;
965                 register_access_descr_t *register_access_descr = entry->value;
966
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);
970         }
971 }
972
973
974 /************************************************************************
975  * Sets current indent
976  ************************************************************************/
977
978 void set_indent(int i)
979 {
980         int j;
981
982         // Generate a string containing i blank characters
983         if(i < MAX_INDENT - 1)
984         {
985                 for(j = 0; j < i; j++)
986                         indent[j] = ' ';
987                 indent[j] = 0x0;
988                 current_indent = i;
989         }
990 }
991
992
993
994 /************************************************************************
995  * Gets current indent value
996  ************************************************************************/
997
998 int  get_indent(void)
999 {
1000         return(current_indent);
1001 }
1002
1003 void dump_complex_operation_block_match(dump_info_t *dump_info, FILE *fp)
1004 {
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));
1006 }
1007
1008
1009 /************************************************************************
1010  * Dumps some evals which are mandatory
1011  ************************************************************************/
1012
1013 void dump_mandatory_evals(dump_info_t *dump_info, int uses_memory, FILE *fp)
1014 {
1015         pmap_entry *entry;
1016
1017         pmap_foreach(dump_info->eval_statements, entry)
1018         {
1019                 char *statement = (char *) entry->key;
1020                 fprintf(fp, "%s%s\n", indent, statement);
1021         }
1022 }
1023
1024
1025 /************************************************************************
1026  * Adds an eval to the list that has to be dumped at the end
1027  ************************************************************************/
1028
1029 void add_eval(dump_info_t *dump_info, char *eval)
1030 {
1031         char *eval_obst = obstack_alloc(&(dump_info->node_names), strlen(eval) + 5);
1032
1033         strcpy(eval_obst, eval);
1034         pmap_insert(dump_info->eval_statements, eval_obst, NULL);
1035 }
1036
1037
1038
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  *************************************************************************/
1043
1044 void change_mode(ir_node *n, ir_mode *m, dump_info_t *dump_info, FILE *fp)
1045 {
1046         char *mode_edge_name = pmap_get(dump_info->mode_edge_map, n);
1047
1048         if(mode_edge_name != NULL)
1049         {
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);
1053         }
1054 }
1055
1056
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
1061  *
1062  *
1063  ************************************************************************/
1064
1065 void dump_irgraph_complete_grgen(ir_graph *irg, char *filename, int append)
1066 {
1067         graph_ana_info_t graph_ana_info;
1068         struct obstack obst;
1069         grgen_dumper_env_t *gd_env;
1070
1071         obstack_init(&obst);
1072
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;
1088
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);
1093
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);
1101 }
1102
1103
1104
1105 /************************************************************************
1106  * Collects all nodes of a ir graph, so that the ir graph can be
1107  * dumped completely
1108  ************************************************************************/
1109
1110
1111 static void collect_nodes(ir_node *n, void * env)
1112 {
1113         graph_ana_info_t *graph_ana_info = (graph_ana_info_t *) env;
1114
1115         pmap_insert(graph_ana_info->nodes_to_dump, n, NULL);
1116 }