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