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, "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" },
87 static const char *if_conv_names[IF_RESULT_LAST] = {
89 "if conv side effect ",
90 "if conv Phi node found ",
91 "if conv to deep DAG's ",
92 "if conv bad control flow ",
93 "if conv denied by arch ",
97 * dumps a opcode hash into human readable form
99 static void simple_dump_opcode_hash(dumper_t *dmp, pset *set)
103 counter_t f_new_node;
107 cnt_clr(&f_new_node);
110 fprintf(dmp->f, "%-16s %-8s %-8s %-8s\n", "Opcode", "alive", "created", "->Id");
111 for (entry = pset_first(set); entry; entry = pset_next(set)) {
112 fprintf(dmp->f, "%-16s %8u %8u %8u\n",
113 get_id_str(entry->op->name), entry->cnt_alive.cnt[0], entry->new_node.cnt[0], entry->into_Id.cnt[0]);
115 cnt_add(&f_alive, &entry->cnt_alive);
116 cnt_add(&f_new_node, &entry->new_node);
117 cnt_add(&f_Id, &entry->into_Id);
119 fprintf(dmp->f, "-------------------------------------------\n");
120 fprintf(dmp->f, "%-16s %8u %8u %8u\n", "Sum",
127 * dumps an optimization hash into human readable form
129 static void simple_dump_opt_hash(dumper_t *dmp, pset *set, int index)
131 opt_entry_t *entry = pset_first(set);
133 assert(index < ARR_SIZE(opt_names) && "index out of range");
134 assert(opt_names[index].kind == index && "opt_names broken");
136 fprintf(dmp->f, "\n%s:\n", opt_names[index].name);
137 fprintf(dmp->f, "%-16s %-8s\n", "Opcode", "deref");
139 for (; entry; entry = pset_next(set)) {
140 fprintf(dmp->f, "%-16s %8u\n",
141 get_id_str(entry->op->name), entry->count.cnt[0]);
147 * dumps the number of real_function_call optimization
149 static void simple_dump_real_func_calls(dumper_t *dmp, counter_t *cnt)
154 if (! cnt_eq(cnt, 0)) {
155 fprintf(dmp->f, "\nReal Function Calls optimized:\n");
156 fprintf(dmp->f, "%-16s %8u\n",
157 "Call", cnt->cnt[0]);
162 * dumps the number of tail_recursion optimization
164 static void simple_dump_tail_recursion(dumper_t *dmp, unsigned num_tail_recursion)
169 if (num_tail_recursion > 0) {
170 fprintf(dmp->f, "\nTail recursion optimized:\n");
171 fprintf(dmp->f, "%-16s %8u\n", "Call", num_tail_recursion);
176 * dumps the edges count
178 static void simple_dump_edges(dumper_t *dmp, counter_t *cnt)
183 fprintf(dmp->f, "%-16s %8d\n", "Edges", cnt->cnt[0]);
189 static void simple_dump_graph(dumper_t *dmp, graph_entry_t *entry)
191 int i, dump_opts = 1;
192 block_entry_t *b_entry;
193 extbb_entry_t *eb_entry;
199 ir_graph *const_irg = get_const_code_irg();
201 if (entry->irg == const_irg) {
202 fprintf(dmp->f, "\nConst code Irg %p", (void *)entry->irg);
206 fprintf(dmp->f, "\nEntity %s, Irg %p", get_entity_ld_name(entry->ent), (void *)entry->irg);
208 fprintf(dmp->f, "\nIrg %p", (void *)entry->irg);
211 fprintf(dmp->f, " %swalked %u over blocks %u:\n"
212 " was inlined : %u\n"
213 " got inlined : %u\n"
214 " strength red : %u\n"
215 " leaf function : %s\n"
216 " calls only leaf functions : %s\n"
220 " indirect calls : %u\n",
221 entry->is_deleted ? "DELETED " : "",
222 entry->cnt_walked.cnt[0], entry->cnt_walked_blocks.cnt[0],
223 entry->cnt_was_inlined.cnt[0],
224 entry->cnt_got_inlined.cnt[0],
225 entry->cnt_strength_red.cnt[0],
226 entry->is_leaf ? "YES" : "NO",
227 entry->is_leaf_call == LCS_NON_LEAF_CALL ? "NO" : (entry->is_leaf_call == LCS_LEAF_CALL ? "Yes" : "Maybe"),
228 entry->is_recursive ? "YES" : "NO",
229 entry->is_chain_call ? "YES" : "NO",
230 entry->cnt_all_calls.cnt[0],
231 entry->cnt_indirect_calls.cnt[0]
234 for (i = 0; i < sizeof(entry->cnt_if_conv)/sizeof(entry->cnt_if_conv[0]); ++i) {
235 fprintf(dmp->f, " %s : %u\n", if_conv_names[i], entry->cnt_if_conv[i].cnt[0]);
240 fprintf(dmp->f, "\nGlobals counts:\n");
241 fprintf(dmp->f, "--------------\n");
245 simple_dump_opcode_hash(dmp, entry->opcode_hash);
246 simple_dump_edges(dmp, &entry->cnt_edges);
248 /* effects of optimizations */
252 simple_dump_real_func_calls(dmp, &entry->cnt_real_func_call);
253 simple_dump_tail_recursion(dmp, entry->num_tail_recursion);
255 for (i = 0; i < sizeof(entry->opt_hash)/sizeof(entry->opt_hash[0]); ++i) {
256 simple_dump_opt_hash(dmp, entry->opt_hash[i], i);
259 /* dump block info */
260 fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s %12s\n", "Block Nr", "Nodes", "intern E", "incoming E", "outgoing E", "Phi", "quot");
261 for (b_entry = pset_first(entry->block_hash);
263 b_entry = pset_next(entry->block_hash)) {
264 fprintf(dmp->f, "BLK %6ld %12u %12u %12u %12u %12u %4.8f\n",
266 b_entry->cnt_nodes.cnt[0],
267 b_entry->cnt_edges.cnt[0],
268 b_entry->cnt_in_edges.cnt[0],
269 b_entry->cnt_out_edges.cnt[0],
270 b_entry->cnt_phi_data.cnt[0],
271 (double)b_entry->cnt_edges.cnt[0] / (double)b_entry->cnt_nodes.cnt[0]
275 if (dmp->status->stat_options & FIRMSTAT_COUNT_EXTBB) {
276 /* dump extended block info */
277 fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s %12s\n", "Extbb Nr", "Nodes", "intern E", "incoming E", "outgoing E", "Phi", "quot");
278 for (eb_entry = pset_first(entry->extbb_hash);
280 eb_entry = pset_next(entry->extbb_hash)) {
281 fprintf(dmp->f, "ExtBB %6ld %12u %12u %12u %12u %12u %4.8f\n",
283 eb_entry->cnt_nodes.cnt[0],
284 eb_entry->cnt_edges.cnt[0],
285 eb_entry->cnt_in_edges.cnt[0],
286 eb_entry->cnt_out_edges.cnt[0],
287 eb_entry->cnt_phi_data.cnt[0],
288 (double)eb_entry->cnt_edges.cnt[0] / (double)eb_entry->cnt_nodes.cnt[0]
298 static void simple_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
308 fprintf(dmp->f, "\nConstant Information:\n");
309 fprintf(dmp->f, "---------------------\n");
311 fprintf(dmp->f, "\nBit usage for integer constants\n");
312 fprintf(dmp->f, "-------------------------------\n");
314 for (i = 0; i < ARR_SIZE(tbl->int_bits_count); ++i) {
315 fprintf(dmp->f, "%5d %12u\n", i + 1, tbl->int_bits_count[i].cnt[0]);
316 cnt_add(&sum, &tbl->int_bits_count[i]);
318 fprintf(dmp->f, "-------------------------------\n");
320 fprintf(dmp->f, "\nFloating point constants classification\n");
321 fprintf(dmp->f, "--------------------------------------\n");
322 for (i = 0; i < ARR_SIZE(tbl->floats); ++i) {
323 fprintf(dmp->f, "%-10s %12u\n", stat_fc_name(i), tbl->floats[i].cnt[0]);
324 cnt_add(&sum, &tbl->floats[i]);
326 fprintf(dmp->f, "--------------------------------------\n");
328 fprintf(dmp->f, "other %12u\n", tbl->others.cnt[0]);
329 cnt_add(&sum, &tbl->others);
330 fprintf(dmp->f, "-------------------------------\n");
332 fprintf(dmp->f, "sum %12u\n", sum.cnt[0]);
336 * initialize the simple dumper
338 static void simple_init(dumper_t *dmp, const char *name)
342 snprintf(fname, sizeof(fname), "%s.txt", name);
343 dmp->f = fopen(fname, "w");
350 * finishes the simple dumper
352 static void simple_finish(dumper_t *dmp)
360 * the simple human readable dumper
362 const dumper_t simple_dumper = {
364 simple_dump_const_tbl,
372 /* ---------------------------------------------------------------------- */
375 * count the nodes as needed:
377 * 1 normal (data) Phi's
382 static void csv_count_nodes(dumper_t *dmp, graph_entry_t *graph, counter_t cnt[])
387 for (i = 0; i < 4; ++i)
390 for (entry = pset_first(graph->opcode_hash); entry; entry = pset_next(graph->opcode_hash)) {
391 if (entry->op == op_Phi) {
393 cnt_add(&cnt[1], &entry->cnt_alive);
395 else if (entry->op == dmp->status->op_PhiM) {
397 cnt_add(&cnt[2], &entry->cnt_alive);
399 else if (entry->op == op_Proj) {
401 cnt_add(&cnt[3], &entry->cnt_alive);
404 /* all other nodes */
405 cnt_add(&cnt[0], &entry->cnt_alive);
413 static void csv_dump_graph(dumper_t *dmp, graph_entry_t *entry)
421 if (entry->irg && !entry->is_deleted) {
422 ir_graph *const_irg = get_const_code_irg();
424 if (entry->irg == const_irg) {
425 name = "<Const code Irg>";
430 name = get_entity_name(entry->ent);
432 name = "<UNKNOWN IRG>";
435 csv_count_nodes(dmp, entry, cnt);
437 fprintf(dmp->f, "%-40s, %p, %d, %d, %d, %d\n",
451 static void csv_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
457 * initialize the simple dumper
459 static void csv_init(dumper_t *dmp, const char *name)
463 snprintf(fname, sizeof(fname), "%s.csv", name);
464 dmp->f = fopen(fname, "a");
471 * finishes the simple dumper
473 static void csv_finish(dumper_t *dmp)
481 * the simple human readable dumper
483 const dumper_t csv_dumper = {