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