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