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" },
88 { FS_BE_IA32_SUB2NEGADD, "ia32 Backend transformation: Created Neg-Add for a Sub due to 2-Addresscode constraints" },
89 { FS_BE_IA32_LEA2ADD, "ia32 Backend transformation: Transformed Lea back into Add" },
92 static const char *if_conv_names[IF_RESULT_LAST] = {
94 "if conv side effect ",
95 "if conv Phi node found ",
96 "if conv to deep DAG's ",
97 "if conv bad control flow ",
98 "if conv denied by arch ",
102 * dumps a opcode hash into human readable form
104 static void simple_dump_opcode_hash(dumper_t *dmp, pset *set)
108 counter_t f_new_node;
112 cnt_clr(&f_new_node);
115 fprintf(dmp->f, "%-16s %-8s %-8s %-8s\n", "Opcode", "alive", "created", "->Id");
116 for (entry = pset_first(set); entry; entry = pset_next(set)) {
117 fprintf(dmp->f, "%-16s %8u %8u %8u\n",
118 get_id_str(entry->op->name), entry->cnt_alive.cnt[0], entry->new_node.cnt[0], entry->into_Id.cnt[0]);
120 cnt_add(&f_alive, &entry->cnt_alive);
121 cnt_add(&f_new_node, &entry->new_node);
122 cnt_add(&f_Id, &entry->into_Id);
124 fprintf(dmp->f, "-------------------------------------------\n");
125 fprintf(dmp->f, "%-16s %8u %8u %8u\n", "Sum",
132 * dumps an optimization hash into human readable form
134 static void simple_dump_opt_hash(dumper_t *dmp, pset *set, int index)
136 opt_entry_t *entry = pset_first(set);
138 assert(index < ARR_SIZE(opt_names) && "index out of range");
139 assert(opt_names[index].kind == index && "opt_names broken");
141 fprintf(dmp->f, "\n%s:\n", opt_names[index].name);
142 fprintf(dmp->f, "%-16s %-8s\n", "Opcode", "deref");
144 for (; entry; entry = pset_next(set)) {
145 fprintf(dmp->f, "%-16s %8u\n",
146 get_id_str(entry->op->name), entry->count.cnt[0]);
152 * dumps the register pressure for each block and for each register class
154 static void simple_dump_be_block_reg_pressure(dumper_t *dmp, graph_entry_t *entry) {
155 be_block_entry_t *b_entry = pset_first(entry->be_block_hash);
156 reg_pressure_entry_t *rp_entry;
158 /* return if no reg pressure information available */
162 /* print table head (register classes) */
163 fprintf(dmp->f, "\nREG PRESSURE:\n");
164 fprintf(dmp->f, "%12s", "Block Nr");
165 for (rp_entry = pset_first(b_entry->reg_pressure);
167 rp_entry = pset_next(b_entry->reg_pressure))
169 fprintf(dmp->f, "%15s", get_id_str(rp_entry->id_name));
171 fprintf(dmp->f, "\n");
173 /* print the reg pressure for all blocks and register classes */
174 for (/* b_entry is already initialized */ ;
176 b_entry = pset_next(entry->be_block_hash))
178 fprintf(dmp->f, "BLK %6ld", b_entry->block_nr);
179 for (rp_entry = pset_first(b_entry->reg_pressure);
181 rp_entry = pset_next(b_entry->reg_pressure))
183 fprintf(dmp->f, "%15d", rp_entry->pressure);
185 fprintf(dmp->f, "\n");
190 * dumps the number of real_function_call optimization
192 static void simple_dump_real_func_calls(dumper_t *dmp, counter_t *cnt)
197 if (! cnt_eq(cnt, 0)) {
198 fprintf(dmp->f, "\nReal Function Calls optimized:\n");
199 fprintf(dmp->f, "%-16s %8u\n",
200 "Call", cnt->cnt[0]);
205 * dumps the number of tail_recursion optimization
207 static void simple_dump_tail_recursion(dumper_t *dmp, unsigned num_tail_recursion)
212 if (num_tail_recursion > 0) {
213 fprintf(dmp->f, "\nTail recursion optimized:\n");
214 fprintf(dmp->f, "%-16s %8u\n", "Call", num_tail_recursion);
219 * dumps the edges count
221 static void simple_dump_edges(dumper_t *dmp, counter_t *cnt)
226 fprintf(dmp->f, "%-16s %8d\n", "Edges", cnt->cnt[0]);
232 static void simple_dump_graph(dumper_t *dmp, graph_entry_t *entry)
234 int i, dump_opts = 1;
235 block_entry_t *b_entry;
236 extbb_entry_t *eb_entry;
242 ir_graph *const_irg = get_const_code_irg();
244 if (entry->irg == const_irg) {
245 fprintf(dmp->f, "\nConst code Irg %p", (void *)entry->irg);
249 fprintf(dmp->f, "\nEntity %s, Irg %p", get_entity_ld_name(entry->ent), (void *)entry->irg);
251 fprintf(dmp->f, "\nIrg %p", (void *)entry->irg);
254 fprintf(dmp->f, " %swalked %u over blocks %u:\n"
255 " was inlined : %u\n"
256 " got inlined : %u\n"
257 " strength red : %u\n"
258 " leaf function : %s\n"
259 " calls only leaf functions : %s\n"
263 " indirect calls : %u\n",
264 entry->is_deleted ? "DELETED " : "",
265 entry->cnt_walked.cnt[0], entry->cnt_walked_blocks.cnt[0],
266 entry->cnt_was_inlined.cnt[0],
267 entry->cnt_got_inlined.cnt[0],
268 entry->cnt_strength_red.cnt[0],
269 entry->is_leaf ? "YES" : "NO",
270 entry->is_leaf_call == LCS_NON_LEAF_CALL ? "NO" : (entry->is_leaf_call == LCS_LEAF_CALL ? "Yes" : "Maybe"),
271 entry->is_recursive ? "YES" : "NO",
272 entry->is_chain_call ? "YES" : "NO",
273 entry->cnt_all_calls.cnt[0],
274 entry->cnt_indirect_calls.cnt[0]
277 for (i = 0; i < sizeof(entry->cnt_if_conv)/sizeof(entry->cnt_if_conv[0]); ++i) {
278 fprintf(dmp->f, " %s : %u\n", if_conv_names[i], entry->cnt_if_conv[i].cnt[0]);
283 fprintf(dmp->f, "\nGlobals counts:\n");
284 fprintf(dmp->f, "--------------\n");
288 simple_dump_opcode_hash(dmp, entry->opcode_hash);
289 simple_dump_edges(dmp, &entry->cnt_edges);
291 /* effects of optimizations */
295 simple_dump_real_func_calls(dmp, &entry->cnt_real_func_call);
296 simple_dump_tail_recursion(dmp, entry->num_tail_recursion);
298 for (i = 0; i < sizeof(entry->opt_hash)/sizeof(entry->opt_hash[0]); ++i) {
299 simple_dump_opt_hash(dmp, entry->opt_hash[i], i);
302 /* dump block info */
303 fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s %12s\n", "Block Nr", "Nodes", "intern E", "incoming E", "outgoing E", "Phi", "quot");
304 for (b_entry = pset_first(entry->block_hash);
306 b_entry = pset_next(entry->block_hash)) {
307 fprintf(dmp->f, "BLK %6ld %12u %12u %12u %12u %12u %4.8f\n",
309 b_entry->cnt_nodes.cnt[0],
310 b_entry->cnt_edges.cnt[0],
311 b_entry->cnt_in_edges.cnt[0],
312 b_entry->cnt_out_edges.cnt[0],
313 b_entry->cnt_phi_data.cnt[0],
314 (double)b_entry->cnt_edges.cnt[0] / (double)b_entry->cnt_nodes.cnt[0]
318 /* dump block reg pressure */
319 simple_dump_be_block_reg_pressure(dmp, entry);
321 if (dmp->status->stat_options & FIRMSTAT_COUNT_EXTBB) {
322 /* dump extended block info */
323 fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s %12s\n", "Extbb Nr", "Nodes", "intern E", "incoming E", "outgoing E", "Phi", "quot");
324 for (eb_entry = pset_first(entry->extbb_hash);
326 eb_entry = pset_next(entry->extbb_hash)) {
327 fprintf(dmp->f, "ExtBB %6ld %12u %12u %12u %12u %12u %4.8f\n",
329 eb_entry->cnt_nodes.cnt[0],
330 eb_entry->cnt_edges.cnt[0],
331 eb_entry->cnt_in_edges.cnt[0],
332 eb_entry->cnt_out_edges.cnt[0],
333 eb_entry->cnt_phi_data.cnt[0],
334 (double)eb_entry->cnt_edges.cnt[0] / (double)eb_entry->cnt_nodes.cnt[0]
344 static void simple_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
354 fprintf(dmp->f, "\nConstant Information:\n");
355 fprintf(dmp->f, "---------------------\n");
357 fprintf(dmp->f, "\nBit usage for integer constants\n");
358 fprintf(dmp->f, "-------------------------------\n");
360 for (i = 0; i < ARR_SIZE(tbl->int_bits_count); ++i) {
361 fprintf(dmp->f, "%5d %12u\n", i + 1, tbl->int_bits_count[i].cnt[0]);
362 cnt_add(&sum, &tbl->int_bits_count[i]);
364 fprintf(dmp->f, "-------------------------------\n");
366 fprintf(dmp->f, "\nFloating point constants classification\n");
367 fprintf(dmp->f, "--------------------------------------\n");
368 for (i = 0; i < ARR_SIZE(tbl->floats); ++i) {
369 fprintf(dmp->f, "%-10s %12u\n", stat_fc_name(i), tbl->floats[i].cnt[0]);
370 cnt_add(&sum, &tbl->floats[i]);
372 fprintf(dmp->f, "--------------------------------------\n");
374 fprintf(dmp->f, "other %12u\n", tbl->others.cnt[0]);
375 cnt_add(&sum, &tbl->others);
376 fprintf(dmp->f, "-------------------------------\n");
378 fprintf(dmp->f, "sum %12u\n", sum.cnt[0]);
382 * initialize the simple dumper
384 static void simple_init(dumper_t *dmp, const char *name)
388 snprintf(fname, sizeof(fname), "%s.txt", name);
389 dmp->f = fopen(fname, "w");
396 * finishes the simple dumper
398 static void simple_finish(dumper_t *dmp)
406 * the simple human readable dumper
408 const dumper_t simple_dumper = {
410 simple_dump_const_tbl,
418 /* ---------------------------------------------------------------------- */
421 * count the nodes as needed:
423 * 1 normal (data) Phi's
428 static void csv_count_nodes(dumper_t *dmp, graph_entry_t *graph, counter_t cnt[])
433 for (i = 0; i < 4; ++i)
436 for (entry = pset_first(graph->opcode_hash); entry; entry = pset_next(graph->opcode_hash)) {
437 if (entry->op == op_Phi) {
439 cnt_add(&cnt[1], &entry->cnt_alive);
441 else if (entry->op == dmp->status->op_PhiM) {
443 cnt_add(&cnt[2], &entry->cnt_alive);
445 else if (entry->op == op_Proj) {
447 cnt_add(&cnt[3], &entry->cnt_alive);
450 /* all other nodes */
451 cnt_add(&cnt[0], &entry->cnt_alive);
459 static void csv_dump_graph(dumper_t *dmp, graph_entry_t *entry)
467 if (entry->irg && !entry->is_deleted) {
468 ir_graph *const_irg = get_const_code_irg();
470 if (entry->irg == const_irg) {
471 name = "<Const code Irg>";
476 name = get_entity_name(entry->ent);
478 name = "<UNKNOWN IRG>";
481 csv_count_nodes(dmp, entry, cnt);
483 fprintf(dmp->f, "%-40s, %p, %d, %d, %d, %d\n",
497 static void csv_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
503 * initialize the simple dumper
505 static void csv_init(dumper_t *dmp, const char *name)
509 snprintf(fname, sizeof(fname), "%s.csv", name);
510 dmp->f = fopen(fname, "a");
517 * finishes the simple dumper
519 static void csv_finish(dumper_t *dmp)
527 * the simple human readable dumper
529 const dumper_t csv_dumper = {