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)
140 if (! cnt_eq(cnt, 0)) {
141 fprintf(dmp->f, "\nReal Function Calls optimized:\n");
142 fprintf(dmp->f, "%-16s %8u\n",
143 "Call", cnt->cnt[0]);
148 * dumps the number of tail_recursion optimization
150 static void simple_dump_tail_recursion(dumper_t *dmp, unsigned num_tail_recursion)
152 if (num_tail_recursion > 0) {
153 fprintf(dmp->f, "\nTail recursion optimized:\n");
154 fprintf(dmp->f, "%-16s %8u\n", "Call", num_tail_recursion);
159 * dumps the edges count
161 static void simple_dump_edges(dumper_t *dmp, counter_t *cnt)
163 fprintf(dmp->f, "%-16s %8d\n", "Edges", cnt->cnt[0]);
169 static void simple_dump_graph(dumper_t *dmp, graph_entry_t *entry)
171 int i, dump_opts = 1;
172 block_entry_t *b_entry;
175 ir_graph *const_irg = get_const_code_irg();
177 if (entry->irg == const_irg) {
178 fprintf(dmp->f, "\nConst code Irg %p", (void *)entry->irg);
182 fprintf(dmp->f, "\nEntity %s, Irg %p", get_entity_ld_name(entry->ent), (void *)entry->irg);
184 fprintf(dmp->f, "\nIrg %p", (void *)entry->irg);
187 fprintf(dmp->f, " %swalked %u over blocks %u:\n"
188 " was inlined : %u\n"
189 " got inlined : %u\n"
190 " strength red : %u\n"
191 " leaf function : %s\n"
192 " calls only leaf functions : %s\n"
196 " indirect calls : %u\n",
197 entry->is_deleted ? "DELETED " : "",
198 entry->cnt_walked.cnt[0], entry->cnt_walked_blocks.cnt[0],
199 entry->cnt_was_inlined.cnt[0],
200 entry->cnt_got_inlined.cnt[0],
201 entry->cnt_strength_red.cnt[0],
202 entry->is_leaf ? "YES" : "NO",
203 entry->is_leaf_call == LCS_NON_LEAF_CALL ? "NO" : (entry->is_leaf_call == LCS_LEAF_CALL ? "Yes" : "Maybe"),
204 entry->is_recursive ? "YES" : "NO",
205 entry->is_chain_call ? "YES" : "NO",
206 entry->cnt_all_calls.cnt[0],
207 entry->cnt_indirect_calls.cnt[0]
210 for (i = 0; i < sizeof(entry->cnt_if_conv)/sizeof(entry->cnt_if_conv[0]); ++i) {
211 fprintf(dmp->f, " %s : %u\n", if_conv_names[i], entry->cnt_if_conv[i].cnt[0]);
216 fprintf(dmp->f, "\nGlobals counts:\n");
217 fprintf(dmp->f, "--------------\n");
221 simple_dump_opcode_hash(dmp, entry->opcode_hash);
222 simple_dump_edges(dmp, &entry->cnt_edges);
224 /* effects of optimizations */
228 simple_dump_real_func_calls(dmp, &entry->cnt_real_func_call);
229 simple_dump_tail_recursion(dmp, entry->num_tail_recursion);
231 for (i = 0; i < sizeof(entry->opt_hash)/sizeof(entry->opt_hash[0]); ++i) {
232 simple_dump_opt_hash(dmp, entry->opt_hash[i], i);
235 /* dump block info */
236 fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s %12s\n", "Block Nr", "Nodes", "intern E", "incoming E", "outgoing E", "Phi", "quot");
237 for (b_entry = pset_first(entry->block_hash);
239 b_entry = pset_next(entry->block_hash)) {
240 fprintf(dmp->f, "BLK %12ld %12u %12u %12u %12u %12u %4.8f\n",
242 b_entry->cnt_nodes.cnt[0],
243 b_entry->cnt_edges.cnt[0],
244 b_entry->cnt_in_edges.cnt[0],
245 b_entry->cnt_out_edges.cnt[0],
246 b_entry->cnt_phi_data.cnt[0],
247 (double)b_entry->cnt_edges.cnt[0] / (double)b_entry->cnt_nodes.cnt[0]
256 static void simple_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
263 fprintf(dmp->f, "\nConstant Information:\n");
264 fprintf(dmp->f, "---------------------\n");
266 fprintf(dmp->f, "\nBit usage for integer constants\n");
267 fprintf(dmp->f, "-------------------------------\n");
269 for (i = 0; i < ARR_SIZE(tbl->int_bits_count); ++i) {
270 fprintf(dmp->f, "%5d %12u\n", i + 1, tbl->int_bits_count[i].cnt[0]);
271 cnt_add(&sum, &tbl->int_bits_count[i]);
273 fprintf(dmp->f, "-------------------------------\n");
275 fprintf(dmp->f, "\nFloating point constants classification\n");
276 fprintf(dmp->f, "--------------------------------------\n");
277 for (i = 0; i < ARR_SIZE(tbl->floats); ++i) {
278 fprintf(dmp->f, "%-10s %12u\n", stat_fc_name(i), tbl->floats[i].cnt[0]);
279 cnt_add(&sum, &tbl->floats[i]);
281 fprintf(dmp->f, "--------------------------------------\n");
283 fprintf(dmp->f, "other %12u\n", tbl->others.cnt[0]);
284 cnt_add(&sum, &tbl->others);
285 fprintf(dmp->f, "-------------------------------\n");
287 fprintf(dmp->f, "sum %12u\n", sum.cnt[0]);
291 * initialize the simple dumper
293 static void simple_init(dumper_t *dmp, const char *name)
297 snprintf(fname, sizeof(fname), "%s.txt", name);
298 dmp->f = fopen(fname, "w");
302 * finishes the simple dumper
304 static void simple_finish(dumper_t *dmp)
311 * the simple human readable dumper
313 const dumper_t simple_dumper = {
315 simple_dump_const_tbl,
323 /* ---------------------------------------------------------------------- */
326 * count the nodes as needed:
328 * 1 normal (data) Phi's
333 static void csv_count_nodes(dumper_t *dmp, graph_entry_t *graph, counter_t cnt[])
338 for (i = 0; i < 4; ++i)
341 for (entry = pset_first(graph->opcode_hash); entry; entry = pset_next(graph->opcode_hash)) {
342 if (entry->op == op_Phi) {
344 cnt_add(&cnt[1], &entry->cnt_alive);
346 else if (entry->op == dmp->status->op_PhiM) {
348 cnt_add(&cnt[2], &entry->cnt_alive);
350 else if (entry->op == op_Proj) {
352 cnt_add(&cnt[3], &entry->cnt_alive);
355 /* all other nodes */
356 cnt_add(&cnt[0], &entry->cnt_alive);
364 static void csv_dump_graph(dumper_t *dmp, graph_entry_t *entry)
370 if (entry->irg && !entry->is_deleted) {
371 ir_graph *const_irg = get_const_code_irg();
373 if (entry->irg == const_irg) {
374 name = "<Const code Irg>";
379 name = get_entity_name(entry->ent);
381 name = "<UNKNOWN IRG>";
384 csv_count_nodes(dmp, entry, cnt);
386 fprintf(dmp->f, "%-40s, %p, %d, %d, %d, %d\n",
400 static void csv_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
406 * initialize the simple dumper
408 static void csv_init(dumper_t *dmp, const char *name)
412 snprintf(fname, sizeof(fname), "%s.csv", name);
413 dmp->f = fopen(fname, "a");
417 * finishes the simple dumper
419 static void csv_finish(dumper_t *dmp)
426 * the simple human readable dumper
428 const dumper_t csv_dumper = {