4a34bc77e8a7ccfb20a55370dda69e9114aed8aa
[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   { FS_BE_IA32_2ADDRCPY,   "ia32 Backend transformation: Copy created due to 2-Addresscode constraints" },
86   { FS_BE_IA32_SPILL2ST,   "ia32 Backend transformation: Created Store for a Spill" },
87   { FS_BE_IA32_RELOAD2LD,  "ia32 Backend transformation: Created Load for a Reload" },
88 };
89
90 static const char *if_conv_names[IF_RESULT_LAST] = {
91   "if conv done             ",
92   "if conv side effect      ",
93   "if conv Phi node found   ",
94   "if conv to deep DAG's    ",
95   "if conv bad control flow ",
96   "if conv denied by arch   ",
97 };
98
99 /**
100  * dumps a opcode hash into human readable form
101  */
102 static void simple_dump_opcode_hash(dumper_t *dmp, pset *set)
103 {
104   node_entry_t *entry;
105   counter_t f_alive;
106   counter_t f_new_node;
107   counter_t f_Id;
108
109   cnt_clr(&f_alive);
110   cnt_clr(&f_new_node);
111   cnt_clr(&f_Id);
112
113   fprintf(dmp->f, "%-16s %-8s %-8s %-8s\n", "Opcode", "alive", "created", "->Id");
114   for (entry = pset_first(set); entry; entry = pset_next(set)) {
115     fprintf(dmp->f, "%-16s %8u %8u %8u\n",
116       get_id_str(entry->op->name), entry->cnt_alive.cnt[0], entry->new_node.cnt[0], entry->into_Id.cnt[0]);
117
118     cnt_add(&f_alive,    &entry->cnt_alive);
119     cnt_add(&f_new_node, &entry->new_node);
120     cnt_add(&f_Id,       &entry->into_Id);
121   }
122   fprintf(dmp->f, "-------------------------------------------\n");
123   fprintf(dmp->f, "%-16s %8u %8u %8u\n", "Sum",
124      f_alive.cnt[0],
125      f_new_node.cnt[0],
126      f_Id.cnt[0]);
127 }
128
129 /**
130  * dumps an optimization hash into human readable form
131  */
132 static void simple_dump_opt_hash(dumper_t *dmp, pset *set, int index)
133 {
134   opt_entry_t *entry = pset_first(set);
135
136   assert(index < ARR_SIZE(opt_names) && "index out of range");
137   assert(opt_names[index].kind == index && "opt_names broken");
138   if (entry) {
139     fprintf(dmp->f, "\n%s:\n", opt_names[index].name);
140     fprintf(dmp->f, "%-16s %-8s\n", "Opcode", "deref");
141
142     for (; entry; entry = pset_next(set)) {
143       fprintf(dmp->f, "%-16s %8u\n",
144         get_id_str(entry->op->name), entry->count.cnt[0]);
145     }
146   }
147 }
148
149 /**
150  * dumps the number of real_function_call optimization
151  */
152 static void simple_dump_real_func_calls(dumper_t *dmp, counter_t *cnt)
153 {
154   if (! dmp->f)
155     return;
156
157   if (! cnt_eq(cnt, 0)) {
158     fprintf(dmp->f, "\nReal Function Calls optimized:\n");
159     fprintf(dmp->f, "%-16s %8u\n",
160       "Call", cnt->cnt[0]);
161   }
162 }
163
164 /**
165  * dumps the number of tail_recursion optimization
166  */
167 static void simple_dump_tail_recursion(dumper_t *dmp, unsigned num_tail_recursion)
168 {
169   if (! dmp->f)
170     return;
171
172   if (num_tail_recursion > 0) {
173     fprintf(dmp->f, "\nTail recursion optimized:\n");
174     fprintf(dmp->f, "%-16s %8u\n", "Call", num_tail_recursion);
175   }
176 }
177
178 /**
179  * dumps the edges count
180  */
181 static void simple_dump_edges(dumper_t *dmp, counter_t *cnt)
182 {
183   if (! dmp->f)
184     return;
185
186   fprintf(dmp->f, "%-16s %8d\n", "Edges", cnt->cnt[0]);
187 }
188
189 /**
190  * dumps the IRG
191  */
192 static void simple_dump_graph(dumper_t *dmp, graph_entry_t *entry)
193 {
194   int i, dump_opts = 1;
195   block_entry_t *b_entry;
196   extbb_entry_t *eb_entry;
197
198   if (! dmp->f)
199     return;
200
201   if (entry->irg) {
202     ir_graph *const_irg = get_const_code_irg();
203
204     if (entry->irg == const_irg) {
205       fprintf(dmp->f, "\nConst code Irg %p", (void *)entry->irg);
206     }
207     else {
208       if (entry->ent)
209         fprintf(dmp->f, "\nEntity %s, Irg %p", get_entity_ld_name(entry->ent), (void *)entry->irg);
210       else
211         fprintf(dmp->f, "\nIrg %p", (void *)entry->irg);
212     }
213
214     fprintf(dmp->f, " %swalked %u over blocks %u:\n"
215                 " was inlined               : %u\n"
216                 " got inlined               : %u\n"
217                 " strength red              : %u\n"
218                 " leaf function             : %s\n"
219                 " calls only leaf functions : %s\n"
220                 " recursive                 : %s\n"
221                 " chain call                : %s\n"
222         " calls                     : %u\n"
223         " indirect calls            : %u\n",
224         entry->is_deleted ? "DELETED " : "",
225         entry->cnt_walked.cnt[0], entry->cnt_walked_blocks.cnt[0],
226         entry->cnt_was_inlined.cnt[0],
227         entry->cnt_got_inlined.cnt[0],
228                 entry->cnt_strength_red.cnt[0],
229                 entry->is_leaf ? "YES" : "NO",
230                 entry->is_leaf_call == LCS_NON_LEAF_CALL ? "NO" : (entry->is_leaf_call == LCS_LEAF_CALL ? "Yes" : "Maybe"),
231                 entry->is_recursive ? "YES" : "NO",
232                 entry->is_chain_call ? "YES" : "NO",
233         entry->cnt_all_calls.cnt[0],
234         entry->cnt_indirect_calls.cnt[0]
235         );
236
237     for (i = 0; i < sizeof(entry->cnt_if_conv)/sizeof(entry->cnt_if_conv[0]); ++i) {
238       fprintf(dmp->f, " %s : %u\n", if_conv_names[i], entry->cnt_if_conv[i].cnt[0]);
239     }
240
241   }
242   else {
243     fprintf(dmp->f, "\nGlobals counts:\n");
244     fprintf(dmp->f, "--------------\n");
245     dump_opts = 0;
246   }
247
248   simple_dump_opcode_hash(dmp, entry->opcode_hash);
249   simple_dump_edges(dmp, &entry->cnt_edges);
250
251   /* effects of optimizations */
252   if (dump_opts) {
253     int i;
254
255     simple_dump_real_func_calls(dmp, &entry->cnt_real_func_call);
256     simple_dump_tail_recursion(dmp, entry->num_tail_recursion);
257
258     for (i = 0; i < sizeof(entry->opt_hash)/sizeof(entry->opt_hash[0]); ++i) {
259       simple_dump_opt_hash(dmp, entry->opt_hash[i], i);
260     }
261
262     /* dump block info */
263     fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s %12s\n", "Block Nr", "Nodes", "intern E", "incoming E", "outgoing E", "Phi", "quot");
264     for (b_entry = pset_first(entry->block_hash);
265                b_entry;
266                b_entry = pset_next(entry->block_hash)) {
267       fprintf(dmp->f, "BLK   %6ld %12u %12u %12u %12u %12u %4.8f\n",
268               b_entry->block_nr,
269               b_entry->cnt_nodes.cnt[0],
270               b_entry->cnt_edges.cnt[0],
271               b_entry->cnt_in_edges.cnt[0],
272               b_entry->cnt_out_edges.cnt[0],
273         b_entry->cnt_phi_data.cnt[0],
274               (double)b_entry->cnt_edges.cnt[0] / (double)b_entry->cnt_nodes.cnt[0]
275       );
276     }
277
278     if (dmp->status->stat_options & FIRMSTAT_COUNT_EXTBB) {
279       /* dump extended block info */
280       fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s %12s\n", "Extbb Nr", "Nodes", "intern E", "incoming E", "outgoing E", "Phi", "quot");
281       for (eb_entry = pset_first(entry->extbb_hash);
282            eb_entry;
283            eb_entry = pset_next(entry->extbb_hash)) {
284         fprintf(dmp->f, "ExtBB %6ld %12u %12u %12u %12u %12u %4.8f\n",
285           eb_entry->block_nr,
286           eb_entry->cnt_nodes.cnt[0],
287           eb_entry->cnt_edges.cnt[0],
288           eb_entry->cnt_in_edges.cnt[0],
289           eb_entry->cnt_out_edges.cnt[0],
290           eb_entry->cnt_phi_data.cnt[0],
291           (double)eb_entry->cnt_edges.cnt[0] / (double)eb_entry->cnt_nodes.cnt[0]
292         );
293       }
294     }
295   }
296 }
297
298 /**
299  * dumps the IRG
300  */
301 static void simple_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
302 {
303   int i;
304   counter_t sum;
305
306   if (! dmp->f)
307     return;
308
309   cnt_clr(&sum);
310
311   fprintf(dmp->f, "\nConstant Information:\n");
312   fprintf(dmp->f, "---------------------\n");
313
314   fprintf(dmp->f, "\nBit usage for integer constants\n");
315   fprintf(dmp->f, "-------------------------------\n");
316
317   for (i = 0; i < ARR_SIZE(tbl->int_bits_count); ++i) {
318     fprintf(dmp->f, "%5d %12u\n", i + 1, tbl->int_bits_count[i].cnt[0]);
319     cnt_add(&sum, &tbl->int_bits_count[i]);
320   }
321   fprintf(dmp->f, "-------------------------------\n");
322
323   fprintf(dmp->f, "\nFloating point constants classification\n");
324   fprintf(dmp->f, "--------------------------------------\n");
325   for (i = 0; i < ARR_SIZE(tbl->floats); ++i) {
326     fprintf(dmp->f, "%-10s %12u\n", stat_fc_name(i), tbl->floats[i].cnt[0]);
327     cnt_add(&sum, &tbl->floats[i]);
328   }
329   fprintf(dmp->f, "--------------------------------------\n");
330
331   fprintf(dmp->f, "other %12u\n", tbl->others.cnt[0]);
332   cnt_add(&sum, &tbl->others);
333   fprintf(dmp->f, "-------------------------------\n");
334
335   fprintf(dmp->f, "sum   %12u\n", sum.cnt[0]);
336 }
337
338 /**
339  * initialize the simple dumper
340  */
341 static void simple_init(dumper_t *dmp, const char *name)
342 {
343   char fname[2048];
344
345   snprintf(fname, sizeof(fname), "%s.txt", name);
346   dmp->f = fopen(fname, "w");
347   if (! dmp->f) {
348     perror(fname);
349   }
350 }
351
352 /**
353  * finishes the simple dumper
354  */
355 static void simple_finish(dumper_t *dmp)
356 {
357   if (dmp->f)
358     fclose(dmp->f);
359   dmp->f = NULL;
360 }
361
362 /**
363  * the simple human readable dumper
364  */
365 const dumper_t simple_dumper = {
366   simple_dump_graph,
367   simple_dump_const_tbl,
368   simple_init,
369   simple_finish,
370   NULL,
371   NULL,
372   NULL,
373 };
374
375 /* ---------------------------------------------------------------------- */
376
377 /**
378  * count the nodes as needed:
379  *
380  * 1 normal (data) Phi's
381  * 2 memory Phi's
382  * 3 Proj
383  * 0 all other nodes
384  */
385 static void csv_count_nodes(dumper_t *dmp, graph_entry_t *graph, counter_t cnt[])
386 {
387   node_entry_t *entry;
388   int i;
389
390   for (i = 0; i < 4; ++i)
391     cnt_clr(&cnt[i]);
392
393   for (entry = pset_first(graph->opcode_hash); entry; entry = pset_next(graph->opcode_hash)) {
394     if (entry->op == op_Phi) {
395       /* normal Phi */
396       cnt_add(&cnt[1], &entry->cnt_alive);
397     }
398     else if (entry->op == dmp->status->op_PhiM) {
399       /* memory Phi */
400       cnt_add(&cnt[2], &entry->cnt_alive);
401     }
402     else if (entry->op == op_Proj) {
403       /* Proj */
404       cnt_add(&cnt[3], &entry->cnt_alive);
405     }
406     else {
407       /* all other nodes */
408       cnt_add(&cnt[0], &entry->cnt_alive);
409     }
410   }
411 }
412
413 /**
414  * dumps the IRG
415  */
416 static void csv_dump_graph(dumper_t *dmp, graph_entry_t *entry)
417 {
418   const char *name;
419   counter_t cnt[4];
420
421   if (! dmp->f)
422     return;
423
424   if (entry->irg && !entry->is_deleted) {
425     ir_graph *const_irg = get_const_code_irg();
426
427     if (entry->irg == const_irg) {
428       name = "<Const code Irg>";
429       return;
430     }
431     else {
432       if (entry->ent)
433         name = get_entity_name(entry->ent);
434       else
435         name = "<UNKNOWN IRG>";
436     }
437
438     csv_count_nodes(dmp, entry, cnt);
439
440     fprintf(dmp->f, "%-40s, %p, %d, %d, %d, %d\n",
441         name,
442         (void *)entry->irg,
443         cnt[0].cnt[0],
444         cnt[1].cnt[0],
445         cnt[2].cnt[0],
446         cnt[3].cnt[0]
447     );
448   }
449 }
450
451 /**
452  * dumps the IRG
453  */
454 static void csv_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
455 {
456   /* FIXME: NYI */
457 }
458
459 /**
460  * initialize the simple dumper
461  */
462 static void csv_init(dumper_t *dmp, const char *name)
463 {
464   char fname[2048];
465
466   snprintf(fname, sizeof(fname), "%s.csv", name);
467   dmp->f = fopen(fname, "a");
468   if (! dmp->f) {
469     perror(fname);
470   }
471 }
472
473 /**
474  * finishes the simple dumper
475  */
476 static void csv_finish(dumper_t *dmp)
477 {
478   if (dmp->f)
479     fclose(dmp->f);
480   dmp->f = NULL;
481 }
482
483 /**
484  * the simple human readable dumper
485  */
486 const dumper_t csv_dumper = {
487   csv_dump_graph,
488   csv_dump_const_tbl,
489   csv_init,
490   csv_finish,
491   NULL,
492   NULL,
493   NULL,
494 };