3 * File name: ir/ir/stat_dmp.c
4 * Purpose: Statistics for Firm.
8 * Copyright: (c) 2004 Universität Karlsruhe
9 * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
19 * names of the optimizations
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" },
54 { FS_OPT_SUB_0_A, "algebraic simplification: 0 - a = -a" },
55 { FS_OPT_MUL_MINUS_1, "algebraic simplification: a * -1 = -a" },
56 { FS_OPT_OR, "algebraic simplification: a | a = a | 0 = 0 | a = a" },
57 { FS_OPT_AND, "algebraic simplification: a & 0b1...1 = 0b1...1 & a = a & a = a" },
58 { FS_OPT_EOR_A_A, "algebraic simplification: a ^ a = 0" },
59 { FS_OPT_EOR_TO_NOT_BOOL,"algebraic simplification: bool ^ 1 = !bool" },
60 { FS_OPT_EOR_TO_NOT, "algebraic simplification: x ^ 0b1..1 = ~x" },
61 { FS_OPT_NOT_CMP, "algebraic simplification: !(a cmp b) = a !cmp b" },
62 { FS_OPT_OR_SHFT_TO_ROT, "algebraic simplification: (x << c) | (x >> (bits - c)) == Rot(x, c)" },
63 { FS_OPT_REASSOC_SHIFT, "algebraic simplification: (x SHF c1) SHF c2 = x SHF (c1+c2)" },
64 { FS_OPT_CONV, "algebraic simplification: Conv could be removed" },
65 { FS_OPT_CAST, "algebraic simplification: a Cast could be removed" },
66 { FS_OPT_MIN_MAX_EQ, "algebraic simplification: Min(a,a) = Max(a,a) = a" },
67 { FS_OPT_MUX_C, "algebraic simplification: Mux(C, f, t) = C ? t : f" },
68 { FS_OPT_MUX_EQ, "algebraic simplification: Mux(v, x, x) = x" },
69 { FS_OPT_MUX_TRANSFORM, "algebraic simplification: Mux(a, b, c) = b OR Mux(a,b, c) = c" },
70 { FS_OPT_MUX_TO_MIN, "algebraic simplification: Mux(a < b, a, b) = Min(a,b)" },
71 { FS_OPT_MUX_TO_MAX, "algebraic simplification: Mux(a > b, a, b) = Max(a,b)" },
72 { FS_OPT_MUX_TO_ABS, "algebraic simplification: Mux(a > b, a, b) = Abs(a,b)" },
73 { FS_OPT_MUX_TO_SHR, "algebraic simplification: Mux(a > b, a, b) = a >> b" },
76 static const char *if_conv_names[IF_RESULT_LAST] = {
78 "if conv side effect ",
79 "if conv Phi node found ",
80 "if conv to deep DAG's ",
81 "if conv bad control flow ",
82 "if conv denied by arch ",
86 * dumps a opcode hash into human readable form
88 static void simple_dump_opcode_hash(dumper_t *dmp, pset *set)
99 fprintf(dmp->f, "%-16s %-8s %-8s %-8s\n", "Opcode", "alive", "created", "->Id");
100 for (entry = pset_first(set); entry; entry = pset_next(set)) {
101 fprintf(dmp->f, "%-16s %8u %8u %8u\n",
102 get_id_str(entry->op->name), entry->cnt_alive.cnt[0], entry->new_node.cnt[0], entry->into_Id.cnt[0]);
104 cnt_add(&f_alive, &entry->cnt_alive);
105 cnt_add(&f_new_node, &entry->new_node);
106 cnt_add(&f_Id, &entry->into_Id);
108 fprintf(dmp->f, "-------------------------------------------\n");
109 fprintf(dmp->f, "%-16s %8u %8u %8u\n", "Sum",
116 * dumps an optimization hash into human readable form
118 static void simple_dump_opt_hash(dumper_t *dmp, pset *set, int index)
120 opt_entry_t *entry = pset_first(set);
122 assert(index < ARR_SIZE(opt_names) && "index out of range");
123 assert(opt_names[index].kind == index && "opt_names broken");
125 fprintf(dmp->f, "\n%s:\n", opt_names[index].name);
126 fprintf(dmp->f, "%-16s %-8s\n", "Opcode", "deref");
128 for (; entry; entry = pset_next(set)) {
129 fprintf(dmp->f, "%-16s %8u\n",
130 get_id_str(entry->op->name), entry->count.cnt[0]);
136 * dumps the number of real_function_call optimization
138 static void simple_dump_real_func_calls(dumper_t *dmp, counter_t *cnt)
143 if (! cnt_eq(cnt, 0)) {
144 fprintf(dmp->f, "\nReal Function Calls optimized:\n");
145 fprintf(dmp->f, "%-16s %8u\n",
146 "Call", cnt->cnt[0]);
151 * dumps the number of tail_recursion optimization
153 static void simple_dump_tail_recursion(dumper_t *dmp, unsigned num_tail_recursion)
158 if (num_tail_recursion > 0) {
159 fprintf(dmp->f, "\nTail recursion optimized:\n");
160 fprintf(dmp->f, "%-16s %8u\n", "Call", num_tail_recursion);
165 * dumps the edges count
167 static void simple_dump_edges(dumper_t *dmp, counter_t *cnt)
172 fprintf(dmp->f, "%-16s %8d\n", "Edges", cnt->cnt[0]);
178 static void simple_dump_graph(dumper_t *dmp, graph_entry_t *entry)
180 int i, dump_opts = 1;
181 block_entry_t *b_entry;
182 extbb_entry_t *eb_entry;
188 ir_graph *const_irg = get_const_code_irg();
190 if (entry->irg == const_irg) {
191 fprintf(dmp->f, "\nConst code Irg %p", (void *)entry->irg);
195 fprintf(dmp->f, "\nEntity %s, Irg %p", get_entity_ld_name(entry->ent), (void *)entry->irg);
197 fprintf(dmp->f, "\nIrg %p", (void *)entry->irg);
200 fprintf(dmp->f, " %swalked %u over blocks %u:\n"
201 " was inlined : %u\n"
202 " got inlined : %u\n"
203 " strength red : %u\n"
204 " leaf function : %s\n"
205 " calls only leaf functions : %s\n"
209 " indirect calls : %u\n",
210 entry->is_deleted ? "DELETED " : "",
211 entry->cnt_walked.cnt[0], entry->cnt_walked_blocks.cnt[0],
212 entry->cnt_was_inlined.cnt[0],
213 entry->cnt_got_inlined.cnt[0],
214 entry->cnt_strength_red.cnt[0],
215 entry->is_leaf ? "YES" : "NO",
216 entry->is_leaf_call == LCS_NON_LEAF_CALL ? "NO" : (entry->is_leaf_call == LCS_LEAF_CALL ? "Yes" : "Maybe"),
217 entry->is_recursive ? "YES" : "NO",
218 entry->is_chain_call ? "YES" : "NO",
219 entry->cnt_all_calls.cnt[0],
220 entry->cnt_indirect_calls.cnt[0]
223 for (i = 0; i < sizeof(entry->cnt_if_conv)/sizeof(entry->cnt_if_conv[0]); ++i) {
224 fprintf(dmp->f, " %s : %u\n", if_conv_names[i], entry->cnt_if_conv[i].cnt[0]);
229 fprintf(dmp->f, "\nGlobals counts:\n");
230 fprintf(dmp->f, "--------------\n");
234 simple_dump_opcode_hash(dmp, entry->opcode_hash);
235 simple_dump_edges(dmp, &entry->cnt_edges);
237 /* effects of optimizations */
241 simple_dump_real_func_calls(dmp, &entry->cnt_real_func_call);
242 simple_dump_tail_recursion(dmp, entry->num_tail_recursion);
244 for (i = 0; i < sizeof(entry->opt_hash)/sizeof(entry->opt_hash[0]); ++i) {
245 simple_dump_opt_hash(dmp, entry->opt_hash[i], i);
248 /* dump block info */
249 fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s %12s\n", "Block Nr", "Nodes", "intern E", "incoming E", "outgoing E", "Phi", "quot");
250 for (b_entry = pset_first(entry->block_hash);
252 b_entry = pset_next(entry->block_hash)) {
253 fprintf(dmp->f, "BLK %6ld %12u %12u %12u %12u %12u %4.8f\n",
255 b_entry->cnt_nodes.cnt[0],
256 b_entry->cnt_edges.cnt[0],
257 b_entry->cnt_in_edges.cnt[0],
258 b_entry->cnt_out_edges.cnt[0],
259 b_entry->cnt_phi_data.cnt[0],
260 (double)b_entry->cnt_edges.cnt[0] / (double)b_entry->cnt_nodes.cnt[0]
264 if (dmp->status->stat_options & FIRMSTAT_COUNT_EXTBB) {
265 /* dump extended block info */
266 fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s %12s\n", "Extbb Nr", "Nodes", "intern E", "incoming E", "outgoing E", "Phi", "quot");
267 for (eb_entry = pset_first(entry->extbb_hash);
269 eb_entry = pset_next(entry->extbb_hash)) {
270 fprintf(dmp->f, "ExtBB %6ld %12u %12u %12u %12u %12u %4.8f\n",
272 eb_entry->cnt_nodes.cnt[0],
273 eb_entry->cnt_edges.cnt[0],
274 eb_entry->cnt_in_edges.cnt[0],
275 eb_entry->cnt_out_edges.cnt[0],
276 eb_entry->cnt_phi_data.cnt[0],
277 (double)eb_entry->cnt_edges.cnt[0] / (double)eb_entry->cnt_nodes.cnt[0]
287 static void simple_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
297 fprintf(dmp->f, "\nConstant Information:\n");
298 fprintf(dmp->f, "---------------------\n");
300 fprintf(dmp->f, "\nBit usage for integer constants\n");
301 fprintf(dmp->f, "-------------------------------\n");
303 for (i = 0; i < ARR_SIZE(tbl->int_bits_count); ++i) {
304 fprintf(dmp->f, "%5d %12u\n", i + 1, tbl->int_bits_count[i].cnt[0]);
305 cnt_add(&sum, &tbl->int_bits_count[i]);
307 fprintf(dmp->f, "-------------------------------\n");
309 fprintf(dmp->f, "\nFloating point constants classification\n");
310 fprintf(dmp->f, "--------------------------------------\n");
311 for (i = 0; i < ARR_SIZE(tbl->floats); ++i) {
312 fprintf(dmp->f, "%-10s %12u\n", stat_fc_name(i), tbl->floats[i].cnt[0]);
313 cnt_add(&sum, &tbl->floats[i]);
315 fprintf(dmp->f, "--------------------------------------\n");
317 fprintf(dmp->f, "other %12u\n", tbl->others.cnt[0]);
318 cnt_add(&sum, &tbl->others);
319 fprintf(dmp->f, "-------------------------------\n");
321 fprintf(dmp->f, "sum %12u\n", sum.cnt[0]);
325 * initialize the simple dumper
327 static void simple_init(dumper_t *dmp, const char *name)
331 snprintf(fname, sizeof(fname), "%s.txt", name);
332 dmp->f = fopen(fname, "w");
339 * finishes the simple dumper
341 static void simple_finish(dumper_t *dmp)
349 * the simple human readable dumper
351 const dumper_t simple_dumper = {
353 simple_dump_const_tbl,
361 /* ---------------------------------------------------------------------- */
364 * count the nodes as needed:
366 * 1 normal (data) Phi's
371 static void csv_count_nodes(dumper_t *dmp, graph_entry_t *graph, counter_t cnt[])
376 for (i = 0; i < 4; ++i)
379 for (entry = pset_first(graph->opcode_hash); entry; entry = pset_next(graph->opcode_hash)) {
380 if (entry->op == op_Phi) {
382 cnt_add(&cnt[1], &entry->cnt_alive);
384 else if (entry->op == dmp->status->op_PhiM) {
386 cnt_add(&cnt[2], &entry->cnt_alive);
388 else if (entry->op == op_Proj) {
390 cnt_add(&cnt[3], &entry->cnt_alive);
393 /* all other nodes */
394 cnt_add(&cnt[0], &entry->cnt_alive);
402 static void csv_dump_graph(dumper_t *dmp, graph_entry_t *entry)
410 if (entry->irg && !entry->is_deleted) {
411 ir_graph *const_irg = get_const_code_irg();
413 if (entry->irg == const_irg) {
414 name = "<Const code Irg>";
419 name = get_entity_name(entry->ent);
421 name = "<UNKNOWN IRG>";
424 csv_count_nodes(dmp, entry, cnt);
426 fprintf(dmp->f, "%-40s, %p, %d, %d, %d, %d\n",
440 static void csv_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
446 * initialize the simple dumper
448 static void csv_init(dumper_t *dmp, const char *name)
452 snprintf(fname, sizeof(fname), "%s.csv", name);
453 dmp->f = fopen(fname, "a");
460 * finishes the simple dumper
462 static void csv_finish(dumper_t *dmp)
470 * the simple human readable dumper
472 const dumper_t csv_dumper = {