remove $Id$, it doesn't work with git anyway
[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
32 /**
33  * names of the optimizations
34  */
35 static const struct {
36         hook_opt_kind kind;
37         const char    *name;
38 } opt_names[] = {
39         { HOOK_OPT_DEAD_BLOCK,                  "dead block elimination" },
40         { HOOK_OPT_STG,                         "straightening optimization" },
41         { HOOK_OPT_IFSIM,                       "if simplification" },
42         { HOOK_OPT_CONST_EVAL,                  "constant evaluation" },
43         { HOOK_OPT_ALGSIM,                      "algebraic simplification" },
44         { HOOK_OPT_PHI,                         "Phi optmization" },
45         { HOOK_OPT_SYNC,                        "Sync optmization" },
46         { HOOK_OPT_WAW,                         "Write-After-Write optimization" },
47         { HOOK_OPT_WAR,                         "Write-After-Read optimization" },
48         { HOOK_OPT_RAW,                         "Read-After-Write optimization" },
49         { HOOK_OPT_RAR,                         "Read-After-Read optimization" },
50         { HOOK_OPT_RC,                          "Read-a-Const optimization" },
51         { HOOK_OPT_TUPLE,                       "Tuple optimization" },
52         { HOOK_OPT_ID,                          "ID optimization" },
53         { HOOK_OPT_CSE,                         "Common subexpression elimination" },
54         { HOOK_OPT_STRENGTH_RED,                "Strength reduction" },
55         { HOOK_OPT_ARCH_DEP,                    "Architecture dependant optimization" },
56         { HOOK_OPT_REASSOC,                     "Reassociation optimization" },
57         { HOOK_OPT_POLY_CALL,                   "Polymorphic call optimization" },
58         { HOOK_OPT_IF_CONV,                     "an if conversion was tried" },
59         { HOOK_OPT_FUNC_CALL,                   "Real function call optimization" },
60         { HOOK_OPT_CONFIRM,                     "Confirm-based optimization: replacement" },
61         { HOOK_OPT_CONFIRM_C,                   "Confirm-based optimization: replaced by const" },
62         { HOOK_OPT_CONFIRM_E,                   "Confirm-based optimization: evaluated" },
63         { HOOK_OPT_EXC_REM,                     "a exception edge was removed due to a Confirmation prove" },
64         { HOOK_OPT_NORMALIZE,                   "a commutative node was normalized" },
65         { HOOK_LOWERED,                         "Lowered" },
66         { HOOK_BACKEND,                         "Backend transformation" },
67         { (hook_opt_kind)FS_OPT_NEUTRAL_0,      "algebraic simplification: a op 0 = 0 op a = a" },
68         { (hook_opt_kind)FS_OPT_NEUTRAL_1,      "algebraic simplification: a op 1 = 1 op a = a" },
69         { (hook_opt_kind)FS_OPT_ADD_A_A,        "algebraic simplification: a + a = a * 2" },
70         { (hook_opt_kind)FS_OPT_ADD_A_MINUS_B,  "algebraic simplification: a + -b = a - b" },
71         { (hook_opt_kind)FS_OPT_ADD_SUB,        "algebraic simplification: (a + x) - x = (a - x) + x = a" },
72         { (hook_opt_kind)FS_OPT_ADD_MUL_A_X_A,  "algebraic simplification: a * x + a = a * (x + 1)" },
73         { (hook_opt_kind)FS_OPT_SUB_0_A,        "algebraic simplification: 0 - a = -a" },
74         { (hook_opt_kind)FS_OPT_MINUS_SUB,      "algebraic simplification: -(a - b) = b - a" },
75         { (hook_opt_kind)FS_OPT_SUB_MINUS,      "algebraic simplification: a - (-b) = a + b" },
76         { (hook_opt_kind)FS_OPT_SUB_MUL_A_X_A,  "algebraic simplification: a * x - a = a * (x - 1)" },
77         { (hook_opt_kind)FS_OPT_SUB_SUB_X_Y_Z,  "algebraic simplification: (x - y) - z = x - (y + z)" },
78         { (hook_opt_kind)FS_OPT_SUB_C_NOT_X,    "algebraic simplification: c - ~a = a + (c+1)" },
79         { (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)" },
80         { (hook_opt_kind)FS_OPT_SUB_TO_NOT,     "algebraic simplification: -1 - x -> ~x" },
81         { (hook_opt_kind)FS_OPT_SUB_TO_CONV,    "algebraic simplification: a - NULL = (int)a" },
82         { (hook_opt_kind)FS_OPT_MUL_MINUS,      "algebraic simplification: (-a) * (b - c) = a * (c - b)" },
83         { (hook_opt_kind)FS_OPT_MUL_MINUS_1,    "algebraic simplification: a * -1 = -a" },
84         { (hook_opt_kind)FS_OPT_MINUS_MUL_C,    "algebraic simplification: (-a) * C = a * (-C)" },
85         { (hook_opt_kind)FS_OPT_MUL_MINUS_MINUS,"algebraic simplification: (-a) * (-b) = a * b" },
86         { (hook_opt_kind)FS_OPT_OR,             "algebraic simplification: a | a = a | 0 = 0 | a = a" },
87         { (hook_opt_kind)FS_OPT_AND,            "algebraic simplification: a & 0b1...1 = 0b1...1 & a = a & a = (a|X) & a = a" },
88         { (hook_opt_kind)FS_OPT_TO_EOR,         "algebraic simplification: (a|b) & ~(a&b) = a^b" },
89         { (hook_opt_kind)FS_OPT_EOR_A_A,        "algebraic simplification: a ^ a = 0" },
90         { (hook_opt_kind)FS_OPT_EOR_A_B_A,      "algebraic simplification: (a ^ b) ^ a = b" },
91         { (hook_opt_kind)FS_OPT_EOR_TO_NOT_BOOL,"boolean simplification: bool ^ 1 = !bool" },
92         { (hook_opt_kind)FS_OPT_EOR_TO_NOT,     "algebraic simplification: x ^ 0b1..1 = ~x, (a ^ b) & b = ~a & b" },
93         { (hook_opt_kind)FS_OPT_NOT_CMP,        "algebraic simplification: !(a cmp b) = a !cmp b" },
94         { (hook_opt_kind)FS_OPT_OR_SHFT_TO_ROTL,"algebraic simplification: (x << c) | (x >> (bits - c)) == Rotl(x, c)" },
95         { (hook_opt_kind)FS_OPT_REASSOC_SHIFT,  "algebraic simplification: (x SHF c1) SHF c2 = x SHF (c1+c2)" },
96         { (hook_opt_kind)FS_OPT_SHIFT_AND,      "algebraic simplification: (a SHF c) AND (b SHF c) = (a AND b) SHF c" },
97         { (hook_opt_kind)FS_OPT_SHIFT_OR,       "algebraic simplification: (a SHF c) OR (b SHF c) = (a OR b) SHF c" },
98         { (hook_opt_kind)FS_OPT_SHIFT_EOR,      "algebraic simplification: (a SHF c) XOR (b SHF c) = (a XOR b) SHF c" },
99         { (hook_opt_kind)FS_OPT_CONV,           "algebraic simplification: Conv could be removed" },
100         { (hook_opt_kind)FS_OPT_CAST,           "algebraic simplification: a Cast 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_IDEM_UNARY,     "algebraic simplification: Idempotent unary operation" },
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         node_entry_t *entry;
196         counter_t f_alive;
197         counter_t f_new_node;
198         counter_t f_Id;
199         counter_t f_normlized;
200
201         cnt_clr(&f_alive);
202         cnt_clr(&f_new_node);
203         cnt_clr(&f_Id);
204         cnt_clr(&f_normlized);
205
206         fprintf(dmp->f, "%-16s %-8s %-8s %-8s %-8s\n", "Opcode", "alive", "created", "->Id", "normalized");
207         foreach_pset(set, node_entry_t*, entry) {
208                 fprintf(dmp->f, "%-16s %8u %8u %8u %8u\n",
209                         get_id_str(entry->op->name),
210                         cnt_to_uint(&entry->cnt_alive),
211                         cnt_to_uint(&entry->new_node),
212                         cnt_to_uint(&entry->into_Id),
213                         cnt_to_uint(&entry->normalized)
214                 );
215
216                 cnt_add(&f_alive,     &entry->cnt_alive);
217                 cnt_add(&f_new_node,  &entry->new_node);
218                 cnt_add(&f_Id,        &entry->into_Id);
219                 cnt_add(&f_normlized, &entry->normalized);
220         }  /* foreach_pset */
221         fprintf(dmp->f, "-------------------------------------------\n");
222         fprintf(dmp->f, "%-16s %8u %8u %8u %8u\n", "Sum",
223                 cnt_to_uint(&f_alive),
224                 cnt_to_uint(&f_new_node),
225                 cnt_to_uint(&f_Id),
226                 cnt_to_uint(&f_normlized)
227         );
228 }  /* simple_dump_opcode_hash */
229
230 /**
231  * Return the name of an optimization.
232  */
233 static const char *get_opt_name(int index)
234 {
235         assert(index < (int) ARRAY_SIZE(opt_names) && "index out of range");
236         assert((int) opt_names[index].kind == index && "opt_names broken");
237         return opt_names[index].name;
238 }  /* get_opt_name */
239
240 /**
241  * dumps an optimization hash into human readable form
242  */
243 static void simple_dump_opt_hash(dumper_t *dmp, pset *set, int index)
244 {
245         if (pset_count(set) > 0) {
246                 opt_entry_t *entry;
247                 const char *name = get_opt_name(index);
248
249                 fprintf(dmp->f, "\n%s:\n", name);
250                 fprintf(dmp->f, "%-16s %-8s\n", "Opcode", "deref");
251
252                 foreach_pset(set, opt_entry_t*, entry) {
253                         fprintf(dmp->f, "%-16s %8u\n",
254                                 get_id_str(entry->op->name), cnt_to_uint(&entry->count));
255                 }  /* foreach_pset */
256         }  /* if */
257 }  /* simple_dump_opt_hash */
258
259 /**
260  * dumps the register pressure for each block and for each register class
261  */
262 static void simple_dump_be_block_reg_pressure(dumper_t *dmp, graph_entry_t *entry)
263 {
264         be_block_entry_t     *b_entry = (be_block_entry_t*)pset_first(entry->be_block_hash);
265         reg_pressure_entry_t *rp_entry;
266
267         /* return if no be statistic information available */
268         if (! b_entry)
269                 return;
270
271         fprintf(dmp->f, "\nREG PRESSURE:\n");
272         fprintf(dmp->f, "%12s", "Block Nr");
273
274         /* print table head (register class names) */
275         foreach_pset(b_entry->reg_pressure, reg_pressure_entry_t*, rp_entry)
276                 fprintf(dmp->f, "%15s", rp_entry->class_name);
277         fprintf(dmp->f, "\n");
278
279         /* print the reg pressure for all blocks and register classes */
280         for (/* b_entry is already initialized */ ;
281              b_entry;
282              b_entry = (be_block_entry_t*)pset_next(entry->be_block_hash)) {
283                 fprintf(dmp->f, "BLK   %6ld", b_entry->block_nr);
284
285                 foreach_pset(b_entry->reg_pressure, reg_pressure_entry_t*, rp_entry)
286                         fprintf(dmp->f, "%15d", rp_entry->pressure);
287                 fprintf(dmp->f, "\n");
288         }  /* for */
289 }  /* simple_dump_be_block_reg_pressure */
290
291 /** prints a distribution entry */
292 static void simple_dump_distrib_entry(const distrib_entry_t *entry, void *env)
293 {
294         dumper_t *dmp = (dumper_t*)env;
295         fprintf(dmp->f, "%12u", cnt_to_uint(&entry->cnt));
296 }  /* simple_dump_distrib_entry */
297
298 /**
299  * dumps the distribution of the amount of ready nodes for each block
300  */
301 static void simple_dump_be_block_sched_ready(dumper_t *dmp, graph_entry_t *entry)
302 {
303         if (pset_count(entry->be_block_hash) > 0) {
304                 be_block_entry_t *b_entry;
305                 int              i;
306
307                 fprintf(dmp->f, "\nSCHEDULING: NUMBER OF READY NODES\n");
308                 fprintf(dmp->f, "%12s %12s %12s %12s %12s %12s %12s\n",
309                         "Block Nr", "1 node", "2 nodes", "3 nodes", "4 nodes", "5 or more", "AVERAGE");
310
311                 foreach_pset(entry->be_block_hash, be_block_entry_t*, b_entry) {
312                         /* this ensures that all keys from 1 to 5 are in the table */
313                         for (i = 1; i < 6; ++i)
314                                 stat_insert_int_distrib_tbl(b_entry->sched_ready, i);
315
316                         fprintf(dmp->f, "BLK   %6ld", b_entry->block_nr);
317                         stat_iterate_distrib_tbl(b_entry->sched_ready, simple_dump_distrib_entry, dmp);
318                         fprintf(dmp->f, "%12.2lf", stat_calc_avg_distrib_tbl(b_entry->sched_ready));
319                         fprintf(dmp->f, "\n");
320                 }  /* foreach_pset */
321         }  /* if */
322 }  /* simple_dump_be_block_sched_ready */
323
324 /**
325  * Adds the counter for given entry to another distribution table.
326  */
327 static void add_distrib_entry(const distrib_entry_t *entry, void *env)
328 {
329         distrib_tbl_t *sum_tbl = (distrib_tbl_t*)env;
330
331         stat_add_int_distrib_tbl(sum_tbl, (int)PTR_TO_INT(entry->object), &entry->cnt);
332 }  /* add_distrib_entry */
333
334 /**
335  * dumps permutation statistics for one and block and one class
336  */
337 static void simple_dump_be_block_permstat_class(dumper_t *dmp, perm_class_entry_t *entry)
338 {
339         perm_stat_entry_t *ps_ent;
340         distrib_tbl_t     *sum_chains = stat_new_int_distrib_tbl();
341         distrib_tbl_t     *sum_cycles = stat_new_int_distrib_tbl();
342         char              buf[16];
343         int               i;
344
345         fprintf(dmp->f, "%12s %12s %12s %12s %12s %12s\n",
346                 "size",
347                 "real size",
348                 "# chains",
349                 "# cycles",
350                 "# copies",
351                 "# exchanges"
352         );
353
354         foreach_pset(entry->perm_stat, perm_stat_entry_t*, ps_ent) {
355                 fprintf(dmp->f, "%12d %12d %12d %12d %12d %12d\n",
356                         ps_ent->size,
357                         ps_ent->real_size,
358                         stat_get_count_distrib_tbl(ps_ent->chains),
359                         stat_get_count_distrib_tbl(ps_ent->cycles),
360                         ps_ent->n_copies,
361                         ps_ent->n_exchg
362                 );
363
364                 /* sum up distribution table for chains */
365                 stat_iterate_distrib_tbl(ps_ent->chains, add_distrib_entry, sum_chains);
366
367                 /* sum up distribution table for cycles */
368                 stat_iterate_distrib_tbl(ps_ent->cycles, add_distrib_entry, sum_cycles);
369         }  /* foreach_pset */
370
371         /* print chain distribution for all perms of this class in this block */
372         fprintf(dmp->f, "chain distribution:\n");
373
374         /* add all missing entries to chain distribution table */
375         for (i = 1; i <= entry->n_regs; i++) {
376                 snprintf(buf, sizeof(buf), "length %d", i);
377                 fprintf(dmp->f, "%12s", buf);
378                 stat_insert_int_distrib_tbl(sum_chains, i);
379         }  /* for */
380         fprintf(dmp->f, "\n");
381         stat_iterate_distrib_tbl(sum_chains, simple_dump_distrib_entry, dmp);
382         fprintf(dmp->f, "\n");
383
384         /* print cycle distribution for all perms of this class in this block */
385         fprintf(dmp->f, "cycle distribution:\n");
386
387         /* add all missing entries to cycle distribution table */
388         for (i = 1; i <= entry->n_regs; i++) {
389                 snprintf(buf, sizeof(buf), "length %d", i);
390                 fprintf(dmp->f, "%12s", buf);
391                 stat_insert_int_distrib_tbl(sum_cycles, i);
392         }  /* for */
393         fprintf(dmp->f, "\n");
394         stat_iterate_distrib_tbl(sum_cycles, simple_dump_distrib_entry, dmp);
395         fprintf(dmp->f, "\n");
396
397         /* delete temporary sum distribution tables */
398         stat_delete_distrib_tbl(sum_chains);
399         stat_delete_distrib_tbl(sum_cycles);
400
401 }  /* simple_dump_be_block_permstat_class */
402
403 /**
404  * dumps statistics about perms
405  */
406 static void simple_dump_be_block_permstat(dumper_t *dmp, graph_entry_t *entry)
407 {
408         if (pset_count(entry->be_block_hash) > 0) {
409                 be_block_entry_t *b_entry;
410
411                 fprintf(dmp->f, "\nPERMUTATION STATISTICS BEGIN:\n");
412                 foreach_pset(entry->be_block_hash, be_block_entry_t*, b_entry) {
413                         perm_class_entry_t *pc_ent;
414
415                         fprintf(dmp->f, "BLOCK %ld:\n", b_entry->block_nr);
416
417                         if (b_entry->perm_class_stat) {
418                                 foreach_pset(b_entry->perm_class_stat, perm_class_entry_t*, pc_ent) {
419                                         fprintf(dmp->f, "register class %s:\n", pc_ent->class_name);
420                                         simple_dump_be_block_permstat_class(dmp, pc_ent);
421                                 }  /* foreach_pset */
422                         }  /* if */
423                 }  /* foreach_pset */
424
425                 fprintf(dmp->f, "PERMUTATION STATISTICS END\n");
426         }  /* if */
427 }  /* simple_dump_be_block_permstat */
428
429 /**
430  * dumps the number of real_function_call optimization
431  */
432 static void simple_dump_real_func_calls(dumper_t *dmp, counter_t *cnt)
433 {
434         if (! dmp->f)
435                 return;
436
437         if (! cnt_eq(cnt, 0)) {
438                 fprintf(dmp->f, "\nReal Function Calls optimized:\n");
439                 fprintf(dmp->f, "%-16s %8u\n", "Call", cnt_to_uint(cnt));
440         }  /* if */
441 }  /* simple_dump_real_func_calls */
442
443 /**
444  * dumps the number of tail_recursion optimization
445  */
446 static void simple_dump_tail_recursion(dumper_t *dmp, unsigned num_tail_recursion)
447 {
448         if (! dmp->f)
449                 return;
450
451         if (num_tail_recursion > 0) {
452                 fprintf(dmp->f, "\nTail recursion optimized:\n");
453                 fprintf(dmp->f, "%-16s %8u\n", "Call", num_tail_recursion);
454         }  /* if */
455 }  /* simple_dump_tail_recursion */
456
457 /**
458  * dumps the edges count
459  */
460 static void simple_dump_edges(dumper_t *dmp, counter_t *cnt)
461 {
462         if (! dmp->f)
463                 return;
464
465         fprintf(dmp->f, "%-16s %8u\n", "Edges", cnt_to_uint(cnt));
466 }  /* simple_dump_edges */
467
468 /**
469  * dumps the IRG
470  */
471 static void simple_dump_graph(dumper_t *dmp, graph_entry_t *entry)
472 {
473         int dump_opts = 1;
474         block_entry_t *b_entry;
475         extbb_entry_t *eb_entry;
476
477         if (! dmp->f)
478                 return;
479
480         if (entry->irg) {
481                 ir_graph *const_irg = get_const_code_irg();
482                 int       i;
483
484                 if (entry->irg == const_irg)
485                         fprintf(dmp->f, "\nConst code Irg %p", (void *)entry->irg);
486                 else {
487                         if (entry->ent)
488                                 fprintf(dmp->f, "\nEntity %s, Irg %p", get_entity_ld_name(entry->ent), (void *)entry->irg);
489                         else
490                                 fprintf(dmp->f, "\nIrg %p", (void *)entry->irg);
491                 }  /* if */
492
493                 fprintf(dmp->f, " %swalked %u over blocks %u:\n"
494                         " was inlined               : %u\n"
495                         " got inlined               : %u\n"
496                         " strength red              : %u\n"
497                         " leaf function             : %s\n"
498                         " calls only leaf functions : %s\n"
499                         " recursive                 : %s\n"
500                         " chain call                : %s\n"
501                         " strict                    : %s\n"
502                         " calls                     : %u\n"
503                         " indirect calls            : %u\n"
504                         " external calls            : %u\n",
505                         entry->is_deleted ? "DELETED " : "",
506                         cnt_to_uint(&entry->cnt[gcnt_acc_walked]), cnt_to_uint(&entry->cnt[gcnt_acc_walked_blocks]),
507                         cnt_to_uint(&entry->cnt[gcnt_acc_was_inlined]),
508                         cnt_to_uint(&entry->cnt[gcnt_acc_got_inlined]),
509                         cnt_to_uint(&entry->cnt[gcnt_acc_strength_red]),
510                         entry->is_leaf ? "YES" : "NO",
511                         entry->is_leaf_call == LCS_NON_LEAF_CALL ? "NO" : (entry->is_leaf_call == LCS_LEAF_CALL ? "Yes" : "Maybe"),
512                         entry->is_recursive ? "YES" : "NO",
513                         entry->is_chain_call ? "YES" : "NO",
514                         entry->is_strict ? "YES" : "NO",
515                         cnt_to_uint(&entry->cnt[gcnt_all_calls]),
516                         cnt_to_uint(&entry->cnt[gcnt_indirect_calls]),
517                         cnt_to_uint(&entry->cnt[gcnt_external_calls])
518                 );
519
520                 for (i = 0; i < IF_RESULT_LAST; ++i) {
521                         fprintf(dmp->f, " %s : %u\n", if_conv_names[i], cnt_to_uint(&entry->cnt[gcnt_if_conv + i]));
522                 }  /* for */
523         } else {
524                 fprintf(dmp->f, "\nGlobals counts:\n");
525                 fprintf(dmp->f, "--------------\n");
526                 dump_opts = 0;
527         }  /* if */
528
529         /* address ops */
530         fprintf(dmp->f,
531                 " pure address calc ops     : %u\n"
532                 " all address calc ops      : %u\n",
533                 cnt_to_uint(&entry->cnt[gcnt_pure_adr_ops]),
534                 cnt_to_uint(&entry->cnt[gcnt_all_adr_ops])
535         );
536
537         /* Load/Store address classification */
538         fprintf(dmp->f,
539                 " global Ld/St address      : %u\n"
540                 " local Ld/St address       : %u\n"
541                 " this Ld/St address        : %u\n"
542                 " param Ld/St address       : %u\n"
543                 " other Ld/St address       : %u\n",
544                 cnt_to_uint(&entry->cnt[gcnt_global_adr]),
545                 cnt_to_uint(&entry->cnt[gcnt_local_adr]),
546                 cnt_to_uint(&entry->cnt[gcnt_this_adr]),
547                 cnt_to_uint(&entry->cnt[gcnt_param_adr]),
548                 cnt_to_uint(&entry->cnt[gcnt_other_adr])
549         );
550
551         simple_dump_opcode_hash(dmp, entry->opcode_hash);
552         simple_dump_edges(dmp, &entry->cnt[gcnt_edges]);
553
554         /* effects of optimizations */
555         if (dump_opts) {
556                 size_t i;
557
558                 simple_dump_real_func_calls(dmp, &entry->cnt[gcnt_acc_real_func_call]);
559                 simple_dump_tail_recursion(dmp, entry->num_tail_recursion);
560
561                 for (i = 0; i < sizeof(entry->opt_hash)/sizeof(entry->opt_hash[0]); ++i) {
562                         simple_dump_opt_hash(dmp, entry->opt_hash[i], i);
563                 }  /* for */
564
565                 /* dump block info */
566                 fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s %12s\n", "Block Nr", "Nodes", "intern E", "incoming E", "outgoing E", "Phi", "quot");
567                 foreach_pset(entry->block_hash, block_entry_t*, b_entry) {
568                         fprintf(dmp->f, "BLK   %6ld %12u %12u %12u %12u %12u %4.8f %s\n",
569                                 b_entry->block_nr,
570                                 cnt_to_uint(&b_entry->cnt[bcnt_nodes]),
571                                 cnt_to_uint(&b_entry->cnt[bcnt_edges]),
572                                 cnt_to_uint(&b_entry->cnt[bcnt_in_edges]),
573                                 cnt_to_uint(&b_entry->cnt[bcnt_out_edges]),
574                                 cnt_to_uint(&b_entry->cnt[bcnt_phi_data]),
575                                 cnt_to_dbl(&b_entry->cnt[bcnt_edges]) / cnt_to_dbl(&b_entry->cnt[bcnt_nodes]),
576                                 b_entry->is_start ? "START" : (b_entry->is_end ? "END" : "")
577                         );
578                 }  /* foreach_pset */
579
580                 /* dump block reg pressure */
581                 simple_dump_be_block_reg_pressure(dmp, entry);
582
583                 /* dump block ready nodes distribution */
584                 simple_dump_be_block_sched_ready(dmp, entry);
585
586                 /* dump block permutation statistics */
587                 simple_dump_be_block_permstat(dmp, entry);
588
589                 if (dmp->status->stat_options & FIRMSTAT_COUNT_EXTBB && entry->extbb_hash) {
590                         /* dump extended block info */
591                         fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s %12s\n", "Extbb Nr", "Nodes", "intern E", "incoming E", "outgoing E", "Phi", "quot");
592                         foreach_pset(entry->extbb_hash, extbb_entry_t*, eb_entry) {
593                                 fprintf(dmp->f, "ExtBB %6ld %12u %12u %12u %12u %12u %4.8f\n",
594                                         eb_entry->block_nr,
595                                         cnt_to_uint(&eb_entry->cnt[bcnt_nodes]),
596                                         cnt_to_uint(&eb_entry->cnt[bcnt_edges]),
597                                         cnt_to_uint(&eb_entry->cnt[bcnt_in_edges]),
598                                         cnt_to_uint(&eb_entry->cnt[bcnt_out_edges]),
599                                         cnt_to_uint(&eb_entry->cnt[bcnt_phi_data]),
600                                         cnt_to_dbl(&eb_entry->cnt[bcnt_edges]) / cnt_to_dbl(&eb_entry->cnt[bcnt_nodes])
601                                 );
602                         }  /* foreach_pset */
603                 }  /* if */
604         }
605 }  /* simple_dump_graph */
606
607 /**
608  * dumps the constant table
609  */
610 static void simple_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
611 {
612         size_t i;
613         counter_t sum;
614
615         if (! dmp->f)
616                 return;
617
618         cnt_clr(&sum);
619
620         fprintf(dmp->f, "\nConstant Information:\n");
621         fprintf(dmp->f, "---------------------\n");
622
623         fprintf(dmp->f, "\nBit usage for integer constants\n");
624         fprintf(dmp->f, "-------------------------------\n");
625
626         for (i = 0; i < ARRAY_SIZE(tbl->int_bits_count); ++i) {
627                 fprintf(dmp->f, "%5u %12u\n", (unsigned) (i + 1), cnt_to_uint(&tbl->int_bits_count[i]));
628                 cnt_add(&sum, &tbl->int_bits_count[i]);
629         }  /* for */
630         fprintf(dmp->f, "-------------------------------\n");
631
632         fprintf(dmp->f, "\nFloating point constants classification\n");
633         fprintf(dmp->f, "--------------------------------------\n");
634         for (i = 0; i < ARRAY_SIZE(tbl->floats); ++i) {
635                 fprintf(dmp->f, "%-10s %12u\n", stat_fc_name((float_classify_t)i), cnt_to_uint(&tbl->floats[i]));
636                 cnt_add(&sum, &tbl->floats[i]);
637         }  /* for */
638         fprintf(dmp->f, "--------------------------------------\n");
639
640         fprintf(dmp->f, "other %12u\n", cnt_to_uint(&tbl->others));
641         cnt_add(&sum, &tbl->others);
642         fprintf(dmp->f, "-------------------------------\n");
643
644         fprintf(dmp->f, "sum   %12u\n", cnt_to_uint(&sum));
645 }  /* simple_dump_const_tbl */
646
647 /**
648  * Dumps a line of the parameter table
649  */
650 static void dump_tbl_line(const distrib_entry_t *entry, void *env)
651 {
652         dumper_t *dmp = (dumper_t*)env;
653
654         fprintf(dmp->f, "%ld : %u\n", (long int)PTR_TO_INT(entry->object),
655                 cnt_to_uint(&entry->cnt));
656 }  /* dump_tbl_line */
657
658 /**
659  * dumps the parameter distribution table
660  */
661 static void simple_dump_param_tbl(dumper_t *dmp, const distrib_tbl_t *tbl, graph_entry_t *global)
662 {
663         fprintf(dmp->f, "\nCall parameter Information:\n");
664         fprintf(dmp->f, "---------------------\n");
665
666         stat_iterate_distrib_tbl(tbl, dump_tbl_line, dmp);
667         fprintf(dmp->f, "-------------------------------\n");
668
669         fprintf(dmp->f, "Number of Calls           %12u\n", cnt_to_uint(&global->cnt[gcnt_all_calls]));
670         fprintf(dmp->f, "indirect calls            %12u\n", cnt_to_uint(&global->cnt[gcnt_indirect_calls]));
671         fprintf(dmp->f, "external calls            %12u\n", cnt_to_uint(&global->cnt[gcnt_external_calls]));
672         fprintf(dmp->f, "with const params         %12u\n", cnt_to_uint(&global->cnt[gcnt_call_with_cnst_arg]));
673         fprintf(dmp->f, "with all const params     %12u\n", cnt_to_uint(&global->cnt[gcnt_call_with_all_cnst_arg]));
674         fprintf(dmp->f, "with local var adr params %12u\n", cnt_to_uint(&global->cnt[gcnt_call_with_local_adr]));
675 }  /* simple_dump_param_tbl */
676
677 /**
678  * dumps the optimization counter table
679  */
680 static void simple_dump_opt_cnt(dumper_t *dmp, const counter_t *tbl, unsigned len)
681 {
682         unsigned i;
683
684         fprintf(dmp->f, "\nOptimization counts:\n");
685         fprintf(dmp->f, "---------------------\n");
686
687         for (i = 0; i < len; ++i) {
688                 unsigned cnt = cnt_to_uint(&tbl[i]);
689
690                 if (cnt > 0) {
691                         fprintf(dmp->f, "%8u %s\n", cnt, get_opt_name(i));
692                 }
693         }
694 }  /* simple_dump_opt_cnt */
695
696 /**
697  * initialize the simple dumper
698  */
699 static void simple_init(dumper_t *dmp, const char *name)
700 {
701         char fname[2048];
702
703         snprintf(fname, sizeof(fname), "%s.txt", name);
704         dmp->f = fopen(fname, "w");
705         if (! dmp->f) {
706                 perror(fname);
707         }  /* if */
708 }  /* simple_init */
709
710 /**
711  * finishes the simple dumper
712  */
713 static void simple_finish(dumper_t *dmp)
714 {
715         if (dmp->f)
716                 fclose(dmp->f);
717         dmp->f = NULL;
718 }  /* simple_finish */
719
720 /**
721  * the simple human readable dumper
722  */
723 const dumper_t simple_dumper = {
724         simple_dump_graph,
725         simple_dump_const_tbl,
726         simple_dump_param_tbl,
727         simple_dump_opt_cnt,
728         simple_init,
729         simple_finish,
730         NULL,
731         NULL,
732         NULL,
733         NULL,
734         FOURCC('S', 'M', 'P', 'L'),
735 };
736
737 /* ---------------------------------------------------------------------- */
738
739 /**
740  * count the nodes as needed:
741  *
742  * 1 normal (data) Phi's
743  * 2 memory Phi's
744  * 3 Proj
745  * 0 all other nodes
746  */
747 static void csv_count_nodes(dumper_t *dmp, graph_entry_t *graph, counter_t cnt[])
748 {
749         node_entry_t *entry;
750         int i;
751
752         for (i = 0; i < 4; ++i)
753                 cnt_clr(&cnt[i]);
754
755         foreach_pset(graph->opcode_hash, node_entry_t*, entry) {
756                 if (entry->op == op_Phi) {
757                         /* normal Phi */
758                         cnt_add(&cnt[1], &entry->cnt_alive);
759                 } else if (entry->op == dmp->status->op_PhiM) {
760                         /* memory Phi */
761                         cnt_add(&cnt[2], &entry->cnt_alive);
762                 } else if (entry->op == op_Proj) {
763                         /* Proj */
764                         cnt_add(&cnt[3], &entry->cnt_alive);
765                 } else {
766                         /* all other nodes */
767                         cnt_add(&cnt[0], &entry->cnt_alive);
768                 }  /* if */
769         }  /* foreach_pset */
770 }  /* csv_count_nodes */
771
772 /**
773  * dumps the IRG
774  */
775 static void csv_dump_graph(dumper_t *dmp, graph_entry_t *entry)
776 {
777         const char *name;
778         counter_t cnt[4];
779
780         if (! dmp->f)
781                 return;
782
783         if (entry->irg && !entry->is_deleted) {
784                 ir_graph *const_irg = get_const_code_irg();
785
786                 if (entry->irg == const_irg) {
787                         name = "<Const code Irg>";
788                         return;
789                 } else {
790                         if (entry->ent)
791                                 name = get_entity_name(entry->ent);
792                         else
793                                 name = "<UNKNOWN IRG>";
794                 }  /* if */
795
796                 csv_count_nodes(dmp, entry, cnt);
797
798                 fprintf(dmp->f, "%-40s, %p, %u, %u, %u, %u\n",
799                         name,
800                         (void *)entry->irg,
801                         cnt_to_uint(&cnt[0]),
802                         cnt_to_uint(&cnt[1]),
803                         cnt_to_uint(&cnt[2]),
804                         cnt_to_uint(&cnt[3])
805                 );
806         }  /* if */
807 }  /* csv_dump_graph */
808
809 /**
810  * dumps the IRG
811  */
812 static void csv_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
813 {
814         (void) dmp;
815         (void) tbl;
816         /* FIXME: NYI */
817 }  /* csv_dump_const_tbl */
818
819 /**
820  * dumps the parameter distribution table
821  */
822 static void csv_dump_param_tbl(dumper_t *dmp, const distrib_tbl_t *tbl, graph_entry_t *global)
823 {
824         (void) dmp;
825         (void) tbl;
826         (void) global;
827         /* FIXME: NYI */
828 }  /* csv_dump_param_tbl */
829
830 /**
831  * dumps the optimization counter
832  */
833 static void csv_dump_opt_cnt(dumper_t *dmp, const counter_t *tbl, unsigned len)
834 {
835         (void) dmp;
836         (void) tbl;
837         (void) len;
838         /* FIXME: NYI */
839 }  /* csv_dump_opt_cnt */
840
841 /**
842  * initialize the simple dumper
843  */
844 static void csv_init(dumper_t *dmp, const char *name)
845 {
846         char fname[2048];
847
848         snprintf(fname, sizeof(fname), "%s.csv", name);
849         dmp->f = fopen(fname, "a");
850         if (! dmp->f)
851                 perror(fname);
852 }  /* csv_init */
853
854 /**
855  * finishes the simple dumper
856  */
857 static void csv_finish(dumper_t *dmp)
858 {
859         if (dmp->f)
860                 fclose(dmp->f);
861         dmp->f = NULL;
862 }  /* csv_finish */
863
864 /**
865  * the simple human readable dumper
866  */
867 const dumper_t csv_dumper = {
868         csv_dump_graph,
869         csv_dump_const_tbl,
870         csv_dump_param_tbl,
871         csv_dump_opt_cnt,
872         csv_init,
873         csv_finish,
874         NULL,
875         NULL,
876         NULL,
877         NULL,
878         FOURCC('C', 'S', 'V', '\0')
879 };