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