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