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