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