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