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