added IA32 backend dbg statistics
[libfirm] / ir / stat / stat_dmp.c
1 /*
2  * Project:     libFIRM
3  * File name:   ir/ir/stat_dmp.c
4  * Purpose:     Statistics for Firm.
5  * Author:      Michael Beck
6  * Created:
7  * CVS-ID:      $Id$
8  * Copyright:   (c) 2004 Universität Karlsruhe
9  * Licence:     This file protected by GPL -  GNU GENERAL PUBLIC LICENSE.
10  */
11 #ifdef HAVE_CONFIG_H
12 # include "config.h"
13 #endif
14
15 #include "stat_dmp.h"
16 #include "irhooks.h"
17
18 /**
19  * names of the optimizations
20  */
21 static const struct {
22   hook_opt_kind kind;
23   const char    *name;
24 } opt_names[] = {
25   { HOOK_OPT_DEAD_BLOCK,   "dead block elimination" },
26   { HOOK_OPT_STG,          "straightening optimization" },
27   { HOOK_OPT_IFSIM,        "if simplification" },
28   { HOOK_OPT_CONST_EVAL,   "constant evaluation" },
29   { HOOK_OPT_ALGSIM,       "algebraic simplification" },
30   { HOOK_OPT_PHI,          "Phi optmization" },
31   { HOOK_OPT_SYNC,         "Sync optmization" },
32   { HOOK_OPT_WAW,          "Write-After-Write optimization" },
33   { HOOK_OPT_WAR,          "Write-After-Read optimization" },
34   { HOOK_OPT_RAW,          "Read-After-Write optimization" },
35   { HOOK_OPT_RAR,          "Read-After-Read optimization" },
36   { HOOK_OPT_RC,           "Read-a-Const optimization" },
37   { HOOK_OPT_TUPLE,        "Tuple optimization" },
38   { HOOK_OPT_ID,           "ID optimization" },
39   { HOOK_OPT_CSE,          "Common subexpression elimination" },
40   { HOOK_OPT_STRENGTH_RED, "Strength reduction" },
41   { HOOK_OPT_ARCH_DEP,     "Architecture dependant optimization" },
42   { HOOK_OPT_REASSOC,      "Reassociation optimization" },
43   { HOOK_OPT_POLY_CALL,    "Polymorphic call optimization" },
44   { HOOK_OPT_IF_CONV,      "an if conversion was tried" },
45   { HOOK_OPT_FUNC_CALL,    "Real function call optimization" },
46   { HOOK_OPT_CONFIRM,      "Confirm-based optimization: replacement" },
47   { HOOK_OPT_CONFIRM_C,    "Confirm-based optimization: replaced by const" },
48   { HOOK_OPT_CONFIRM_E,    "Confirm-based optimization: evaluated" },
49   { HOOK_OPT_EXC_REM,      "a exception edge was removed due to a Confirmation prove" },
50   { HOOK_LOWERED,          "Lowered" },
51   { HOOK_BACKEND,          "Backend transformation" },
52   { FS_OPT_NEUTRAL_0,      "algebraic simplification: a op 0 = 0 op a = a" },
53   { FS_OPT_NEUTRAL_1,      "algebraic simplification: a op 1 = 1 op a = a" },
54   { FS_OPT_ADD_A_A,        "algebraic simplification: a + a = a * 2" },
55   { FS_OPT_ADD_A_MINUS_B,  "algebraic simplification: a + -b = a - b" },
56   { FS_OPT_ADD_SUB,        "algebraic simplification: (a + x) - x = (a - x) + x = a" },
57   { FS_OPT_ADD_MUL_A_X_A,  "algebraic simplification: a * x + a = a * (x + 1)" },
58   { FS_OPT_SUB_0_A,        "algebraic simplification: 0 - a = -a" },
59   { FS_OPT_SUB_MUL_A_X_A,  "algebraic simplification: a * x - a = a * (x - 1)" },
60   { FS_OPT_MUL_MINUS_1,    "algebraic simplification: a * -1 = -a" },
61   { FS_OPT_OR,             "algebraic simplification: a | a = a | 0 = 0 | a = a" },
62   { FS_OPT_AND,            "algebraic simplification: a & 0b1...1 = 0b1...1 & a =  a & a = a" },
63   { FS_OPT_EOR_A_A,        "algebraic simplification: a ^ a = 0" },
64   { FS_OPT_EOR_TO_NOT_BOOL,"algebraic simplification: bool ^ 1 = !bool" },
65   { FS_OPT_EOR_TO_NOT,     "algebraic simplification: x ^ 0b1..1 = ~x" },
66   { FS_OPT_NOT_CMP,        "algebraic simplification: !(a cmp b) = a !cmp b" },
67   { FS_OPT_OR_SHFT_TO_ROT, "algebraic simplification: (x << c) | (x >> (bits - c)) == Rot(x, c)" },
68   { FS_OPT_REASSOC_SHIFT,  "algebraic simplification: (x SHF c1) SHF c2 = x SHF (c1+c2)" },
69   { FS_OPT_CONV,           "algebraic simplification: Conv could be removed" },
70   { FS_OPT_CAST,           "algebraic simplification: a Cast could be removed" },
71   { FS_OPT_MIN_MAX_EQ,     "algebraic simplification: Min(a,a) = Max(a,a) = a" },
72   { FS_OPT_MUX_C,          "algebraic simplification: Mux(C, f, t) = C ? t : f" },
73   { FS_OPT_MUX_EQ,         "algebraic simplification: Mux(v, x, x) = x" },
74   { FS_OPT_MUX_TRANSFORM,  "algebraic simplification: Mux(a, b, c) = b OR Mux(a,b, c) = c" },
75   { FS_OPT_MUX_TO_MIN,     "algebraic simplification: Mux(a < b, a, b) = Min(a,b)" },
76   { FS_OPT_MUX_TO_MAX,     "algebraic simplification: Mux(a > b, a, b) = Max(a,b)" },
77   { FS_OPT_MUX_TO_ABS,     "algebraic simplification: Mux(a > b, a, b) = Abs(a,b)" },
78   { FS_OPT_MUX_TO_SHR,     "algebraic simplification: Mux(a > b, a, b) = a >> b" },
79   { FS_BE_IA32_LEA,        "ia32 Backend transformation: Lea was created" },
80   { FS_BE_IA32_LOAD_LEA,   "ia32 Backend transformation: Load merged with a Lea" },
81   { FS_BE_IA32_STORE_LEA,  "ia32 Backend transformation: Store merged with a Lea" },
82   { FS_BE_IA32_AM_S,       "ia32 Backend transformation: Source address mode node created" },
83   { FS_BE_IA32_AM_D,       "ia32 Backend transformation: Destination address mode node created" },
84   { FS_BE_IA32_CJMP,       "ia32 Backend transformation: CJmp created to save a cmp/test" },
85 };
86
87 static const char *if_conv_names[IF_RESULT_LAST] = {
88   "if conv done             ",
89   "if conv side effect      ",
90   "if conv Phi node found   ",
91   "if conv to deep DAG's    ",
92   "if conv bad control flow ",
93   "if conv denied by arch   ",
94 };
95
96 /**
97  * dumps a opcode hash into human readable form
98  */
99 static void simple_dump_opcode_hash(dumper_t *dmp, pset *set)
100 {
101   node_entry_t *entry;
102   counter_t f_alive;
103   counter_t f_new_node;
104   counter_t f_Id;
105
106   cnt_clr(&f_alive);
107   cnt_clr(&f_new_node);
108   cnt_clr(&f_Id);
109
110   fprintf(dmp->f, "%-16s %-8s %-8s %-8s\n", "Opcode", "alive", "created", "->Id");
111   for (entry = pset_first(set); entry; entry = pset_next(set)) {
112     fprintf(dmp->f, "%-16s %8u %8u %8u\n",
113       get_id_str(entry->op->name), entry->cnt_alive.cnt[0], entry->new_node.cnt[0], entry->into_Id.cnt[0]);
114
115     cnt_add(&f_alive,    &entry->cnt_alive);
116     cnt_add(&f_new_node, &entry->new_node);
117     cnt_add(&f_Id,       &entry->into_Id);
118   }
119   fprintf(dmp->f, "-------------------------------------------\n");
120   fprintf(dmp->f, "%-16s %8u %8u %8u\n", "Sum",
121      f_alive.cnt[0],
122      f_new_node.cnt[0],
123      f_Id.cnt[0]);
124 }
125
126 /**
127  * dumps an optimization hash into human readable form
128  */
129 static void simple_dump_opt_hash(dumper_t *dmp, pset *set, int index)
130 {
131   opt_entry_t *entry = pset_first(set);
132
133   assert(index < ARR_SIZE(opt_names) && "index out of range");
134   assert(opt_names[index].kind == index && "opt_names broken");
135   if (entry) {
136     fprintf(dmp->f, "\n%s:\n", opt_names[index].name);
137     fprintf(dmp->f, "%-16s %-8s\n", "Opcode", "deref");
138
139     for (; entry; entry = pset_next(set)) {
140       fprintf(dmp->f, "%-16s %8u\n",
141         get_id_str(entry->op->name), entry->count.cnt[0]);
142     }
143   }
144 }
145
146 /**
147  * dumps the number of real_function_call optimization
148  */
149 static void simple_dump_real_func_calls(dumper_t *dmp, counter_t *cnt)
150 {
151   if (! dmp->f)
152     return;
153
154   if (! cnt_eq(cnt, 0)) {
155     fprintf(dmp->f, "\nReal Function Calls optimized:\n");
156     fprintf(dmp->f, "%-16s %8u\n",
157       "Call", cnt->cnt[0]);
158   }
159 }
160
161 /**
162  * dumps the number of tail_recursion optimization
163  */
164 static void simple_dump_tail_recursion(dumper_t *dmp, unsigned num_tail_recursion)
165 {
166   if (! dmp->f)
167     return;
168
169   if (num_tail_recursion > 0) {
170     fprintf(dmp->f, "\nTail recursion optimized:\n");
171     fprintf(dmp->f, "%-16s %8u\n", "Call", num_tail_recursion);
172   }
173 }
174
175 /**
176  * dumps the edges count
177  */
178 static void simple_dump_edges(dumper_t *dmp, counter_t *cnt)
179 {
180   if (! dmp->f)
181     return;
182
183   fprintf(dmp->f, "%-16s %8d\n", "Edges", cnt->cnt[0]);
184 }
185
186 /**
187  * dumps the IRG
188  */
189 static void simple_dump_graph(dumper_t *dmp, graph_entry_t *entry)
190 {
191   int i, dump_opts = 1;
192   block_entry_t *b_entry;
193   extbb_entry_t *eb_entry;
194
195   if (! dmp->f)
196     return;
197
198   if (entry->irg) {
199     ir_graph *const_irg = get_const_code_irg();
200
201     if (entry->irg == const_irg) {
202       fprintf(dmp->f, "\nConst code Irg %p", (void *)entry->irg);
203     }
204     else {
205       if (entry->ent)
206         fprintf(dmp->f, "\nEntity %s, Irg %p", get_entity_ld_name(entry->ent), (void *)entry->irg);
207       else
208         fprintf(dmp->f, "\nIrg %p", (void *)entry->irg);
209     }
210
211     fprintf(dmp->f, " %swalked %u over blocks %u:\n"
212                     " was inlined               : %u\n"
213                     " got inlined               : %u\n"
214                     " strength red              : %u\n"
215                     " leaf function             : %s\n"
216                     " calls only leaf functions : %s\n"
217                     " recursive                 : %s\n"
218                     " chain call                : %s\n"
219         " calls                     : %u\n"
220         " indirect calls            : %u\n",
221         entry->is_deleted ? "DELETED " : "",
222         entry->cnt_walked.cnt[0], entry->cnt_walked_blocks.cnt[0],
223         entry->cnt_was_inlined.cnt[0],
224         entry->cnt_got_inlined.cnt[0],
225               entry->cnt_strength_red.cnt[0],
226               entry->is_leaf ? "YES" : "NO",
227               entry->is_leaf_call == LCS_NON_LEAF_CALL ? "NO" : (entry->is_leaf_call == LCS_LEAF_CALL ? "Yes" : "Maybe"),
228               entry->is_recursive ? "YES" : "NO",
229               entry->is_chain_call ? "YES" : "NO",
230         entry->cnt_all_calls.cnt[0],
231         entry->cnt_indirect_calls.cnt[0]
232     );
233
234     for (i = 0; i < sizeof(entry->cnt_if_conv)/sizeof(entry->cnt_if_conv[0]); ++i) {
235       fprintf(dmp->f, " %s : %u\n", if_conv_names[i], entry->cnt_if_conv[i].cnt[0]);
236     }
237
238   }
239   else {
240     fprintf(dmp->f, "\nGlobals counts:\n");
241     fprintf(dmp->f, "--------------\n");
242     dump_opts = 0;
243   }
244
245   simple_dump_opcode_hash(dmp, entry->opcode_hash);
246   simple_dump_edges(dmp, &entry->cnt_edges);
247
248   /* effects of optimizations */
249   if (dump_opts) {
250     int i;
251
252     simple_dump_real_func_calls(dmp, &entry->cnt_real_func_call);
253     simple_dump_tail_recursion(dmp, entry->num_tail_recursion);
254
255     for (i = 0; i < sizeof(entry->opt_hash)/sizeof(entry->opt_hash[0]); ++i) {
256       simple_dump_opt_hash(dmp, entry->opt_hash[i], i);
257     }
258
259     /* dump block info */
260     fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s %12s\n", "Block Nr", "Nodes", "intern E", "incoming E", "outgoing E", "Phi", "quot");
261     for (b_entry = pset_first(entry->block_hash);
262                b_entry;
263                b_entry = pset_next(entry->block_hash)) {
264       fprintf(dmp->f, "BLK   %6ld %12u %12u %12u %12u %12u %4.8f\n",
265               b_entry->block_nr,
266               b_entry->cnt_nodes.cnt[0],
267               b_entry->cnt_edges.cnt[0],
268               b_entry->cnt_in_edges.cnt[0],
269               b_entry->cnt_out_edges.cnt[0],
270         b_entry->cnt_phi_data.cnt[0],
271               (double)b_entry->cnt_edges.cnt[0] / (double)b_entry->cnt_nodes.cnt[0]
272       );
273     }
274
275     if (dmp->status->stat_options & FIRMSTAT_COUNT_EXTBB) {
276       /* dump extended block info */
277       fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s %12s\n", "Extbb Nr", "Nodes", "intern E", "incoming E", "outgoing E", "Phi", "quot");
278       for (eb_entry = pset_first(entry->extbb_hash);
279            eb_entry;
280            eb_entry = pset_next(entry->extbb_hash)) {
281         fprintf(dmp->f, "ExtBB %6ld %12u %12u %12u %12u %12u %4.8f\n",
282           eb_entry->block_nr,
283           eb_entry->cnt_nodes.cnt[0],
284           eb_entry->cnt_edges.cnt[0],
285           eb_entry->cnt_in_edges.cnt[0],
286           eb_entry->cnt_out_edges.cnt[0],
287           eb_entry->cnt_phi_data.cnt[0],
288           (double)eb_entry->cnt_edges.cnt[0] / (double)eb_entry->cnt_nodes.cnt[0]
289         );
290       }
291     }
292   }
293 }
294
295 /**
296  * dumps the IRG
297  */
298 static void simple_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
299 {
300   int i;
301   counter_t sum;
302
303   if (! dmp->f)
304     return;
305
306   cnt_clr(&sum);
307
308   fprintf(dmp->f, "\nConstant Information:\n");
309   fprintf(dmp->f, "---------------------\n");
310
311   fprintf(dmp->f, "\nBit usage for integer constants\n");
312   fprintf(dmp->f, "-------------------------------\n");
313
314   for (i = 0; i < ARR_SIZE(tbl->int_bits_count); ++i) {
315     fprintf(dmp->f, "%5d %12u\n", i + 1, tbl->int_bits_count[i].cnt[0]);
316     cnt_add(&sum, &tbl->int_bits_count[i]);
317   }
318   fprintf(dmp->f, "-------------------------------\n");
319
320   fprintf(dmp->f, "\nFloating point constants classification\n");
321   fprintf(dmp->f, "--------------------------------------\n");
322   for (i = 0; i < ARR_SIZE(tbl->floats); ++i) {
323     fprintf(dmp->f, "%-10s %12u\n", stat_fc_name(i), tbl->floats[i].cnt[0]);
324     cnt_add(&sum, &tbl->floats[i]);
325   }
326   fprintf(dmp->f, "--------------------------------------\n");
327
328   fprintf(dmp->f, "other %12u\n", tbl->others.cnt[0]);
329   cnt_add(&sum, &tbl->others);
330   fprintf(dmp->f, "-------------------------------\n");
331
332   fprintf(dmp->f, "sum   %12u\n", sum.cnt[0]);
333 }
334
335 /**
336  * initialize the simple dumper
337  */
338 static void simple_init(dumper_t *dmp, const char *name)
339 {
340   char fname[2048];
341
342   snprintf(fname, sizeof(fname), "%s.txt", name);
343   dmp->f = fopen(fname, "w");
344   if (! dmp->f) {
345     perror(fname);
346   }
347 }
348
349 /**
350  * finishes the simple dumper
351  */
352 static void simple_finish(dumper_t *dmp)
353 {
354   if (dmp->f)
355     fclose(dmp->f);
356   dmp->f = NULL;
357 }
358
359 /**
360  * the simple human readable dumper
361  */
362 const dumper_t simple_dumper = {
363   simple_dump_graph,
364   simple_dump_const_tbl,
365   simple_init,
366   simple_finish,
367   NULL,
368   NULL,
369   NULL,
370 };
371
372 /* ---------------------------------------------------------------------- */
373
374 /**
375  * count the nodes as needed:
376  *
377  * 1 normal (data) Phi's
378  * 2 memory Phi's
379  * 3 Proj
380  * 0 all other nodes
381  */
382 static void csv_count_nodes(dumper_t *dmp, graph_entry_t *graph, counter_t cnt[])
383 {
384   node_entry_t *entry;
385   int i;
386
387   for (i = 0; i < 4; ++i)
388     cnt_clr(&cnt[i]);
389
390   for (entry = pset_first(graph->opcode_hash); entry; entry = pset_next(graph->opcode_hash)) {
391     if (entry->op == op_Phi) {
392       /* normal Phi */
393       cnt_add(&cnt[1], &entry->cnt_alive);
394     }
395     else if (entry->op == dmp->status->op_PhiM) {
396       /* memory Phi */
397       cnt_add(&cnt[2], &entry->cnt_alive);
398     }
399     else if (entry->op == op_Proj) {
400       /* Proj */
401       cnt_add(&cnt[3], &entry->cnt_alive);
402     }
403     else {
404       /* all other nodes */
405       cnt_add(&cnt[0], &entry->cnt_alive);
406     }
407   }
408 }
409
410 /**
411  * dumps the IRG
412  */
413 static void csv_dump_graph(dumper_t *dmp, graph_entry_t *entry)
414 {
415   const char *name;
416   counter_t cnt[4];
417
418   if (! dmp->f)
419     return;
420
421   if (entry->irg && !entry->is_deleted) {
422     ir_graph *const_irg = get_const_code_irg();
423
424     if (entry->irg == const_irg) {
425       name = "<Const code Irg>";
426       return;
427     }
428     else {
429       if (entry->ent)
430         name = get_entity_name(entry->ent);
431       else
432         name = "<UNKNOWN IRG>";
433     }
434
435     csv_count_nodes(dmp, entry, cnt);
436
437     fprintf(dmp->f, "%-40s, %p, %d, %d, %d, %d\n",
438         name,
439         (void *)entry->irg,
440         cnt[0].cnt[0],
441         cnt[1].cnt[0],
442         cnt[2].cnt[0],
443         cnt[3].cnt[0]
444     );
445   }
446 }
447
448 /**
449  * dumps the IRG
450  */
451 static void csv_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
452 {
453   /* FIXME: NYI */
454 }
455
456 /**
457  * initialize the simple dumper
458  */
459 static void csv_init(dumper_t *dmp, const char *name)
460 {
461   char fname[2048];
462
463   snprintf(fname, sizeof(fname), "%s.csv", name);
464   dmp->f = fopen(fname, "a");
465   if (! dmp->f) {
466     perror(fname);
467   }
468 }
469
470 /**
471  * finishes the simple dumper
472  */
473 static void csv_finish(dumper_t *dmp)
474 {
475   if (dmp->f)
476     fclose(dmp->f);
477   dmp->f = NULL;
478 }
479
480 /**
481  * the simple human readable dumper
482  */
483 const dumper_t csv_dumper = {
484   csv_dump_graph,
485   csv_dump_const_tbl,
486   csv_init,
487   csv_finish,
488   NULL,
489   NULL,
490   NULL,
491 };