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