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