check file handle, so it does not crash if the file could not be opened
[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
183   if (! dmp->f)
184     return;
185
186   if (entry->irg) {
187     ir_graph *const_irg = get_const_code_irg();
188
189     if (entry->irg == const_irg) {
190       fprintf(dmp->f, "\nConst code Irg %p", (void *)entry->irg);
191     }
192     else {
193       if (entry->ent)
194         fprintf(dmp->f, "\nEntity %s, Irg %p", get_entity_ld_name(entry->ent), (void *)entry->irg);
195       else
196         fprintf(dmp->f, "\nIrg %p", (void *)entry->irg);
197     }
198
199     fprintf(dmp->f, " %swalked %u over blocks %u:\n"
200                     " was inlined               : %u\n"
201                     " got inlined               : %u\n"
202                     " strength red              : %u\n"
203                     " leaf function             : %s\n"
204                     " calls only leaf functions : %s\n"
205                     " recursive                 : %s\n"
206                     " chain call                : %s\n"
207         " calls                     : %u\n"
208         " indirect calls            : %u\n",
209         entry->is_deleted ? "DELETED " : "",
210         entry->cnt_walked.cnt[0], entry->cnt_walked_blocks.cnt[0],
211         entry->cnt_was_inlined.cnt[0],
212         entry->cnt_got_inlined.cnt[0],
213               entry->cnt_strength_red.cnt[0],
214               entry->is_leaf ? "YES" : "NO",
215               entry->is_leaf_call == LCS_NON_LEAF_CALL ? "NO" : (entry->is_leaf_call == LCS_LEAF_CALL ? "Yes" : "Maybe"),
216               entry->is_recursive ? "YES" : "NO",
217               entry->is_chain_call ? "YES" : "NO",
218         entry->cnt_all_calls.cnt[0],
219         entry->cnt_indirect_calls.cnt[0]
220     );
221
222     for (i = 0; i < sizeof(entry->cnt_if_conv)/sizeof(entry->cnt_if_conv[0]); ++i) {
223       fprintf(dmp->f, " %s : %u\n", if_conv_names[i], entry->cnt_if_conv[i].cnt[0]);
224     }
225
226   }
227   else {
228     fprintf(dmp->f, "\nGlobals counts:\n");
229     fprintf(dmp->f, "--------------\n");
230     dump_opts = 0;
231   }
232
233   simple_dump_opcode_hash(dmp, entry->opcode_hash);
234   simple_dump_edges(dmp, &entry->cnt_edges);
235
236   /* effects of optimizations */
237   if (dump_opts) {
238     int i;
239
240     simple_dump_real_func_calls(dmp, &entry->cnt_real_func_call);
241     simple_dump_tail_recursion(dmp, entry->num_tail_recursion);
242
243     for (i = 0; i < sizeof(entry->opt_hash)/sizeof(entry->opt_hash[0]); ++i) {
244       simple_dump_opt_hash(dmp, entry->opt_hash[i], i);
245     }
246
247     /* dump block info */
248     fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s %12s\n", "Block Nr", "Nodes", "intern E", "incoming E", "outgoing E", "Phi", "quot");
249     for (b_entry = pset_first(entry->block_hash);
250                b_entry;
251                b_entry = pset_next(entry->block_hash)) {
252       fprintf(dmp->f, "BLK %12ld %12u %12u %12u %12u %12u %4.8f\n",
253               b_entry->block_nr,
254               b_entry->cnt_nodes.cnt[0],
255               b_entry->cnt_edges.cnt[0],
256               b_entry->cnt_in_edges.cnt[0],
257               b_entry->cnt_out_edges.cnt[0],
258               b_entry->cnt_phi_data.cnt[0],
259               (double)b_entry->cnt_edges.cnt[0] / (double)b_entry->cnt_nodes.cnt[0]
260       );
261     }
262   }
263 }
264
265 /**
266  * dumps the IRG
267  */
268 static void simple_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
269 {
270   int i;
271   counter_t sum;
272
273   if (! dmp->f)
274     return;
275
276   cnt_clr(&sum);
277
278   fprintf(dmp->f, "\nConstant Information:\n");
279   fprintf(dmp->f, "---------------------\n");
280
281   fprintf(dmp->f, "\nBit usage for integer constants\n");
282   fprintf(dmp->f, "-------------------------------\n");
283
284   for (i = 0; i < ARR_SIZE(tbl->int_bits_count); ++i) {
285     fprintf(dmp->f, "%5d %12u\n", i + 1, tbl->int_bits_count[i].cnt[0]);
286     cnt_add(&sum, &tbl->int_bits_count[i]);
287   }
288   fprintf(dmp->f, "-------------------------------\n");
289
290   fprintf(dmp->f, "\nFloating point constants classification\n");
291   fprintf(dmp->f, "--------------------------------------\n");
292   for (i = 0; i < ARR_SIZE(tbl->floats); ++i) {
293     fprintf(dmp->f, "%-10s %12u\n", stat_fc_name(i), tbl->floats[i].cnt[0]);
294     cnt_add(&sum, &tbl->floats[i]);
295   }
296   fprintf(dmp->f, "--------------------------------------\n");
297
298   fprintf(dmp->f, "other %12u\n", tbl->others.cnt[0]);
299   cnt_add(&sum, &tbl->others);
300   fprintf(dmp->f, "-------------------------------\n");
301
302   fprintf(dmp->f, "sum   %12u\n", sum.cnt[0]);
303 }
304
305 /**
306  * initialize the simple dumper
307  */
308 static void simple_init(dumper_t *dmp, const char *name)
309 {
310   char fname[2048];
311
312   snprintf(fname, sizeof(fname), "%s.txt", name);
313   dmp->f = fopen(fname, "w");
314   if (! dmp->f) {
315     perror(fname);
316   }
317 }
318
319 /**
320  * finishes the simple dumper
321  */
322 static void simple_finish(dumper_t *dmp)
323 {
324   if (dmp->f)
325     fclose(dmp->f);
326   dmp->f = NULL;
327 }
328
329 /**
330  * the simple human readable dumper
331  */
332 const dumper_t simple_dumper = {
333   simple_dump_graph,
334   simple_dump_const_tbl,
335   simple_init,
336   simple_finish,
337   NULL,
338   NULL,
339   NULL,
340 };
341
342 /* ---------------------------------------------------------------------- */
343
344 /**
345  * count the nodes as needed:
346  *
347  * 1 normal (data) Phi's
348  * 2 memory Phi's
349  * 3 Proj
350  * 0 all other nodes
351  */
352 static void csv_count_nodes(dumper_t *dmp, graph_entry_t *graph, counter_t cnt[])
353 {
354   node_entry_t *entry;
355   int i;
356
357   for (i = 0; i < 4; ++i)
358     cnt_clr(&cnt[i]);
359
360   for (entry = pset_first(graph->opcode_hash); entry; entry = pset_next(graph->opcode_hash)) {
361     if (entry->op == op_Phi) {
362       /* normal Phi */
363       cnt_add(&cnt[1], &entry->cnt_alive);
364     }
365     else if (entry->op == dmp->status->op_PhiM) {
366       /* memory Phi */
367       cnt_add(&cnt[2], &entry->cnt_alive);
368     }
369     else if (entry->op == op_Proj) {
370       /* Proj */
371       cnt_add(&cnt[3], &entry->cnt_alive);
372     }
373     else {
374       /* all other nodes */
375       cnt_add(&cnt[0], &entry->cnt_alive);
376     }
377   }
378 }
379
380 /**
381  * dumps the IRG
382  */
383 static void csv_dump_graph(dumper_t *dmp, graph_entry_t *entry)
384 {
385   const char *name;
386   counter_t cnt[4];
387
388   if (! dmp->f)
389     return;
390
391   if (entry->irg && !entry->is_deleted) {
392     ir_graph *const_irg = get_const_code_irg();
393
394     if (entry->irg == const_irg) {
395       name = "<Const code Irg>";
396       return;
397     }
398     else {
399       if (entry->ent)
400         name = get_entity_name(entry->ent);
401       else
402         name = "<UNKNOWN IRG>";
403     }
404
405     csv_count_nodes(dmp, entry, cnt);
406
407     fprintf(dmp->f, "%-40s, %p, %d, %d, %d, %d\n",
408         name,
409         (void *)entry->irg,
410         cnt[0].cnt[0],
411         cnt[1].cnt[0],
412         cnt[2].cnt[0],
413         cnt[3].cnt[0]
414     );
415   }
416 }
417
418 /**
419  * dumps the IRG
420  */
421 static void csv_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
422 {
423   /* FIXME: NYI */
424 }
425
426 /**
427  * initialize the simple dumper
428  */
429 static void csv_init(dumper_t *dmp, const char *name)
430 {
431   char fname[2048];
432
433   snprintf(fname, sizeof(fname), "%s.csv", name);
434   dmp->f = fopen(fname, "a");
435   if (! dmp->f) {
436     perror(fname);
437   }
438 }
439
440 /**
441  * finishes the simple dumper
442  */
443 static void csv_finish(dumper_t *dmp)
444 {
445   if (dmp->f)
446     fclose(dmp->f);
447   dmp->f = NULL;
448 }
449
450 /**
451  * the simple human readable dumper
452  */
453 const dumper_t csv_dumper = {
454   csv_dump_graph,
455   csv_dump_const_tbl,
456   csv_init,
457   csv_finish,
458   NULL,
459   NULL,
460   NULL,
461 };