- get_Block_cfgpred_arr() IS supported, but should not be in the official
[libfirm] / ir / ir / irdump_grgen.c
1 /*
2 * Copyright (C) 1995-2007 University of Karlsruhe.  All right reserved.
3 *
4 * This file is part of libFirm.
5 *
6 * This file may be distributed and/or modified under the terms of the
7 * GNU General Public License version 2 as published by the Free Software
8 * Foundation and appearing in the file LICENSE.GPL included in the
9 * packaging of this file.
10 *
11 * Licensees holding valid libFirm Professional Edition licenses may use
12 * this file in accordance with the libFirm Commercial License.
13 * Agreement provided with the Software.
14 *
15 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE.
18 */
19
20 /**
21 * @file
22 * @brief   Write ir graph as a grgen construction rule
23 * @author  Andreas Schoesser
24 * @version $Id$
25 */
26
27 /*
28  * THIS IS A COMPLETE QUICK HACK! USE WITH CARE
29  * NOT FOR PRODUCTION BUILD ;-)
30  */
31
32 #define MAX_NODENAME_LEN 100
33
34 #include <assert.h>
35 #include <stdio.h>
36 #include <obst.h>
37
38
39 #include "irgraph.h"
40 #include "firm_types.h"
41 #include "pmap.h"
42 #include "tv.h"
43 #include "irgwalk.h"
44 #include "firm_types.h"
45 #include "irdump_grgen.h"
46
47
48 typedef struct
49 {
50         ir_graph *irg;
51         struct pmap *mode_edge_map;
52         struct pmap *edge_name_map;
53         struct pmap *node_name_map;  // Contains the mapping firm node -> node name
54         struct obstack node_names;   // Contains the node name data
55         struct pmap *mode_name_map;  // Contains the mapping firm mode -> mode node name
56         struct obstack mode_names;   // Contains the "mode node name" data
57         struct pmap *nodes_to_dump;  // Contains firm nodes, that have to be dumped
58 } grgen_dumpinfo_t;
59
60 typedef struct                  // Holds information needed througout the usage of a grgen dumper instance
61 {
62         FILE *output_file;      // The file the grgen rules will be dumped to
63 } irg_grgen_dumper_env_t;
64
65 static void dump_grg_node(ir_node *n, grgen_dumpinfo_t *dump_info, FILE *fp);
66 static void dump_grg_egde(ir_node *n, int n_edge, grgen_dumpinfo_t *dump_info, FILE *fp);
67 static void dump_grgen_mode(ir_node *n, grgen_dumpinfo_t *dump_info, FILE *fp, ir_mode *alt_mode);
68 static char *dump_grgen_mode_node(ir_mode *irn_mode, grgen_dumpinfo_t *dump_info, FILE *fp);
69 static void dump_grgen_eval(ir_node *n, grgen_dumpinfo_t *dump_info, FILE *fp);
70 static int dump_pattern(grgen_dumpinfo_t *dump_info, FILE *fp);
71 static void set_indent(int i);
72
73
74
75 /*****************************************************************************
76 * Program:              grgen_dumper.c
77 * Function:             Dumps parts of a firm graph (those which have to be extracted
78 *                               as search and replace patterns) as a grGen rule.
79 * Depends on:   Needs the analysis info generated by the pattern creator
80 * Author:               Andreas Schoesser
81 * Date:         2006-12-07
82 *****************************************************************************/
83
84
85 // ---------------------------- INCLUDES --------------------------------
86
87
88
89
90 /* #include "grgen_dumper__t.h"
91 #include "create_pattern_t.h"
92 #include "firm_node_ext.h" */
93
94 // ----------------------------- GLOABALS --------------------------------
95
96 // Saves the current indent value and keeps spaces in a string
97 #define MAX_INDENT 100
98 static char indent[MAX_INDENT] = "";
99
100 // Saves the current node number to generate node names
101 static int node_counter;
102 static int edge_counter;
103
104
105
106
107 /************************************************************************
108 * Initializes the grgen_dumper module and dumps the GrGen File header
109 * Returns:              An environment to be passed to all functions of the GrGen
110 *                               dumper.
111 * Parameters:   file:   filename of the file to dump to
112 *                               append: 1 if the previous file content should be
113 *                                               maintained.
114 ************************************************************************/
115
116 irg_grgen_dumper_env_t *init_irg_grgen_dumper(char *file, int append)
117 {
118         irg_grgen_dumper_env_t *const grgen_dumper_env = XMALLOC(irg_grgen_dumper_env_t);
119         FILE *fp;
120
121         if(append)
122                 fp = fopen(file, "at");
123         else
124         {
125                 fp = fopen(file, "wt");
126
127                 // *** Dump header
128                 fprintf(fp, "%susing Firm;\n\n", indent);
129         }
130
131         grgen_dumper_env -> output_file = fp;
132         return(grgen_dumper_env);
133 }
134
135
136
137 /************************************************************************
138 * Frees information used by the grgen_dumper and closes the output file
139 ************************************************************************/
140
141 void deinit_irg_grgen_dumper(irg_grgen_dumper_env_t *grgen_dumper_env)
142 {
143         fclose(grgen_dumper_env->output_file);
144         xfree(grgen_dumper_env);
145 }
146
147 static void collect_nodes(ir_node *n, void * env)
148 {
149         pmap *nodes_to_dump = (pmap *) env;
150
151         pmap_insert(nodes_to_dump, n, NULL);
152 }
153
154
155
156
157 /************************************************************************
158  * Starts dumping
159  ************************************************************************/
160
161 void dump_irg_grgen_file(ir_graph *irg, char *filename, int append)
162 {
163         FILE *fp;
164         grgen_dumpinfo_t dump_info;
165         int uses_memory = 0;
166
167
168         irg_grgen_dumper_env_t *grgen_dumper_env = init_irg_grgen_dumper(filename, append);
169         fp = grgen_dumper_env -> output_file;
170
171         // Do initialization
172         dump_info.irg = irg;                    // Basically copy the graph_ana_struct, ugly
173         dump_info.mode_edge_map = pmap_create();                // Create some additional pmaps to hold
174         dump_info.edge_name_map = pmap_create();                // node and edge name information etc.
175         dump_info.node_name_map = pmap_create();
176         dump_info.mode_name_map = pmap_create();
177         dump_info.nodes_to_dump = pmap_create();
178
179         // Node and egde count start at 0 for each pattern to be dumped.
180         node_counter = 0;
181         edge_counter = 0;
182         obstack_init(&(dump_info.node_names));
183         obstack_init(&(dump_info.mode_names));
184
185         // Dump rule header
186         set_indent(0);
187         fprintf(fp, "\n\n%srule %s\n%s{\n", indent, get_entity_name(get_irg_entity(irg)), indent);
188         set_indent(2);
189
190         fprintf(fp, "%spattern { }\n", indent);                  // Empty pattern
191         fprintf(fp, "%sreplace\n%s{\n", indent, indent); // Graph is contrcuted in the replacement part
192
193         set_indent(4);
194
195         irg_walk_graph(irg, collect_nodes, NULL, dump_info.nodes_to_dump);
196         uses_memory = dump_pattern(&dump_info, fp);
197
198         // *** Dump footer
199         set_indent(0);
200         fprintf(fp, "%s}\n", indent);
201
202         // Clean up
203         pmap_destroy(dump_info.mode_edge_map);
204         pmap_destroy(dump_info.edge_name_map);
205         pmap_destroy(dump_info.node_name_map);
206         pmap_destroy(dump_info.mode_name_map);
207         obstack_free(&(dump_info.node_names), NULL);
208         obstack_finish(&(dump_info.node_names));
209         obstack_free(&(dump_info.mode_names), NULL);
210         obstack_finish(&(dump_info.mode_names));
211
212         deinit_irg_grgen_dumper(grgen_dumper_env);
213 }
214
215
216 void dump_irg_grgen(ir_graph *irg, char *suffix)
217 {
218   char filename[100] = "";
219
220   strncat(filename, get_entity_name(get_irg_entity(irg)), 100);
221   strncat(filename, suffix, 100);
222   strncat(filename, ".grg", 100);
223
224   dump_irg_grgen_file(irg, filename, 0);
225 }
226
227
228 /************************************************************************
229  * Dumps the left hand side of the rule
230  ************************************************************************/
231
232 static int dump_pattern(grgen_dumpinfo_t *dump_info, FILE *fp)
233 {
234         struct pmap *nodes_to_dump = dump_info->nodes_to_dump;
235         pmap_entry *entry;
236         int uses_memory = 0;
237
238         // Dump all nodes
239         foreach_pmap(nodes_to_dump, entry)
240         {
241                 ir_node *n = (ir_node *) entry->key;
242
243                 // Dump node
244                 if(get_irn_opcode(n) == iro_Proj && get_irn_modecode(n) == irm_M)
245                         uses_memory = 1;
246                 dump_grg_node(n, dump_info, fp);
247                 dump_grgen_mode(n, dump_info, fp, NULL);
248         }
249
250         // Dump all edges
251         foreach_pmap(nodes_to_dump, entry)
252         {
253                 ir_node *n = (ir_node *) entry->key;
254                 int i;
255
256                 // Dump edges
257                 for(i = is_Block(n) ? 0 : -1; i < get_irn_arity(n); i++)
258                         dump_grg_egde(n, i, dump_info, fp);
259         }
260
261         fprintf(fp, "%seval {\n", indent);
262         set_indent(6);
263         foreach_pmap(nodes_to_dump, entry)
264         {
265                 ir_node *n = (ir_node *) entry->key;
266                 dump_grgen_eval(n, dump_info, fp);
267         }
268         set_indent(4);
269         fprintf(fp, "%s}\n", indent);
270
271
272         set_indent(2);
273         fprintf(fp, "%s} /* Replacement */\n", indent);
274         return(uses_memory);
275 }
276
277
278
279 /************************************************************************
280 * Dumps a node in GrGen Format
281 ************************************************************************/
282
283 static void dump_grg_node(ir_node *n, grgen_dumpinfo_t *dump_info, FILE *fp)
284 {
285         char *node_name;
286
287         // Already dumped the node? Then do nothing
288         if(pmap_contains(dump_info -> node_name_map, n))
289                 return;
290
291         // Else generate new node name and dump the node
292
293         node_name = obstack_alloc(&(dump_info -> node_names), MAX_NODENAME_LEN);
294
295         sprintf(node_name, "%s%ld", get_op_name(get_irn_op(n)), get_irn_node_nr(n));
296         fprintf(fp, "%s%s : %s;\n", indent, node_name, get_op_name(get_irn_op(n)));
297
298         pmap_insert(dump_info -> node_name_map, n, node_name);
299         node_counter++;
300 }
301
302
303
304 /************************************************************************
305 * Dumps an edge in GrGen format
306 ************************************************************************/
307
308 static void dump_grg_egde(ir_node *n, int n_edge, grgen_dumpinfo_t *dump_info, FILE *fp)
309 {
310         ir_node *to_node;
311         char *from_node_name, *to_node_name;
312         char **nodes_edge_names;
313
314
315         // Check if to_node has also to be dumped. If not, skip this edge
316         // We have to dump to_node here, because to_node has to be known by grgen before
317         // connecting an edge to it.
318         to_node =  get_irn_n(n, n_edge);
319         if(!pmap_contains(dump_info -> nodes_to_dump, to_node))
320                 return;
321
322         if((nodes_edge_names = pmap_get(dump_info -> edge_name_map, n)) == NULL)
323         {
324                 nodes_edge_names = (char **) obstack_alloc(&(dump_info->node_names), (get_irn_arity(n) + 1) * sizeof(char *));
325                 memset(nodes_edge_names, 0, (get_irn_arity(n) + 1) * sizeof(char *));
326                 pmap_insert(dump_info->edge_name_map, n, nodes_edge_names);
327         }
328
329         assert(pmap_contains(dump_info -> node_name_map, n));
330         assert(pmap_contains(dump_info -> node_name_map, to_node));
331         from_node_name = (char *) pmap_get(dump_info -> node_name_map, n);
332         to_node_name = (char *) pmap_get(dump_info -> node_name_map, to_node);
333
334         {
335
336         char edge_name[50], *edge_name_obst;
337
338         sprintf(edge_name, "pos%d_%d", n_edge + 1, edge_counter++);
339         edge_name_obst = obstack_alloc(&(dump_info->node_names), strlen(edge_name) + 1);
340         strcpy(edge_name_obst, edge_name);
341         nodes_edge_names[n_edge + 1] = edge_name_obst;
342
343         fprintf(fp, "%s%s -%s:df-> %s;\n", indent, from_node_name, edge_name_obst, to_node_name);
344         }
345
346
347 }
348
349
350
351 /************************************************************************
352 * Dumps an FIRM Mode as GrGen Code
353 * If source_node_name == NULL, that name of n that was already
354 * generated is used.
355 * If source_node_name != NULL, this given source will be used
356 * (useful for retyped nodes)
357 ************************************************************************/
358
359 static void dump_grgen_mode(ir_node *n, grgen_dumpinfo_t *dump_info, FILE *fp, ir_mode *alt_mode)
360 {
361         char *node_name = (char *) pmap_get(dump_info -> node_name_map, n);
362         ir_mode *irn_mode = (alt_mode != NULL) ? alt_mode : get_irn_mode(n);
363         char edge_name[50];
364         char *mode_node_name;
365
366         mode_node_name = dump_grgen_mode_node(irn_mode, dump_info, fp);
367
368         //mode_code =  get_mode_modecode(irn_mode);
369         //mode_name =  get_mode_name(irn_mode);
370
371         // Yes, use the given mode-node
372         //mode_node_name = pmap_get(dump_info -> mode_name_map, (void *) mode_code);
373         sprintf(edge_name, "m%d", edge_counter++);
374
375         if(pmap_get(dump_info->mode_edge_map, n) == NULL)
376         {
377                 char *edge_name_obst = obstack_alloc(&(dump_info->node_names), strlen(edge_name) + 1);
378                 strcpy(edge_name_obst, edge_name);
379                 pmap_insert(dump_info->mode_edge_map, n, edge_name_obst);
380         }
381
382         // Dump the edge from the current node to it's mode node
383         fprintf(fp, "%s%s -%s:has_mode-> %s;\n", indent, node_name, edge_name, mode_node_name);
384 }
385
386
387
388 /************************************************************************
389 * Dumps a node representing a node
390 ************************************************************************/
391
392 static char *dump_grgen_mode_node(ir_mode *irn_mode, grgen_dumpinfo_t *dump_info, FILE *fp)
393 {
394         ir_modecode mode_code = get_mode_modecode(irn_mode);
395         const char *mode_name =  get_mode_name(irn_mode);
396         char *mode_node_name;
397
398         if(!pmap_contains(dump_info -> mode_name_map, (void *) mode_code))
399         {
400                 // No, create a new mode-node
401                 mode_node_name = obstack_alloc(&(dump_info -> mode_names), MAX_NODENAME_LEN);
402                 sprintf(mode_node_name, "mode_%s_node", mode_name);
403                 pmap_insert(dump_info -> mode_name_map, (void *) mode_code, mode_node_name);
404                 fprintf(fp, "%s%s : Mode_%s;\n", indent, mode_node_name, mode_name);
405                 return(mode_node_name);
406         }
407         else
408         {
409                 return((char *) pmap_get(dump_info -> mode_name_map, (void *) mode_code));
410         }
411
412 }
413
414
415
416 /************************************************************************
417 * Dumps the condition for the given node, depending on the node's
418 * attributes and the node's opcode
419 ************************************************************************/
420
421 static void dump_grgen_eval(ir_node *n, grgen_dumpinfo_t *dump_info, FILE *fp)
422 {
423         char *node_name;
424         ir_opcode code = get_irn_opcode(n);
425
426         if(code == iro_Const)
427         {
428                 node_name = pmap_get(dump_info->node_name_map, n);
429                 fprintf(fp, "%s%s.value = \"%ld\";\n", indent, node_name, get_tarval_long(get_Const_tarval(n)));
430         }
431
432
433         if(code == iro_Proj)
434         {
435                 node_name = pmap_get(dump_info->node_name_map, n);
436                 fprintf(fp, "%s%s.proj = %ld;\n", indent, node_name, get_Proj_proj(n));
437         }
438
439         /*if(code == iro_Block)
440         {
441                 node_name = pmap_get(dump_info->node_name_map, n);
442                 fprintf(fp, "%s%s.pos = %d;\n", indent, node_name, ??);
443         }
444
445         if(code == iro_Phi)
446         {
447                 node_name = pmap_get(dump_info->node_name_map, n);
448                 fprintf(fp, "%s%s.pos = %d;\n", indent, node_name, ??);
449         }*/
450
451         // TODO: Dump Block evals: edge numbers
452
453
454         if(code == iro_Phi || code == iro_Block)
455         {
456                 char **edge_names;
457                 int i;
458
459                 //assert((get_irn_arity(n) == get_irn_arity(phi_block)) && "Phi has other arity than it's block! Pattern seems to be broken.");
460
461                 // Load the edge names that have been saved
462                 edge_names = pmap_get(dump_info->edge_name_map, n);
463                 assert(edge_names && "Some edge names have not been dumped!");
464
465                 // Correlate the matched phi edges with the matched block edges
466                 // Caution: Position 0 in the edge_names array is the block edge, so start at 1
467                 for(i = code == iro_Block; i < get_irn_arity(n) + 1; i++)
468                 {
469                         assert(edge_names[i] != NULL && "Some edges have not been dumped!");
470
471                         fprintf(fp, "%s%s.pos = %d;\n", indent, edge_names[i], i);
472                 }
473                 return;
474         }
475 }
476
477
478
479
480
481 /************************************************************************
482 * Sets current indent
483 ************************************************************************/
484
485 static void set_indent(int i)
486 {
487         int j;
488
489         // Generate a string containing i blank characters
490         if(i < MAX_INDENT - 1)
491         {
492                 for(j = 0; j < i; j++)
493                         indent[j] = ' ';
494                 indent[j] = 0x0;
495         }
496 }