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)
156 be_block_entry_t *b_entry = pset_first(entry->be_block_hash);
157 reg_pressure_entry_t *rp_entry;
159 /* return if no be statistic information available */
163 fprintf(dmp->f, "\nREG PRESSURE:\n");
164 fprintf(dmp->f, "%12s", "Block Nr");
166 /* print table head (register class names) */
167 for (rp_entry = pset_first(b_entry->reg_pressure);
169 rp_entry = pset_next(b_entry->reg_pressure))
171 fprintf(dmp->f, "%15s", get_id_str(rp_entry->id_name));
173 fprintf(dmp->f, "\n");
175 /* print the reg pressure for all blocks and register classes */
176 for (/* b_entry is already initialized */ ;
178 b_entry = pset_next(entry->be_block_hash))
180 fprintf(dmp->f, "BLK %6ld", b_entry->block_nr);
182 for (rp_entry = pset_first(b_entry->reg_pressure);
184 rp_entry = pset_next(b_entry->reg_pressure))
186 fprintf(dmp->f, "%15d", rp_entry->pressure);
188 fprintf(dmp->f, "\n");
192 /** prints a distribution entry */
193 void dump_block_sched_ready_distrib(const distrib_entry_t *entry, void *env)
196 fprintf(dmp_f, "%12d", entry->cnt.cnt[0]);
200 * dumps the distribution of the amount of ready nodes for each block
202 static void simple_dump_be_block_sched_ready(dumper_t *dmp, graph_entry_t *entry)
204 be_block_entry_t *b_entry = pset_first(entry->be_block_hash);
205 const counter_t *cnt_0 = cnt_get_0();
208 /* return if no be statistic information available */
212 fprintf(dmp->f, "\nSCHEDULING: NUMBER OF READY NODES\n");
213 fprintf(dmp->f, "%12s %12s %12s %12s %12s %12s %12s\n",
214 "Block Nr", "1 node", "2 nodes", "3 nodes", "4 nodes", "5 or more", "AVERAGE");
216 for (/* b_entry is already initialized */ ;
218 b_entry = pset_next(entry->be_block_hash))
220 /* this ensures that all keys from 1 to 5 are in the table */
221 for (i = 1; i < 6; i++)
222 stat_add_int_distrib_tbl(b_entry->sched_ready, i, cnt_0);
224 fprintf(dmp->f, "BLK %6ld", b_entry->block_nr);
225 stat_iterate_distrib_tbl(b_entry->sched_ready, dump_block_sched_ready_distrib, dmp->f);
226 fprintf(dmp->f, "%12.2lf", stat_calc_avg_distrib_tbl(b_entry->sched_ready));
227 fprintf(dmp->f, "\n");
232 * dumps permutation statistics for one and block and one class
234 static void simple_dump_be_block_permstat_class(dumper_t *dmp, perm_class_entry_t *entry)
236 perm_stat_entry_t *ps_ent;
238 fprintf(dmp->f, "%12s %12s\n", "size", "real size");
239 for (ps_ent = pset_first(entry->perm_stat);
241 ps_ent = pset_next(entry->perm_stat))
243 fprintf(dmp->f, "%12d %12d\n", ps_ent->size, ps_ent->real_size);
248 * dumps statistics about perms
250 static void simple_dump_be_block_permstat(dumper_t *dmp, graph_entry_t *entry)
252 be_block_entry_t *b_entry = pset_first(entry->be_block_hash);
254 /* return if no be statistic information available */
258 fprintf(dmp->f, "\nPERMUTATION STATISTICS BEGIN:\n");
259 for (/* b_entry is already initialized */ ;
261 b_entry = pset_next(entry->be_block_hash))
263 perm_class_entry_t *pc_ent;
265 fprintf(dmp->f, "BLOCK %ld:\n", b_entry->block_nr);
267 if (! b_entry->perm_class_stat)
270 for (pc_ent = pset_first(b_entry->perm_class_stat);
272 pc_ent = pset_next(b_entry->perm_class_stat))
274 fprintf(dmp->f, "register class %s:\n", get_id_str(pc_ent->id_name));
275 simple_dump_be_block_permstat_class(dmp, pc_ent);
279 fprintf(dmp->f, "PERMUTATION STATISTICS END\n");
283 * dumps the number of real_function_call optimization
285 static void simple_dump_real_func_calls(dumper_t *dmp, counter_t *cnt)
290 if (! cnt_eq(cnt, 0)) {
291 fprintf(dmp->f, "\nReal Function Calls optimized:\n");
292 fprintf(dmp->f, "%-16s %8u\n", "Call", cnt->cnt[0]);
297 * dumps the number of tail_recursion optimization
299 static void simple_dump_tail_recursion(dumper_t *dmp, unsigned num_tail_recursion)
304 if (num_tail_recursion > 0) {
305 fprintf(dmp->f, "\nTail recursion optimized:\n");
306 fprintf(dmp->f, "%-16s %8u\n", "Call", num_tail_recursion);
311 * dumps the edges count
313 static void simple_dump_edges(dumper_t *dmp, counter_t *cnt)
318 fprintf(dmp->f, "%-16s %8d\n", "Edges", cnt->cnt[0]);
324 static void simple_dump_graph(dumper_t *dmp, graph_entry_t *entry)
326 int i, dump_opts = 1;
327 block_entry_t *b_entry;
328 extbb_entry_t *eb_entry;
334 ir_graph *const_irg = get_const_code_irg();
336 if (entry->irg == const_irg) {
337 fprintf(dmp->f, "\nConst code Irg %p", (void *)entry->irg);
341 fprintf(dmp->f, "\nEntity %s, Irg %p", get_entity_ld_name(entry->ent), (void *)entry->irg);
343 fprintf(dmp->f, "\nIrg %p", (void *)entry->irg);
346 fprintf(dmp->f, " %swalked %u over blocks %u:\n"
347 " was inlined : %u\n"
348 " got inlined : %u\n"
349 " strength red : %u\n"
350 " leaf function : %s\n"
351 " calls only leaf functions : %s\n"
355 " indirect calls : %u\n",
356 entry->is_deleted ? "DELETED " : "",
357 entry->cnt_walked.cnt[0], entry->cnt_walked_blocks.cnt[0],
358 entry->cnt_was_inlined.cnt[0],
359 entry->cnt_got_inlined.cnt[0],
360 entry->cnt_strength_red.cnt[0],
361 entry->is_leaf ? "YES" : "NO",
362 entry->is_leaf_call == LCS_NON_LEAF_CALL ? "NO" : (entry->is_leaf_call == LCS_LEAF_CALL ? "Yes" : "Maybe"),
363 entry->is_recursive ? "YES" : "NO",
364 entry->is_chain_call ? "YES" : "NO",
365 entry->cnt_all_calls.cnt[0],
366 entry->cnt_indirect_calls.cnt[0]
369 for (i = 0; i < sizeof(entry->cnt_if_conv)/sizeof(entry->cnt_if_conv[0]); ++i) {
370 fprintf(dmp->f, " %s : %u\n", if_conv_names[i], entry->cnt_if_conv[i].cnt[0]);
375 fprintf(dmp->f, "\nGlobals counts:\n");
376 fprintf(dmp->f, "--------------\n");
380 simple_dump_opcode_hash(dmp, entry->opcode_hash);
381 simple_dump_edges(dmp, &entry->cnt_edges);
383 /* effects of optimizations */
387 simple_dump_real_func_calls(dmp, &entry->cnt_real_func_call);
388 simple_dump_tail_recursion(dmp, entry->num_tail_recursion);
390 for (i = 0; i < sizeof(entry->opt_hash)/sizeof(entry->opt_hash[0]); ++i) {
391 simple_dump_opt_hash(dmp, entry->opt_hash[i], i);
394 /* dump block info */
395 fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s %12s\n", "Block Nr", "Nodes", "intern E", "incoming E", "outgoing E", "Phi", "quot");
396 for (b_entry = pset_first(entry->block_hash);
398 b_entry = pset_next(entry->block_hash))
400 fprintf(dmp->f, "BLK %6ld %12u %12u %12u %12u %12u %4.8f\n",
402 b_entry->cnt_nodes.cnt[0],
403 b_entry->cnt_edges.cnt[0],
404 b_entry->cnt_in_edges.cnt[0],
405 b_entry->cnt_out_edges.cnt[0],
406 b_entry->cnt_phi_data.cnt[0],
407 (double)b_entry->cnt_edges.cnt[0] / (double)b_entry->cnt_nodes.cnt[0]
411 /* dump block reg pressure */
412 simple_dump_be_block_reg_pressure(dmp, entry);
414 /* dump block ready nodes distribution */
415 simple_dump_be_block_sched_ready(dmp, entry);
417 /* dump block permutation statistics */
418 simple_dump_be_block_permstat(dmp, entry);
420 if (dmp->status->stat_options & FIRMSTAT_COUNT_EXTBB) {
421 /* dump extended block info */
422 fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s %12s\n", "Extbb Nr", "Nodes", "intern E", "incoming E", "outgoing E", "Phi", "quot");
423 for (eb_entry = pset_first(entry->extbb_hash);
425 eb_entry = pset_next(entry->extbb_hash))
427 fprintf(dmp->f, "ExtBB %6ld %12u %12u %12u %12u %12u %4.8f\n",
429 eb_entry->cnt_nodes.cnt[0],
430 eb_entry->cnt_edges.cnt[0],
431 eb_entry->cnt_in_edges.cnt[0],
432 eb_entry->cnt_out_edges.cnt[0],
433 eb_entry->cnt_phi_data.cnt[0],
434 (double)eb_entry->cnt_edges.cnt[0] / (double)eb_entry->cnt_nodes.cnt[0]
444 static void simple_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
454 fprintf(dmp->f, "\nConstant Information:\n");
455 fprintf(dmp->f, "---------------------\n");
457 fprintf(dmp->f, "\nBit usage for integer constants\n");
458 fprintf(dmp->f, "-------------------------------\n");
460 for (i = 0; i < ARR_SIZE(tbl->int_bits_count); ++i) {
461 fprintf(dmp->f, "%5d %12u\n", i + 1, tbl->int_bits_count[i].cnt[0]);
462 cnt_add(&sum, &tbl->int_bits_count[i]);
464 fprintf(dmp->f, "-------------------------------\n");
466 fprintf(dmp->f, "\nFloating point constants classification\n");
467 fprintf(dmp->f, "--------------------------------------\n");
468 for (i = 0; i < ARR_SIZE(tbl->floats); ++i) {
469 fprintf(dmp->f, "%-10s %12u\n", stat_fc_name(i), tbl->floats[i].cnt[0]);
470 cnt_add(&sum, &tbl->floats[i]);
472 fprintf(dmp->f, "--------------------------------------\n");
474 fprintf(dmp->f, "other %12u\n", tbl->others.cnt[0]);
475 cnt_add(&sum, &tbl->others);
476 fprintf(dmp->f, "-------------------------------\n");
478 fprintf(dmp->f, "sum %12u\n", sum.cnt[0]);
482 * initialize the simple dumper
484 static void simple_init(dumper_t *dmp, const char *name)
488 snprintf(fname, sizeof(fname), "%s.txt", name);
489 dmp->f = fopen(fname, "w");
496 * finishes the simple dumper
498 static void simple_finish(dumper_t *dmp)
506 * the simple human readable dumper
508 const dumper_t simple_dumper = {
510 simple_dump_const_tbl,
518 /* ---------------------------------------------------------------------- */
521 * count the nodes as needed:
523 * 1 normal (data) Phi's
528 static void csv_count_nodes(dumper_t *dmp, graph_entry_t *graph, counter_t cnt[])
533 for (i = 0; i < 4; ++i)
536 for (entry = pset_first(graph->opcode_hash); entry; entry = pset_next(graph->opcode_hash)) {
537 if (entry->op == op_Phi) {
539 cnt_add(&cnt[1], &entry->cnt_alive);
541 else if (entry->op == dmp->status->op_PhiM) {
543 cnt_add(&cnt[2], &entry->cnt_alive);
545 else if (entry->op == op_Proj) {
547 cnt_add(&cnt[3], &entry->cnt_alive);
550 /* all other nodes */
551 cnt_add(&cnt[0], &entry->cnt_alive);
559 static void csv_dump_graph(dumper_t *dmp, graph_entry_t *entry)
567 if (entry->irg && !entry->is_deleted) {
568 ir_graph *const_irg = get_const_code_irg();
570 if (entry->irg == const_irg) {
571 name = "<Const code Irg>";
576 name = get_entity_name(entry->ent);
578 name = "<UNKNOWN IRG>";
581 csv_count_nodes(dmp, entry, cnt);
583 fprintf(dmp->f, "%-40s, %p, %d, %d, %d, %d\n",
597 static void csv_dump_const_tbl(dumper_t *dmp, const constant_info_t *tbl)
603 * initialize the simple dumper
605 static void csv_init(dumper_t *dmp, const char *name)
609 snprintf(fname, sizeof(fname), "%s.csv", name);
610 dmp->f = fopen(fname, "a");
617 * finishes the simple dumper
619 static void csv_finish(dumper_t *dmp)
627 * the simple human readable dumper
629 const dumper_t csv_dumper = {