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