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