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