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