add optimizations for Or,And,Eor and Shift
[libfirm] / ir / stat / stat_dmp.c
1 /*
2  * Copyright (C) 1995-2007 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19
20 /**
21  * @file
22  * @brief   Statistics for Firm. Dumping.
23  * @author  Michael Beck
24  * @version $Id$
25  */
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include "stat_dmp.h"
31 #include "irtools.h"
32 #include "irhooks.h"
33
34 /**
35  * names of the optimizations
36  */
37 static const struct {
38         hook_opt_kind kind;
39         const char    *name;
40 } opt_names[] = {
41         { HOOK_OPT_DEAD_BLOCK,   "dead block elimination" },
42         { HOOK_OPT_STG,          "straightening optimization" },
43         { HOOK_OPT_IFSIM,        "if simplification" },
44         { HOOK_OPT_CONST_EVAL,   "constant evaluation" },
45         { HOOK_OPT_ALGSIM,       "algebraic simplification" },
46         { HOOK_OPT_PHI,          "Phi optmization" },
47         { HOOK_OPT_SYNC,         "Sync optmization" },
48         { HOOK_OPT_WAW,          "Write-After-Write optimization" },
49         { HOOK_OPT_WAR,          "Write-After-Read optimization" },
50         { HOOK_OPT_RAW,          "Read-After-Write optimization" },
51         { HOOK_OPT_RAR,          "Read-After-Read optimization" },
52         { HOOK_OPT_RC,           "Read-a-Const optimization" },
53         { HOOK_OPT_TUPLE,        "Tuple optimization" },
54         { HOOK_OPT_ID,           "ID optimization" },
55         { HOOK_OPT_CSE,          "Common subexpression elimination" },
56         { HOOK_OPT_STRENGTH_RED, "Strength reduction" },
57         { HOOK_OPT_ARCH_DEP,     "Architecture dependant optimization" },
58         { HOOK_OPT_REASSOC,      "Reassociation optimization" },
59         { HOOK_OPT_POLY_CALL,    "Polymorphic call optimization" },
60         { HOOK_OPT_IF_CONV,      "an if conversion was tried" },
61         { HOOK_OPT_FUNC_CALL,    "Real function call optimization" },
62         { HOOK_OPT_CONFIRM,      "Confirm-based optimization: replacement" },
63         { HOOK_OPT_CONFIRM_C,    "Confirm-based optimization: replaced by const" },
64         { HOOK_OPT_CONFIRM_E,    "Confirm-based optimization: evaluated" },
65         { HOOK_OPT_EXC_REM,      "a exception edge was removed due to a Confirmation prove" },
66         { HOOK_LOWERED,          "Lowered" },
67         { HOOK_BACKEND,          "Backend transformation" },
68         { FS_OPT_NEUTRAL_0,      "algebraic simplification: a op 0 = 0 op a = a" },
69         { FS_OPT_NEUTRAL_1,      "algebraic simplification: a op 1 = 1 op a = a" },
70         { FS_OPT_ADD_A_A,        "algebraic simplification: a + a = a * 2" },
71         { FS_OPT_ADD_A_MINUS_B,  "algebraic simplification: a + -b = a - b" },
72         { FS_OPT_ADD_SUB,        "algebraic simplification: (a + x) - x = (a - x) + x = a" },
73         { FS_OPT_ADD_MUL_A_X_A,  "algebraic simplification: a * x + a = a * (x + 1)" },
74         { FS_OPT_SUB_0_A,        "algebraic simplification: 0 - a = -a" },
75         { FS_OPT_SUB_MUL_A_X_A,  "algebraic simplification: a * x - a = a * (x - 1)" },
76         { FS_OPT_SUB_SUB_X_Y_Z,  "algebraic simplification: (x - y) - z = x - (y + z)" },
77         { FS_OPT_MUL_MINUS_1,    "algebraic simplification: a * -1 = -a" },
78         { FS_OPT_OR,             "algebraic simplification: a | a = a | 0 = 0 | a = a" },
79         { FS_OPT_AND,            "algebraic simplification: a & 0b1...1 = 0b1...1 & a =  a & a = a" },
80         { FS_OPT_EOR_A_A,        "algebraic simplification: a ^ a = 0" },
81         { FS_OPT_EOR_TO_NOT_BOOL,"algebraic simplification: bool ^ 1 = !bool" },
82         { FS_OPT_EOR_TO_NOT,     "algebraic simplification: x ^ 0b1..1 = ~x" },
83         { FS_OPT_NOT_CMP,        "algebraic simplification: !(a cmp b) = a !cmp b" },
84         { FS_OPT_OR_SHFT_TO_ROT, "algebraic simplification: (x << c) | (x >> (bits - c)) == Rot(x, c)" },
85         { FS_OPT_REASSOC_SHIFT,  "algebraic simplification: (x SHF c1) SHF c2 = x SHF (c1+c2)" },
86         { FS_OPT_SHIFT_AND,      "algebraic simplification: (a SHF c) AND (b SHF c) = (a AND b) SHF c" },
87         { FS_OPT_SHIFT_OR,       "algebraic simplification: (a SHF c) OR (b SHF c) = (a OR b) SHF c" },
88         { FS_OPT_SHIFT_EOR,      "algebraic simplification: (a SHF c) XOR (b SHF c) = (a XOR b) SHF c" },
89         { FS_OPT_CONV,           "algebraic simplification: Conv could be removed" },
90         { FS_OPT_CAST,           "algebraic simplification: a Cast could be removed" },
91         { FS_OPT_MIN_MAX_EQ,     "algebraic simplification: Min(a,a) = Max(a,a) = a" },
92         { FS_OPT_MUX_C,          "algebraic simplification: Mux(C, f, t) = C ? t : f" },
93         { FS_OPT_MUX_EQ,         "algebraic simplification: Mux(v, x, x) = x" },
94         { FS_OPT_MUX_TRANSFORM,  "algebraic simplification: Mux(a, b, c) = b OR Mux(a,b, c) = c" },
95         { FS_OPT_MUX_TO_MIN,     "algebraic simplification: Mux(a < b, a, b) = Min(a,b)" },
96         { FS_OPT_MUX_TO_MAX,     "algebraic simplification: Mux(a > b, a, b) = Max(a,b)" },
97         { FS_OPT_MUX_TO_ABS,     "algebraic simplification: Mux(a > b, a, b) = Abs(a,b)" },
98         { FS_OPT_MUX_TO_SHR,     "algebraic simplification: Mux(a > b, a, b) = a >> b" },
99         { FS_OPT_CONST_PHI,      "constant evaluation on Phi node" },
100         { FS_BE_IA32_LEA,        "ia32 Backend transformation: Lea was created" },
101         { FS_BE_IA32_LOAD_LEA,   "ia32 Backend transformation: Load merged with a Lea" },
102         { FS_BE_IA32_STORE_LEA,  "ia32 Backend transformation: Store merged with a Lea" },
103         { FS_BE_IA32_AM_S,       "ia32 Backend transformation: Source address mode node created" },
104         { FS_BE_IA32_AM_D,       "ia32 Backend transformation: Destination address mode node created" },
105         { FS_BE_IA32_CJMP,       "ia32 Backend transformation: CJmp created to save a cmp/test" },
106         { FS_BE_IA32_2ADDRCPY,   "ia32 Backend transformation: Copy created due to 2-Addresscode constraints" },
107         { FS_BE_IA32_SPILL2ST,   "ia32 Backend transformation: Created Store for a Spill" },
108         { FS_BE_IA32_RELOAD2LD,  "ia32 Backend transformation: Created Load for a Reload" },
109         { FS_BE_IA32_SUB2NEGADD, "ia32 Backend transformation: Created Neg-Add for a Sub due to 2-Addresscode constraints" },
110         { FS_BE_IA32_LEA2ADD,    "ia32 Backend transformation: Transformed Lea back into Add" },
111 };
112
113 static const char *if_conv_names[IF_RESULT_LAST] = {
114         "if conv done             ",
115         "if conv side effect      ",
116         "if conv Phi node found   ",
117         "if conv to deep DAG's    ",
118         "if conv bad control flow ",
119         "if conv denied by arch   ",
120 };
121
122 /**
123  * dumps a opcode hash into human readable form
124  */
125 static void simple_dump_opcode_hash(dumper_t *dmp, pset *set)
126 {
127         node_entry_t *entry;
128         counter_t f_alive;
129         counter_t f_new_node;
130         counter_t f_Id;
131
132         cnt_clr(&f_alive);
133         cnt_clr(&f_new_node);
134         cnt_clr(&f_Id);
135
136         fprintf(dmp->f, "%-16s %-8s %-8s %-8s\n", "Opcode", "alive", "created", "->Id");
137         foreach_pset(set, entry) {
138                 fprintf(dmp->f, "%-16s %8u %8u %8u\n",
139                         get_id_str(entry->op->name),
140                         cnt_to_uint(&entry->cnt_alive),
141                         cnt_to_uint(&entry->new_node),
142                         cnt_to_uint(&entry->into_Id)
143                 );
144
145                 cnt_add(&f_alive,    &entry->cnt_alive);
146                 cnt_add(&f_new_node, &entry->new_node);
147                 cnt_add(&f_Id,       &entry->into_Id);
148         }  /* foreach_pset */
149         fprintf(dmp->f, "-------------------------------------------\n");
150         fprintf(dmp->f, "%-16s %8u %8u %8u\n", "Sum",
151                 cnt_to_uint(&f_alive),
152                 cnt_to_uint(&f_new_node),
153                 cnt_to_uint(&f_Id)
154         );
155 }  /* simple_dump_opcode_hash */
156
157 /**
158  * dumps an optimization hash into human readable form
159  */
160 static void simple_dump_opt_hash(dumper_t *dmp, pset *set, int index)
161 {
162         assert(index < (int) ARR_SIZE(opt_names) && "index out of range");
163         assert((int) opt_names[index].kind == index && "opt_names broken");
164
165         if (pset_count(set) > 0) {
166                 opt_entry_t *entry;
167
168                 fprintf(dmp->f, "\n%s:\n", opt_names[index].name);
169                 fprintf(dmp->f, "%-16s %-8s\n", "Opcode", "deref");
170
171                 foreach_pset(set, entry) {
172                         fprintf(dmp->f, "%-16s %8u\n",
173                                 get_id_str(entry->op->name), cnt_to_uint(&entry->count));
174                 }  /* foreach_pset */
175         }  /* if */
176 }  /* simple_dump_opt_hash */
177
178 /**
179  * dumps the register pressure for each block and for each register class
180  */
181 static void simple_dump_be_block_reg_pressure(dumper_t *dmp, graph_entry_t *entry)
182 {
183         be_block_entry_t     *b_entry = pset_first(entry->be_block_hash);
184         reg_pressure_entry_t *rp_entry;
185
186         /* return if no be statistic information available */
187         if (! b_entry)
188                 return;
189
190         fprintf(dmp->f, "\nREG PRESSURE:\n");
191         fprintf(dmp->f, "%12s", "Block Nr");
192
193         /* print table head (register class names) */
194         foreach_pset(b_entry->reg_pressure, rp_entry)
195                 fprintf(dmp->f, "%15s", rp_entry->class_name);
196         fprintf(dmp->f, "\n");
197
198         /* print the reg pressure for all blocks and register classes */
199         for (/* b_entry is already initialized */ ;
200              b_entry;
201              b_entry = pset_next(entry->be_block_hash)) {
202                 fprintf(dmp->f, "BLK   %6ld", b_entry->block_nr);
203
204                 foreach_pset(b_entry->reg_pressure, rp_entry)
205                         fprintf(dmp->f, "%15d", rp_entry->pressure);
206                 fprintf(dmp->f, "\n");
207         }  /* for */
208 }  /* simple_dump_be_block_reg_pressure */
209
210 /** prints a distribution entry */
211 static void simple_dump_distrib_entry(const distrib_entry_t *entry, void *env) {
212         dumper_t *dmp = env;
213         fprintf(dmp->f, "%12d", cnt_to_uint(&entry->cnt));
214 }  /* simple_dump_distrib_entry */
215
216 /**
217  * dumps the distribution of the amount of ready nodes for each block
218  */
219 static void simple_dump_be_block_sched_ready(dumper_t *dmp, graph_entry_t *entry)
220 {
221         if (pset_count(entry->be_block_hash) > 0) {
222                 be_block_entry_t *b_entry;
223                 int              i;
224
225                 fprintf(dmp->f, "\nSCHEDULING: NUMBER OF READY NODES\n");
226                 fprintf(dmp->f, "%12s %12s %12s %12s %12s %12s %12s\n",
227                         "Block Nr", "1 node", "2 nodes", "3 nodes", "4 nodes", "5 or more", "AVERAGE");
228
229                 foreach_pset(entry->be_block_hash, b_entry) {
230                         /* this ensures that all keys from 1 to 5 are in the table */
231                         for (i = 1; i < 6; ++i)
232                                 stat_insert_int_distrib_tbl(b_entry->sched_ready, i);
233
234                         fprintf(dmp->f, "BLK   %6ld", b_entry->block_nr);
235                         stat_iterate_distrib_tbl(b_entry->sched_ready, simple_dump_distrib_entry, dmp);
236                         fprintf(dmp->f, "%12.2lf", stat_calc_avg_distrib_tbl(b_entry->sched_ready));
237                         fprintf(dmp->f, "\n");
238                 }  /* foreach_pset */
239         }  /* if */
240 }  /* simple_dump_be_block_sched_ready */
241
242 /**
243  * Adds the counter for given entry to another distribution table.
244  */
245 static void add_distrib_entry(const distrib_entry_t *entry, void *env) {
246         distrib_tbl_t *sum_tbl = env;
247
248         stat_add_int_distrib_tbl(sum_tbl, (int)(entry->object), &entry->cnt);
249 }  /* add_distrib_entry */
250
251 /**
252  * dumps permutation statistics for one and block and one class
253  */
254 static void simple_dump_be_block_permstat_class(dumper_t *dmp, perm_class_entry_t *entry)
255 {
256         perm_stat_entry_t *ps_ent;
257         distrib_tbl_t     *sum_chains = stat_new_int_distrib_tbl();
258         distrib_tbl_t     *sum_cycles = stat_new_int_distrib_tbl();
259         char              buf[16];
260         int               i;
261
262         fprintf(dmp->f, "%12s %12s %12s %12s %12s %12s\n",
263                 "size",
264                 "real size",
265                 "# chains",
266                 "# cycles",
267                 "# copies",
268                 "# exchanges"
269         );
270
271         foreach_pset(entry->perm_stat, ps_ent) {
272                 fprintf(dmp->f, "%12d %12d %12d %12d %12d %12d\n",
273                         ps_ent->size,
274                         ps_ent->real_size,
275                         stat_get_count_distrib_tbl(ps_ent->chains),
276                         stat_get_count_distrib_tbl(ps_ent->cycles),
277                         ps_ent->n_copies,
278                         ps_ent->n_exchg
279                 );
280
281                 /* sum up distribution table for chains */
282                 stat_iterate_distrib_tbl(ps_ent->chains, add_distrib_entry, sum_chains);
283
284                 /* sum up distribution table for cycles */
285                 stat_iterate_distrib_tbl(ps_ent->cycles, add_distrib_entry, sum_cycles);
286         }  /* foreach_pset */
287
288         /* print chain distribution for all perms of this class in this block */
289         fprintf(dmp->f, "chain distribution:\n");
290
291         /* add all missing entries to chain distribution table */
292         for (i = 1; i <= entry->n_regs; i++) {
293                 snprintf(buf, sizeof(buf), "length %d", i);
294                 fprintf(dmp->f, "%12s", buf);
295                 stat_insert_int_distrib_tbl(sum_chains, i);
296         }  /* for */
297         fprintf(dmp->f, "\n");
298         stat_iterate_distrib_tbl(sum_chains, simple_dump_distrib_entry, dmp);
299         fprintf(dmp->f, "\n");
300
301         /* print cycle distribution for all perms of this class in this block */
302         fprintf(dmp->f, "cycle distribution:\n");
303
304         /* add all missing entries to cycle distribution table */
305         for (i = 1; i <= entry->n_regs; i++) {
306                 snprintf(buf, sizeof(buf), "length %d", i);
307                 fprintf(dmp->f, "%12s", buf);
308                 stat_insert_int_distrib_tbl(sum_cycles, i);
309         }  /* for */
310         fprintf(dmp->f, "\n");
311         stat_iterate_distrib_tbl(sum_cycles, simple_dump_distrib_entry, dmp);
312         fprintf(dmp->f, "\n");
313
314         /* delete temporary sum distribution tables */
315         stat_delete_distrib_tbl(sum_chains);
316         stat_delete_distrib_tbl(sum_cycles);
317
318 }  /* simple_dump_be_block_permstat_class */
319
320 /**
321  * dumps statistics about perms
322  */
323 static void simple_dump_be_block_permstat(dumper_t *dmp, graph_entry_t *entry)
324 {
325         if (pset_count(entry->be_block_hash) > 0) {
326                 be_block_entry_t *b_entry;
327
328                 fprintf(dmp->f, "\nPERMUTATION STATISTICS BEGIN:\n");
329                 foreach_pset(entry->be_block_hash, b_entry) {
330                         perm_class_entry_t *pc_ent;
331
332                         fprintf(dmp->f, "BLOCK %ld:\n", b_entry->block_nr);
333
334                         if (b_entry->perm_class_stat) {
335                                 foreach_pset(b_entry->perm_class_stat, pc_ent) {
336                                         fprintf(dmp->f, "register class %s:\n", pc_ent->class_name);
337                                         simple_dump_be_block_permstat_class(dmp, pc_ent);
338                                 }  /* foreach_pset */
339                         }  /* if */
340                 }  /* foreach_pset */
341
342                 fprintf(dmp->f, "PERMUTATION STATISTICS END\n");
343         }  /* if */
344 }  /* simple_dump_be_block_permstat */
345
346 /**
347  * dumps the number of real_function_call optimization
348  */
349 static void simple_dump_real_func_calls(dumper_t *dmp, counter_t *cnt)
350 {
351         if (! dmp->f)
352                 return;
353
354         if (! cnt_eq(cnt, 0)) {
355                 fprintf(dmp->f, "\nReal Function Calls optimized:\n");
356                 fprintf(dmp->f, "%-16s %8u\n", "Call", cnt_to_uint(cnt));
357         }  /* if */
358 }  /* simple_dump_real_func_calls */
359
360 /**
361  * dumps the number of tail_recursion optimization
362  */
363 static void simple_dump_tail_recursion(dumper_t *dmp, unsigned num_tail_recursion)
364 {
365         if (! dmp->f)
366                 return;
367
368         if (num_tail_recursion > 0) {
369                 fprintf(dmp->f, "\nTail recursion optimized:\n");
370                 fprintf(dmp->f, "%-16s %8u\n", "Call", num_tail_recursion);
371         }  /* if */
372 }  /* simple_dump_tail_recursion */
373
374 /**
375  * dumps the edges count
376  */
377 static void simple_dump_edges(dumper_t *dmp, counter_t *cnt)
378 {
379         if (! dmp->f)
380                 return;
381
382         fprintf(dmp->f, "%-16s %8d\n", "Edges", cnt_to_uint(cnt));
383 }  /* simple_dump_edges */
384
385 /**
386  * dumps the IRG
387  */
388 static void simple_dump_graph(dumper_t *dmp, graph_entry_t *entry)
389 {
390         int i, dump_opts = 1;
391         block_entry_t *b_entry;
392         extbb_entry_t *eb_entry;
393
394         if (! dmp->f)
395                 return;
396
397         if (entry->irg) {
398                 ir_graph *const_irg = get_const_code_irg();
399
400                 if (entry->irg == const_irg)
401                         fprintf(dmp->f, "\nConst code Irg %p", (void *)entry->irg);
402                 else {
403                         if (entry->ent)
404                                 fprintf(dmp->f, "\nEntity %s, Irg %p", get_entity_ld_name(entry->ent), (void *)entry->irg);
405                         else
406                                 fprintf(dmp->f, "\nIrg %p", (void *)entry->irg);
407                 }  /* if */
408
409                 fprintf(dmp->f, " %swalked %u over blocks %u:\n"
410                         " was inlined               : %u\n"
411                         " got inlined               : %u\n"
412                         " strength red              : %u\n"
413                         " leaf function             : %s\n"
414                         " calls only leaf functions : %s\n"
415                         " recursive                 : %s\n"
416                         " chain call                : %s\n"
417                         " calls                     : %u\n"
418                         " indirect calls            : %u\n",
419                         entry->is_deleted ? "DELETED " : "",
420                         cnt_to_uint(&entry->cnt[gcnt_acc_walked]), cnt_to_uint(&entry->cnt[gcnt_acc_walked_blocks]),
421                         cnt_to_uint(&entry->cnt[gcnt_acc_was_inlined]),
422                         cnt_to_uint(&entry->cnt[gcnt_acc_got_inlined]),
423                         cnt_to_uint(&entry->cnt[gcnt_acc_strength_red]),
424                         entry->is_leaf ? "YES" : "NO",
425                         entry->is_leaf_call == LCS_NON_LEAF_CALL ? "NO" : (entry->is_leaf_call == LCS_LEAF_CALL ? "Yes" : "Maybe"),
426                         entry->is_recursive ? "YES" : "NO",
427                         entry->is_chain_call ? "YES" : "NO",
428                         cnt_to_uint(&entry->cnt[gcnt_all_calls]),
429                         cnt_to_uint(&entry->cnt[gcnt_indirect_calls])
430                 );
431
432                 for (i = 0; i < IF_RESULT_LAST; ++i) {
433                         fprintf(dmp->f, " %s : %u\n", if_conv_names[i], cnt_to_uint(&entry->cnt[gcnt_if_conv + i]));
434                 }  /* for */
435         } else {
436                 fprintf(dmp->f, "\nGlobals counts:\n");
437                 fprintf(dmp->f, "--------------\n");
438                 dump_opts = 0;
439         }  /* if */
440
441         /* address ops */
442         fprintf(dmp->f,
443                 " pure address calc ops     : %u\n"
444                 " all address calc ops      : %u\n",
445                 cnt_to_uint(&entry->cnt[gcnt_pure_adr_ops]),
446                 cnt_to_uint(&entry->cnt[gcnt_all_adr_ops])
447         );
448
449         /* Load/Store address classification */
450         fprintf(dmp->f,
451                 " global Ld/St address      : %u\n"
452                 " local Ld/St address       : %u\n"
453                 " this Ld/St address        : %u\n"
454                 " param Ld/St address       : %u\n"
455                 " other Ld/St address       : %u\n",
456                 cnt_to_uint(&entry->cnt[gcnt_global_adr]),
457                 cnt_to_uint(&entry->cnt[gcnt_local_adr]),
458                 cnt_to_uint(&entry->cnt[gcnt_this_adr]),
459                 cnt_to_uint(&entry->cnt[gcnt_param_adr]),
460                 cnt_to_uint(&entry->cnt[gcnt_other_adr])
461         );
462
463         simple_dump_opcode_hash(dmp, entry->opcode_hash);
464         simple_dump_edges(dmp, &entry->cnt[gcnt_edges]);
465
466         /* effects of optimizations */
467         if (dump_opts) {
468                 size_t i;
469
470                 simple_dump_real_func_calls(dmp, &entry->cnt[gcnt_acc_real_func_call]);
471                 simple_dump_tail_recursion(dmp, entry->num_tail_recursion);
472
473                 for (i = 0; i < sizeof(entry->opt_hash)/sizeof(entry->opt_hash[0]); ++i) {
474                         simple_dump_opt_hash(dmp, entry->opt_hash[i], i);
475                 }  /* for */
476
477                 /* dump block info */
478                 fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s %12s\n", "Block Nr", "Nodes", "intern E", "incoming E", "outgoing E", "Phi", "quot");
479                 foreach_pset(entry->block_hash, b_entry) {
480                         fprintf(dmp->f, "BLK   %6ld %12u %12u %12u %12u %12u %4.8f\n",
481                                 b_entry->block_nr,
482                                 cnt_to_uint(&b_entry->cnt[bcnt_nodes]),
483                                 cnt_to_uint(&b_entry->cnt[bcnt_edges]),
484                                 cnt_to_uint(&b_entry->cnt[bcnt_in_edges]),
485                                 cnt_to_uint(&b_entry->cnt[bcnt_out_edges]),
486                                 cnt_to_uint(&b_entry->cnt[bcnt_phi_data]),
487                                 cnt_to_dbl(&b_entry->cnt[bcnt_edges]) / cnt_to_dbl(&b_entry->cnt[bcnt_nodes])
488                         );
489                 }  /* foreach_pset */
490
491                 /* dump block reg pressure */
492                 simple_dump_be_block_reg_pressure(dmp, entry);
493
494                 /* dump block ready nodes distribution */
495                 simple_dump_be_block_sched_ready(dmp, entry);
496
497                 /* dump block permutation statistics */
498                 simple_dump_be_block_permstat(dmp, entry);
499
500                 if (dmp->status->stat_options & FIRMSTAT_COUNT_EXTBB && entry->extbb_hash) {
501                         /* dump extended block info */
502                         fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s %12s\n", "Extbb Nr", "Nodes", "intern E", "incoming E", "outgoing E", "Phi", "quot");
503                         foreach_pset(entry->extbb_hash, eb_entry) {
504                                 fprintf(dmp->f, "ExtBB %6ld %12u %12u %12u %12u %12u %4.8f\n",
505                                         eb_entry->block_nr,
506                                         cnt_to_uint(&eb_entry->cnt[bcnt_nodes]),
507                                         cnt_to_uint(&eb_entry->cnt[bcnt_edges]),
508                                         cnt_to_uint(&eb_entry->cnt[bcnt_in_edges]),
509                                         cnt_to_uint(&eb_entry->cnt[bcnt_out_edges]),
510                                         cnt_to_uint(&eb_entry->cnt[bcnt_phi_data]),
511                                         cnt_to_dbl(&eb_entry->cnt[bcnt_edges]) / cnt_to_dbl(&eb_entry->cnt[bcnt_nodes])
512                                 );
513                         }  /* foreach_pset */
514                 }  /* if */
515         }
516 }  /* simple_dump_graph */
517
518 /**
519  * dumps the constant table
520  */
521 static void simple_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
522 {
523         size_t i;
524         counter_t sum;
525
526         if (! dmp->f)
527                 return;
528
529         cnt_clr(&sum);
530
531         fprintf(dmp->f, "\nConstant Information:\n");
532         fprintf(dmp->f, "---------------------\n");
533
534         fprintf(dmp->f, "\nBit usage for integer constants\n");
535         fprintf(dmp->f, "-------------------------------\n");
536
537         for (i = 0; i < ARR_SIZE(tbl->int_bits_count); ++i) {
538                 fprintf(dmp->f, "%5d %12u\n", i + 1, cnt_to_uint(&tbl->int_bits_count[i]));
539                 cnt_add(&sum, &tbl->int_bits_count[i]);
540         }  /* for */
541         fprintf(dmp->f, "-------------------------------\n");
542
543         fprintf(dmp->f, "\nFloating point constants classification\n");
544         fprintf(dmp->f, "--------------------------------------\n");
545         for (i = 0; i < ARR_SIZE(tbl->floats); ++i) {
546                 fprintf(dmp->f, "%-10s %12u\n", stat_fc_name(i), cnt_to_uint(&tbl->floats[i]));
547                 cnt_add(&sum, &tbl->floats[i]);
548         }  /* for */
549         fprintf(dmp->f, "--------------------------------------\n");
550
551         fprintf(dmp->f, "other %12u\n", cnt_to_uint(&tbl->others));
552         cnt_add(&sum, &tbl->others);
553         fprintf(dmp->f, "-------------------------------\n");
554
555         fprintf(dmp->f, "sum   %12u\n", cnt_to_uint(&sum));
556 }  /* simple_dump_const_tbl */
557
558 /**
559  * Dumps a line of the parameter table
560  */
561 static void dump_tbl_line(const distrib_entry_t *entry, void *env) {
562         dumper_t *dmp = env;
563
564         fprintf(dmp->f, "%d : %u\n", PTR_TO_INT(entry->object), cnt_to_uint(&entry->cnt));
565 }  /* dump_tbl_line */
566
567 /**
568  * dumps the parameter distribution table
569  */
570 static void simple_dump_param_tbl(dumper_t *dmp, const distrib_tbl_t *tbl, graph_entry_t *global) {
571         fprintf(dmp->f, "\nCall parameter Information:\n");
572         fprintf(dmp->f, "---------------------\n");
573
574         stat_iterate_distrib_tbl(tbl, dump_tbl_line, dmp);
575         fprintf(dmp->f, "-------------------------------\n");
576
577         fprintf(dmp->f, "Number of Calls           %12u\n", cnt_to_uint(&global->cnt[gcnt_all_calls]));
578         fprintf(dmp->f, "with const params         %12u\n", cnt_to_uint(&global->cnt[gcnt_call_with_cnst_arg]));
579         fprintf(dmp->f, "with all const params     %12u\n", cnt_to_uint(&global->cnt[gcnt_call_with_all_cnst_arg]));
580         fprintf(dmp->f, "with local var adr params %12u\n", cnt_to_uint(&global->cnt[gcnt_call_with_local_adr]));
581 }  /* simple_dump_param_tbl */
582
583 /**
584  * initialize the simple dumper
585  */
586 static void simple_init(dumper_t *dmp, const char *name) {
587         char fname[2048];
588
589         snprintf(fname, sizeof(fname), "%s.txt", name);
590         dmp->f = fopen(fname, "w");
591         if (! dmp->f) {
592                 perror(fname);
593         }  /* if */
594 }  /* simple_init */
595
596 /**
597  * finishes the simple dumper
598  */
599 static void simple_finish(dumper_t *dmp) {
600         if (dmp->f)
601                 fclose(dmp->f);
602         dmp->f = NULL;
603 }  /* simple_finish */
604
605 /**
606  * the simple human readable dumper
607  */
608 const dumper_t simple_dumper = {
609         simple_dump_graph,
610         simple_dump_const_tbl,
611         simple_dump_param_tbl,
612         simple_init,
613         simple_finish,
614         NULL,
615         NULL,
616         NULL,
617         NULL,
618         FOURCC('S', 'M', 'P', 'L'),
619 };
620
621 /* ---------------------------------------------------------------------- */
622
623 /**
624  * count the nodes as needed:
625  *
626  * 1 normal (data) Phi's
627  * 2 memory Phi's
628  * 3 Proj
629  * 0 all other nodes
630  */
631 static void csv_count_nodes(dumper_t *dmp, graph_entry_t *graph, counter_t cnt[])
632 {
633         node_entry_t *entry;
634         int i;
635
636         for (i = 0; i < 4; ++i)
637                 cnt_clr(&cnt[i]);
638
639         foreach_pset(graph->opcode_hash, entry) {
640                 if (entry->op == op_Phi) {
641                         /* normal Phi */
642                         cnt_add(&cnt[1], &entry->cnt_alive);
643                 } else if (entry->op == dmp->status->op_PhiM) {
644                         /* memory Phi */
645                         cnt_add(&cnt[2], &entry->cnt_alive);
646                 } else if (entry->op == op_Proj) {
647                         /* Proj */
648                         cnt_add(&cnt[3], &entry->cnt_alive);
649                 } else {
650                         /* all other nodes */
651                         cnt_add(&cnt[0], &entry->cnt_alive);
652                 }  /* if */
653         }  /* foreach_pset */
654 }  /* csv_count_nodes */
655
656 /**
657  * dumps the IRG
658  */
659 static void csv_dump_graph(dumper_t *dmp, graph_entry_t *entry)
660 {
661         const char *name;
662         counter_t cnt[4];
663
664         if (! dmp->f)
665                 return;
666
667         if (entry->irg && !entry->is_deleted) {
668                 ir_graph *const_irg = get_const_code_irg();
669
670                 if (entry->irg == const_irg) {
671                         name = "<Const code Irg>";
672                         return;
673                 } else {
674                         if (entry->ent)
675                                 name = get_entity_name(entry->ent);
676                         else
677                                 name = "<UNKNOWN IRG>";
678                 }  /* if */
679
680                 csv_count_nodes(dmp, entry, cnt);
681
682                 fprintf(dmp->f, "%-40s, %p, %d, %d, %d, %d\n",
683                         name,
684                         (void *)entry->irg,
685                         cnt_to_uint(&cnt[0]),
686                         cnt_to_uint(&cnt[1]),
687                         cnt_to_uint(&cnt[2]),
688                         cnt_to_uint(&cnt[3])
689                 );
690         }  /* if */
691 }  /* csv_dump_graph */
692
693 /**
694  * dumps the IRG
695  */
696 static void csv_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
697 {
698         (void) dmp;
699         (void) tbl;
700         /* FIXME: NYI */
701 }  /* csv_dump_const_tbl */
702
703 /**
704  * dumps the parameter distribution table
705  */
706 static void csv_dump_param_tbl(dumper_t *dmp, const distrib_tbl_t *tbl, graph_entry_t *global) {
707         (void) dmp;
708         (void) tbl;
709         (void) global;
710         /* FIXME: NYI */
711 }  /* csv_dump_param_tbl */
712
713 /**
714  * initialize the simple dumper
715  */
716 static void csv_init(dumper_t *dmp, const char *name)
717 {
718         char fname[2048];
719
720         snprintf(fname, sizeof(fname), "%s.csv", name);
721         dmp->f = fopen(fname, "a");
722         if (! dmp->f)
723                 perror(fname);
724 }  /* csv_init */
725
726 /**
727  * finishes the simple dumper
728  */
729 static void csv_finish(dumper_t *dmp)
730 {
731         if (dmp->f)
732                 fclose(dmp->f);
733         dmp->f = NULL;
734 }  /* csv_finish */
735
736 /**
737  * the simple human readable dumper
738  */
739 const dumper_t csv_dumper = {
740         csv_dump_graph,
741         csv_dump_const_tbl,
742         csv_dump_param_tbl,
743         csv_init,
744         csv_finish,
745         NULL,
746         NULL,
747         NULL,
748         NULL,
749         FOURCC('C', 'S', 'V', '\0')
750 };