6caaa3313a3eb411ea5db7a5a6ec7c72473cb0a6
[libfirm] / ir / stat / stat_dmp.c
1 /*
2  * Project:     libFIRM
3  * File name:   ir/ir/stat_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 #ifdef HAVE_CONFIG_H
12 # include "config.h"
13 #endif
14
15 #include "stat_dmp.h"
16 #include "irhooks.h"
17
18 /**
19  * names of the optimizations
20  */
21 static const struct {
22         hook_opt_kind kind;
23         const char    *name;
24 } opt_names[] = {
25         { HOOK_OPT_DEAD_BLOCK,   "dead block elimination" },
26         { HOOK_OPT_STG,          "straightening optimization" },
27         { HOOK_OPT_IFSIM,        "if simplification" },
28         { HOOK_OPT_CONST_EVAL,   "constant evaluation" },
29         { HOOK_OPT_ALGSIM,       "algebraic simplification" },
30         { HOOK_OPT_PHI,          "Phi optmization" },
31         { HOOK_OPT_SYNC,         "Sync optmization" },
32         { HOOK_OPT_WAW,          "Write-After-Write optimization" },
33         { HOOK_OPT_WAR,          "Write-After-Read optimization" },
34         { HOOK_OPT_RAW,          "Read-After-Write optimization" },
35         { HOOK_OPT_RAR,          "Read-After-Read optimization" },
36         { HOOK_OPT_RC,           "Read-a-Const optimization" },
37         { HOOK_OPT_TUPLE,        "Tuple optimization" },
38         { HOOK_OPT_ID,           "ID optimization" },
39         { HOOK_OPT_CSE,          "Common subexpression elimination" },
40         { HOOK_OPT_STRENGTH_RED, "Strength reduction" },
41         { HOOK_OPT_ARCH_DEP,     "Architecture dependant optimization" },
42         { HOOK_OPT_REASSOC,      "Reassociation optimization" },
43         { HOOK_OPT_POLY_CALL,    "Polymorphic call optimization" },
44         { HOOK_OPT_IF_CONV,      "an if conversion was tried" },
45         { HOOK_OPT_FUNC_CALL,    "Real function call optimization" },
46         { HOOK_OPT_CONFIRM,      "Confirm-based optimization: replacement" },
47         { HOOK_OPT_CONFIRM_C,    "Confirm-based optimization: replaced by const" },
48         { HOOK_OPT_CONFIRM_E,    "Confirm-based optimization: evaluated" },
49         { HOOK_OPT_EXC_REM,      "a exception edge was removed due to a Confirmation prove" },
50         { HOOK_LOWERED,          "Lowered" },
51         { HOOK_BACKEND,          "Backend transformation" },
52         { FS_OPT_NEUTRAL_0,      "algebraic simplification: a op 0 = 0 op a = a" },
53         { FS_OPT_NEUTRAL_1,      "algebraic simplification: a op 1 = 1 op a = a" },
54         { FS_OPT_ADD_A_A,        "algebraic simplification: a + a = a * 2" },
55         { FS_OPT_ADD_A_MINUS_B,  "algebraic simplification: a + -b = a - b" },
56         { FS_OPT_ADD_SUB,        "algebraic simplification: (a + x) - x = (a - x) + x = a" },
57         { FS_OPT_ADD_MUL_A_X_A,  "algebraic simplification: a * x + a = a * (x + 1)" },
58         { FS_OPT_SUB_0_A,        "algebraic simplification: 0 - a = -a" },
59         { FS_OPT_SUB_MUL_A_X_A,  "algebraic simplification: a * x - a = a * (x - 1)" },
60         { FS_OPT_MUL_MINUS_1,    "algebraic simplification: a * -1 = -a" },
61         { FS_OPT_OR,             "algebraic simplification: a | a = a | 0 = 0 | a = a" },
62         { FS_OPT_AND,            "algebraic simplification: a & 0b1...1 = 0b1...1 & a =  a & a = a" },
63         { FS_OPT_EOR_A_A,        "algebraic simplification: a ^ a = 0" },
64         { FS_OPT_EOR_TO_NOT_BOOL,"algebraic simplification: bool ^ 1 = !bool" },
65         { FS_OPT_EOR_TO_NOT,     "algebraic simplification: x ^ 0b1..1 = ~x" },
66         { FS_OPT_NOT_CMP,        "algebraic simplification: !(a cmp b) = a !cmp b" },
67         { FS_OPT_OR_SHFT_TO_ROT, "algebraic simplification: (x << c) | (x >> (bits - c)) == Rot(x, c)" },
68         { FS_OPT_REASSOC_SHIFT,  "algebraic simplification: (x SHF c1) SHF c2 = x SHF (c1+c2)" },
69         { FS_OPT_CONV,           "algebraic simplification: Conv could be removed" },
70         { FS_OPT_CAST,           "algebraic simplification: a Cast could be removed" },
71         { FS_OPT_MIN_MAX_EQ,     "algebraic simplification: Min(a,a) = Max(a,a) = a" },
72         { FS_OPT_MUX_C,          "algebraic simplification: Mux(C, f, t) = C ? t : f" },
73         { FS_OPT_MUX_EQ,         "algebraic simplification: Mux(v, x, x) = x" },
74         { FS_OPT_MUX_TRANSFORM,  "algebraic simplification: Mux(a, b, c) = b OR Mux(a,b, c) = c" },
75         { FS_OPT_MUX_TO_MIN,     "algebraic simplification: Mux(a < b, a, b) = Min(a,b)" },
76         { FS_OPT_MUX_TO_MAX,     "algebraic simplification: Mux(a > b, a, b) = Max(a,b)" },
77         { FS_OPT_MUX_TO_ABS,     "algebraic simplification: Mux(a > b, a, b) = Abs(a,b)" },
78         { FS_OPT_MUX_TO_SHR,     "algebraic simplification: Mux(a > b, a, b) = a >> b" },
79         { FS_BE_IA32_LEA,        "ia32 Backend transformation: Lea was created" },
80         { FS_BE_IA32_LOAD_LEA,   "ia32 Backend transformation: Load merged with a Lea" },
81         { FS_BE_IA32_STORE_LEA,  "ia32 Backend transformation: Store merged with a Lea" },
82         { FS_BE_IA32_AM_S,       "ia32 Backend transformation: Source address mode node created" },
83         { FS_BE_IA32_AM_D,       "ia32 Backend transformation: Destination address mode node created" },
84         { FS_BE_IA32_CJMP,       "ia32 Backend transformation: CJmp created to save a cmp/test" },
85         { FS_BE_IA32_2ADDRCPY,   "ia32 Backend transformation: Copy created due to 2-Addresscode constraints" },
86         { FS_BE_IA32_SPILL2ST,   "ia32 Backend transformation: Created Store for a Spill" },
87         { FS_BE_IA32_RELOAD2LD,  "ia32 Backend transformation: Created Load for a Reload" },
88         { FS_BE_IA32_SUB2NEGADD, "ia32 Backend transformation: Created Neg-Add for a Sub due to 2-Addresscode constraints" },
89         { FS_BE_IA32_LEA2ADD,    "ia32 Backend transformation: Transformed Lea back into Add" },
90 };
91
92 static const char *if_conv_names[IF_RESULT_LAST] = {
93         "if conv done             ",
94         "if conv side effect      ",
95         "if conv Phi node found   ",
96         "if conv to deep DAG's    ",
97         "if conv bad control flow ",
98         "if conv denied by arch   ",
99 };
100
101 /**
102  * dumps a opcode hash into human readable form
103  */
104 static void simple_dump_opcode_hash(dumper_t *dmp, pset *set)
105 {
106         node_entry_t *entry;
107         counter_t f_alive;
108         counter_t f_new_node;
109         counter_t f_Id;
110
111         cnt_clr(&f_alive);
112         cnt_clr(&f_new_node);
113         cnt_clr(&f_Id);
114
115         fprintf(dmp->f, "%-16s %-8s %-8s %-8s\n", "Opcode", "alive", "created", "->Id");
116         foreach_pset(set, entry) {
117                 fprintf(dmp->f, "%-16s %8u %8u %8u\n",
118                         get_id_str(entry->op->name),
119                         cnt_to_uint(&entry->cnt_alive),
120                         cnt_to_uint(&entry->new_node),
121                         cnt_to_uint(&entry->into_Id)
122                 );
123
124                 cnt_add(&f_alive,    &entry->cnt_alive);
125                 cnt_add(&f_new_node, &entry->new_node);
126                 cnt_add(&f_Id,       &entry->into_Id);
127         }
128         fprintf(dmp->f, "-------------------------------------------\n");
129         fprintf(dmp->f, "%-16s %8u %8u %8u\n", "Sum",
130                 cnt_to_uint(&f_alive),
131                 cnt_to_uint(&f_new_node),
132                 cnt_to_uint(&f_Id)
133         );
134 }
135
136 /**
137  * dumps an optimization hash into human readable form
138  */
139 static void simple_dump_opt_hash(dumper_t *dmp, pset *set, int index)
140 {
141         assert(index < ARR_SIZE(opt_names) && "index out of range");
142         assert(opt_names[index].kind == index && "opt_names broken");
143
144         if (pset_count(set) > 0) {
145                 opt_entry_t *entry;
146
147                 fprintf(dmp->f, "\n%s:\n", opt_names[index].name);
148                 fprintf(dmp->f, "%-16s %-8s\n", "Opcode", "deref");
149
150                 foreach_pset(set, entry) {
151                         fprintf(dmp->f, "%-16s %8u\n",
152                                 get_id_str(entry->op->name), cnt_to_uint(&entry->count));
153                 }
154         }
155 }
156
157 /**
158  * dumps the register pressure for each block and for each register class
159  */
160 static void simple_dump_be_block_reg_pressure(dumper_t *dmp, graph_entry_t *entry)
161 {
162         be_block_entry_t     *b_entry = pset_first(entry->be_block_hash);
163         reg_pressure_entry_t *rp_entry;
164
165         /* return if no be statistic information available */
166         if (! b_entry)
167                 return;
168
169         fprintf(dmp->f, "\nREG PRESSURE:\n");
170         fprintf(dmp->f, "%12s", "Block Nr");
171
172         /* print table head (register class names) */
173         foreach_pset(b_entry->reg_pressure, rp_entry)
174                 fprintf(dmp->f, "%15s", rp_entry->class_name);
175         fprintf(dmp->f, "\n");
176
177         /* print the reg pressure for all blocks and register classes */
178         for (/* b_entry is already initialized */ ;
179              b_entry;
180              b_entry = pset_next(entry->be_block_hash)) {
181                 fprintf(dmp->f, "BLK   %6ld", b_entry->block_nr);
182
183                 foreach_pset(b_entry->reg_pressure, rp_entry)
184                         fprintf(dmp->f, "%15d", rp_entry->pressure);
185                 fprintf(dmp->f, "\n");
186         }
187 }
188
189 /** prints a distribution entry */
190 void dump_block_sched_ready_distrib(const distrib_entry_t *entry, void *env)
191 {
192         FILE *dmp_f = env;
193         fprintf(dmp_f, "%12d", cnt_to_uint(&entry->cnt));
194 }
195
196 /**
197  * dumps the distribution of the amount of ready nodes for each block
198  */
199 static void simple_dump_be_block_sched_ready(dumper_t *dmp, graph_entry_t *entry)
200 {
201         if (pset_count(entry->be_block_hash) > 0) {
202                 be_block_entry_t *b_entry;
203                 int              i;
204
205                 fprintf(dmp->f, "\nSCHEDULING: NUMBER OF READY NODES\n");
206                 fprintf(dmp->f, "%12s %12s %12s %12s %12s %12s %12s\n",
207                         "Block Nr", "1 node", "2 nodes", "3 nodes", "4 nodes", "5 or more", "AVERAGE");
208
209                 foreach_pset(entry->be_block_hash, b_entry) {
210                         /* this ensures that all keys from 1 to 5 are in the table */
211                         for (i = 1; i < 6; ++i)
212                                 stat_insert_int_distrib_tbl(b_entry->sched_ready, i);
213
214                         fprintf(dmp->f, "BLK   %6ld", b_entry->block_nr);
215                         stat_iterate_distrib_tbl(b_entry->sched_ready, dump_block_sched_ready_distrib, dmp->f);
216                         fprintf(dmp->f, "%12.2lf", stat_calc_avg_distrib_tbl(b_entry->sched_ready));
217                         fprintf(dmp->f, "\n");
218                 }
219         }
220 }
221
222 /**
223  * dumps permutation statistics for one and block and one class
224  */
225 static void simple_dump_be_block_permstat_class(dumper_t *dmp, perm_class_entry_t *entry)
226 {
227         perm_stat_entry_t *ps_ent;
228
229         fprintf(dmp->f, "%12s %12s %12s %12s\n", "size", "real size", "# chains", "# cycles");
230         foreach_pset(entry->perm_stat, ps_ent) {
231                 fprintf(dmp->f, "%12d %12d %12d %12d\n",
232                         ps_ent->size,
233                         ps_ent->real_size,
234                         stat_get_count_distrib_tbl(ps_ent->chains),
235                         stat_get_count_distrib_tbl(ps_ent->cycles)
236                 );
237         }
238 }
239
240 /**
241  * dumps statistics about perms
242  */
243 static void simple_dump_be_block_permstat(dumper_t *dmp, graph_entry_t *entry)
244 {
245         if (pset_count(entry->be_block_hash) > 0) {
246                 be_block_entry_t *b_entry;
247
248                 fprintf(dmp->f, "\nPERMUTATION STATISTICS BEGIN:\n");
249                 foreach_pset(entry->be_block_hash, b_entry) {
250                         perm_class_entry_t *pc_ent;
251
252                         fprintf(dmp->f, "BLOCK %ld:\n", b_entry->block_nr);
253
254                         if (b_entry->perm_class_stat)
255                                 foreach_pset(b_entry->perm_class_stat, pc_ent) {
256                                         fprintf(dmp->f, "register class %s:\n", pc_ent->class_name);
257                                         simple_dump_be_block_permstat_class(dmp, pc_ent);
258                                 }
259                 }
260
261                 fprintf(dmp->f, "PERMUTATION STATISTICS END\n");
262         }
263 }
264
265 /**
266  * dumps the number of real_function_call optimization
267  */
268 static void simple_dump_real_func_calls(dumper_t *dmp, counter_t *cnt)
269 {
270         if (! dmp->f)
271                 return;
272
273         if (! cnt_eq(cnt, 0)) {
274                 fprintf(dmp->f, "\nReal Function Calls optimized:\n");
275                 fprintf(dmp->f, "%-16s %8u\n", "Call", cnt_to_uint(cnt));
276         }
277 }
278
279 /**
280  * dumps the number of tail_recursion optimization
281  */
282 static void simple_dump_tail_recursion(dumper_t *dmp, unsigned num_tail_recursion)
283 {
284         if (! dmp->f)
285                 return;
286
287         if (num_tail_recursion > 0) {
288                 fprintf(dmp->f, "\nTail recursion optimized:\n");
289                 fprintf(dmp->f, "%-16s %8u\n", "Call", num_tail_recursion);
290         }
291 }
292
293 /**
294  * dumps the edges count
295  */
296 static void simple_dump_edges(dumper_t *dmp, counter_t *cnt)
297 {
298         if (! dmp->f)
299                 return;
300
301         fprintf(dmp->f, "%-16s %8d\n", "Edges", cnt_to_uint(cnt));
302 }
303
304 /**
305  * dumps the IRG
306  */
307 static void simple_dump_graph(dumper_t *dmp, graph_entry_t *entry)
308 {
309         int i, dump_opts = 1;
310         block_entry_t *b_entry;
311         extbb_entry_t *eb_entry;
312
313         if (! dmp->f)
314                 return;
315
316         if (entry->irg) {
317                 ir_graph *const_irg = get_const_code_irg();
318
319                 if (entry->irg == const_irg)
320                         fprintf(dmp->f, "\nConst code Irg %p", (void *)entry->irg);
321                 else {
322                         if (entry->ent)
323                                 fprintf(dmp->f, "\nEntity %s, Irg %p", get_entity_ld_name(entry->ent), (void *)entry->irg);
324                         else
325                                 fprintf(dmp->f, "\nIrg %p", (void *)entry->irg);
326                 }
327
328                 fprintf(dmp->f, " %swalked %u over blocks %u:\n"
329                         " was inlined               : %u\n"
330                         " got inlined               : %u\n"
331                         " strength red              : %u\n"
332                         " leaf function             : %s\n"
333                         " calls only leaf functions : %s\n"
334                         " recursive                 : %s\n"
335                         " chain call                : %s\n"
336                         " calls                     : %u\n"
337                         " indirect calls            : %u\n",
338                         entry->is_deleted ? "DELETED " : "",
339                         cnt_to_uint(&entry->cnt_walked), cnt_to_uint(&entry->cnt_walked_blocks),
340                         cnt_to_uint(&entry->cnt_was_inlined),
341                         cnt_to_uint(&entry->cnt_got_inlined),
342                         cnt_to_uint(&entry->cnt_strength_red),
343                         entry->is_leaf ? "YES" : "NO",
344                         entry->is_leaf_call == LCS_NON_LEAF_CALL ? "NO" : (entry->is_leaf_call == LCS_LEAF_CALL ? "Yes" : "Maybe"),
345                         entry->is_recursive ? "YES" : "NO",
346                         entry->is_chain_call ? "YES" : "NO",
347                         cnt_to_uint(&entry->cnt_all_calls),
348                         cnt_to_uint(&entry->cnt_indirect_calls)
349                 );
350
351                 for (i = 0; i < sizeof(entry->cnt_if_conv)/sizeof(entry->cnt_if_conv[0]); ++i) {
352                         fprintf(dmp->f, " %s : %u\n", if_conv_names[i], cnt_to_uint(&entry->cnt_if_conv[i]));
353                 }
354         }
355         else {
356                 fprintf(dmp->f, "\nGlobals counts:\n");
357                 fprintf(dmp->f, "--------------\n");
358                 dump_opts = 0;
359         }
360
361         simple_dump_opcode_hash(dmp, entry->opcode_hash);
362         simple_dump_edges(dmp, &entry->cnt_edges);
363
364         /* effects of optimizations */
365         if (dump_opts) {
366                 int i;
367
368                 simple_dump_real_func_calls(dmp, &entry->cnt_real_func_call);
369                 simple_dump_tail_recursion(dmp, entry->num_tail_recursion);
370
371                 for (i = 0; i < sizeof(entry->opt_hash)/sizeof(entry->opt_hash[0]); ++i) {
372                         simple_dump_opt_hash(dmp, entry->opt_hash[i], i);
373                 }
374
375                 /* dump block info */
376                 fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s %12s\n", "Block Nr", "Nodes", "intern E", "incoming E", "outgoing E", "Phi", "quot");
377                 foreach_pset(entry->block_hash, b_entry) {
378                         fprintf(dmp->f, "BLK   %6ld %12u %12u %12u %12u %12u %4.8f\n",
379                                 b_entry->block_nr,
380                                 cnt_to_uint(&b_entry->cnt_nodes),
381                                 cnt_to_uint(&b_entry->cnt_edges),
382                                 cnt_to_uint(&b_entry->cnt_in_edges),
383                                 cnt_to_uint(&b_entry->cnt_out_edges),
384                                 cnt_to_uint(&b_entry->cnt_phi_data),
385                                 cnt_to_dbl(&b_entry->cnt_edges) / cnt_to_dbl(&b_entry->cnt_nodes)
386                         );
387                 }
388
389                 /* dump block reg pressure */
390                 simple_dump_be_block_reg_pressure(dmp, entry);
391
392                 /* dump block ready nodes distribution */
393                 simple_dump_be_block_sched_ready(dmp, entry);
394
395                 /* dump block permutation statistics */
396                 simple_dump_be_block_permstat(dmp, entry);
397
398                 if (dmp->status->stat_options & FIRMSTAT_COUNT_EXTBB) {
399                         /* dump extended block info */
400                         fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s %12s\n", "Extbb Nr", "Nodes", "intern E", "incoming E", "outgoing E", "Phi", "quot");
401                         foreach_pset(entry->extbb_hash, eb_entry) {
402                                 fprintf(dmp->f, "ExtBB %6ld %12u %12u %12u %12u %12u %4.8f\n",
403                                         eb_entry->block_nr,
404                                         cnt_to_uint(&eb_entry->cnt_nodes),
405                                         cnt_to_uint(&eb_entry->cnt_edges),
406                                         cnt_to_uint(&eb_entry->cnt_in_edges),
407                                         cnt_to_uint(&eb_entry->cnt_out_edges),
408                                         cnt_to_uint(&eb_entry->cnt_phi_data),
409                                         cnt_to_dbl(&eb_entry->cnt_edges) / cnt_to_dbl(&eb_entry->cnt_nodes)
410                                 );
411                         }
412                 }
413         }
414 }
415
416 /**
417  * dumps the IRG
418  */
419 static void simple_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
420 {
421         int i;
422         counter_t sum;
423
424         if (! dmp->f)
425                 return;
426
427         cnt_clr(&sum);
428
429         fprintf(dmp->f, "\nConstant Information:\n");
430         fprintf(dmp->f, "---------------------\n");
431
432         fprintf(dmp->f, "\nBit usage for integer constants\n");
433         fprintf(dmp->f, "-------------------------------\n");
434
435         for (i = 0; i < ARR_SIZE(tbl->int_bits_count); ++i) {
436                 fprintf(dmp->f, "%5d %12u\n", i + 1, cnt_to_uint(&tbl->int_bits_count[i]));
437                 cnt_add(&sum, &tbl->int_bits_count[i]);
438         }
439         fprintf(dmp->f, "-------------------------------\n");
440
441         fprintf(dmp->f, "\nFloating point constants classification\n");
442         fprintf(dmp->f, "--------------------------------------\n");
443         for (i = 0; i < ARR_SIZE(tbl->floats); ++i) {
444                 fprintf(dmp->f, "%-10s %12u\n", stat_fc_name(i), cnt_to_uint(&tbl->floats[i]));
445                 cnt_add(&sum, &tbl->floats[i]);
446         }
447         fprintf(dmp->f, "--------------------------------------\n");
448
449         fprintf(dmp->f, "other %12u\n", cnt_to_uint(&tbl->others));
450         cnt_add(&sum, &tbl->others);
451         fprintf(dmp->f, "-------------------------------\n");
452
453         fprintf(dmp->f, "sum   %12u\n", cnt_to_uint(&sum));
454 }
455
456 /**
457  * initialize the simple dumper
458  */
459 static void simple_init(dumper_t *dmp, const char *name)
460 {
461         char fname[2048];
462
463         snprintf(fname, sizeof(fname), "%s.txt", name);
464         dmp->f = fopen(fname, "w");
465         if (! dmp->f) {
466                 perror(fname);
467         }
468 }
469
470 /**
471  * finishes the simple dumper
472  */
473 static void simple_finish(dumper_t *dmp)
474 {
475         if (dmp->f)
476                 fclose(dmp->f);
477         dmp->f = NULL;
478 }
479
480 /**
481  * the simple human readable dumper
482  */
483 const dumper_t simple_dumper = {
484         simple_dump_graph,
485         simple_dump_const_tbl,
486         simple_init,
487         simple_finish,
488         NULL,
489         NULL,
490         NULL,
491 };
492
493 /* ---------------------------------------------------------------------- */
494
495 /**
496  * count the nodes as needed:
497  *
498  * 1 normal (data) Phi's
499  * 2 memory Phi's
500  * 3 Proj
501  * 0 all other nodes
502  */
503 static void csv_count_nodes(dumper_t *dmp, graph_entry_t *graph, counter_t cnt[])
504 {
505         node_entry_t *entry;
506         int i;
507
508         for (i = 0; i < 4; ++i)
509                 cnt_clr(&cnt[i]);
510
511         foreach_pset(graph->opcode_hash, entry) {
512                 if (entry->op == op_Phi) {
513                         /* normal Phi */
514                         cnt_add(&cnt[1], &entry->cnt_alive);
515                 }
516                 else if (entry->op == dmp->status->op_PhiM) {
517                         /* memory Phi */
518                         cnt_add(&cnt[2], &entry->cnt_alive);
519                 }
520                 else if (entry->op == op_Proj) {
521                         /* Proj */
522                         cnt_add(&cnt[3], &entry->cnt_alive);
523                 }
524                 else {
525                         /* all other nodes */
526                         cnt_add(&cnt[0], &entry->cnt_alive);
527                 }
528         }
529 }
530
531 /**
532  * dumps the IRG
533  */
534 static void csv_dump_graph(dumper_t *dmp, graph_entry_t *entry)
535 {
536         const char *name;
537         counter_t cnt[4];
538
539         if (! dmp->f)
540                 return;
541
542         if (entry->irg && !entry->is_deleted) {
543                 ir_graph *const_irg = get_const_code_irg();
544
545                 if (entry->irg == const_irg) {
546                         name = "<Const code Irg>";
547                         return;
548                 }
549                 else {
550                         if (entry->ent)
551                                 name = get_entity_name(entry->ent);
552                         else
553                                 name = "<UNKNOWN IRG>";
554                 }
555
556                 csv_count_nodes(dmp, entry, cnt);
557
558                 fprintf(dmp->f, "%-40s, %p, %d, %d, %d, %d\n",
559                         name,
560                         (void *)entry->irg,
561                         cnt_to_uint(&cnt[0]),
562                         cnt_to_uint(&cnt[1]),
563                         cnt_to_uint(&cnt[2]),
564                         cnt_to_uint(&cnt[3])
565                 );
566         }
567 }
568
569 /**
570  * dumps the IRG
571  */
572 static void csv_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
573 {
574         /* FIXME: NYI */
575 }
576
577 /**
578  * initialize the simple dumper
579  */
580 static void csv_init(dumper_t *dmp, const char *name)
581 {
582         char fname[2048];
583
584         snprintf(fname, sizeof(fname), "%s.csv", name);
585         dmp->f = fopen(fname, "a");
586         if (! dmp->f)
587                 perror(fname);
588 }
589
590 /**
591  * finishes the simple dumper
592  */
593 static void csv_finish(dumper_t *dmp)
594 {
595         if (dmp->f)
596                 fclose(dmp->f);
597         dmp->f = NULL;
598 }
599
600 /**
601  * the simple human readable dumper
602  */
603 const dumper_t csv_dumper = {
604         csv_dump_graph,
605         csv_dump_const_tbl,
606         csv_init,
607         csv_finish,
608         NULL,
609         NULL,
610         NULL,
611 };