2 * Copyright (C) 1995-2007 University of Karlsruhe. All right reserved.
4 * This file is part of libFirm.
6 * This file may be distributed and/or modified under the terms of the
7 * GNU General Public License version 2 as published by the Free Software
8 * Foundation and appearing in the file LICENSE.GPL included in the
9 * packaging of this file.
11 * Licensees holding valid libFirm Professional Edition licenses may use
12 * this file in accordance with the libFirm Commercial License.
13 * Agreement provided with the Software.
15 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * @brief Write ir graph as a grgen construction rule
23 * @author Andreas Schoesser
28 * THIS IS A COMPLETE QUICK HACK! USE WITH CARE
29 * NOT FOR PRODUCTION BUILD ;-)
32 #define MAX_NODENAME_LEN 100
40 #include "firm_types.h"
44 #include "firm_types.h"
45 #include "irdump_grgen.h"
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
60 typedef struct // Holds information needed througout the usage of a grgen dumper instance
62 FILE *output_file; // The file the grgen rules will be dumped to
63 } irg_grgen_dumper_env_t;
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);
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
82 *****************************************************************************/
85 // ---------------------------- INCLUDES --------------------------------
90 /* #include "grgen_dumper__t.h"
91 #include "create_pattern_t.h"
92 #include "firm_node_ext.h" */
94 // ----------------------------- GLOABALS --------------------------------
96 // Saves the current indent value and keeps spaces in a string
97 #define MAX_INDENT 100
98 static char indent[MAX_INDENT] = "";
100 // Saves the current node number to generate node names
101 static int node_counter;
102 static int edge_counter;
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
111 * Parameters: file: filename of the file to dump to
112 * append: 1 if the previous file content should be
114 ************************************************************************/
116 irg_grgen_dumper_env_t *init_irg_grgen_dumper(char *file, int append)
118 irg_grgen_dumper_env_t *const grgen_dumper_env = XMALLOC(irg_grgen_dumper_env_t);
122 fp = fopen(file, "at");
125 fp = fopen(file, "wt");
128 fprintf(fp, "%susing Firm;\n\n", indent);
131 grgen_dumper_env -> output_file = fp;
132 return(grgen_dumper_env);
137 /************************************************************************
138 * Frees information used by the grgen_dumper and closes the output file
139 ************************************************************************/
141 void deinit_irg_grgen_dumper(irg_grgen_dumper_env_t *grgen_dumper_env)
143 fclose(grgen_dumper_env->output_file);
144 xfree(grgen_dumper_env);
147 static void collect_nodes(ir_node *n, void * env)
149 pmap *nodes_to_dump = (pmap *) env;
151 pmap_insert(nodes_to_dump, n, NULL);
157 /************************************************************************
159 ************************************************************************/
161 void dump_irg_grgen_file(ir_graph *irg, char *filename, int append)
164 grgen_dumpinfo_t dump_info;
168 irg_grgen_dumper_env_t *grgen_dumper_env = init_irg_grgen_dumper(filename, append);
169 fp = grgen_dumper_env -> output_file;
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();
179 // Node and egde count start at 0 for each pattern to be dumped.
182 obstack_init(&(dump_info.node_names));
183 obstack_init(&(dump_info.mode_names));
187 fprintf(fp, "\n\n%srule %s\n%s{\n", indent, get_entity_name(get_irg_entity(irg)), indent);
190 fprintf(fp, "%spattern { }\n", indent); // Empty pattern
191 fprintf(fp, "%sreplace\n%s{\n", indent, indent); // Graph is contrcuted in the replacement part
195 irg_walk_graph(irg, collect_nodes, NULL, dump_info.nodes_to_dump);
196 uses_memory = dump_pattern(&dump_info, fp);
200 fprintf(fp, "%s}\n", indent);
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));
212 deinit_irg_grgen_dumper(grgen_dumper_env);
216 void dump_irg_grgen(ir_graph *irg, char *suffix)
218 char filename[100] = "";
220 strncat(filename, get_entity_name(get_irg_entity(irg)), sizeof(filename)-1);
221 strncat(filename, suffix, sizeof(filename)-1);
222 strncat(filename, ".grg", sizeof(filename)-1);
224 dump_irg_grgen_file(irg, filename, 0);
228 /************************************************************************
229 * Dumps the left hand side of the rule
230 ************************************************************************/
232 static int dump_pattern(grgen_dumpinfo_t *dump_info, FILE *fp)
234 struct pmap *nodes_to_dump = dump_info->nodes_to_dump;
239 foreach_pmap(nodes_to_dump, entry)
241 ir_node *n = (ir_node *) entry->key;
244 if(get_irn_opcode(n) == iro_Proj && get_irn_mode(n) == mode_M)
246 dump_grg_node(n, dump_info, fp);
247 dump_grgen_mode(n, dump_info, fp, NULL);
251 foreach_pmap(nodes_to_dump, entry)
253 ir_node *n = (ir_node *) entry->key;
257 for(i = is_Block(n) ? 0 : -1; i < get_irn_arity(n); i++)
258 dump_grg_egde(n, i, dump_info, fp);
261 fprintf(fp, "%seval {\n", indent);
263 foreach_pmap(nodes_to_dump, entry)
265 ir_node *n = (ir_node *) entry->key;
266 dump_grgen_eval(n, dump_info, fp);
269 fprintf(fp, "%s}\n", indent);
273 fprintf(fp, "%s} /* Replacement */\n", indent);
279 /************************************************************************
280 * Dumps a node in GrGen Format
281 ************************************************************************/
283 static void dump_grg_node(ir_node *n, grgen_dumpinfo_t *dump_info, FILE *fp)
287 // Already dumped the node? Then do nothing
288 if(pmap_contains(dump_info -> node_name_map, n))
291 // Else generate new node name and dump the node
293 node_name = obstack_alloc(&(dump_info -> node_names), MAX_NODENAME_LEN);
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)));
298 pmap_insert(dump_info -> node_name_map, n, node_name);
304 /************************************************************************
305 * Dumps an edge in GrGen format
306 ************************************************************************/
308 static void dump_grg_egde(ir_node *n, int n_edge, grgen_dumpinfo_t *dump_info, FILE *fp)
311 char *from_node_name, *to_node_name;
312 char **nodes_edge_names;
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))
322 if((nodes_edge_names = pmap_get(dump_info -> edge_name_map, n)) == NULL)
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);
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);
336 char edge_name[50], *edge_name_obst;
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;
343 fprintf(fp, "%s%s -%s:df-> %s;\n", indent, from_node_name, edge_name_obst, to_node_name);
351 /************************************************************************
352 * Dumps an FIRM Mode as GrGen Code
353 * If source_node_name == NULL, that name of n that was already
355 * If source_node_name != NULL, this given source will be used
356 * (useful for retyped nodes)
357 ************************************************************************/
359 static void dump_grgen_mode(ir_node *n, grgen_dumpinfo_t *dump_info, FILE *fp, ir_mode *alt_mode)
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);
364 char *mode_node_name;
366 mode_node_name = dump_grgen_mode_node(irn_mode, dump_info, fp);
368 //mode_code = get_mode_modecode(irn_mode);
369 //mode_name = get_mode_name(irn_mode);
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++);
375 if(pmap_get(dump_info->mode_edge_map, n) == NULL)
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);
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);
388 /************************************************************************
389 * Dumps a node representing a node
390 ************************************************************************/
392 static char *dump_grgen_mode_node(ir_mode *irn_mode, grgen_dumpinfo_t *dump_info, FILE *fp)
394 const char *mode_name = get_mode_name(irn_mode);
395 char *mode_node_name;
397 if(!pmap_contains(dump_info -> mode_name_map, irn_mode))
399 // No, create a new mode-node
400 mode_node_name = obstack_alloc(&(dump_info -> mode_names), MAX_NODENAME_LEN);
401 sprintf(mode_node_name, "mode_%s_node", mode_name);
402 pmap_insert(dump_info -> mode_name_map, irn_mode, mode_node_name);
403 fprintf(fp, "%s%s : Mode_%s;\n", indent, mode_node_name, mode_name);
404 return(mode_node_name);
408 return((char *) pmap_get(dump_info -> mode_name_map, irn_mode));
415 /************************************************************************
416 * Dumps the condition for the given node, depending on the node's
417 * attributes and the node's opcode
418 ************************************************************************/
420 static void dump_grgen_eval(ir_node *n, grgen_dumpinfo_t *dump_info, FILE *fp)
423 ir_opcode code = get_irn_opcode(n);
425 if(code == iro_Const)
427 node_name = pmap_get(dump_info->node_name_map, n);
428 fprintf(fp, "%s%s.value = \"%ld\";\n", indent, node_name, get_tarval_long(get_Const_tarval(n)));
434 node_name = pmap_get(dump_info->node_name_map, n);
435 fprintf(fp, "%s%s.proj = %ld;\n", indent, node_name, get_Proj_proj(n));
438 /*if(code == iro_Block)
440 node_name = pmap_get(dump_info->node_name_map, n);
441 fprintf(fp, "%s%s.pos = %d;\n", indent, node_name, ??);
446 node_name = pmap_get(dump_info->node_name_map, n);
447 fprintf(fp, "%s%s.pos = %d;\n", indent, node_name, ??);
450 // TODO: Dump Block evals: edge numbers
453 if(code == iro_Phi || code == iro_Block)
458 //assert((get_irn_arity(n) == get_irn_arity(phi_block)) && "Phi has other arity than it's block! Pattern seems to be broken.");
460 // Load the edge names that have been saved
461 edge_names = pmap_get(dump_info->edge_name_map, n);
462 assert(edge_names && "Some edge names have not been dumped!");
464 // Correlate the matched phi edges with the matched block edges
465 // Caution: Position 0 in the edge_names array is the block edge, so start at 1
466 for(i = code == iro_Block; i < get_irn_arity(n) + 1; i++)
468 assert(edge_names[i] != NULL && "Some edges have not been dumped!");
470 fprintf(fp, "%s%s.pos = %d;\n", indent, edge_names[i], i);
480 /************************************************************************
481 * Sets current indent
482 ************************************************************************/
484 static void set_indent(int i)
488 // Generate a string containing i blank characters
489 if(i < MAX_INDENT - 1)
491 for(j = 0; j < i; j++)