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