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" },
85 { FS_BE_IA32_2ADDRCPY, "ia32 Backend transformation: Copy created due to 2-Addresscode constraints" },
86 { FS_BE_IA32_SPILL2ST, "ia32 Backend transformation: Created Store for a Spill" },
87 { FS_BE_IA32_RELOAD2LD, "ia32 Backend transformation: Created Load for a Reload" },
90 static const char *if_conv_names[IF_RESULT_LAST] = {
92 "if conv side effect ",
93 "if conv Phi node found ",
94 "if conv to deep DAG's ",
95 "if conv bad control flow ",
96 "if conv denied by arch ",
100 * dumps a opcode hash into human readable form
102 static void simple_dump_opcode_hash(dumper_t *dmp, pset *set)
106 counter_t f_new_node;
110 cnt_clr(&f_new_node);
113 fprintf(dmp->f, "%-16s %-8s %-8s %-8s\n", "Opcode", "alive", "created", "->Id");
114 for (entry = pset_first(set); entry; entry = pset_next(set)) {
115 fprintf(dmp->f, "%-16s %8u %8u %8u\n",
116 get_id_str(entry->op->name), entry->cnt_alive.cnt[0], entry->new_node.cnt[0], entry->into_Id.cnt[0]);
118 cnt_add(&f_alive, &entry->cnt_alive);
119 cnt_add(&f_new_node, &entry->new_node);
120 cnt_add(&f_Id, &entry->into_Id);
122 fprintf(dmp->f, "-------------------------------------------\n");
123 fprintf(dmp->f, "%-16s %8u %8u %8u\n", "Sum",
130 * dumps an optimization hash into human readable form
132 static void simple_dump_opt_hash(dumper_t *dmp, pset *set, int index)
134 opt_entry_t *entry = pset_first(set);
136 assert(index < ARR_SIZE(opt_names) && "index out of range");
137 assert(opt_names[index].kind == index && "opt_names broken");
139 fprintf(dmp->f, "\n%s:\n", opt_names[index].name);
140 fprintf(dmp->f, "%-16s %-8s\n", "Opcode", "deref");
142 for (; entry; entry = pset_next(set)) {
143 fprintf(dmp->f, "%-16s %8u\n",
144 get_id_str(entry->op->name), entry->count.cnt[0]);
150 * dumps the number of real_function_call optimization
152 static void simple_dump_real_func_calls(dumper_t *dmp, counter_t *cnt)
157 if (! cnt_eq(cnt, 0)) {
158 fprintf(dmp->f, "\nReal Function Calls optimized:\n");
159 fprintf(dmp->f, "%-16s %8u\n",
160 "Call", cnt->cnt[0]);
165 * dumps the number of tail_recursion optimization
167 static void simple_dump_tail_recursion(dumper_t *dmp, unsigned num_tail_recursion)
172 if (num_tail_recursion > 0) {
173 fprintf(dmp->f, "\nTail recursion optimized:\n");
174 fprintf(dmp->f, "%-16s %8u\n", "Call", num_tail_recursion);
179 * dumps the edges count
181 static void simple_dump_edges(dumper_t *dmp, counter_t *cnt)
186 fprintf(dmp->f, "%-16s %8d\n", "Edges", cnt->cnt[0]);
192 static void simple_dump_graph(dumper_t *dmp, graph_entry_t *entry)
194 int i, dump_opts = 1;
195 block_entry_t *b_entry;
196 extbb_entry_t *eb_entry;
202 ir_graph *const_irg = get_const_code_irg();
204 if (entry->irg == const_irg) {
205 fprintf(dmp->f, "\nConst code Irg %p", (void *)entry->irg);
209 fprintf(dmp->f, "\nEntity %s, Irg %p", get_entity_ld_name(entry->ent), (void *)entry->irg);
211 fprintf(dmp->f, "\nIrg %p", (void *)entry->irg);
214 fprintf(dmp->f, " %swalked %u over blocks %u:\n"
215 " was inlined : %u\n"
216 " got inlined : %u\n"
217 " strength red : %u\n"
218 " leaf function : %s\n"
219 " calls only leaf functions : %s\n"
223 " indirect calls : %u\n",
224 entry->is_deleted ? "DELETED " : "",
225 entry->cnt_walked.cnt[0], entry->cnt_walked_blocks.cnt[0],
226 entry->cnt_was_inlined.cnt[0],
227 entry->cnt_got_inlined.cnt[0],
228 entry->cnt_strength_red.cnt[0],
229 entry->is_leaf ? "YES" : "NO",
230 entry->is_leaf_call == LCS_NON_LEAF_CALL ? "NO" : (entry->is_leaf_call == LCS_LEAF_CALL ? "Yes" : "Maybe"),
231 entry->is_recursive ? "YES" : "NO",
232 entry->is_chain_call ? "YES" : "NO",
233 entry->cnt_all_calls.cnt[0],
234 entry->cnt_indirect_calls.cnt[0]
237 for (i = 0; i < sizeof(entry->cnt_if_conv)/sizeof(entry->cnt_if_conv[0]); ++i) {
238 fprintf(dmp->f, " %s : %u\n", if_conv_names[i], entry->cnt_if_conv[i].cnt[0]);
243 fprintf(dmp->f, "\nGlobals counts:\n");
244 fprintf(dmp->f, "--------------\n");
248 simple_dump_opcode_hash(dmp, entry->opcode_hash);
249 simple_dump_edges(dmp, &entry->cnt_edges);
251 /* effects of optimizations */
255 simple_dump_real_func_calls(dmp, &entry->cnt_real_func_call);
256 simple_dump_tail_recursion(dmp, entry->num_tail_recursion);
258 for (i = 0; i < sizeof(entry->opt_hash)/sizeof(entry->opt_hash[0]); ++i) {
259 simple_dump_opt_hash(dmp, entry->opt_hash[i], i);
262 /* dump block info */
263 fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s %12s\n", "Block Nr", "Nodes", "intern E", "incoming E", "outgoing E", "Phi", "quot");
264 for (b_entry = pset_first(entry->block_hash);
266 b_entry = pset_next(entry->block_hash)) {
267 fprintf(dmp->f, "BLK %6ld %12u %12u %12u %12u %12u %4.8f\n",
269 b_entry->cnt_nodes.cnt[0],
270 b_entry->cnt_edges.cnt[0],
271 b_entry->cnt_in_edges.cnt[0],
272 b_entry->cnt_out_edges.cnt[0],
273 b_entry->cnt_phi_data.cnt[0],
274 (double)b_entry->cnt_edges.cnt[0] / (double)b_entry->cnt_nodes.cnt[0]
278 if (dmp->status->stat_options & FIRMSTAT_COUNT_EXTBB) {
279 /* dump extended block info */
280 fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s %12s\n", "Extbb Nr", "Nodes", "intern E", "incoming E", "outgoing E", "Phi", "quot");
281 for (eb_entry = pset_first(entry->extbb_hash);
283 eb_entry = pset_next(entry->extbb_hash)) {
284 fprintf(dmp->f, "ExtBB %6ld %12u %12u %12u %12u %12u %4.8f\n",
286 eb_entry->cnt_nodes.cnt[0],
287 eb_entry->cnt_edges.cnt[0],
288 eb_entry->cnt_in_edges.cnt[0],
289 eb_entry->cnt_out_edges.cnt[0],
290 eb_entry->cnt_phi_data.cnt[0],
291 (double)eb_entry->cnt_edges.cnt[0] / (double)eb_entry->cnt_nodes.cnt[0]
301 static void simple_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
311 fprintf(dmp->f, "\nConstant Information:\n");
312 fprintf(dmp->f, "---------------------\n");
314 fprintf(dmp->f, "\nBit usage for integer constants\n");
315 fprintf(dmp->f, "-------------------------------\n");
317 for (i = 0; i < ARR_SIZE(tbl->int_bits_count); ++i) {
318 fprintf(dmp->f, "%5d %12u\n", i + 1, tbl->int_bits_count[i].cnt[0]);
319 cnt_add(&sum, &tbl->int_bits_count[i]);
321 fprintf(dmp->f, "-------------------------------\n");
323 fprintf(dmp->f, "\nFloating point constants classification\n");
324 fprintf(dmp->f, "--------------------------------------\n");
325 for (i = 0; i < ARR_SIZE(tbl->floats); ++i) {
326 fprintf(dmp->f, "%-10s %12u\n", stat_fc_name(i), tbl->floats[i].cnt[0]);
327 cnt_add(&sum, &tbl->floats[i]);
329 fprintf(dmp->f, "--------------------------------------\n");
331 fprintf(dmp->f, "other %12u\n", tbl->others.cnt[0]);
332 cnt_add(&sum, &tbl->others);
333 fprintf(dmp->f, "-------------------------------\n");
335 fprintf(dmp->f, "sum %12u\n", sum.cnt[0]);
339 * initialize the simple dumper
341 static void simple_init(dumper_t *dmp, const char *name)
345 snprintf(fname, sizeof(fname), "%s.txt", name);
346 dmp->f = fopen(fname, "w");
353 * finishes the simple dumper
355 static void simple_finish(dumper_t *dmp)
363 * the simple human readable dumper
365 const dumper_t simple_dumper = {
367 simple_dump_const_tbl,
375 /* ---------------------------------------------------------------------- */
378 * count the nodes as needed:
380 * 1 normal (data) Phi's
385 static void csv_count_nodes(dumper_t *dmp, graph_entry_t *graph, counter_t cnt[])
390 for (i = 0; i < 4; ++i)
393 for (entry = pset_first(graph->opcode_hash); entry; entry = pset_next(graph->opcode_hash)) {
394 if (entry->op == op_Phi) {
396 cnt_add(&cnt[1], &entry->cnt_alive);
398 else if (entry->op == dmp->status->op_PhiM) {
400 cnt_add(&cnt[2], &entry->cnt_alive);
402 else if (entry->op == op_Proj) {
404 cnt_add(&cnt[3], &entry->cnt_alive);
407 /* all other nodes */
408 cnt_add(&cnt[0], &entry->cnt_alive);
416 static void csv_dump_graph(dumper_t *dmp, graph_entry_t *entry)
424 if (entry->irg && !entry->is_deleted) {
425 ir_graph *const_irg = get_const_code_irg();
427 if (entry->irg == const_irg) {
428 name = "<Const code Irg>";
433 name = get_entity_name(entry->ent);
435 name = "<UNKNOWN IRG>";
438 csv_count_nodes(dmp, entry, cnt);
440 fprintf(dmp->f, "%-40s, %p, %d, %d, %d, %d\n",
454 static void csv_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
460 * initialize the simple dumper
462 static void csv_init(dumper_t *dmp, const char *name)
466 snprintf(fname, sizeof(fname), "%s.csv", name);
467 dmp->f = fopen(fname, "a");
474 * finishes the simple dumper
476 static void csv_finish(dumper_t *dmp)
484 * the simple human readable dumper
486 const dumper_t csv_dumper = {