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