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