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