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