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