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