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