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