remove $Id$, it doesn't work with git anyway
[libfirm] / ir / stat / pattern_dmp.c
1 /*
2  * Copyright (C) 1995-2008 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   Statistics for Firm. Dumping patterns.
23  * @author  Michael Beck
24  */
25 #include "config.h"
26
27 #include <stdio.h>
28 #include <stdlib.h>
29
30 #include "ident.h"
31 #include "irop_t.h"
32 #include "irmode.h"
33 #include "firmstat_t.h"
34 #include "pattern_dmp.h"
35
36 /* dumper operations */
37 typedef void (*DUMP_NEW_PATTERN_FUNC)(pattern_dumper_t *self, counter_t *cnt);
38 typedef void (*DUMP_FINISH_PATTERN_FUNC)(pattern_dumper_t *self);
39 typedef void (*DUMP_NODE_FUNC)(pattern_dumper_t *self, unsigned id, unsigned op_code, unsigned mode_code, void *attr);
40 typedef void (*DUMP_REF_FUNC)(pattern_dumper_t *self, unsigned id);
41 typedef void (*DUMP_EDGE_FUNC)(pattern_dumper_t *self, unsigned tgt, unsigned src, unsigned pos, unsigned mode_code);
42 typedef void (*DUMP_START_CHILDREN_FUNC)(pattern_dumper_t *self, unsigned id);
43 typedef void (*DUMP_FINISH_CHILDREN_FUNC)(pattern_dumper_t *self, unsigned id);
44 typedef void (*DUMP_START_FUNC)(pattern_dumper_t *self);
45 typedef void (*DUMP_END_FUNC)(pattern_dumper_t *self);
46
47 /**
48  * the pattern dumper
49  */
50 struct pattern_dumper_t {
51         DUMP_NEW_PATTERN_FUNC      dump_new_pattern;
52         DUMP_FINISH_PATTERN_FUNC   dump_finish_pattern;
53         DUMP_NODE_FUNC             dump_node;
54         DUMP_REF_FUNC              dump_ref;
55         DUMP_EDGE_FUNC             dump_edge;
56         DUMP_START_CHILDREN_FUNC   dump_start_children;
57         DUMP_FINISH_CHILDREN_FUNC  dump_finish_children;
58         DUMP_START_FUNC            dump_start;
59         DUMP_END_FUNC              dump_end;
60         void                       *data;
61 };
62
63 /**
64  * VCG private data
65  */
66 typedef struct vcg_private_t {
67         FILE     *f;          /**< file to dump to */
68         unsigned pattern_id;  /**< ID of the pattern */
69         unsigned max_pattern; /**< maximum number of pattern to be dumped */
70 } vcg_private_t;
71
72 /**
73  * Starts a new VCG graph.
74  */
75 static void vcg_dump_start(pattern_dumper_t *self)
76 {
77         vcg_private_t *priv = (vcg_private_t*)self->data;
78
79         fprintf(priv->f,
80                 "graph: { title: \"Most found pattern\"\n"
81                 "  display_edge_labels: no\n"
82                 "  layoutalgorithm: mindepth\n"
83                 "  manhattan_edges: yes\n"
84                 "  port_sharing: no\n"
85                 "  orientation: bottom_to_top\n"
86                 );
87 }  /* vcg_dump_start */
88
89 /**
90  * Ends a new VCG graph.
91  */
92 static void vcg_dump_end(pattern_dumper_t *self)
93 {
94         vcg_private_t *priv = (vcg_private_t*)self->data;
95
96         fprintf(priv->f, "}\n");
97         fclose(priv->f);
98 }  /* vcg_dump_end */
99
100 /**
101  * Starts a new pattern.
102  */
103 static void vcg_dump_new_pattern(pattern_dumper_t *self, counter_t *cnt)
104 {
105         vcg_private_t *priv = (vcg_private_t*)self->data;
106         static unsigned nr = 0;
107
108         if (priv->pattern_id > priv->max_pattern)
109                 return;
110
111         fprintf(priv->f,
112                 "  graph: { title: \"g%u\" label: \"pattern %u\" status:clustered color:yellow\n",
113                 priv->pattern_id, priv->pattern_id );
114
115         /* add a pseudo node for the count of this pattern */
116         fprintf(priv->f,
117                 "    node: {title: \"c%u\" label: \"cnt: %u\" color:red }\n",
118                 ++nr, cnt_to_uint(cnt)
119         );
120 }  /* vcg_dump_new_pattern */
121
122 /**
123  * Finish the current pattern.
124  */
125 static void vcg_dump_finish_pattern(pattern_dumper_t *self)
126 {
127         vcg_private_t *priv = (vcg_private_t*)self->data;
128
129         if (priv->pattern_id > priv->max_pattern)
130                 return;
131
132         fprintf(priv->f, "  }\n");
133
134         if (priv->pattern_id > 0)
135                 fprintf(priv->f, "  edge: { sourcename: \"g%u\" targetname: \"g%u\" linestyle:invisible}\n",
136                         priv->pattern_id,
137                         priv->pattern_id - 1);
138
139         ++priv->pattern_id;
140 }  /* vcg_dump_finish_pattern */
141
142 /**
143  * Dumps a node.
144  */
145 static void vcg_dump_node(pattern_dumper_t *self, unsigned id,
146     unsigned op_code, unsigned mode_code, void *attr)
147 {
148         vcg_private_t *priv = (vcg_private_t*)self->data;
149         ir_op *op           = stat_get_op_from_opcode(op_code);
150         ir_mode *mode       = get_irp_mode(mode_code);
151         long l              = attr ? *(long *)attr : 0;
152
153         if (priv->pattern_id > priv->max_pattern)
154                 return;
155
156         if (attr) {
157                 fprintf(priv->f, "    node: {title: \"n%u_%u\" label: \"%s%s %ld n%u\" }\n",
158                         priv->pattern_id, id, get_id_str(op->name), mode ? get_mode_name(mode) : "", l, id);
159         } else {
160                 fprintf(priv->f, "    node: {title: \"n%u_%u\" label: \"%s%s n%u\" }\n",
161                         priv->pattern_id, id, get_id_str(op->name), mode ? get_mode_name(mode) : "", id);
162         }  /* if */
163 }  /* vcg_dump_node */
164
165 /**
166  * Dumps an edge.
167  */
168 static void vcg_dump_edge(pattern_dumper_t *self, unsigned tgt, unsigned src, unsigned pos, unsigned mode_code)
169 {
170         vcg_private_t *priv = (vcg_private_t*)self->data;
171         (void) mode_code;
172
173         if (priv->pattern_id > priv->max_pattern)
174                 return;
175
176         fprintf(priv->f, "    edge: { sourcename: \"n%u_%u\" targetname: \"n%u_%u\" label: \"%u\" }\n",
177                 priv->pattern_id, src,
178                 priv->pattern_id, tgt,
179                 pos
180         );
181 }  /* vcg_dump_edge */
182
183 /**
184  * The VCG dumper.
185  */
186 static pattern_dumper_t vcg_dump = {
187         vcg_dump_new_pattern,
188         vcg_dump_finish_pattern,
189         vcg_dump_node,
190         NULL,
191         vcg_dump_edge,
192         NULL,
193         NULL,
194         vcg_dump_start,
195         vcg_dump_end,
196         NULL
197 };
198
199 /**
200  * Starts a new pattern.
201  */
202 static void stdout_dump_new_pattern(pattern_dumper_t *self, counter_t *cnt)
203 {
204         FILE *f = (FILE*)self->data;
205
206         fprintf(f, "%8u ", cnt_to_uint(cnt));
207 }  /* stdout_dump_new_pattern */
208
209
210 /**
211  * Finish the current pattern.
212  */
213 static void stdout_dump_finish_pattern(pattern_dumper_t *self)
214 {
215         FILE *f = (FILE*)self->data;
216
217         fprintf(f, "\n");
218 }  /* stdout_dump_finish_pattern */
219
220 /**
221  * Dumps a node.
222  */
223 static void stdout_dump_node(pattern_dumper_t *self, unsigned id, unsigned op_code, unsigned mode_code, void *attr)
224 {
225         FILE *f       = (FILE*)self->data;
226         ir_op *op     = stat_get_op_from_opcode(op_code);
227         ir_mode *mode = get_irp_mode(mode_code);
228         (void) attr;
229
230         /* if (env->options & OPT_ENC_GRAPH) */
231         fprintf(f, "%u:", id);
232
233         fprintf(f, "%s", get_id_str(op->name));
234
235         if (mode)
236                 fprintf(f, "%s", get_mode_name(mode));
237 }  /* stdout_dump_node */
238
239 /**
240  * Dump a ref
241  */
242 static void stdout_dump_ref(pattern_dumper_t *self, unsigned id)
243 {
244         FILE *f = (FILE*)self->data;
245
246         fprintf(f, "REF:%u", id);
247 }  /* stdout_dump_ref */
248
249 /**
250  * Dump an edge.
251  */
252 static void stdout_dump_edge(pattern_dumper_t *self, unsigned tgt, unsigned src, unsigned pos, unsigned mode_code)
253 {
254         FILE *f = (FILE*)self->data;
255         (void) tgt;
256         (void) src;
257         (void) pos;
258         (void) mode_code;
259
260         if (pos > 0)
261                 fprintf(f, ", ");
262 }  /* stdout_dump_edge */
263
264 /**
265  * Start the children dumper.
266  */
267 static void stdout_start_children(pattern_dumper_t *self, unsigned id)
268 {
269         FILE *f = (FILE*)self->data;
270         (void) id;
271
272         fprintf(f, "(");
273 }  /* stdout_start_children */
274
275 /**
276  * Finish the children dumper.
277  */
278 static void stdout_finish_children(pattern_dumper_t *self, unsigned id)
279 {
280         FILE *f = (FILE*)self->data;
281         (void) id;
282
283         fprintf(f, ")");
284 }  /* stdout_finish_children */
285
286 /**
287  * The stdout dumper.
288  */
289 static const pattern_dumper_t stdout_dump = {
290         stdout_dump_new_pattern,
291         stdout_dump_finish_pattern,
292         stdout_dump_node,
293         stdout_dump_ref,
294         stdout_dump_edge,
295         stdout_start_children,
296         stdout_finish_children,
297         NULL,
298         NULL,
299         NULL
300 };
301
302 /* ------------------------------------ API ------------------------------------- */
303
304 /*
305  * Starts a new pattern.
306  */
307 void pattern_dump_new_pattern(pattern_dumper_t *self, counter_t *cnt)
308 {
309         if (self->dump_new_pattern)
310                 self->dump_new_pattern(self, cnt);
311 }  /* pattern_dump_new_pattern */
312
313
314 /*
315  * Finish the current pattern.
316  */
317 void pattern_dump_finish_pattern(pattern_dumper_t *self)
318 {
319         if (self->dump_finish_pattern)
320                 self->dump_finish_pattern(self);
321 }  /* pattern_dump_finish_pattern */
322
323
324 /*
325  * Dumps a node.
326  */
327 void pattern_dump_node(pattern_dumper_t *self, unsigned id, unsigned op_code, unsigned mode_code, void *attr)
328 {
329         if (self->dump_node)
330                 self->dump_node(self, id, op_code, mode_code, attr);
331 }  /* pattern_dump_node */
332
333 /*
334  * Dump a ref.
335  */
336 void pattern_dump_ref(pattern_dumper_t *self, unsigned id)
337 {
338         if (self->dump_ref)
339                 self->dump_ref(self, id);
340 }  /* pattern_dump_ref */
341
342 /*
343  * Dump an edge.
344  */
345 void pattern_dump_edge(pattern_dumper_t *self, unsigned tgt, unsigned src, unsigned pos, unsigned mode_code)
346 {
347         if (self->dump_edge)
348                 self->dump_edge(self, tgt, src, pos, mode_code);
349 }  /* pattern_dump_edge */
350
351 /*
352  * Start the children dumper.
353  */
354 void pattern_start_children(pattern_dumper_t *self, unsigned id)
355 {
356         if (self->dump_start_children)
357                 self->dump_start_children(self, id);
358 }  /* pattern_start_children */
359
360 /*
361  * Finish the the children dumper.
362  */
363 void pattern_finish_children(pattern_dumper_t *self, unsigned id)
364 {
365         if (self->dump_finish_children)
366                 self->dump_finish_children(self, id);
367 }  /* pattern_finish_children */
368
369 /*
370  * Finish the the dumper.
371  */
372 void pattern_end(pattern_dumper_t *self)
373 {
374         if (self->dump_end)
375                 self->dump_end(self);
376
377         free(self);
378 }  /* pattern_end */
379
380 /**
381  * pattern dumper factory for text dumper
382  */
383 pattern_dumper_t *new_text_dumper(void)
384 {
385         pattern_dumper_t *res = XMALLOC(pattern_dumper_t);
386
387         *res = stdout_dump;
388         res->data = stdout;
389
390         if (res->dump_start)
391                 res->dump_start(res);
392         return res;
393 }  /* new_text_dumper */
394
395 /**
396  * pattern dumper factory for vcg dumper
397  */
398 pattern_dumper_t *new_vcg_dumper(const char *vcg_name, unsigned max_pattern)
399 {
400         pattern_dumper_t *res = (pattern_dumper_t*)malloc(sizeof(*res) + sizeof(vcg_private_t));
401         vcg_private_t *priv;
402
403         if (res) {
404                 FILE *f;
405
406                 memcpy(res, &vcg_dump, sizeof(*res));
407
408                 priv = (vcg_private_t *)(res + 1);
409                 memset(priv, 0, sizeof(*priv));
410
411                 f = fopen(vcg_name, "w");
412                 priv->f           = f;
413                 priv->pattern_id  = 0;
414                 priv->max_pattern = max_pattern ? max_pattern : (unsigned)-1;
415                 res->data         = priv;
416
417                 if (res->dump_start)
418                         res->dump_start(res);
419         }  /* if */
420
421         return res;
422 }  /* new_vcg_dumper */