Use foreach_pset().
[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_CAST,           "algebraic simplification: a Cast could be removed" },
102         { (hook_opt_kind)FS_OPT_MIN_MAX_EQ,     "algebraic simplification: Min(a,a) = Max(a,a) = a" },
103         { (hook_opt_kind)FS_OPT_MUX_COMBINE,    "boolean simplification: two Mux nodes where combined into one" },
104         { (hook_opt_kind)FS_OPT_MUX_CONV,       "boolean simplification: MuxI(sel, 1, 0) = (I)sel" },
105         { (hook_opt_kind)FS_OPT_MUX_BOOL,       "boolean simplification: Muxb(sel, true, false) = sel" },
106         { (hook_opt_kind)FS_OPT_MUX_NOT_BOOL,   "boolean simplification: Muxb(sel, false, true) = Not(sel)" },
107         { (hook_opt_kind)FS_OPT_MUX_OR_BOOL,    "boolean simplification: Muxb(sel, true, x) = Or(sel, x)" },
108         { (hook_opt_kind)FS_OPT_MUX_ORNOT_BOOL, "boolean simplification: Muxb(sel, x, true) = Or(Not(sel), x)" },
109         { (hook_opt_kind)FS_OPT_MUX_AND_BOOL,   "boolean simplification: Muxb(sel, x, false) = And(sel, x)" },
110         { (hook_opt_kind)FS_OPT_MUX_ANDNOT_BOOL,"boolean simplification: Muxb(sel, false, x) = And(Not(sel), x)" },
111         { (hook_opt_kind)FS_OPT_MUX_C,          "algebraic simplification: Mux(C, f, t) = C ? t : f" },
112         { (hook_opt_kind)FS_OPT_MUX_EQ,         "algebraic simplification: Mux(v, x, x) = x" },
113         { (hook_opt_kind)FS_OPT_MUX_TRANSFORM,  "algebraic simplification: Mux(t ==/!= f, t, f) = f/t, Mux(t ==/!= 0, -t, t) = -t/t" },
114         { (hook_opt_kind)FS_OPT_MUX_TO_MIN,     "algebraic simplification: Mux(a < b, a, b) = Min(a,b)" },
115         { (hook_opt_kind)FS_OPT_MUX_TO_MAX,     "algebraic simplification: Mux(a > b, a, b) = Max(a,b)" },
116         { (hook_opt_kind)FS_OPT_MUX_TO_BITOP,   "algebraic simplification: Mux((a & 2^x) ==/!= 0, 2^x, 0) = (a & 2^x) (xor 2^x)" },
117         { (hook_opt_kind)FS_OPT_IDEM_UNARY,     "algebraic simplification: Idempotent unary operation" },
118         { (hook_opt_kind)FS_OPT_MINUS_NOT,      "algebraic simplification: -(~x) = x + 1" },
119         { (hook_opt_kind)FS_OPT_NOT_MINUS_1,    "algebraic simplification: ~(x - 1) = -x" },
120         { (hook_opt_kind)FS_OPT_NOT_PLUS_1,     "algebraic simplification: ~x + 1 = -x" },
121         { (hook_opt_kind)FS_OPT_ADD_X_NOT_X,    "algebraic simplification: ~x + x = -1" },
122         { (hook_opt_kind)FS_OPT_FP_INV_MUL,     "algebraic simplification: x / y = x * (1.0/y)" },
123         { (hook_opt_kind)FS_OPT_CONST_PHI,      "constant evaluation on Phi node" },
124         { (hook_opt_kind)FS_OPT_PREDICATE,      "predicate optimization" },
125         { (hook_opt_kind)FS_OPT_DEMORGAN,       "optimization using DeMorgan's law" },
126         { (hook_opt_kind)FS_OPT_CMP_OP_OP,      "CMP optimization: Cmp(OP(x), OP(y)) = Cmp(x, y)" },
127         { (hook_opt_kind)FS_OPT_CMP_OP_C,       "CMP optimization: Cmp(OP(x), c1) = Cmp(x, c2)" },
128         { (hook_opt_kind)FS_OPT_CMP_CONV_CONV,  "CMP optimization: Cmp(Conv(x), Conv(y)) = Cmp(x, y)" },
129         { (hook_opt_kind)FS_OPT_CMP_CONV,       "CMP optimization: Cmp(Conv(x), Conv(y)) = Cmp(Conv(x), y)" },
130         { (hook_opt_kind)FS_OPT_CMP_TO_BOOL,    "CMP optimization: Cmp(x, y) = BoolOP(x, y)" },
131         { (hook_opt_kind)FS_OPT_CMP_CNST_MAGN,  "CMP optimization: reduced magnitude of a const" },
132         { (hook_opt_kind)FS_OPT_CMP_SHF_TO_AND, "CMP optimization: transformed shift into And" },
133         { (hook_opt_kind)FS_OPT_CMP_MOD_TO_AND, "CMP optimization: transformed Mod into And" },
134         { (hook_opt_kind)FS_OPT_NOP,            "the operation is a NOP" },
135         { (hook_opt_kind)FS_OPT_GVN_FOLLOWER,   "GVN-PRE: replaced a follower" },
136         { (hook_opt_kind)FS_OPT_GVN_FULLY,      "GVN-PRE: replaced by fully redundant value" },
137         { (hook_opt_kind)FS_OPT_GVN_PARTLY,     "GVN-PRE: replaced by partly redundant value" },
138         { (hook_opt_kind)FS_OPT_COMBO_CONST,    "Combo: evaluated into Constant" },
139         { (hook_opt_kind)FS_OPT_COMBO_CF,       "Combo: removed conditional control flow" },
140         { (hook_opt_kind)FS_OPT_COMBO_FOLLOWER, "Combo: removed a follower" },
141         { (hook_opt_kind)FS_OPT_COMBO_CONGRUENT,"Combo: replaced by congruent" },
142         { (hook_opt_kind)FS_OPT_JUMPTHREADING,  "Jump threading: removed conditional control flow" },
143         { (hook_opt_kind)FS_OPT_RTS_ABS,        "RTS optimization: call to abs() replaced" },
144         { (hook_opt_kind)FS_OPT_RTS_ALLOCA,     "RTS optimization: call to alloca() replaced" },
145         { (hook_opt_kind)FS_OPT_RTS_SQRT,       "RTS optimization: call to sqrt() replaced" },
146         { (hook_opt_kind)FS_OPT_RTS_CBRT,       "RTS optimization: call to cbrt() replaced" },
147         { (hook_opt_kind)FS_OPT_RTS_POW,        "RTS optimization: call to pow() replaced" },
148         { (hook_opt_kind)FS_OPT_RTS_EXP,        "RTS optimization: call to exp() replaced" },
149         { (hook_opt_kind)FS_OPT_RTS_LOG,        "RTS optimization: call to log() replaced" },
150         { (hook_opt_kind)FS_OPT_RTS_SIN,        "RTS optimization: call to sin() replaced" },
151         { (hook_opt_kind)FS_OPT_RTS_COS,        "RTS optimization: call to cos() replaced" },
152         { (hook_opt_kind)FS_OPT_RTS_TAN,        "RTS optimization: call to tan() replaced" },
153         { (hook_opt_kind)FS_OPT_RTS_ASIN,       "RTS optimization: call to asin() replaced" },
154         { (hook_opt_kind)FS_OPT_RTS_ACOS,       "RTS optimization: call to atan() replaced" },
155         { (hook_opt_kind)FS_OPT_RTS_ATAN,       "RTS optimization: call to acos() replaced" },
156         { (hook_opt_kind)FS_OPT_RTS_SINH,       "RTS optimization: call to sinh() replaced" },
157         { (hook_opt_kind)FS_OPT_RTS_COSH,       "RTS optimization: call to cosh() replaced" },
158         { (hook_opt_kind)FS_OPT_RTS_TANH,       "RTS optimization: call to tanh() replaced" },
159         { (hook_opt_kind)FS_OPT_RTS_SYMMETRIC,  "RTS optimization: call to symmetric function f(-x) replaced by f(x)" },
160         { (hook_opt_kind)FS_OPT_RTS_STRCMP,     "RTS optimization: call to strcmp() replaced" },
161         { (hook_opt_kind)FS_OPT_RTS_STRNCMP,    "RTS optimization: call to strncmp() replaced" },
162         { (hook_opt_kind)FS_OPT_RTS_STRCPY,     "RTS optimization: call to strcpy() replaced" },
163         { (hook_opt_kind)FS_OPT_RTS_STRLEN,     "RTS optimization: call to strlen() replaced" },
164         { (hook_opt_kind)FS_OPT_RTS_MEMCPY,     "RTS optimization: call to memcpy() replaced" },
165         { (hook_opt_kind)FS_OPT_RTS_MEMPCPY,    "RTS optimization: call to mempcpy() replaced" },
166         { (hook_opt_kind)FS_OPT_RTS_MEMMOVE,    "RTS optimization: call to memmove() replaced" },
167         { (hook_opt_kind)FS_OPT_RTS_MEMSET,     "RTS optimization: call to memset() replaced" },
168         { (hook_opt_kind)FS_OPT_RTS_MEMCMP,     "RTS optimization: call to memcmp() replaced" },
169         { (hook_opt_kind)FS_BE_IA32_LEA,        "ia32 Backend transformation: Lea was created" },
170         { (hook_opt_kind)FS_BE_IA32_LOAD_LEA,   "ia32 Backend transformation: Load merged with a Lea" },
171         { (hook_opt_kind)FS_BE_IA32_STORE_LEA,  "ia32 Backend transformation: Store merged with a Lea" },
172         { (hook_opt_kind)FS_BE_IA32_AM_S,       "ia32 Backend transformation: Source address mode node created" },
173         { (hook_opt_kind)FS_BE_IA32_AM_D,       "ia32 Backend transformation: Destination address mode node created" },
174         { (hook_opt_kind)FS_BE_IA32_CJMP,       "ia32 Backend transformation: CJmp created to save a cmp/test" },
175         { (hook_opt_kind)FS_BE_IA32_2ADDRCPY,   "ia32 Backend transformation: Copy created due to 2-Addresscode constraints" },
176         { (hook_opt_kind)FS_BE_IA32_SPILL2ST,   "ia32 Backend transformation: Created Store for a Spill" },
177         { (hook_opt_kind)FS_BE_IA32_RELOAD2LD,  "ia32 Backend transformation: Created Load for a Reload" },
178         { (hook_opt_kind)FS_BE_IA32_SUB2NEGADD, "ia32 Backend transformation: Created Neg-Add for a Sub due to 2-Addresscode constraints" },
179         { (hook_opt_kind)FS_BE_IA32_LEA2ADD,    "ia32 Backend transformation: Transformed Lea back into Add" },
180 };
181
182 static const char *if_conv_names[IF_RESULT_LAST] = {
183         "if conv done             ",
184         "if conv side effect      ",
185         "if conv Phi node found   ",
186         "if conv to deep DAG's    ",
187         "if conv bad control flow ",
188         "if conv denied by arch   ",
189 };
190
191 /**
192  * dumps a opcode hash into human readable form
193  */
194 static void simple_dump_opcode_hash(dumper_t *dmp, pset *set)
195 {
196         node_entry_t *entry;
197         counter_t f_alive;
198         counter_t f_new_node;
199         counter_t f_Id;
200         counter_t f_normlized;
201
202         cnt_clr(&f_alive);
203         cnt_clr(&f_new_node);
204         cnt_clr(&f_Id);
205         cnt_clr(&f_normlized);
206
207         fprintf(dmp->f, "%-16s %-8s %-8s %-8s %-8s\n", "Opcode", "alive", "created", "->Id", "normalized");
208         foreach_pset(set, node_entry_t*, entry) {
209                 fprintf(dmp->f, "%-16s %8u %8u %8u %8u\n",
210                         get_id_str(entry->op->name),
211                         cnt_to_uint(&entry->cnt_alive),
212                         cnt_to_uint(&entry->new_node),
213                         cnt_to_uint(&entry->into_Id),
214                         cnt_to_uint(&entry->normalized)
215                 );
216
217                 cnt_add(&f_alive,     &entry->cnt_alive);
218                 cnt_add(&f_new_node,  &entry->new_node);
219                 cnt_add(&f_Id,        &entry->into_Id);
220                 cnt_add(&f_normlized, &entry->normalized);
221         }  /* foreach_pset */
222         fprintf(dmp->f, "-------------------------------------------\n");
223         fprintf(dmp->f, "%-16s %8u %8u %8u %8u\n", "Sum",
224                 cnt_to_uint(&f_alive),
225                 cnt_to_uint(&f_new_node),
226                 cnt_to_uint(&f_Id),
227                 cnt_to_uint(&f_normlized)
228         );
229 }  /* simple_dump_opcode_hash */
230
231 /**
232  * Return the name of an optimization.
233  */
234 static const char *get_opt_name(int index)
235 {
236         assert(index < (int) ARRAY_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, opt_entry_t*, 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 = (be_block_entry_t*)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, reg_pressure_entry_t*, 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         foreach_pset(entry->block_hash, be_block_entry_t*, b_entry) {
282                 fprintf(dmp->f, "BLK   %6ld", b_entry->block_nr);
283
284                 foreach_pset(b_entry->reg_pressure, reg_pressure_entry_t*, rp_entry)
285                         fprintf(dmp->f, "%15d", rp_entry->pressure);
286                 fprintf(dmp->f, "\n");
287         }  /* for */
288 }  /* simple_dump_be_block_reg_pressure */
289
290 /** prints a distribution entry */
291 static void simple_dump_distrib_entry(const distrib_entry_t *entry, void *env)
292 {
293         dumper_t *dmp = (dumper_t*)env;
294         fprintf(dmp->f, "%12u", cnt_to_uint(&entry->cnt));
295 }  /* simple_dump_distrib_entry */
296
297 /**
298  * dumps the distribution of the amount of ready nodes for each block
299  */
300 static void simple_dump_be_block_sched_ready(dumper_t *dmp, graph_entry_t *entry)
301 {
302         if (pset_count(entry->be_block_hash) > 0) {
303                 be_block_entry_t *b_entry;
304                 int              i;
305
306                 fprintf(dmp->f, "\nSCHEDULING: NUMBER OF READY NODES\n");
307                 fprintf(dmp->f, "%12s %12s %12s %12s %12s %12s %12s\n",
308                         "Block Nr", "1 node", "2 nodes", "3 nodes", "4 nodes", "5 or more", "AVERAGE");
309
310                 foreach_pset(entry->be_block_hash, be_block_entry_t*, b_entry) {
311                         /* this ensures that all keys from 1 to 5 are in the table */
312                         for (i = 1; i < 6; ++i)
313                                 stat_insert_int_distrib_tbl(b_entry->sched_ready, i);
314
315                         fprintf(dmp->f, "BLK   %6ld", b_entry->block_nr);
316                         stat_iterate_distrib_tbl(b_entry->sched_ready, simple_dump_distrib_entry, dmp);
317                         fprintf(dmp->f, "%12.2lf", stat_calc_avg_distrib_tbl(b_entry->sched_ready));
318                         fprintf(dmp->f, "\n");
319                 }  /* foreach_pset */
320         }  /* if */
321 }  /* simple_dump_be_block_sched_ready */
322
323 /**
324  * Adds the counter for given entry to another distribution table.
325  */
326 static void add_distrib_entry(const distrib_entry_t *entry, void *env)
327 {
328         distrib_tbl_t *sum_tbl = (distrib_tbl_t*)env;
329
330         stat_add_int_distrib_tbl(sum_tbl, (int)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, perm_stat_entry_t*, 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, be_block_entry_t*, 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, perm_class_entry_t*, 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 %8u\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 dump_opts = 1;
473         block_entry_t *b_entry;
474
475         if (! dmp->f)
476                 return;
477
478         if (entry->irg) {
479                 ir_graph *const_irg = get_const_code_irg();
480                 int       i;
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 != ARRAY_SIZE(entry->opt_hash); ++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, block_entry_t*, 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 }  /* simple_dump_graph */
588
589 /**
590  * dumps the constant table
591  */
592 static void simple_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
593 {
594         size_t i;
595         counter_t sum;
596
597         if (! dmp->f)
598                 return;
599
600         cnt_clr(&sum);
601
602         fprintf(dmp->f, "\nConstant Information:\n");
603         fprintf(dmp->f, "---------------------\n");
604
605         fprintf(dmp->f, "\nBit usage for integer constants\n");
606         fprintf(dmp->f, "-------------------------------\n");
607
608         for (i = 0; i < ARRAY_SIZE(tbl->int_bits_count); ++i) {
609                 fprintf(dmp->f, "%5u %12u\n", (unsigned) (i + 1), cnt_to_uint(&tbl->int_bits_count[i]));
610                 cnt_add(&sum, &tbl->int_bits_count[i]);
611         }  /* for */
612         fprintf(dmp->f, "-------------------------------\n");
613
614         fprintf(dmp->f, "\nFloating point constants classification\n");
615         fprintf(dmp->f, "--------------------------------------\n");
616         for (i = 0; i < ARRAY_SIZE(tbl->floats); ++i) {
617                 fprintf(dmp->f, "%-10s %12u\n", stat_fc_name((float_classify_t)i), cnt_to_uint(&tbl->floats[i]));
618                 cnt_add(&sum, &tbl->floats[i]);
619         }  /* for */
620         fprintf(dmp->f, "--------------------------------------\n");
621
622         fprintf(dmp->f, "other %12u\n", cnt_to_uint(&tbl->others));
623         cnt_add(&sum, &tbl->others);
624         fprintf(dmp->f, "-------------------------------\n");
625
626         fprintf(dmp->f, "sum   %12u\n", cnt_to_uint(&sum));
627 }  /* simple_dump_const_tbl */
628
629 /**
630  * Dumps a line of the parameter table
631  */
632 static void dump_tbl_line(const distrib_entry_t *entry, void *env)
633 {
634         dumper_t *dmp = (dumper_t*)env;
635
636         fprintf(dmp->f, "%ld : %u\n", (long int)PTR_TO_INT(entry->object),
637                 cnt_to_uint(&entry->cnt));
638 }  /* dump_tbl_line */
639
640 /**
641  * dumps the parameter distribution table
642  */
643 static void simple_dump_param_tbl(dumper_t *dmp, const distrib_tbl_t *tbl, graph_entry_t *global)
644 {
645         fprintf(dmp->f, "\nCall parameter Information:\n");
646         fprintf(dmp->f, "---------------------\n");
647
648         stat_iterate_distrib_tbl(tbl, dump_tbl_line, dmp);
649         fprintf(dmp->f, "-------------------------------\n");
650
651         fprintf(dmp->f, "Number of Calls           %12u\n", cnt_to_uint(&global->cnt[gcnt_all_calls]));
652         fprintf(dmp->f, "indirect calls            %12u\n", cnt_to_uint(&global->cnt[gcnt_indirect_calls]));
653         fprintf(dmp->f, "external calls            %12u\n", cnt_to_uint(&global->cnt[gcnt_external_calls]));
654         fprintf(dmp->f, "with const params         %12u\n", cnt_to_uint(&global->cnt[gcnt_call_with_cnst_arg]));
655         fprintf(dmp->f, "with all const params     %12u\n", cnt_to_uint(&global->cnt[gcnt_call_with_all_cnst_arg]));
656         fprintf(dmp->f, "with local var adr params %12u\n", cnt_to_uint(&global->cnt[gcnt_call_with_local_adr]));
657 }  /* simple_dump_param_tbl */
658
659 /**
660  * dumps the optimization counter table
661  */
662 static void simple_dump_opt_cnt(dumper_t *dmp, const counter_t *tbl, unsigned len)
663 {
664         unsigned i;
665
666         fprintf(dmp->f, "\nOptimization counts:\n");
667         fprintf(dmp->f, "---------------------\n");
668
669         for (i = 0; i < len; ++i) {
670                 unsigned cnt = cnt_to_uint(&tbl[i]);
671
672                 if (cnt > 0) {
673                         fprintf(dmp->f, "%8u %s\n", cnt, get_opt_name(i));
674                 }
675         }
676 }  /* simple_dump_opt_cnt */
677
678 /**
679  * initialize the simple dumper
680  */
681 static void simple_init(dumper_t *dmp, const char *name)
682 {
683         char fname[2048];
684
685         snprintf(fname, sizeof(fname), "%s.txt", name);
686         dmp->f = fopen(fname, "w");
687         if (! dmp->f) {
688                 perror(fname);
689         }  /* if */
690 }  /* simple_init */
691
692 /**
693  * finishes the simple dumper
694  */
695 static void simple_finish(dumper_t *dmp)
696 {
697         if (dmp->f)
698                 fclose(dmp->f);
699         dmp->f = NULL;
700 }  /* simple_finish */
701
702 /**
703  * the simple human readable dumper
704  */
705 const dumper_t simple_dumper = {
706         simple_dump_graph,
707         simple_dump_const_tbl,
708         simple_dump_param_tbl,
709         simple_dump_opt_cnt,
710         simple_init,
711         simple_finish,
712         NULL,
713         NULL,
714         NULL,
715         NULL,
716         FOURCC('S', 'M', 'P', 'L'),
717 };
718
719 /* ---------------------------------------------------------------------- */
720
721 /**
722  * count the nodes as needed:
723  *
724  * 1 normal (data) Phi's
725  * 2 memory Phi's
726  * 3 Proj
727  * 0 all other nodes
728  */
729 static void csv_count_nodes(dumper_t *dmp, graph_entry_t *graph, counter_t cnt[])
730 {
731         node_entry_t *entry;
732         int i;
733
734         for (i = 0; i < 4; ++i)
735                 cnt_clr(&cnt[i]);
736
737         foreach_pset(graph->opcode_hash, node_entry_t*, entry) {
738                 if (entry->op == op_Phi) {
739                         /* normal Phi */
740                         cnt_add(&cnt[1], &entry->cnt_alive);
741                 } else if (entry->op == dmp->status->op_PhiM) {
742                         /* memory Phi */
743                         cnt_add(&cnt[2], &entry->cnt_alive);
744                 } else if (entry->op == op_Proj) {
745                         /* Proj */
746                         cnt_add(&cnt[3], &entry->cnt_alive);
747                 } else {
748                         /* all other nodes */
749                         cnt_add(&cnt[0], &entry->cnt_alive);
750                 }  /* if */
751         }  /* foreach_pset */
752 }  /* csv_count_nodes */
753
754 /**
755  * dumps the IRG
756  */
757 static void csv_dump_graph(dumper_t *dmp, graph_entry_t *entry)
758 {
759         const char *name;
760         counter_t cnt[4];
761
762         if (! dmp->f)
763                 return;
764
765         if (entry->irg && !entry->is_deleted) {
766                 ir_graph *const_irg = get_const_code_irg();
767
768                 if (entry->irg == const_irg) {
769                         name = "<Const code Irg>";
770                         return;
771                 } else {
772                         if (entry->ent)
773                                 name = get_entity_name(entry->ent);
774                         else
775                                 name = "<UNKNOWN IRG>";
776                 }  /* if */
777
778                 csv_count_nodes(dmp, entry, cnt);
779
780                 fprintf(dmp->f, "%-40s, %p, %u, %u, %u, %u\n",
781                         name,
782                         (void *)entry->irg,
783                         cnt_to_uint(&cnt[0]),
784                         cnt_to_uint(&cnt[1]),
785                         cnt_to_uint(&cnt[2]),
786                         cnt_to_uint(&cnt[3])
787                 );
788         }  /* if */
789 }  /* csv_dump_graph */
790
791 /**
792  * dumps the IRG
793  */
794 static void csv_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
795 {
796         (void) dmp;
797         (void) tbl;
798         /* FIXME: NYI */
799 }  /* csv_dump_const_tbl */
800
801 /**
802  * dumps the parameter distribution table
803  */
804 static void csv_dump_param_tbl(dumper_t *dmp, const distrib_tbl_t *tbl, graph_entry_t *global)
805 {
806         (void) dmp;
807         (void) tbl;
808         (void) global;
809         /* FIXME: NYI */
810 }  /* csv_dump_param_tbl */
811
812 /**
813  * dumps the optimization counter
814  */
815 static void csv_dump_opt_cnt(dumper_t *dmp, const counter_t *tbl, unsigned len)
816 {
817         (void) dmp;
818         (void) tbl;
819         (void) len;
820         /* FIXME: NYI */
821 }  /* csv_dump_opt_cnt */
822
823 /**
824  * initialize the simple dumper
825  */
826 static void csv_init(dumper_t *dmp, const char *name)
827 {
828         char fname[2048];
829
830         snprintf(fname, sizeof(fname), "%s.csv", name);
831         dmp->f = fopen(fname, "a");
832         if (! dmp->f)
833                 perror(fname);
834 }  /* csv_init */
835
836 /**
837  * finishes the simple dumper
838  */
839 static void csv_finish(dumper_t *dmp)
840 {
841         if (dmp->f)
842                 fclose(dmp->f);
843         dmp->f = NULL;
844 }  /* csv_finish */
845
846 /**
847  * the simple human readable dumper
848  */
849 const dumper_t csv_dumper = {
850         csv_dump_graph,
851         csv_dump_const_tbl,
852         csv_dump_param_tbl,
853         csv_dump_opt_cnt,
854         csv_init,
855         csv_finish,
856         NULL,
857         NULL,
858         NULL,
859         NULL,
860         FOURCC('C', 'S', 'V', '\0')
861 };