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