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_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, "Backend transformation: Lea was created" },
82 static const char *if_conv_names[IF_RESULT_LAST] = {
84 "if conv side effect ",
85 "if conv Phi node found ",
86 "if conv to deep DAG's ",
87 "if conv bad control flow ",
88 "if conv denied by arch ",
92 * dumps a opcode hash into human readable form
94 static void simple_dump_opcode_hash(dumper_t *dmp, pset *set)
102 cnt_clr(&f_new_node);
105 fprintf(dmp->f, "%-16s %-8s %-8s %-8s\n", "Opcode", "alive", "created", "->Id");
106 for (entry = pset_first(set); entry; entry = pset_next(set)) {
107 fprintf(dmp->f, "%-16s %8u %8u %8u\n",
108 get_id_str(entry->op->name), entry->cnt_alive.cnt[0], entry->new_node.cnt[0], entry->into_Id.cnt[0]);
110 cnt_add(&f_alive, &entry->cnt_alive);
111 cnt_add(&f_new_node, &entry->new_node);
112 cnt_add(&f_Id, &entry->into_Id);
114 fprintf(dmp->f, "-------------------------------------------\n");
115 fprintf(dmp->f, "%-16s %8u %8u %8u\n", "Sum",
122 * dumps an optimization hash into human readable form
124 static void simple_dump_opt_hash(dumper_t *dmp, pset *set, int index)
126 opt_entry_t *entry = pset_first(set);
128 assert(index < ARR_SIZE(opt_names) && "index out of range");
129 assert(opt_names[index].kind == index && "opt_names broken");
131 fprintf(dmp->f, "\n%s:\n", opt_names[index].name);
132 fprintf(dmp->f, "%-16s %-8s\n", "Opcode", "deref");
134 for (; entry; entry = pset_next(set)) {
135 fprintf(dmp->f, "%-16s %8u\n",
136 get_id_str(entry->op->name), entry->count.cnt[0]);
142 * dumps the number of real_function_call optimization
144 static void simple_dump_real_func_calls(dumper_t *dmp, counter_t *cnt)
149 if (! cnt_eq(cnt, 0)) {
150 fprintf(dmp->f, "\nReal Function Calls optimized:\n");
151 fprintf(dmp->f, "%-16s %8u\n",
152 "Call", cnt->cnt[0]);
157 * dumps the number of tail_recursion optimization
159 static void simple_dump_tail_recursion(dumper_t *dmp, unsigned num_tail_recursion)
164 if (num_tail_recursion > 0) {
165 fprintf(dmp->f, "\nTail recursion optimized:\n");
166 fprintf(dmp->f, "%-16s %8u\n", "Call", num_tail_recursion);
171 * dumps the edges count
173 static void simple_dump_edges(dumper_t *dmp, counter_t *cnt)
178 fprintf(dmp->f, "%-16s %8d\n", "Edges", cnt->cnt[0]);
184 static void simple_dump_graph(dumper_t *dmp, graph_entry_t *entry)
186 int i, dump_opts = 1;
187 block_entry_t *b_entry;
188 extbb_entry_t *eb_entry;
194 ir_graph *const_irg = get_const_code_irg();
196 if (entry->irg == const_irg) {
197 fprintf(dmp->f, "\nConst code Irg %p", (void *)entry->irg);
201 fprintf(dmp->f, "\nEntity %s, Irg %p", get_entity_ld_name(entry->ent), (void *)entry->irg);
203 fprintf(dmp->f, "\nIrg %p", (void *)entry->irg);
206 fprintf(dmp->f, " %swalked %u over blocks %u:\n"
207 " was inlined : %u\n"
208 " got inlined : %u\n"
209 " strength red : %u\n"
210 " leaf function : %s\n"
211 " calls only leaf functions : %s\n"
215 " indirect calls : %u\n",
216 entry->is_deleted ? "DELETED " : "",
217 entry->cnt_walked.cnt[0], entry->cnt_walked_blocks.cnt[0],
218 entry->cnt_was_inlined.cnt[0],
219 entry->cnt_got_inlined.cnt[0],
220 entry->cnt_strength_red.cnt[0],
221 entry->is_leaf ? "YES" : "NO",
222 entry->is_leaf_call == LCS_NON_LEAF_CALL ? "NO" : (entry->is_leaf_call == LCS_LEAF_CALL ? "Yes" : "Maybe"),
223 entry->is_recursive ? "YES" : "NO",
224 entry->is_chain_call ? "YES" : "NO",
225 entry->cnt_all_calls.cnt[0],
226 entry->cnt_indirect_calls.cnt[0]
229 for (i = 0; i < sizeof(entry->cnt_if_conv)/sizeof(entry->cnt_if_conv[0]); ++i) {
230 fprintf(dmp->f, " %s : %u\n", if_conv_names[i], entry->cnt_if_conv[i].cnt[0]);
235 fprintf(dmp->f, "\nGlobals counts:\n");
236 fprintf(dmp->f, "--------------\n");
240 simple_dump_opcode_hash(dmp, entry->opcode_hash);
241 simple_dump_edges(dmp, &entry->cnt_edges);
243 /* effects of optimizations */
247 simple_dump_real_func_calls(dmp, &entry->cnt_real_func_call);
248 simple_dump_tail_recursion(dmp, entry->num_tail_recursion);
250 for (i = 0; i < sizeof(entry->opt_hash)/sizeof(entry->opt_hash[0]); ++i) {
251 simple_dump_opt_hash(dmp, entry->opt_hash[i], i);
254 /* dump block info */
255 fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s %12s\n", "Block Nr", "Nodes", "intern E", "incoming E", "outgoing E", "Phi", "quot");
256 for (b_entry = pset_first(entry->block_hash);
258 b_entry = pset_next(entry->block_hash)) {
259 fprintf(dmp->f, "BLK %6ld %12u %12u %12u %12u %12u %4.8f\n",
261 b_entry->cnt_nodes.cnt[0],
262 b_entry->cnt_edges.cnt[0],
263 b_entry->cnt_in_edges.cnt[0],
264 b_entry->cnt_out_edges.cnt[0],
265 b_entry->cnt_phi_data.cnt[0],
266 (double)b_entry->cnt_edges.cnt[0] / (double)b_entry->cnt_nodes.cnt[0]
270 if (dmp->status->stat_options & FIRMSTAT_COUNT_EXTBB) {
271 /* dump extended block info */
272 fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s %12s\n", "Extbb Nr", "Nodes", "intern E", "incoming E", "outgoing E", "Phi", "quot");
273 for (eb_entry = pset_first(entry->extbb_hash);
275 eb_entry = pset_next(entry->extbb_hash)) {
276 fprintf(dmp->f, "ExtBB %6ld %12u %12u %12u %12u %12u %4.8f\n",
278 eb_entry->cnt_nodes.cnt[0],
279 eb_entry->cnt_edges.cnt[0],
280 eb_entry->cnt_in_edges.cnt[0],
281 eb_entry->cnt_out_edges.cnt[0],
282 eb_entry->cnt_phi_data.cnt[0],
283 (double)eb_entry->cnt_edges.cnt[0] / (double)eb_entry->cnt_nodes.cnt[0]
293 static void simple_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
303 fprintf(dmp->f, "\nConstant Information:\n");
304 fprintf(dmp->f, "---------------------\n");
306 fprintf(dmp->f, "\nBit usage for integer constants\n");
307 fprintf(dmp->f, "-------------------------------\n");
309 for (i = 0; i < ARR_SIZE(tbl->int_bits_count); ++i) {
310 fprintf(dmp->f, "%5d %12u\n", i + 1, tbl->int_bits_count[i].cnt[0]);
311 cnt_add(&sum, &tbl->int_bits_count[i]);
313 fprintf(dmp->f, "-------------------------------\n");
315 fprintf(dmp->f, "\nFloating point constants classification\n");
316 fprintf(dmp->f, "--------------------------------------\n");
317 for (i = 0; i < ARR_SIZE(tbl->floats); ++i) {
318 fprintf(dmp->f, "%-10s %12u\n", stat_fc_name(i), tbl->floats[i].cnt[0]);
319 cnt_add(&sum, &tbl->floats[i]);
321 fprintf(dmp->f, "--------------------------------------\n");
323 fprintf(dmp->f, "other %12u\n", tbl->others.cnt[0]);
324 cnt_add(&sum, &tbl->others);
325 fprintf(dmp->f, "-------------------------------\n");
327 fprintf(dmp->f, "sum %12u\n", sum.cnt[0]);
331 * initialize the simple dumper
333 static void simple_init(dumper_t *dmp, const char *name)
337 snprintf(fname, sizeof(fname), "%s.txt", name);
338 dmp->f = fopen(fname, "w");
345 * finishes the simple dumper
347 static void simple_finish(dumper_t *dmp)
355 * the simple human readable dumper
357 const dumper_t simple_dumper = {
359 simple_dump_const_tbl,
367 /* ---------------------------------------------------------------------- */
370 * count the nodes as needed:
372 * 1 normal (data) Phi's
377 static void csv_count_nodes(dumper_t *dmp, graph_entry_t *graph, counter_t cnt[])
382 for (i = 0; i < 4; ++i)
385 for (entry = pset_first(graph->opcode_hash); entry; entry = pset_next(graph->opcode_hash)) {
386 if (entry->op == op_Phi) {
388 cnt_add(&cnt[1], &entry->cnt_alive);
390 else if (entry->op == dmp->status->op_PhiM) {
392 cnt_add(&cnt[2], &entry->cnt_alive);
394 else if (entry->op == op_Proj) {
396 cnt_add(&cnt[3], &entry->cnt_alive);
399 /* all other nodes */
400 cnt_add(&cnt[0], &entry->cnt_alive);
408 static void csv_dump_graph(dumper_t *dmp, graph_entry_t *entry)
416 if (entry->irg && !entry->is_deleted) {
417 ir_graph *const_irg = get_const_code_irg();
419 if (entry->irg == const_irg) {
420 name = "<Const code Irg>";
425 name = get_entity_name(entry->ent);
427 name = "<UNKNOWN IRG>";
430 csv_count_nodes(dmp, entry, cnt);
432 fprintf(dmp->f, "%-40s, %p, %d, %d, %d, %d\n",
446 static void csv_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
452 * initialize the simple dumper
454 static void csv_init(dumper_t *dmp, const char *name)
458 snprintf(fname, sizeof(fname), "%s.csv", name);
459 dmp->f = fopen(fname, "a");
466 * finishes the simple dumper
468 static void csv_finish(dumper_t *dmp)
476 * the simple human readable dumper
478 const dumper_t csv_dumper = {