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 foreach_pset(set, entry) {
117 fprintf(dmp->f, "%-16s %8u %8u %8u\n",
118 get_id_str(entry->op->name),
119 cnt_to_uint(&entry->cnt_alive),
120 cnt_to_uint(&entry->new_node),
121 cnt_to_uint(&entry->into_Id)
124 cnt_add(&f_alive, &entry->cnt_alive);
125 cnt_add(&f_new_node, &entry->new_node);
126 cnt_add(&f_Id, &entry->into_Id);
128 fprintf(dmp->f, "-------------------------------------------\n");
129 fprintf(dmp->f, "%-16s %8u %8u %8u\n", "Sum",
130 cnt_to_uint(&f_alive),
131 cnt_to_uint(&f_new_node),
137 * dumps an optimization hash into human readable form
139 static void simple_dump_opt_hash(dumper_t *dmp, pset *set, int index)
141 assert(index < ARR_SIZE(opt_names) && "index out of range");
142 assert(opt_names[index].kind == index && "opt_names broken");
144 if (pset_count(set) > 0) {
147 fprintf(dmp->f, "\n%s:\n", opt_names[index].name);
148 fprintf(dmp->f, "%-16s %-8s\n", "Opcode", "deref");
150 foreach_pset(set, entry) {
151 fprintf(dmp->f, "%-16s %8u\n",
152 get_id_str(entry->op->name), cnt_to_uint(&entry->count));
158 * dumps the register pressure for each block and for each register class
160 static void simple_dump_be_block_reg_pressure(dumper_t *dmp, graph_entry_t *entry)
162 be_block_entry_t *b_entry = pset_first(entry->be_block_hash);
163 reg_pressure_entry_t *rp_entry;
165 /* return if no be statistic information available */
169 fprintf(dmp->f, "\nREG PRESSURE:\n");
170 fprintf(dmp->f, "%12s", "Block Nr");
172 /* print table head (register class names) */
173 foreach_pset(b_entry->reg_pressure, rp_entry)
174 fprintf(dmp->f, "%15s", rp_entry->class_name);
175 fprintf(dmp->f, "\n");
177 /* print the reg pressure for all blocks and register classes */
178 for (/* b_entry is already initialized */ ;
180 b_entry = pset_next(entry->be_block_hash)) {
181 fprintf(dmp->f, "BLK %6ld", b_entry->block_nr);
183 foreach_pset(b_entry->reg_pressure, rp_entry)
184 fprintf(dmp->f, "%15d", rp_entry->pressure);
185 fprintf(dmp->f, "\n");
189 /** prints a distribution entry */
190 void dump_block_sched_ready_distrib(const distrib_entry_t *entry, void *env)
193 fprintf(dmp_f, "%12d", cnt_to_uint(&entry->cnt));
197 * dumps the distribution of the amount of ready nodes for each block
199 static void simple_dump_be_block_sched_ready(dumper_t *dmp, graph_entry_t *entry)
201 if (pset_count(entry->be_block_hash) > 0) {
202 be_block_entry_t *b_entry;
205 fprintf(dmp->f, "\nSCHEDULING: NUMBER OF READY NODES\n");
206 fprintf(dmp->f, "%12s %12s %12s %12s %12s %12s %12s\n",
207 "Block Nr", "1 node", "2 nodes", "3 nodes", "4 nodes", "5 or more", "AVERAGE");
209 foreach_pset(entry->be_block_hash, b_entry) {
210 /* this ensures that all keys from 1 to 5 are in the table */
211 for (i = 1; i < 6; ++i)
212 stat_insert_int_distrib_tbl(b_entry->sched_ready, i);
214 fprintf(dmp->f, "BLK %6ld", b_entry->block_nr);
215 stat_iterate_distrib_tbl(b_entry->sched_ready, dump_block_sched_ready_distrib, dmp->f);
216 fprintf(dmp->f, "%12.2lf", stat_calc_avg_distrib_tbl(b_entry->sched_ready));
217 fprintf(dmp->f, "\n");
223 * dumps permutation statistics for one and block and one class
225 static void simple_dump_be_block_permstat_class(dumper_t *dmp, perm_class_entry_t *entry)
227 perm_stat_entry_t *ps_ent;
229 fprintf(dmp->f, "%12s %12s %12s %12s\n", "size", "real size", "# chains", "# cycles");
230 foreach_pset(entry->perm_stat, ps_ent) {
231 fprintf(dmp->f, "%12d %12d %12d %12d\n",
234 stat_get_count_distrib_tbl(ps_ent->chains),
235 stat_get_count_distrib_tbl(ps_ent->cycles)
241 * dumps statistics about perms
243 static void simple_dump_be_block_permstat(dumper_t *dmp, graph_entry_t *entry)
245 if (pset_count(entry->be_block_hash) > 0) {
246 be_block_entry_t *b_entry;
248 fprintf(dmp->f, "\nPERMUTATION STATISTICS BEGIN:\n");
249 foreach_pset(entry->be_block_hash, b_entry) {
250 perm_class_entry_t *pc_ent;
252 fprintf(dmp->f, "BLOCK %ld:\n", b_entry->block_nr);
254 if (b_entry->perm_class_stat)
255 foreach_pset(b_entry->perm_class_stat, pc_ent) {
256 fprintf(dmp->f, "register class %s:\n", pc_ent->class_name);
257 simple_dump_be_block_permstat_class(dmp, pc_ent);
261 fprintf(dmp->f, "PERMUTATION STATISTICS END\n");
266 * dumps the number of real_function_call optimization
268 static void simple_dump_real_func_calls(dumper_t *dmp, counter_t *cnt)
273 if (! cnt_eq(cnt, 0)) {
274 fprintf(dmp->f, "\nReal Function Calls optimized:\n");
275 fprintf(dmp->f, "%-16s %8u\n", "Call", cnt_to_uint(cnt));
280 * dumps the number of tail_recursion optimization
282 static void simple_dump_tail_recursion(dumper_t *dmp, unsigned num_tail_recursion)
287 if (num_tail_recursion > 0) {
288 fprintf(dmp->f, "\nTail recursion optimized:\n");
289 fprintf(dmp->f, "%-16s %8u\n", "Call", num_tail_recursion);
294 * dumps the edges count
296 static void simple_dump_edges(dumper_t *dmp, counter_t *cnt)
301 fprintf(dmp->f, "%-16s %8d\n", "Edges", cnt_to_uint(cnt));
307 static void simple_dump_graph(dumper_t *dmp, graph_entry_t *entry)
309 int i, dump_opts = 1;
310 block_entry_t *b_entry;
311 extbb_entry_t *eb_entry;
317 ir_graph *const_irg = get_const_code_irg();
319 if (entry->irg == const_irg)
320 fprintf(dmp->f, "\nConst code Irg %p", (void *)entry->irg);
323 fprintf(dmp->f, "\nEntity %s, Irg %p", get_entity_ld_name(entry->ent), (void *)entry->irg);
325 fprintf(dmp->f, "\nIrg %p", (void *)entry->irg);
328 fprintf(dmp->f, " %swalked %u over blocks %u:\n"
329 " was inlined : %u\n"
330 " got inlined : %u\n"
331 " strength red : %u\n"
332 " leaf function : %s\n"
333 " calls only leaf functions : %s\n"
337 " indirect calls : %u\n",
338 entry->is_deleted ? "DELETED " : "",
339 cnt_to_uint(&entry->cnt_walked), cnt_to_uint(&entry->cnt_walked_blocks),
340 cnt_to_uint(&entry->cnt_was_inlined),
341 cnt_to_uint(&entry->cnt_got_inlined),
342 cnt_to_uint(&entry->cnt_strength_red),
343 entry->is_leaf ? "YES" : "NO",
344 entry->is_leaf_call == LCS_NON_LEAF_CALL ? "NO" : (entry->is_leaf_call == LCS_LEAF_CALL ? "Yes" : "Maybe"),
345 entry->is_recursive ? "YES" : "NO",
346 entry->is_chain_call ? "YES" : "NO",
347 cnt_to_uint(&entry->cnt_all_calls),
348 cnt_to_uint(&entry->cnt_indirect_calls)
351 for (i = 0; i < sizeof(entry->cnt_if_conv)/sizeof(entry->cnt_if_conv[0]); ++i) {
352 fprintf(dmp->f, " %s : %u\n", if_conv_names[i], cnt_to_uint(&entry->cnt_if_conv[i]));
356 fprintf(dmp->f, "\nGlobals counts:\n");
357 fprintf(dmp->f, "--------------\n");
361 simple_dump_opcode_hash(dmp, entry->opcode_hash);
362 simple_dump_edges(dmp, &entry->cnt_edges);
364 /* effects of optimizations */
368 simple_dump_real_func_calls(dmp, &entry->cnt_real_func_call);
369 simple_dump_tail_recursion(dmp, entry->num_tail_recursion);
371 for (i = 0; i < sizeof(entry->opt_hash)/sizeof(entry->opt_hash[0]); ++i) {
372 simple_dump_opt_hash(dmp, entry->opt_hash[i], i);
375 /* dump block info */
376 fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s %12s\n", "Block Nr", "Nodes", "intern E", "incoming E", "outgoing E", "Phi", "quot");
377 foreach_pset(entry->block_hash, b_entry) {
378 fprintf(dmp->f, "BLK %6ld %12u %12u %12u %12u %12u %4.8f\n",
380 cnt_to_uint(&b_entry->cnt_nodes),
381 cnt_to_uint(&b_entry->cnt_edges),
382 cnt_to_uint(&b_entry->cnt_in_edges),
383 cnt_to_uint(&b_entry->cnt_out_edges),
384 cnt_to_uint(&b_entry->cnt_phi_data),
385 cnt_to_dbl(&b_entry->cnt_edges) / cnt_to_dbl(&b_entry->cnt_nodes)
389 /* dump block reg pressure */
390 simple_dump_be_block_reg_pressure(dmp, entry);
392 /* dump block ready nodes distribution */
393 simple_dump_be_block_sched_ready(dmp, entry);
395 /* dump block permutation statistics */
396 simple_dump_be_block_permstat(dmp, entry);
398 if (dmp->status->stat_options & FIRMSTAT_COUNT_EXTBB) {
399 /* dump extended block info */
400 fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s %12s\n", "Extbb Nr", "Nodes", "intern E", "incoming E", "outgoing E", "Phi", "quot");
401 foreach_pset(entry->extbb_hash, eb_entry) {
402 fprintf(dmp->f, "ExtBB %6ld %12u %12u %12u %12u %12u %4.8f\n",
404 cnt_to_uint(&eb_entry->cnt_nodes),
405 cnt_to_uint(&eb_entry->cnt_edges),
406 cnt_to_uint(&eb_entry->cnt_in_edges),
407 cnt_to_uint(&eb_entry->cnt_out_edges),
408 cnt_to_uint(&eb_entry->cnt_phi_data),
409 cnt_to_dbl(&eb_entry->cnt_edges) / cnt_to_dbl(&eb_entry->cnt_nodes)
419 static void simple_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
429 fprintf(dmp->f, "\nConstant Information:\n");
430 fprintf(dmp->f, "---------------------\n");
432 fprintf(dmp->f, "\nBit usage for integer constants\n");
433 fprintf(dmp->f, "-------------------------------\n");
435 for (i = 0; i < ARR_SIZE(tbl->int_bits_count); ++i) {
436 fprintf(dmp->f, "%5d %12u\n", i + 1, cnt_to_uint(&tbl->int_bits_count[i]));
437 cnt_add(&sum, &tbl->int_bits_count[i]);
439 fprintf(dmp->f, "-------------------------------\n");
441 fprintf(dmp->f, "\nFloating point constants classification\n");
442 fprintf(dmp->f, "--------------------------------------\n");
443 for (i = 0; i < ARR_SIZE(tbl->floats); ++i) {
444 fprintf(dmp->f, "%-10s %12u\n", stat_fc_name(i), cnt_to_uint(&tbl->floats[i]));
445 cnt_add(&sum, &tbl->floats[i]);
447 fprintf(dmp->f, "--------------------------------------\n");
449 fprintf(dmp->f, "other %12u\n", cnt_to_uint(&tbl->others));
450 cnt_add(&sum, &tbl->others);
451 fprintf(dmp->f, "-------------------------------\n");
453 fprintf(dmp->f, "sum %12u\n", cnt_to_uint(&sum));
457 * initialize the simple dumper
459 static void simple_init(dumper_t *dmp, const char *name)
463 snprintf(fname, sizeof(fname), "%s.txt", name);
464 dmp->f = fopen(fname, "w");
471 * finishes the simple dumper
473 static void simple_finish(dumper_t *dmp)
481 * the simple human readable dumper
483 const dumper_t simple_dumper = {
485 simple_dump_const_tbl,
493 /* ---------------------------------------------------------------------- */
496 * count the nodes as needed:
498 * 1 normal (data) Phi's
503 static void csv_count_nodes(dumper_t *dmp, graph_entry_t *graph, counter_t cnt[])
508 for (i = 0; i < 4; ++i)
511 foreach_pset(graph->opcode_hash, entry) {
512 if (entry->op == op_Phi) {
514 cnt_add(&cnt[1], &entry->cnt_alive);
516 else if (entry->op == dmp->status->op_PhiM) {
518 cnt_add(&cnt[2], &entry->cnt_alive);
520 else if (entry->op == op_Proj) {
522 cnt_add(&cnt[3], &entry->cnt_alive);
525 /* all other nodes */
526 cnt_add(&cnt[0], &entry->cnt_alive);
534 static void csv_dump_graph(dumper_t *dmp, graph_entry_t *entry)
542 if (entry->irg && !entry->is_deleted) {
543 ir_graph *const_irg = get_const_code_irg();
545 if (entry->irg == const_irg) {
546 name = "<Const code Irg>";
551 name = get_entity_name(entry->ent);
553 name = "<UNKNOWN IRG>";
556 csv_count_nodes(dmp, entry, cnt);
558 fprintf(dmp->f, "%-40s, %p, %d, %d, %d, %d\n",
561 cnt_to_uint(&cnt[0]),
562 cnt_to_uint(&cnt[1]),
563 cnt_to_uint(&cnt[2]),
572 static void csv_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
578 * initialize the simple dumper
580 static void csv_init(dumper_t *dmp, const char *name)
584 snprintf(fname, sizeof(fname), "%s.csv", name);
585 dmp->f = fopen(fname, "a");
591 * finishes the simple dumper
593 static void csv_finish(dumper_t *dmp)
601 * the simple human readable dumper
603 const dumper_t csv_dumper = {