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