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