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