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