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