- add dumping of indirect/external calls
[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                         " external calls            : %u\n",
474                         entry->is_deleted ? "DELETED " : "",
475                         cnt_to_uint(&entry->cnt[gcnt_acc_walked]), cnt_to_uint(&entry->cnt[gcnt_acc_walked_blocks]),
476                         cnt_to_uint(&entry->cnt[gcnt_acc_was_inlined]),
477                         cnt_to_uint(&entry->cnt[gcnt_acc_got_inlined]),
478                         cnt_to_uint(&entry->cnt[gcnt_acc_strength_red]),
479                         entry->is_leaf ? "YES" : "NO",
480                         entry->is_leaf_call == LCS_NON_LEAF_CALL ? "NO" : (entry->is_leaf_call == LCS_LEAF_CALL ? "Yes" : "Maybe"),
481                         entry->is_recursive ? "YES" : "NO",
482                         entry->is_chain_call ? "YES" : "NO",
483                         cnt_to_uint(&entry->cnt[gcnt_all_calls]),
484                         cnt_to_uint(&entry->cnt[gcnt_indirect_calls]),
485                         cnt_to_uint(&entry->cnt[gcnt_external_calls])
486                 );
487
488                 for (i = 0; i < IF_RESULT_LAST; ++i) {
489                         fprintf(dmp->f, " %s : %u\n", if_conv_names[i], cnt_to_uint(&entry->cnt[gcnt_if_conv + i]));
490                 }  /* for */
491         } else {
492                 fprintf(dmp->f, "\nGlobals counts:\n");
493                 fprintf(dmp->f, "--------------\n");
494                 dump_opts = 0;
495         }  /* if */
496
497         /* address ops */
498         fprintf(dmp->f,
499                 " pure address calc ops     : %u\n"
500                 " all address calc ops      : %u\n",
501                 cnt_to_uint(&entry->cnt[gcnt_pure_adr_ops]),
502                 cnt_to_uint(&entry->cnt[gcnt_all_adr_ops])
503         );
504
505         /* Load/Store address classification */
506         fprintf(dmp->f,
507                 " global Ld/St address      : %u\n"
508                 " local Ld/St address       : %u\n"
509                 " this Ld/St address        : %u\n"
510                 " param Ld/St address       : %u\n"
511                 " other Ld/St address       : %u\n",
512                 cnt_to_uint(&entry->cnt[gcnt_global_adr]),
513                 cnt_to_uint(&entry->cnt[gcnt_local_adr]),
514                 cnt_to_uint(&entry->cnt[gcnt_this_adr]),
515                 cnt_to_uint(&entry->cnt[gcnt_param_adr]),
516                 cnt_to_uint(&entry->cnt[gcnt_other_adr])
517         );
518
519         simple_dump_opcode_hash(dmp, entry->opcode_hash);
520         simple_dump_edges(dmp, &entry->cnt[gcnt_edges]);
521
522         /* effects of optimizations */
523         if (dump_opts) {
524                 size_t i;
525
526                 simple_dump_real_func_calls(dmp, &entry->cnt[gcnt_acc_real_func_call]);
527                 simple_dump_tail_recursion(dmp, entry->num_tail_recursion);
528
529                 for (i = 0; i < sizeof(entry->opt_hash)/sizeof(entry->opt_hash[0]); ++i) {
530                         simple_dump_opt_hash(dmp, entry->opt_hash[i], i);
531                 }  /* for */
532
533                 /* dump block info */
534                 fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s %12s\n", "Block Nr", "Nodes", "intern E", "incoming E", "outgoing E", "Phi", "quot");
535                 foreach_pset(entry->block_hash, b_entry) {
536                         fprintf(dmp->f, "BLK   %6ld %12u %12u %12u %12u %12u %4.8f %s\n",
537                                 b_entry->block_nr,
538                                 cnt_to_uint(&b_entry->cnt[bcnt_nodes]),
539                                 cnt_to_uint(&b_entry->cnt[bcnt_edges]),
540                                 cnt_to_uint(&b_entry->cnt[bcnt_in_edges]),
541                                 cnt_to_uint(&b_entry->cnt[bcnt_out_edges]),
542                                 cnt_to_uint(&b_entry->cnt[bcnt_phi_data]),
543                                 cnt_to_dbl(&b_entry->cnt[bcnt_edges]) / cnt_to_dbl(&b_entry->cnt[bcnt_nodes]),
544                                 b_entry->is_start ? "START" : (b_entry->is_end ? "END" : "")
545                         );
546                 }  /* foreach_pset */
547
548                 /* dump block reg pressure */
549                 simple_dump_be_block_reg_pressure(dmp, entry);
550
551                 /* dump block ready nodes distribution */
552                 simple_dump_be_block_sched_ready(dmp, entry);
553
554                 /* dump block permutation statistics */
555                 simple_dump_be_block_permstat(dmp, entry);
556
557                 if (dmp->status->stat_options & FIRMSTAT_COUNT_EXTBB && entry->extbb_hash) {
558                         /* dump extended block info */
559                         fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s %12s\n", "Extbb Nr", "Nodes", "intern E", "incoming E", "outgoing E", "Phi", "quot");
560                         foreach_pset(entry->extbb_hash, eb_entry) {
561                                 fprintf(dmp->f, "ExtBB %6ld %12u %12u %12u %12u %12u %4.8f\n",
562                                         eb_entry->block_nr,
563                                         cnt_to_uint(&eb_entry->cnt[bcnt_nodes]),
564                                         cnt_to_uint(&eb_entry->cnt[bcnt_edges]),
565                                         cnt_to_uint(&eb_entry->cnt[bcnt_in_edges]),
566                                         cnt_to_uint(&eb_entry->cnt[bcnt_out_edges]),
567                                         cnt_to_uint(&eb_entry->cnt[bcnt_phi_data]),
568                                         cnt_to_dbl(&eb_entry->cnt[bcnt_edges]) / cnt_to_dbl(&eb_entry->cnt[bcnt_nodes])
569                                 );
570                         }  /* foreach_pset */
571                 }  /* if */
572         }
573 }  /* simple_dump_graph */
574
575 /**
576  * dumps the constant table
577  */
578 static void simple_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
579 {
580         size_t i;
581         counter_t sum;
582
583         if (! dmp->f)
584                 return;
585
586         cnt_clr(&sum);
587
588         fprintf(dmp->f, "\nConstant Information:\n");
589         fprintf(dmp->f, "---------------------\n");
590
591         fprintf(dmp->f, "\nBit usage for integer constants\n");
592         fprintf(dmp->f, "-------------------------------\n");
593
594         for (i = 0; i < ARR_SIZE(tbl->int_bits_count); ++i) {
595                 fprintf(dmp->f, "%5u %12u\n", (unsigned) (i + 1), cnt_to_uint(&tbl->int_bits_count[i]));
596                 cnt_add(&sum, &tbl->int_bits_count[i]);
597         }  /* for */
598         fprintf(dmp->f, "-------------------------------\n");
599
600         fprintf(dmp->f, "\nFloating point constants classification\n");
601         fprintf(dmp->f, "--------------------------------------\n");
602         for (i = 0; i < ARR_SIZE(tbl->floats); ++i) {
603                 fprintf(dmp->f, "%-10s %12u\n", stat_fc_name(i), cnt_to_uint(&tbl->floats[i]));
604                 cnt_add(&sum, &tbl->floats[i]);
605         }  /* for */
606         fprintf(dmp->f, "--------------------------------------\n");
607
608         fprintf(dmp->f, "other %12u\n", cnt_to_uint(&tbl->others));
609         cnt_add(&sum, &tbl->others);
610         fprintf(dmp->f, "-------------------------------\n");
611
612         fprintf(dmp->f, "sum   %12u\n", cnt_to_uint(&sum));
613 }  /* simple_dump_const_tbl */
614
615 /**
616  * Dumps a line of the parameter table
617  */
618 static void dump_tbl_line(const distrib_entry_t *entry, void *env) {
619         dumper_t *dmp = env;
620
621         fprintf(dmp->f, "%d : %u\n", PTR_TO_INT(entry->object), cnt_to_uint(&entry->cnt));
622 }  /* dump_tbl_line */
623
624 /**
625  * dumps the parameter distribution table
626  */
627 static void simple_dump_param_tbl(dumper_t *dmp, const distrib_tbl_t *tbl, graph_entry_t *global) {
628         fprintf(dmp->f, "\nCall parameter Information:\n");
629         fprintf(dmp->f, "---------------------\n");
630
631         stat_iterate_distrib_tbl(tbl, dump_tbl_line, dmp);
632         fprintf(dmp->f, "-------------------------------\n");
633
634         fprintf(dmp->f, "Number of Calls           %12u\n", cnt_to_uint(&global->cnt[gcnt_all_calls]));
635         fprintf(dmp->f, "indirect calls            %12u\n", cnt_to_uint(&global->cnt[gcnt_indirect_calls]));
636         fprintf(dmp->f, "external calls            %12u\n", cnt_to_uint(&global->cnt[gcnt_external_calls]));
637         fprintf(dmp->f, "with const params         %12u\n", cnt_to_uint(&global->cnt[gcnt_call_with_cnst_arg]));
638         fprintf(dmp->f, "with all const params     %12u\n", cnt_to_uint(&global->cnt[gcnt_call_with_all_cnst_arg]));
639         fprintf(dmp->f, "with local var adr params %12u\n", cnt_to_uint(&global->cnt[gcnt_call_with_local_adr]));
640 }  /* simple_dump_param_tbl */
641
642 /**
643  * dumps the optimization counter table
644  */
645 static void simple_dump_opt_cnt(dumper_t *dmp, const counter_t *tbl, unsigned len) {
646         unsigned i;
647
648         fprintf(dmp->f, "\nOptimization counts:\n");
649         fprintf(dmp->f, "---------------------\n");
650
651         for (i = 0; i < len; ++i) {
652                 unsigned cnt = cnt_to_uint(&tbl[i]);
653
654                 if (cnt > 0) {
655                         fprintf(dmp->f, "%8u %s\n", cnt, get_opt_name(i));
656                 }
657         }
658 }  /* simple_dump_opt_cnt */
659
660 /**
661  * initialize the simple dumper
662  */
663 static void simple_init(dumper_t *dmp, const char *name) {
664         char fname[2048];
665
666         snprintf(fname, sizeof(fname), "%s.txt", name);
667         dmp->f = fopen(fname, "w");
668         if (! dmp->f) {
669                 perror(fname);
670         }  /* if */
671 }  /* simple_init */
672
673 /**
674  * finishes the simple dumper
675  */
676 static void simple_finish(dumper_t *dmp) {
677         if (dmp->f)
678                 fclose(dmp->f);
679         dmp->f = NULL;
680 }  /* simple_finish */
681
682 /**
683  * the simple human readable dumper
684  */
685 const dumper_t simple_dumper = {
686         simple_dump_graph,
687         simple_dump_const_tbl,
688         simple_dump_param_tbl,
689         simple_dump_opt_cnt,
690         simple_init,
691         simple_finish,
692         NULL,
693         NULL,
694         NULL,
695         NULL,
696         FOURCC('S', 'M', 'P', 'L'),
697 };
698
699 /* ---------------------------------------------------------------------- */
700
701 /**
702  * count the nodes as needed:
703  *
704  * 1 normal (data) Phi's
705  * 2 memory Phi's
706  * 3 Proj
707  * 0 all other nodes
708  */
709 static void csv_count_nodes(dumper_t *dmp, graph_entry_t *graph, counter_t cnt[])
710 {
711         node_entry_t *entry;
712         int i;
713
714         for (i = 0; i < 4; ++i)
715                 cnt_clr(&cnt[i]);
716
717         foreach_pset(graph->opcode_hash, entry) {
718                 if (entry->op == op_Phi) {
719                         /* normal Phi */
720                         cnt_add(&cnt[1], &entry->cnt_alive);
721                 } else if (entry->op == dmp->status->op_PhiM) {
722                         /* memory Phi */
723                         cnt_add(&cnt[2], &entry->cnt_alive);
724                 } else if (entry->op == op_Proj) {
725                         /* Proj */
726                         cnt_add(&cnt[3], &entry->cnt_alive);
727                 } else {
728                         /* all other nodes */
729                         cnt_add(&cnt[0], &entry->cnt_alive);
730                 }  /* if */
731         }  /* foreach_pset */
732 }  /* csv_count_nodes */
733
734 /**
735  * dumps the IRG
736  */
737 static void csv_dump_graph(dumper_t *dmp, graph_entry_t *entry)
738 {
739         const char *name;
740         counter_t cnt[4];
741
742         if (! dmp->f)
743                 return;
744
745         if (entry->irg && !entry->is_deleted) {
746                 ir_graph *const_irg = get_const_code_irg();
747
748                 if (entry->irg == const_irg) {
749                         name = "<Const code Irg>";
750                         return;
751                 } else {
752                         if (entry->ent)
753                                 name = get_entity_name(entry->ent);
754                         else
755                                 name = "<UNKNOWN IRG>";
756                 }  /* if */
757
758                 csv_count_nodes(dmp, entry, cnt);
759
760                 fprintf(dmp->f, "%-40s, %p, %d, %d, %d, %d\n",
761                         name,
762                         (void *)entry->irg,
763                         cnt_to_uint(&cnt[0]),
764                         cnt_to_uint(&cnt[1]),
765                         cnt_to_uint(&cnt[2]),
766                         cnt_to_uint(&cnt[3])
767                 );
768         }  /* if */
769 }  /* csv_dump_graph */
770
771 /**
772  * dumps the IRG
773  */
774 static void csv_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
775 {
776         (void) dmp;
777         (void) tbl;
778         /* FIXME: NYI */
779 }  /* csv_dump_const_tbl */
780
781 /**
782  * dumps the parameter distribution table
783  */
784 static void csv_dump_param_tbl(dumper_t *dmp, const distrib_tbl_t *tbl, graph_entry_t *global) {
785         (void) dmp;
786         (void) tbl;
787         (void) global;
788         /* FIXME: NYI */
789 }  /* csv_dump_param_tbl */
790
791 /**
792  * dumps the optimization counter
793  */
794 static void csv_dump_opt_cnt(dumper_t *dmp, const counter_t *tbl, unsigned len) {
795         (void) dmp;
796         (void) tbl;
797         (void) len;
798         /* FIXME: NYI */
799 }  /* csv_dump_opt_cnt */
800
801 /**
802  * initialize the simple dumper
803  */
804 static void csv_init(dumper_t *dmp, const char *name)
805 {
806         char fname[2048];
807
808         snprintf(fname, sizeof(fname), "%s.csv", name);
809         dmp->f = fopen(fname, "a");
810         if (! dmp->f)
811                 perror(fname);
812 }  /* csv_init */
813
814 /**
815  * finishes the simple dumper
816  */
817 static void csv_finish(dumper_t *dmp)
818 {
819         if (dmp->f)
820                 fclose(dmp->f);
821         dmp->f = NULL;
822 }  /* csv_finish */
823
824 /**
825  * the simple human readable dumper
826  */
827 const dumper_t csv_dumper = {
828         csv_dump_graph,
829         csv_dump_const_tbl,
830         csv_dump_param_tbl,
831         csv_dump_opt_cnt,
832         csv_init,
833         csv_finish,
834         NULL,
835         NULL,
836         NULL,
837         NULL,
838         FOURCC('C', 'S', 'V', '\0')
839 };