doxygen comment updated
[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         }  /* foreach_pset */
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 }  /* simple_dump_opcode_hash */
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                 }  /* foreach_pset */
156         }  /* if */
157 }  /* simple_dump_opt_hash */
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         }  /* for */
189 }  /* simple_dump_be_block_reg_pressure */
190
191 /** prints a distribution entry */
192 static void simple_dump_distrib_entry(const distrib_entry_t *entry, void *env) {
193         FILE *dmp_f = env;
194         fprintf(dmp_f, "%12d", cnt_to_uint(&entry->cnt));
195 }  /* simple_dump_distrib_entry */
196
197 /**
198  * dumps the distribution of the amount of ready nodes for each block
199  */
200 static void simple_dump_be_block_sched_ready(dumper_t *dmp, graph_entry_t *entry)
201 {
202         if (pset_count(entry->be_block_hash) > 0) {
203                 be_block_entry_t *b_entry;
204                 int              i;
205
206                 fprintf(dmp->f, "\nSCHEDULING: NUMBER OF READY NODES\n");
207                 fprintf(dmp->f, "%12s %12s %12s %12s %12s %12s %12s\n",
208                         "Block Nr", "1 node", "2 nodes", "3 nodes", "4 nodes", "5 or more", "AVERAGE");
209
210                 foreach_pset(entry->be_block_hash, b_entry) {
211                         /* this ensures that all keys from 1 to 5 are in the table */
212                         for (i = 1; i < 6; ++i)
213                                 stat_insert_int_distrib_tbl(b_entry->sched_ready, i);
214
215                         fprintf(dmp->f, "BLK   %6ld", b_entry->block_nr);
216                         stat_iterate_distrib_tbl(b_entry->sched_ready, simple_dump_distrib_entry, dmp->f);
217                         fprintf(dmp->f, "%12.2lf", stat_calc_avg_distrib_tbl(b_entry->sched_ready));
218                         fprintf(dmp->f, "\n");
219                 }  /* foreach_pset */
220         }  /* if */
221 }  /* simple_dump_be_block_sched_ready */
222
223 /**
224  * Adds the counter for given entry to another distribution table.
225  */
226 static void add_distrib_entry(const distrib_entry_t *entry, void *env) {
227         distrib_tbl_t *sum_tbl = env;
228
229         stat_add_int_distrib_tbl(sum_tbl, (int)(entry->object), &entry->cnt);
230 }  /* add_distrib_entry */
231
232 /**
233  * dumps permutation statistics for one and block and one class
234  */
235 static void simple_dump_be_block_permstat_class(dumper_t *dmp, perm_class_entry_t *entry)
236 {
237         perm_stat_entry_t *ps_ent;
238         distrib_tbl_t     *sum_chains = stat_new_int_distrib_tbl();
239         distrib_tbl_t     *sum_cycles = stat_new_int_distrib_tbl();
240         char              buf[16];
241         int               i;
242
243         fprintf(dmp->f, "%12s %12s %12s %12s %12s %12s\n",
244                 "size",
245                 "real size",
246                 "# chains",
247                 "# cycles",
248                 "# copies",
249                 "# exchanges"
250         );
251
252         foreach_pset(entry->perm_stat, ps_ent) {
253                 fprintf(dmp->f, "%12d %12d %12d %12d %12d %12d\n",
254                         ps_ent->size,
255                         ps_ent->real_size,
256                         stat_get_count_distrib_tbl(ps_ent->chains),
257                         stat_get_count_distrib_tbl(ps_ent->cycles),
258                         ps_ent->n_copies,
259                         ps_ent->n_exchg
260                 );
261
262                 /* sum up distribution table for chains */
263                 stat_iterate_distrib_tbl(ps_ent->chains, add_distrib_entry, sum_chains);
264
265                 /* sum up distribution table for cycles */
266                 stat_iterate_distrib_tbl(ps_ent->cycles, add_distrib_entry, sum_cycles);
267         }  /* foreach_pset */
268
269         /* print chain distribution for all perms of this class in this block */
270         fprintf(dmp->f, "chain distribution:\n");
271
272         /* add all missing entries to chain distribution table */
273         for (i = 1; i <= entry->n_regs; i++) {
274                 snprintf(buf, sizeof(buf), "length %d", i);
275                 fprintf(dmp->f, "%12s", buf);
276                 stat_insert_int_distrib_tbl(sum_chains, i);
277         }  /* for */
278         fprintf(dmp->f, "\n");
279         stat_iterate_distrib_tbl(sum_chains, simple_dump_distrib_entry, dmp->f);
280         fprintf(dmp->f, "\n");
281
282         /* print cycle distribution for all perms of this class in this block */
283         fprintf(dmp->f, "cycle distribution:\n");
284
285         /* add all missing entries to cycle distribution table */
286         for (i = 1; i <= entry->n_regs; i++) {
287                 snprintf(buf, sizeof(buf), "length %d", i);
288                 fprintf(dmp->f, "%12s", buf);
289                 stat_insert_int_distrib_tbl(sum_cycles, i);
290         }  /* for */
291         fprintf(dmp->f, "\n");
292         stat_iterate_distrib_tbl(sum_cycles, simple_dump_distrib_entry, dmp->f);
293         fprintf(dmp->f, "\n");
294
295         /* delete temporary sum distribution tables */
296         stat_delete_distrib_tbl(sum_chains);
297         stat_delete_distrib_tbl(sum_cycles);
298
299 }  /* simple_dump_be_block_permstat_class */
300
301 /**
302  * dumps statistics about perms
303  */
304 static void simple_dump_be_block_permstat(dumper_t *dmp, graph_entry_t *entry)
305 {
306         if (pset_count(entry->be_block_hash) > 0) {
307                 be_block_entry_t *b_entry;
308
309                 fprintf(dmp->f, "\nPERMUTATION STATISTICS BEGIN:\n");
310                 foreach_pset(entry->be_block_hash, b_entry) {
311                         perm_class_entry_t *pc_ent;
312
313                         fprintf(dmp->f, "BLOCK %ld:\n", b_entry->block_nr);
314
315                         if (b_entry->perm_class_stat) {
316                                 foreach_pset(b_entry->perm_class_stat, pc_ent) {
317                                         fprintf(dmp->f, "register class %s:\n", pc_ent->class_name);
318                                         simple_dump_be_block_permstat_class(dmp, pc_ent);
319                                 }  /* foreach_pset */
320                         }  /* if */
321                 }  /* foreach_pset */
322
323                 fprintf(dmp->f, "PERMUTATION STATISTICS END\n");
324         }  /* if */
325 }  /* simple_dump_be_block_permstat */
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         }  /* if */
339 }  /* simple_dump_real_func_calls */
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         }  /* if */
353 }  /* simple_dump_tail_recursion */
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 }  /* simple_dump_edges */
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                 }  /* if */
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[gcnt_acc_walked]), cnt_to_uint(&entry->cnt[gcnt_acc_walked_blocks]),
402                         cnt_to_uint(&entry->cnt[gcnt_acc_was_inlined]),
403                         cnt_to_uint(&entry->cnt[gcnt_acc_got_inlined]),
404                         cnt_to_uint(&entry->cnt[gcnt_acc_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[gcnt_all_calls]),
410                         cnt_to_uint(&entry->cnt[gcnt_indirect_calls])
411                 );
412
413                 for (i = 0; i < IF_RESULT_LAST; ++i) {
414                         fprintf(dmp->f, " %s : %u\n", if_conv_names[i], cnt_to_uint(&entry->cnt[gcnt_if_conv + i]));
415                 }  /* for */
416         } else {
417                 fprintf(dmp->f, "\nGlobals counts:\n");
418                 fprintf(dmp->f, "--------------\n");
419                 dump_opts = 0;
420         }  /* if */
421
422         /* address ops */
423         fprintf(dmp->f,
424                 " pure address calc ops     : %u\n"
425                 " all address calc ops      : %u\n",
426                 cnt_to_uint(&entry->cnt[gcnt_pure_adr_ops]),
427                 cnt_to_uint(&entry->cnt[gcnt_all_adr_ops])
428         );
429
430         /* Load/Store address classification */
431         fprintf(dmp->f,
432                 " global Ld/St address      : %u\n"
433                 " local Ld/St address       : %u\n"
434                 " this Ld/St address        : %u\n"
435                 " param Ld/St address       : %u\n"
436                 " other Ld/St address       : %u\n",
437                 cnt_to_uint(&entry->cnt[gcnt_global_adr]),
438                 cnt_to_uint(&entry->cnt[gcnt_local_adr]),
439                 cnt_to_uint(&entry->cnt[gcnt_this_adr]),
440                 cnt_to_uint(&entry->cnt[gcnt_param_adr]),
441                 cnt_to_uint(&entry->cnt[gcnt_other_adr])
442         );
443
444         simple_dump_opcode_hash(dmp, entry->opcode_hash);
445         simple_dump_edges(dmp, &entry->cnt[gcnt_edges]);
446
447         /* effects of optimizations */
448         if (dump_opts) {
449                 int i;
450
451                 simple_dump_real_func_calls(dmp, &entry->cnt[gcnt_acc_real_func_call]);
452                 simple_dump_tail_recursion(dmp, entry->num_tail_recursion);
453
454                 for (i = 0; i < sizeof(entry->opt_hash)/sizeof(entry->opt_hash[0]); ++i) {
455                         simple_dump_opt_hash(dmp, entry->opt_hash[i], i);
456                 }  /* for */
457
458                 /* dump block info */
459                 fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s %12s\n", "Block Nr", "Nodes", "intern E", "incoming E", "outgoing E", "Phi", "quot");
460                 foreach_pset(entry->block_hash, b_entry) {
461                         fprintf(dmp->f, "BLK   %6ld %12u %12u %12u %12u %12u %4.8f\n",
462                                 b_entry->block_nr,
463                                 cnt_to_uint(&b_entry->cnt[bcnt_nodes]),
464                                 cnt_to_uint(&b_entry->cnt[bcnt_edges]),
465                                 cnt_to_uint(&b_entry->cnt[bcnt_in_edges]),
466                                 cnt_to_uint(&b_entry->cnt[bcnt_out_edges]),
467                                 cnt_to_uint(&b_entry->cnt[bcnt_phi_data]),
468                                 cnt_to_dbl(&b_entry->cnt[bcnt_edges]) / cnt_to_dbl(&b_entry->cnt[bcnt_nodes])
469                         );
470                 }  /* foreach_pset */
471
472                 /* dump block reg pressure */
473                 simple_dump_be_block_reg_pressure(dmp, entry);
474
475                 /* dump block ready nodes distribution */
476                 simple_dump_be_block_sched_ready(dmp, entry);
477
478                 /* dump block permutation statistics */
479                 simple_dump_be_block_permstat(dmp, entry);
480
481                 if (dmp->status->stat_options & FIRMSTAT_COUNT_EXTBB && entry->extbb_hash) {
482                         /* dump extended block info */
483                         fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s %12s\n", "Extbb Nr", "Nodes", "intern E", "incoming E", "outgoing E", "Phi", "quot");
484                         foreach_pset(entry->extbb_hash, eb_entry) {
485                                 fprintf(dmp->f, "ExtBB %6ld %12u %12u %12u %12u %12u %4.8f\n",
486                                         eb_entry->block_nr,
487                                         cnt_to_uint(&eb_entry->cnt[bcnt_nodes]),
488                                         cnt_to_uint(&eb_entry->cnt[bcnt_edges]),
489                                         cnt_to_uint(&eb_entry->cnt[bcnt_in_edges]),
490                                         cnt_to_uint(&eb_entry->cnt[bcnt_out_edges]),
491                                         cnt_to_uint(&eb_entry->cnt[bcnt_phi_data]),
492                                         cnt_to_dbl(&eb_entry->cnt[bcnt_edges]) / cnt_to_dbl(&eb_entry->cnt[bcnt_nodes])
493                                 );
494                         }  /* foreach_pset */
495                 }  /* if */
496         }
497 }  /* simple_dump_graph */
498
499 /**
500  * dumps the constant table
501  */
502 static void simple_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
503 {
504         int i;
505         counter_t sum;
506
507         if (! dmp->f)
508                 return;
509
510         cnt_clr(&sum);
511
512         fprintf(dmp->f, "\nConstant Information:\n");
513         fprintf(dmp->f, "---------------------\n");
514
515         fprintf(dmp->f, "\nBit usage for integer constants\n");
516         fprintf(dmp->f, "-------------------------------\n");
517
518         for (i = 0; i < ARR_SIZE(tbl->int_bits_count); ++i) {
519                 fprintf(dmp->f, "%5d %12u\n", i + 1, cnt_to_uint(&tbl->int_bits_count[i]));
520                 cnt_add(&sum, &tbl->int_bits_count[i]);
521         }  /* for */
522         fprintf(dmp->f, "-------------------------------\n");
523
524         fprintf(dmp->f, "\nFloating point constants classification\n");
525         fprintf(dmp->f, "--------------------------------------\n");
526         for (i = 0; i < ARR_SIZE(tbl->floats); ++i) {
527                 fprintf(dmp->f, "%-10s %12u\n", stat_fc_name(i), cnt_to_uint(&tbl->floats[i]));
528                 cnt_add(&sum, &tbl->floats[i]);
529         }  /* for */
530         fprintf(dmp->f, "--------------------------------------\n");
531
532         fprintf(dmp->f, "other %12u\n", cnt_to_uint(&tbl->others));
533         cnt_add(&sum, &tbl->others);
534         fprintf(dmp->f, "-------------------------------\n");
535
536         fprintf(dmp->f, "sum   %12u\n", cnt_to_uint(&sum));
537 }  /* simple_dump_const_tbl */
538
539 /**
540  * initialize the simple dumper
541  */
542 static void simple_init(dumper_t *dmp, const char *name) {
543         char fname[2048];
544
545         snprintf(fname, sizeof(fname), "%s.txt", name);
546         dmp->f = fopen(fname, "w");
547         if (! dmp->f) {
548                 perror(fname);
549         }  /* if */
550 }  /* simple_init */
551
552 /**
553  * finishes the simple dumper
554  */
555 static void simple_finish(dumper_t *dmp) {
556         if (dmp->f)
557                 fclose(dmp->f);
558         dmp->f = NULL;
559 }  /* simple_finish */
560
561 /**
562  * the simple human readable dumper
563  */
564 const dumper_t simple_dumper = {
565         simple_dump_graph,
566         simple_dump_const_tbl,
567         simple_init,
568         simple_finish,
569         NULL,
570         NULL,
571         NULL,
572         NULL,
573         FOURCC('S', 'M', 'P', 'L'),
574 };
575
576 /* ---------------------------------------------------------------------- */
577
578 /**
579  * count the nodes as needed:
580  *
581  * 1 normal (data) Phi's
582  * 2 memory Phi's
583  * 3 Proj
584  * 0 all other nodes
585  */
586 static void csv_count_nodes(dumper_t *dmp, graph_entry_t *graph, counter_t cnt[])
587 {
588         node_entry_t *entry;
589         int i;
590
591         for (i = 0; i < 4; ++i)
592                 cnt_clr(&cnt[i]);
593
594         foreach_pset(graph->opcode_hash, entry) {
595                 if (entry->op == op_Phi) {
596                         /* normal Phi */
597                         cnt_add(&cnt[1], &entry->cnt_alive);
598                 } else if (entry->op == dmp->status->op_PhiM) {
599                         /* memory Phi */
600                         cnt_add(&cnt[2], &entry->cnt_alive);
601                 } else if (entry->op == op_Proj) {
602                         /* Proj */
603                         cnt_add(&cnt[3], &entry->cnt_alive);
604                 } else {
605                         /* all other nodes */
606                         cnt_add(&cnt[0], &entry->cnt_alive);
607                 }  /* if */
608         }  /* foreach_pset */
609 }  /* csv_count_nodes */
610
611 /**
612  * dumps the IRG
613  */
614 static void csv_dump_graph(dumper_t *dmp, graph_entry_t *entry)
615 {
616         const char *name;
617         counter_t cnt[4];
618
619         if (! dmp->f)
620                 return;
621
622         if (entry->irg && !entry->is_deleted) {
623                 ir_graph *const_irg = get_const_code_irg();
624
625                 if (entry->irg == const_irg) {
626                         name = "<Const code Irg>";
627                         return;
628                 } else {
629                         if (entry->ent)
630                                 name = get_entity_name(entry->ent);
631                         else
632                                 name = "<UNKNOWN IRG>";
633                 }  /* if */
634
635                 csv_count_nodes(dmp, entry, cnt);
636
637                 fprintf(dmp->f, "%-40s, %p, %d, %d, %d, %d\n",
638                         name,
639                         (void *)entry->irg,
640                         cnt_to_uint(&cnt[0]),
641                         cnt_to_uint(&cnt[1]),
642                         cnt_to_uint(&cnt[2]),
643                         cnt_to_uint(&cnt[3])
644                 );
645         }  /* if */
646 }  /* csv_dump_graph */
647
648 /**
649  * dumps the IRG
650  */
651 static void csv_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
652 {
653         /* FIXME: NYI */
654 }  /* csv_dump_const_tbl */
655
656 /**
657  * initialize the simple dumper
658  */
659 static void csv_init(dumper_t *dmp, const char *name)
660 {
661         char fname[2048];
662
663         snprintf(fname, sizeof(fname), "%s.csv", name);
664         dmp->f = fopen(fname, "a");
665         if (! dmp->f)
666                 perror(fname);
667 }  /* csv_init */
668
669 /**
670  * finishes the simple dumper
671  */
672 static void csv_finish(dumper_t *dmp)
673 {
674         if (dmp->f)
675                 fclose(dmp->f);
676         dmp->f = NULL;
677 }  /* csv_finish */
678
679 /**
680  * the simple human readable dumper
681  */
682 const dumper_t csv_dumper = {
683         csv_dump_graph,
684         csv_dump_const_tbl,
685         csv_init,
686         csv_finish,
687         NULL,
688         NULL,
689         NULL,
690         NULL,
691         FOURCC('C', 'S', 'V', '\0')
692 };