added permutations statistics
[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         for (entry = pset_first(set); entry; entry = pset_next(set)) {
117                 fprintf(dmp->f, "%-16s %8u %8u %8u\n",
118                         get_id_str(entry->op->name), entry->cnt_alive.cnt[0], entry->new_node.cnt[0], entry->into_Id.cnt[0]);
119
120                 cnt_add(&f_alive,    &entry->cnt_alive);
121                 cnt_add(&f_new_node, &entry->new_node);
122                 cnt_add(&f_Id,       &entry->into_Id);
123         }
124         fprintf(dmp->f, "-------------------------------------------\n");
125         fprintf(dmp->f, "%-16s %8u %8u %8u\n", "Sum",
126                 f_alive.cnt[0],
127                 f_new_node.cnt[0],
128                 f_Id.cnt[0]);
129 }
130
131 /**
132  * dumps an optimization hash into human readable form
133  */
134 static void simple_dump_opt_hash(dumper_t *dmp, pset *set, int index)
135 {
136         opt_entry_t *entry = pset_first(set);
137
138         assert(index < ARR_SIZE(opt_names) && "index out of range");
139         assert(opt_names[index].kind == index && "opt_names broken");
140         if (entry) {
141                 fprintf(dmp->f, "\n%s:\n", opt_names[index].name);
142                 fprintf(dmp->f, "%-16s %-8s\n", "Opcode", "deref");
143
144                 for (; entry; entry = pset_next(set)) {
145                         fprintf(dmp->f, "%-16s %8u\n",
146                                 get_id_str(entry->op->name), entry->count.cnt[0]);
147                 }
148         }
149 }
150
151 /**
152  * dumps the register pressure for each block and for each register class
153  */
154 static void simple_dump_be_block_reg_pressure(dumper_t *dmp, graph_entry_t *entry)
155 {
156         be_block_entry_t     *b_entry = pset_first(entry->be_block_hash);
157         reg_pressure_entry_t *rp_entry;
158
159         /* return if no be statistic information available */
160         if (! b_entry)
161                 return;
162
163         fprintf(dmp->f, "\nREG PRESSURE:\n");
164         fprintf(dmp->f, "%12s", "Block Nr");
165
166         /* print table head (register class names) */
167         for (rp_entry = pset_first(b_entry->reg_pressure);
168              rp_entry;
169              rp_entry = pset_next(b_entry->reg_pressure))
170         {
171                 fprintf(dmp->f, "%15s", get_id_str(rp_entry->id_name));
172         }
173         fprintf(dmp->f, "\n");
174
175         /* print the reg pressure for all blocks and register classes */
176         for (/* b_entry is already initialized */ ;
177          b_entry;
178              b_entry = pset_next(entry->be_block_hash))
179         {
180                 fprintf(dmp->f, "BLK   %6ld", b_entry->block_nr);
181
182                 for (rp_entry = pset_first(b_entry->reg_pressure);
183                      rp_entry;
184                      rp_entry = pset_next(b_entry->reg_pressure))
185                 {
186                         fprintf(dmp->f, "%15d", rp_entry->pressure);
187                 }
188                 fprintf(dmp->f, "\n");
189         }
190 }
191
192 /** prints a distribution entry */
193 void dump_block_sched_ready_distrib(const distrib_entry_t *entry, void *env)
194 {
195         FILE *dmp_f = env;
196         fprintf(dmp_f, "%12d", entry->cnt.cnt[0]);
197 }
198
199 /**
200  * dumps the distribution of the amount of ready nodes for each block
201  */
202 static void simple_dump_be_block_sched_ready(dumper_t *dmp, graph_entry_t *entry)
203 {
204         be_block_entry_t *b_entry = pset_first(entry->be_block_hash);
205         const counter_t  *cnt_0   = cnt_get_0();
206         int               i;
207
208         /* return if no be statistic information available */
209         if (! b_entry)
210                 return;
211
212         fprintf(dmp->f, "\nSCHEDULING: NUMBER OF READY NODES\n");
213         fprintf(dmp->f, "%12s %12s %12s %12s %12s %12s %12s\n",
214                 "Block Nr", "1 node", "2 nodes", "3 nodes", "4 nodes", "5 or more", "AVERAGE");
215
216         for (/* b_entry is already initialized */ ;
217              b_entry;
218              b_entry = pset_next(entry->be_block_hash))
219         {
220                 /* this ensures that all keys from 1 to 5 are in the table */
221                 for (i = 1; i < 6; i++)
222                         stat_add_int_distrib_tbl(b_entry->sched_ready, i, cnt_0);
223
224                 fprintf(dmp->f, "BLK   %6ld", b_entry->block_nr);
225                 stat_iterate_distrib_tbl(b_entry->sched_ready, dump_block_sched_ready_distrib, dmp->f);
226                 fprintf(dmp->f, "%12.2lf", stat_calc_avg_distrib_tbl(b_entry->sched_ready));
227                 fprintf(dmp->f, "\n");
228         }
229 }
230
231 /**
232  * dumps permutation statistics for one and block and one class
233  */
234 static void simple_dump_be_block_permstat_class(dumper_t *dmp, perm_class_entry_t *entry)
235 {
236         perm_stat_entry_t *ps_ent;
237
238         fprintf(dmp->f, "%12s %12s\n", "size", "real size");
239         for (ps_ent = pset_first(entry->perm_stat);
240              ps_ent;
241              ps_ent = pset_next(entry->perm_stat))
242         {
243                 fprintf(dmp->f, "%12d %12d\n", ps_ent->size, ps_ent->real_size);
244         }
245 }
246
247 /**
248  * dumps statistics about perms
249  */
250 static void simple_dump_be_block_permstat(dumper_t *dmp, graph_entry_t *entry)
251 {
252         be_block_entry_t *b_entry = pset_first(entry->be_block_hash);
253
254         /* return if no be statistic information available */
255         if (! b_entry)
256                 return;
257
258         fprintf(dmp->f, "\nPERMUTATION STATISTICS BEGIN:\n");
259         for (/* b_entry is already initialized */ ;
260              b_entry;
261              b_entry = pset_next(entry->be_block_hash))
262         {
263                 perm_class_entry_t *pc_ent;
264
265                 fprintf(dmp->f, "BLOCK %ld:\n", b_entry->block_nr);
266
267                 if (! b_entry->perm_class_stat)
268                         continue;
269
270                 for (pc_ent = pset_first(b_entry->perm_class_stat);
271                      pc_ent;
272                      pc_ent = pset_next(b_entry->perm_class_stat))
273                 {
274                         fprintf(dmp->f, "register class %s:\n", get_id_str(pc_ent->id_name));
275                         simple_dump_be_block_permstat_class(dmp, pc_ent);
276                 }
277         }
278
279         fprintf(dmp->f, "PERMUTATION STATISTICS END\n");
280 }
281
282 /**
283  * dumps the number of real_function_call optimization
284  */
285 static void simple_dump_real_func_calls(dumper_t *dmp, counter_t *cnt)
286 {
287         if (! dmp->f)
288                 return;
289
290         if (! cnt_eq(cnt, 0)) {
291                 fprintf(dmp->f, "\nReal Function Calls optimized:\n");
292                 fprintf(dmp->f, "%-16s %8u\n", "Call", cnt->cnt[0]);
293         }
294 }
295
296 /**
297  * dumps the number of tail_recursion optimization
298  */
299 static void simple_dump_tail_recursion(dumper_t *dmp, unsigned num_tail_recursion)
300 {
301         if (! dmp->f)
302                 return;
303
304         if (num_tail_recursion > 0) {
305                 fprintf(dmp->f, "\nTail recursion optimized:\n");
306                 fprintf(dmp->f, "%-16s %8u\n", "Call", num_tail_recursion);
307         }
308 }
309
310 /**
311  * dumps the edges count
312  */
313 static void simple_dump_edges(dumper_t *dmp, counter_t *cnt)
314 {
315         if (! dmp->f)
316                 return;
317
318         fprintf(dmp->f, "%-16s %8d\n", "Edges", cnt->cnt[0]);
319 }
320
321 /**
322  * dumps the IRG
323  */
324 static void simple_dump_graph(dumper_t *dmp, graph_entry_t *entry)
325 {
326         int i, dump_opts = 1;
327         block_entry_t *b_entry;
328         extbb_entry_t *eb_entry;
329
330         if (! dmp->f)
331                 return;
332
333         if (entry->irg) {
334                 ir_graph *const_irg = get_const_code_irg();
335
336                 if (entry->irg == const_irg) {
337                         fprintf(dmp->f, "\nConst code Irg %p", (void *)entry->irg);
338                 }
339                 else {
340                         if (entry->ent)
341                                 fprintf(dmp->f, "\nEntity %s, Irg %p", get_entity_ld_name(entry->ent), (void *)entry->irg);
342                         else
343                                 fprintf(dmp->f, "\nIrg %p", (void *)entry->irg);
344                 }
345
346                 fprintf(dmp->f, " %swalked %u over blocks %u:\n"
347                         " was inlined               : %u\n"
348                         " got inlined               : %u\n"
349                         " strength red              : %u\n"
350                         " leaf function             : %s\n"
351                         " calls only leaf functions : %s\n"
352                         " recursive                 : %s\n"
353                         " chain call                : %s\n"
354                         " calls                     : %u\n"
355                         " indirect calls            : %u\n",
356                         entry->is_deleted ? "DELETED " : "",
357                         entry->cnt_walked.cnt[0], entry->cnt_walked_blocks.cnt[0],
358                         entry->cnt_was_inlined.cnt[0],
359                         entry->cnt_got_inlined.cnt[0],
360                         entry->cnt_strength_red.cnt[0],
361                         entry->is_leaf ? "YES" : "NO",
362                         entry->is_leaf_call == LCS_NON_LEAF_CALL ? "NO" : (entry->is_leaf_call == LCS_LEAF_CALL ? "Yes" : "Maybe"),
363                         entry->is_recursive ? "YES" : "NO",
364                         entry->is_chain_call ? "YES" : "NO",
365                         entry->cnt_all_calls.cnt[0],
366                         entry->cnt_indirect_calls.cnt[0]
367                 );
368
369                 for (i = 0; i < sizeof(entry->cnt_if_conv)/sizeof(entry->cnt_if_conv[0]); ++i) {
370                         fprintf(dmp->f, " %s : %u\n", if_conv_names[i], entry->cnt_if_conv[i].cnt[0]);
371                 }
372
373         }
374         else {
375                 fprintf(dmp->f, "\nGlobals counts:\n");
376                 fprintf(dmp->f, "--------------\n");
377                 dump_opts = 0;
378         }
379
380         simple_dump_opcode_hash(dmp, entry->opcode_hash);
381         simple_dump_edges(dmp, &entry->cnt_edges);
382
383         /* effects of optimizations */
384         if (dump_opts) {
385                 int i;
386
387                 simple_dump_real_func_calls(dmp, &entry->cnt_real_func_call);
388                 simple_dump_tail_recursion(dmp, entry->num_tail_recursion);
389
390                 for (i = 0; i < sizeof(entry->opt_hash)/sizeof(entry->opt_hash[0]); ++i) {
391                         simple_dump_opt_hash(dmp, entry->opt_hash[i], i);
392                 }
393
394                 /* dump block info */
395                 fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s %12s\n", "Block Nr", "Nodes", "intern E", "incoming E", "outgoing E", "Phi", "quot");
396                 for (b_entry = pset_first(entry->block_hash);
397                      b_entry;
398                      b_entry = pset_next(entry->block_hash))
399                 {
400                         fprintf(dmp->f, "BLK   %6ld %12u %12u %12u %12u %12u %4.8f\n",
401                                 b_entry->block_nr,
402                                 b_entry->cnt_nodes.cnt[0],
403                                 b_entry->cnt_edges.cnt[0],
404                                 b_entry->cnt_in_edges.cnt[0],
405                                 b_entry->cnt_out_edges.cnt[0],
406                                 b_entry->cnt_phi_data.cnt[0],
407                                 (double)b_entry->cnt_edges.cnt[0] / (double)b_entry->cnt_nodes.cnt[0]
408                         );
409                 }
410
411                 /* dump block reg pressure */
412                 simple_dump_be_block_reg_pressure(dmp, entry);
413
414                 /* dump block ready nodes distribution */
415                 simple_dump_be_block_sched_ready(dmp, entry);
416
417                 /* dump block permutation statistics */
418                 simple_dump_be_block_permstat(dmp, entry);
419
420                 if (dmp->status->stat_options & FIRMSTAT_COUNT_EXTBB) {
421                         /* dump extended block info */
422                         fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s %12s\n", "Extbb Nr", "Nodes", "intern E", "incoming E", "outgoing E", "Phi", "quot");
423                         for (eb_entry = pset_first(entry->extbb_hash);
424                              eb_entry;
425                              eb_entry = pset_next(entry->extbb_hash))
426                         {
427                                 fprintf(dmp->f, "ExtBB %6ld %12u %12u %12u %12u %12u %4.8f\n",
428                                         eb_entry->block_nr,
429                                         eb_entry->cnt_nodes.cnt[0],
430                                         eb_entry->cnt_edges.cnt[0],
431                                         eb_entry->cnt_in_edges.cnt[0],
432                                         eb_entry->cnt_out_edges.cnt[0],
433                                         eb_entry->cnt_phi_data.cnt[0],
434                                         (double)eb_entry->cnt_edges.cnt[0] / (double)eb_entry->cnt_nodes.cnt[0]
435                                 );
436                         }
437                 }
438         }
439 }
440
441 /**
442  * dumps the IRG
443  */
444 static void simple_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
445 {
446         int i;
447         counter_t sum;
448
449         if (! dmp->f)
450                 return;
451
452         cnt_clr(&sum);
453
454         fprintf(dmp->f, "\nConstant Information:\n");
455         fprintf(dmp->f, "---------------------\n");
456
457         fprintf(dmp->f, "\nBit usage for integer constants\n");
458         fprintf(dmp->f, "-------------------------------\n");
459
460         for (i = 0; i < ARR_SIZE(tbl->int_bits_count); ++i) {
461                 fprintf(dmp->f, "%5d %12u\n", i + 1, tbl->int_bits_count[i].cnt[0]);
462                 cnt_add(&sum, &tbl->int_bits_count[i]);
463         }
464         fprintf(dmp->f, "-------------------------------\n");
465
466         fprintf(dmp->f, "\nFloating point constants classification\n");
467         fprintf(dmp->f, "--------------------------------------\n");
468         for (i = 0; i < ARR_SIZE(tbl->floats); ++i) {
469                 fprintf(dmp->f, "%-10s %12u\n", stat_fc_name(i), tbl->floats[i].cnt[0]);
470                 cnt_add(&sum, &tbl->floats[i]);
471         }
472         fprintf(dmp->f, "--------------------------------------\n");
473
474         fprintf(dmp->f, "other %12u\n", tbl->others.cnt[0]);
475         cnt_add(&sum, &tbl->others);
476         fprintf(dmp->f, "-------------------------------\n");
477
478         fprintf(dmp->f, "sum   %12u\n", sum.cnt[0]);
479 }
480
481 /**
482  * initialize the simple dumper
483  */
484 static void simple_init(dumper_t *dmp, const char *name)
485 {
486         char fname[2048];
487
488         snprintf(fname, sizeof(fname), "%s.txt", name);
489         dmp->f = fopen(fname, "w");
490         if (! dmp->f) {
491                 perror(fname);
492         }
493 }
494
495 /**
496  * finishes the simple dumper
497  */
498 static void simple_finish(dumper_t *dmp)
499 {
500         if (dmp->f)
501                 fclose(dmp->f);
502         dmp->f = NULL;
503 }
504
505 /**
506  * the simple human readable dumper
507  */
508 const dumper_t simple_dumper = {
509         simple_dump_graph,
510         simple_dump_const_tbl,
511         simple_init,
512         simple_finish,
513         NULL,
514         NULL,
515         NULL,
516 };
517
518 /* ---------------------------------------------------------------------- */
519
520 /**
521  * count the nodes as needed:
522  *
523  * 1 normal (data) Phi's
524  * 2 memory Phi's
525  * 3 Proj
526  * 0 all other nodes
527  */
528 static void csv_count_nodes(dumper_t *dmp, graph_entry_t *graph, counter_t cnt[])
529 {
530         node_entry_t *entry;
531         int i;
532
533         for (i = 0; i < 4; ++i)
534                 cnt_clr(&cnt[i]);
535
536         for (entry = pset_first(graph->opcode_hash); entry; entry = pset_next(graph->opcode_hash)) {
537                 if (entry->op == op_Phi) {
538                         /* normal Phi */
539                         cnt_add(&cnt[1], &entry->cnt_alive);
540                 }
541                 else if (entry->op == dmp->status->op_PhiM) {
542                         /* memory Phi */
543                         cnt_add(&cnt[2], &entry->cnt_alive);
544                 }
545                 else if (entry->op == op_Proj) {
546                         /* Proj */
547                         cnt_add(&cnt[3], &entry->cnt_alive);
548                 }
549                 else {
550                         /* all other nodes */
551                         cnt_add(&cnt[0], &entry->cnt_alive);
552                 }
553         }
554 }
555
556 /**
557  * dumps the IRG
558  */
559 static void csv_dump_graph(dumper_t *dmp, graph_entry_t *entry)
560 {
561         const char *name;
562         counter_t cnt[4];
563
564         if (! dmp->f)
565                 return;
566
567         if (entry->irg && !entry->is_deleted) {
568                 ir_graph *const_irg = get_const_code_irg();
569
570                 if (entry->irg == const_irg) {
571                         name = "<Const code Irg>";
572                         return;
573                 }
574                 else {
575                         if (entry->ent)
576                                 name = get_entity_name(entry->ent);
577                         else
578                                 name = "<UNKNOWN IRG>";
579                 }
580
581                 csv_count_nodes(dmp, entry, cnt);
582
583                 fprintf(dmp->f, "%-40s, %p, %d, %d, %d, %d\n",
584                         name,
585                         (void *)entry->irg,
586                         cnt[0].cnt[0],
587                         cnt[1].cnt[0],
588                         cnt[2].cnt[0],
589                         cnt[3].cnt[0]
590                 );
591         }
592 }
593
594 /**
595  * dumps the IRG
596  */
597 static void csv_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
598 {
599         /* FIXME: NYI */
600 }
601
602 /**
603  * initialize the simple dumper
604  */
605 static void csv_init(dumper_t *dmp, const char *name)
606 {
607         char fname[2048];
608
609         snprintf(fname, sizeof(fname), "%s.csv", name);
610         dmp->f = fopen(fname, "a");
611         if (! dmp->f) {
612                 perror(fname);
613         }
614 }
615
616 /**
617  * finishes the simple dumper
618  */
619 static void csv_finish(dumper_t *dmp)
620 {
621         if (dmp->f)
622                 fclose(dmp->f);
623         dmp->f = NULL;
624 }
625
626 /**
627  * the simple human readable dumper
628  */
629 const dumper_t csv_dumper = {
630         csv_dump_graph,
631         csv_dump_const_tbl,
632         csv_init,
633         csv_finish,
634         NULL,
635         NULL,
636         NULL,
637 };