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