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