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;
187 ir_graph *const_irg = get_const_code_irg();
189 if (entry->irg == const_irg) {
190 fprintf(dmp->f, "\nConst code Irg %p", (void *)entry->irg);
194 fprintf(dmp->f, "\nEntity %s, Irg %p", get_entity_ld_name(entry->ent), (void *)entry->irg);
196 fprintf(dmp->f, "\nIrg %p", (void *)entry->irg);
199 fprintf(dmp->f, " %swalked %u over blocks %u:\n"
200 " was inlined : %u\n"
201 " got inlined : %u\n"
202 " strength red : %u\n"
203 " leaf function : %s\n"
204 " calls only leaf functions : %s\n"
208 " indirect calls : %u\n",
209 entry->is_deleted ? "DELETED " : "",
210 entry->cnt_walked.cnt[0], entry->cnt_walked_blocks.cnt[0],
211 entry->cnt_was_inlined.cnt[0],
212 entry->cnt_got_inlined.cnt[0],
213 entry->cnt_strength_red.cnt[0],
214 entry->is_leaf ? "YES" : "NO",
215 entry->is_leaf_call == LCS_NON_LEAF_CALL ? "NO" : (entry->is_leaf_call == LCS_LEAF_CALL ? "Yes" : "Maybe"),
216 entry->is_recursive ? "YES" : "NO",
217 entry->is_chain_call ? "YES" : "NO",
218 entry->cnt_all_calls.cnt[0],
219 entry->cnt_indirect_calls.cnt[0]
222 for (i = 0; i < sizeof(entry->cnt_if_conv)/sizeof(entry->cnt_if_conv[0]); ++i) {
223 fprintf(dmp->f, " %s : %u\n", if_conv_names[i], entry->cnt_if_conv[i].cnt[0]);
228 fprintf(dmp->f, "\nGlobals counts:\n");
229 fprintf(dmp->f, "--------------\n");
233 simple_dump_opcode_hash(dmp, entry->opcode_hash);
234 simple_dump_edges(dmp, &entry->cnt_edges);
236 /* effects of optimizations */
240 simple_dump_real_func_calls(dmp, &entry->cnt_real_func_call);
241 simple_dump_tail_recursion(dmp, entry->num_tail_recursion);
243 for (i = 0; i < sizeof(entry->opt_hash)/sizeof(entry->opt_hash[0]); ++i) {
244 simple_dump_opt_hash(dmp, entry->opt_hash[i], i);
247 /* dump block info */
248 fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s %12s\n", "Block Nr", "Nodes", "intern E", "incoming E", "outgoing E", "Phi", "quot");
249 for (b_entry = pset_first(entry->block_hash);
251 b_entry = pset_next(entry->block_hash)) {
252 fprintf(dmp->f, "BLK %12ld %12u %12u %12u %12u %12u %4.8f\n",
254 b_entry->cnt_nodes.cnt[0],
255 b_entry->cnt_edges.cnt[0],
256 b_entry->cnt_in_edges.cnt[0],
257 b_entry->cnt_out_edges.cnt[0],
258 b_entry->cnt_phi_data.cnt[0],
259 (double)b_entry->cnt_edges.cnt[0] / (double)b_entry->cnt_nodes.cnt[0]
268 static void simple_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
278 fprintf(dmp->f, "\nConstant Information:\n");
279 fprintf(dmp->f, "---------------------\n");
281 fprintf(dmp->f, "\nBit usage for integer constants\n");
282 fprintf(dmp->f, "-------------------------------\n");
284 for (i = 0; i < ARR_SIZE(tbl->int_bits_count); ++i) {
285 fprintf(dmp->f, "%5d %12u\n", i + 1, tbl->int_bits_count[i].cnt[0]);
286 cnt_add(&sum, &tbl->int_bits_count[i]);
288 fprintf(dmp->f, "-------------------------------\n");
290 fprintf(dmp->f, "\nFloating point constants classification\n");
291 fprintf(dmp->f, "--------------------------------------\n");
292 for (i = 0; i < ARR_SIZE(tbl->floats); ++i) {
293 fprintf(dmp->f, "%-10s %12u\n", stat_fc_name(i), tbl->floats[i].cnt[0]);
294 cnt_add(&sum, &tbl->floats[i]);
296 fprintf(dmp->f, "--------------------------------------\n");
298 fprintf(dmp->f, "other %12u\n", tbl->others.cnt[0]);
299 cnt_add(&sum, &tbl->others);
300 fprintf(dmp->f, "-------------------------------\n");
302 fprintf(dmp->f, "sum %12u\n", sum.cnt[0]);
306 * initialize the simple dumper
308 static void simple_init(dumper_t *dmp, const char *name)
312 snprintf(fname, sizeof(fname), "%s.txt", name);
313 dmp->f = fopen(fname, "w");
320 * finishes the simple dumper
322 static void simple_finish(dumper_t *dmp)
330 * the simple human readable dumper
332 const dumper_t simple_dumper = {
334 simple_dump_const_tbl,
342 /* ---------------------------------------------------------------------- */
345 * count the nodes as needed:
347 * 1 normal (data) Phi's
352 static void csv_count_nodes(dumper_t *dmp, graph_entry_t *graph, counter_t cnt[])
357 for (i = 0; i < 4; ++i)
360 for (entry = pset_first(graph->opcode_hash); entry; entry = pset_next(graph->opcode_hash)) {
361 if (entry->op == op_Phi) {
363 cnt_add(&cnt[1], &entry->cnt_alive);
365 else if (entry->op == dmp->status->op_PhiM) {
367 cnt_add(&cnt[2], &entry->cnt_alive);
369 else if (entry->op == op_Proj) {
371 cnt_add(&cnt[3], &entry->cnt_alive);
374 /* all other nodes */
375 cnt_add(&cnt[0], &entry->cnt_alive);
383 static void csv_dump_graph(dumper_t *dmp, graph_entry_t *entry)
391 if (entry->irg && !entry->is_deleted) {
392 ir_graph *const_irg = get_const_code_irg();
394 if (entry->irg == const_irg) {
395 name = "<Const code Irg>";
400 name = get_entity_name(entry->ent);
402 name = "<UNKNOWN IRG>";
405 csv_count_nodes(dmp, entry, cnt);
407 fprintf(dmp->f, "%-40s, %p, %d, %d, %d, %d\n",
421 static void csv_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
427 * initialize the simple dumper
429 static void csv_init(dumper_t *dmp, const char *name)
433 snprintf(fname, sizeof(fname), "%s.csv", name);
434 dmp->f = fopen(fname, "a");
441 * finishes the simple dumper
443 static void csv_finish(dumper_t *dmp)
451 * the simple human readable dumper
453 const dumper_t csv_dumper = {