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