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 = 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" },
78 static const char *if_conv_names[IF_RESULT_LAST] = {
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 ",
88 * dumps a opcode hash into human readable form
90 static void simple_dump_opcode_hash(dumper_t *dmp, pset *set)
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]);
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);
110 fprintf(dmp->f, "-------------------------------------------\n");
111 fprintf(dmp->f, "%-16s %8u %8u %8u\n", "Sum",
118 * dumps an optimization hash into human readable form
120 static void simple_dump_opt_hash(dumper_t *dmp, pset *set, int index)
122 opt_entry_t *entry = pset_first(set);
124 assert(index < ARR_SIZE(opt_names) && "index out of range");
125 assert(opt_names[index].kind == index && "opt_names broken");
127 fprintf(dmp->f, "\n%s:\n", opt_names[index].name);
128 fprintf(dmp->f, "%-16s %-8s\n", "Opcode", "deref");
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]);
138 * dumps the number of real_function_call optimization
140 static void simple_dump_real_func_calls(dumper_t *dmp, counter_t *cnt)
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]);
153 * dumps the number of tail_recursion optimization
155 static void simple_dump_tail_recursion(dumper_t *dmp, unsigned num_tail_recursion)
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);
167 * dumps the edges count
169 static void simple_dump_edges(dumper_t *dmp, counter_t *cnt)
174 fprintf(dmp->f, "%-16s %8d\n", "Edges", cnt->cnt[0]);
180 static void simple_dump_graph(dumper_t *dmp, graph_entry_t *entry)
182 int i, dump_opts = 1;
183 block_entry_t *b_entry;
184 extbb_entry_t *eb_entry;
190 ir_graph *const_irg = get_const_code_irg();
192 if (entry->irg == const_irg) {
193 fprintf(dmp->f, "\nConst code Irg %p", (void *)entry->irg);
197 fprintf(dmp->f, "\nEntity %s, Irg %p", get_entity_ld_name(entry->ent), (void *)entry->irg);
199 fprintf(dmp->f, "\nIrg %p", (void *)entry->irg);
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"
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]
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]);
231 fprintf(dmp->f, "\nGlobals counts:\n");
232 fprintf(dmp->f, "--------------\n");
236 simple_dump_opcode_hash(dmp, entry->opcode_hash);
237 simple_dump_edges(dmp, &entry->cnt_edges);
239 /* effects of optimizations */
243 simple_dump_real_func_calls(dmp, &entry->cnt_real_func_call);
244 simple_dump_tail_recursion(dmp, entry->num_tail_recursion);
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);
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);
254 b_entry = pset_next(entry->block_hash)) {
255 fprintf(dmp->f, "BLK %6ld %12u %12u %12u %12u %12u %4.8f\n",
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]
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);
271 eb_entry = pset_next(entry->extbb_hash)) {
272 fprintf(dmp->f, "ExtBB %6ld %12u %12u %12u %12u %12u %4.8f\n",
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]
289 static void simple_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
299 fprintf(dmp->f, "\nConstant Information:\n");
300 fprintf(dmp->f, "---------------------\n");
302 fprintf(dmp->f, "\nBit usage for integer constants\n");
303 fprintf(dmp->f, "-------------------------------\n");
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]);
309 fprintf(dmp->f, "-------------------------------\n");
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]);
317 fprintf(dmp->f, "--------------------------------------\n");
319 fprintf(dmp->f, "other %12u\n", tbl->others.cnt[0]);
320 cnt_add(&sum, &tbl->others);
321 fprintf(dmp->f, "-------------------------------\n");
323 fprintf(dmp->f, "sum %12u\n", sum.cnt[0]);
327 * initialize the simple dumper
329 static void simple_init(dumper_t *dmp, const char *name)
333 snprintf(fname, sizeof(fname), "%s.txt", name);
334 dmp->f = fopen(fname, "w");
341 * finishes the simple dumper
343 static void simple_finish(dumper_t *dmp)
351 * the simple human readable dumper
353 const dumper_t simple_dumper = {
355 simple_dump_const_tbl,
363 /* ---------------------------------------------------------------------- */
366 * count the nodes as needed:
368 * 1 normal (data) Phi's
373 static void csv_count_nodes(dumper_t *dmp, graph_entry_t *graph, counter_t cnt[])
378 for (i = 0; i < 4; ++i)
381 for (entry = pset_first(graph->opcode_hash); entry; entry = pset_next(graph->opcode_hash)) {
382 if (entry->op == op_Phi) {
384 cnt_add(&cnt[1], &entry->cnt_alive);
386 else if (entry->op == dmp->status->op_PhiM) {
388 cnt_add(&cnt[2], &entry->cnt_alive);
390 else if (entry->op == op_Proj) {
392 cnt_add(&cnt[3], &entry->cnt_alive);
395 /* all other nodes */
396 cnt_add(&cnt[0], &entry->cnt_alive);
404 static void csv_dump_graph(dumper_t *dmp, graph_entry_t *entry)
412 if (entry->irg && !entry->is_deleted) {
413 ir_graph *const_irg = get_const_code_irg();
415 if (entry->irg == const_irg) {
416 name = "<Const code Irg>";
421 name = get_entity_name(entry->ent);
423 name = "<UNKNOWN IRG>";
426 csv_count_nodes(dmp, entry, cnt);
428 fprintf(dmp->f, "%-40s, %p, %d, %d, %d, %d\n",
442 static void csv_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
448 * initialize the simple dumper
450 static void csv_init(dumper_t *dmp, const char *name)
454 snprintf(fname, sizeof(fname), "%s.csv", name);
455 dmp->f = fopen(fname, "a");
462 * finishes the simple dumper
464 static void csv_finish(dumper_t *dmp)
472 * the simple human readable dumper
474 const dumper_t csv_dumper = {