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