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