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