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