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