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