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