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