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