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