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