3 * File name: ir/ir/firmstat.c
4 * Purpose: Statistics for Firm.
8 * Copyright: (c) 2004 Universität Karlsruhe
9 * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
16 #ifdef FIRM_STATISTICS
22 #include "firmstat_t.h"
27 * names of the optimizations
29 static const char *opt_names[] = {
30 "straightening optimization",
32 "constant evaluation",
33 "algebraic simplification",
35 "Write-After-Write optimization",
36 "Write-After-Read optimization",
37 "Read-After-Write optimization",
38 "Read-After-Read optimization",
39 "Read-a-Const optimization",
42 "Common subexpression elimination",
44 "Architecture dependant optimization",
45 "Reassociation optimization",
46 "Polymorphic call optimization",
51 * need this to be static:
52 * Special pseudo Opcodes that we need to count some interesting cases
56 * The Phi0, a node that is created during SSA construction
58 static ir_op _op_Phi0;
60 /** The PhiM, just to count memorty Phi's. */
61 static ir_op _op_PhiM;
63 /** The Mul by Const node. */
64 static ir_op _op_MulC;
66 /** The Div by Const node. */
67 static ir_op _op_DivC;
69 /** The Div by Const node. */
70 static ir_op _op_ModC;
72 /** The Div by Const node. */
73 static ir_op _op_DivModC;
75 /* ---------------------------------------------------------------------------------- */
77 #define STAT_ENTER ++status->recursive
78 #define STAT_LEAVE --status->recursive
79 #define STAT_ENTER_SINGLE do { if (status->recursive > 0) return; ++status->recursive; } while (0)
84 static stat_info_t _status, *status = &_status;
87 * compare two elements of the opcode hash
89 static int opcode_cmp(const void *elt, const void *key)
91 const node_entry_t *e1 = elt;
92 const node_entry_t *e2 = key;
94 return e1->op->code - e2->op->code;
98 * compare two elements of the graph hash
100 static int graph_cmp(const void *elt, const void *key)
102 const graph_entry_t *e1 = elt;
103 const graph_entry_t *e2 = key;
105 return e1->irg != e2->irg;
109 * compare two elements of the optimization hash
111 static int opt_cmp(const void *elt, const void *key)
113 const opt_entry_t *e1 = elt;
114 const opt_entry_t *e2 = key;
116 return e1->op->code != e2->op->code;
120 * compare two elements of the block hash
122 static int block_cmp(const void *elt, const void *key)
124 const block_entry_t *e1 = elt;
125 const block_entry_t *e2 = key;
127 return e1->block_nr != e2->block_nr;
131 * compare two elements of the ir_op hash
133 static int opcode_cmp_2(const void *elt, const void *key)
135 const ir_op *e1 = elt;
136 const ir_op *e2 = key;
138 return e1->code != e2->code;
142 * clears all counter in a node_entry_t
144 static void opcode_clear_entry(node_entry_t *elem)
146 cnt_clr(&elem->cnt_alive);
147 cnt_clr(&elem->new_node);
148 cnt_clr(&elem->into_Id);
152 * Returns the associates node_entry_t for an ir_op
154 static node_entry_t *opcode_get_entry(const ir_op *op, pset *set)
161 elem = pset_find(set, &key, op->code);
165 elem = obstack_alloc(&status->cnts, sizeof(*elem));
168 opcode_clear_entry(elem);
172 return pset_insert(set, elem, op->code);
176 * Returns the associates ir_op for an opcode
178 static ir_op *opcode_find_entry(opcode code, pset *set)
183 return pset_find(set, &key, code);
187 * calculates a hash value for an irg
188 * Addresses are typically aligned at 32bit, so we ignore the lowest bits
190 static INLINE unsigned irg_hash(const ir_graph *irg)
192 return (unsigned)irg >> 3;
196 * clears all counter in a graph_entry_t
198 static void graph_clear_entry(graph_entry_t *elem)
200 cnt_clr(&elem->cnt_walked);
201 cnt_clr(&elem->cnt_walked_blocks);
202 cnt_clr(&elem->cnt_was_inlined);
203 cnt_clr(&elem->cnt_got_inlined);
204 cnt_clr(&elem->cnt_strength_red);
205 cnt_clr(&elem->cnt_edges);
206 cnt_clr(&elem->cnt_all_calls);
207 cnt_clr(&elem->cnt_indirect_calls);
211 * Returns the acssociates graph_entry_t for an irg
213 static graph_entry_t *graph_get_entry(ir_graph *irg, pset *set)
221 elem = pset_find(set, &key, irg_hash(irg));
225 /* allocate a new one */
226 elem = obstack_alloc(&status->cnts, sizeof(*elem));
229 graph_clear_entry(elem);
231 /* new hash table for opcodes here */
232 elem->opcode_hash = new_pset(opcode_cmp, 5);
233 elem->block_hash = new_pset(block_cmp, 5);
236 for (i = 0; i < sizeof(elem->opt_hash)/sizeof(elem->opt_hash[0]); ++i)
237 elem->opt_hash[i] = new_pset(opt_cmp, 4);
239 return pset_insert(set, elem, irg_hash(irg));
243 * clears all counter in an opt_entry_t
245 static void opt_clear_entry(opt_entry_t *elem)
247 cnt_clr(&elem->count);
251 * Returns the associates opt_entry_t for an ir_op
253 static opt_entry_t *opt_get_entry(const ir_op *op, pset *set)
260 elem = pset_find(set, &key, op->code);
264 elem = obstack_alloc(&status->cnts, sizeof(*elem));
266 /* clear new counter */
267 opt_clear_entry(elem);
271 return pset_insert(set, elem, op->code);
275 * clears all counter in a block_entry_t
277 static void block_clear_entry(block_entry_t *elem)
279 cnt_clr(&elem->cnt_nodes);
280 cnt_clr(&elem->cnt_edges);
281 cnt_clr(&elem->cnt_in_edges);
282 cnt_clr(&elem->cnt_out_edges);
286 * Returns the associates block_entry_t for an block
288 static block_entry_t *block_get_entry(long block_nr, pset *set)
293 key.block_nr = block_nr;
295 elem = pset_find(set, &key, block_nr);
299 elem = obstack_alloc(&status->cnts, sizeof(*elem));
301 /* clear new counter */
302 block_clear_entry(elem);
304 elem->block_nr = block_nr;
306 return pset_insert(set, elem, block_nr);
311 * Returns the ir_op for an IR-node,
312 * handles special cases and return pseudo op codes
314 static ir_op *stat_get_irn_op(ir_node *node)
316 ir_op *op = get_irn_op(node);
318 if (op->code == iro_Phi && get_irn_arity(node) == 0) {
319 /* special case, a Phi0 node, count on extra counter */
320 op = status->op_Phi0;
322 else if (op->code == iro_Phi && get_irn_mode(node) == mode_M) {
323 /* special case, a Memory Phi node, count on extra counter */
324 op = status->op_PhiM;
326 else if (op->code == iro_Mul &&
327 (get_irn_op(get_Mul_left(node)) == op_Const || get_irn_op(get_Mul_right(node)) == op_Const)) {
328 /* special case, a Multiply by a const, count on extra counter */
329 op = status->op_MulC ? status->op_MulC : op_Mul;
331 else if (op->code == iro_Div && get_irn_op(get_Div_right(node)) == op_Const) {
332 /* special case, a division by a const, count on extra counter */
333 op = status->op_DivC ? status->op_DivC : op_Div;
335 else if (op->code == iro_Mod && get_irn_op(get_Mod_right(node)) == op_Const) {
336 /* special case, a module by a const, count on extra counter */
337 op = status->op_ModC ? status->op_ModC : op_Mod;
339 else if (op->code == iro_DivMod && get_irn_op(get_DivMod_right(node)) == op_Const) {
340 /* special case, a division/modulo by a const, count on extra counter */
341 op = status->op_DivModC ? status->op_DivModC : op_DivMod;
348 * update the block counter
350 static void count_block_info(ir_node *node, graph_entry_t *graph)
352 ir_op *op = get_irn_op(node);
354 block_entry_t *b_entry;
357 /* check for block */
358 if (op == op_Block) {
359 arity = get_irn_arity(node);
360 b_entry = block_get_entry(get_irn_node_nr(node), graph->block_hash);
362 /* count all incoming edges */
363 for (i = 0; i < arity; ++i) {
364 ir_node *pred = get_irn_n(node, i);
365 ir_node *other_block = get_nodes_block(pred);
366 block_entry_t *b_entry_other = block_get_entry(get_irn_node_nr(other_block), graph->block_hash);
368 cnt_inc(&b_entry->cnt_in_edges); /* an edge coming from another block */
369 cnt_inc(&b_entry_other->cnt_out_edges);
373 else if (op == op_Call) {
377 block = get_nodes_block(node);
378 b_entry = block_get_entry(get_irn_node_nr(block), graph->block_hash);
380 /* we have a new nodes */
381 cnt_inc(&b_entry->cnt_nodes);
383 arity = get_irn_arity(node);
385 for (i = 0; i < arity; ++i) {
386 ir_node *pred = get_irn_n(node, i);
387 ir_node *other_block;
389 if (get_irn_op(pred) == op_Block)
392 other_block = get_nodes_block(pred);
394 if (other_block == block)
395 cnt_inc(&b_entry->cnt_edges); /* a in block edge */
397 block_entry_t *b_entry_other = block_get_entry(get_irn_node_nr(other_block), graph->block_hash);
399 cnt_inc(&b_entry->cnt_in_edges); /* an edge coming from another block */
400 cnt_inc(&b_entry_other->cnt_out_edges);
406 * update info on calls
408 static void update_call_stat(ir_node *call, graph_entry_t *graph)
410 ir_node *ptr = get_Call_ptr(call);
413 cnt_inc(&graph->cnt_all_calls);
415 /* found a call, is not a leaf function */
418 if (get_irn_op(ptr) == op_SymConst) {
419 if (get_SymConst_kind(ptr) == symconst_addr_ent) {
420 /* ok, we seems to know the entity */
421 ent = get_SymConst_entity(ptr);
423 if (get_entity_irg(ent) == graph->irg)
424 graph->is_recursive = 1;
429 cnt_inc(&graph->cnt_indirect_calls);
432 /* check, if it's a chain-call: Then, the call-block
433 * must dominate the end block. */
435 ir_node *curr = get_irg_end_block(graph->irg);
436 ir_node *block = get_nodes_block(call);
437 int depth = get_Block_dom_depth(block);
439 for (; curr != block && get_Block_dom_depth(curr) > depth;) {
440 curr = get_Block_idom(curr);
442 if (! curr || is_no_Block(curr))
447 graph->is_chain_call = 0;
452 * walker for reachable nodes count
454 static void update_node_stat(ir_node *node, void *env)
456 graph_entry_t *graph = env;
459 ir_op *op = stat_get_irn_op(node);
460 int arity = get_irn_arity(node);
462 entry = opcode_get_entry(op, graph->opcode_hash);
464 cnt_inc(&entry->cnt_alive);
465 cnt_add_i(&graph->cnt_edges, arity);
467 /* count block edges */
468 count_block_info(node, graph);
470 /* check for properties that depends on calls like recursion/leaf/indirect call */
471 if (get_irn_op(node) == op_Call)
472 update_call_stat(node, graph);
476 * called for every graph when the graph is either deleted or stat_finish
477 * is called, must recalculate all statistic info
479 static void update_graph_stat(graph_entry_t *global, graph_entry_t *graph)
483 /* clear first the alive counter in the graph */
484 for (entry = pset_first(graph->opcode_hash); entry; entry = pset_next(graph->opcode_hash)) {
485 cnt_clr(&entry->cnt_alive);
488 /* set pessimistic values */
490 graph->is_recursive = 0;
491 graph->is_chain_call = 1;
493 /* we need dominator info */
494 if (graph->irg != get_const_code_irg())
495 if (get_irg_dom_state(graph->irg) != dom_consistent)
496 compute_doms(graph->irg);
498 /* count the nodes in the graph */
499 irg_walk_graph(graph->irg, update_node_stat, NULL, graph);
502 entry = opcode_get_entry(op_Call, graph->opcode_hash);
504 /* check if we have more than 1 call */
505 if (cnt_gt(entry->cnt_alive, 1))
506 graph->is_chain_call = 0;
509 /* recursive functions are never chain calls, leafs don't have calls */
510 if (graph->is_recursive || graph->is_leaf)
511 graph->is_chain_call = 0;
513 /* assume we walk every graph only ONCE, we could sum here the global count */
514 for (entry = pset_first(graph->opcode_hash); entry; entry = pset_next(graph->opcode_hash)) {
515 node_entry_t *g_entry = opcode_get_entry(entry->op, global->opcode_hash);
517 /* update the node counter */
518 cnt_add(&g_entry->cnt_alive, &entry->cnt_alive);
521 /* update the edge counter */
522 cnt_add(&global->cnt_edges, &graph->cnt_edges);
528 static void stat_register_dumper(dumper_t *dumper)
530 dumper->next = status->dumper;
531 status->dumper = dumper;
537 static void dump_graph(graph_entry_t *entry)
541 for (dumper = status->dumper; dumper; dumper = dumper->next) {
542 if (dumper->dump_graph)
543 dumper->dump_graph(dumper, entry);
548 * initialise the dumper
550 static void dump_init(const char *name)
554 for (dumper = status->dumper; dumper; dumper = dumper->next) {
556 dumper->init(dumper, name);
563 static void dump_finish(void)
567 for (dumper = status->dumper; dumper; dumper = dumper->next) {
569 dumper->finish(dumper);
573 /* ---------------------------------------------------------------------- */
576 * dumps a opcode hash into human readable form
578 static void simple_dump_opcode_hash(dumper_t *dmp, pset *set)
582 counter_t f_new_node;
586 cnt_clr(&f_new_node);
589 fprintf(dmp->f, "%-16s %-8s %-8s %-8s\n", "Opcode", "alive", "created", "->Id");
590 for (entry = pset_first(set); entry; entry = pset_next(set)) {
591 fprintf(dmp->f, "%-16s %8d %8d %8d\n",
592 get_id_str(entry->op->name), entry->cnt_alive.cnt[0], entry->new_node.cnt[0], entry->into_Id.cnt[0]);
594 cnt_add(&f_alive, &entry->cnt_alive);
595 cnt_add(&f_new_node, &entry->new_node);
596 cnt_add(&f_Id, &entry->into_Id);
598 fprintf(dmp->f, "-------------------------------------------\n");
599 fprintf(dmp->f, "%-16s %8d %8d %8d\n", "Sum",
606 * dumps a optimization hash into human readable form
608 static void simple_dump_opt_hash(dumper_t *dmp, pset *set, int index)
610 opt_entry_t *entry = pset_first(set);
613 fprintf(dmp->f, "\n%s:\n", opt_names[index]);
614 fprintf(dmp->f, "%-16s %-8s\n", "Opcode", "deref");
616 for (; entry; entry = pset_next(set)) {
617 fprintf(dmp->f, "%-16s %8d\n",
618 get_id_str(entry->op->name), entry->count.cnt[0]);
624 * dumps the endges count
626 static void simple_dump_edges(dumper_t *dmp, counter_t *cnt)
628 fprintf(dmp->f, "%-16s %8d\n", "Edges", cnt->cnt[0]);
634 static void simple_dump_graph(dumper_t *dmp, graph_entry_t *entry)
637 block_entry_t *b_entry;
640 ir_graph *const_irg = get_const_code_irg();
642 if (entry->irg == const_irg) {
643 fprintf(dmp->f, "\nConst code Irg %p", (void *)entry->irg);
647 fprintf(dmp->f, "\nEntity %s, Irg %p", get_entity_name(entry->ent), (void *)entry->irg);
649 fprintf(dmp->f, "\nIrg %p", (void *)entry->irg);
652 fprintf(dmp->f, " %swalked %u over blocks %u:\n"
653 " was inlined : %u\n"
654 " got inlined : %u\n"
655 " strength red : %u\n"
656 " leaf function : %s\n"
660 " indirect calls: %u\n",
661 entry->is_deleted ? "DELETED " : "",
662 entry->cnt_walked.cnt[0], entry->cnt_walked_blocks.cnt[0],
663 entry->cnt_was_inlined.cnt[0],
664 entry->cnt_got_inlined.cnt[0],
665 entry->cnt_strength_red.cnt[0],
666 entry->is_leaf ? "YES" : "NO",
667 entry->is_recursive ? "YES" : "NO",
668 entry->is_chain_call ? "YES" : "NO",
669 entry->cnt_all_calls.cnt[0],
670 entry->cnt_indirect_calls.cnt[0]
674 fprintf(dmp->f, "\nGlobals counts:\n");
675 fprintf(dmp->f, "--------------\n");
679 simple_dump_opcode_hash(dmp, entry->opcode_hash);
680 simple_dump_edges(dmp, &entry->cnt_edges);
682 /* effects of optimizations */
686 for (i = 0; i < sizeof(entry->opt_hash)/sizeof(entry->opt_hash[0]); ++i) {
687 simple_dump_opt_hash(dmp, entry->opt_hash[i], i);
690 /* dump block info */
691 fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s\n", "Block Nr", "Nodes", "intern E", "incoming E", "outgoing E", "quot");
692 for (b_entry = pset_first(entry->block_hash);
694 b_entry = pset_next(entry->block_hash)) {
695 fprintf(dmp->f, "BLK %12ld %12u %12u %12u %12u %4.8f\n",
697 b_entry->cnt_nodes.cnt[0],
698 b_entry->cnt_edges.cnt[0],
699 b_entry->cnt_in_edges.cnt[0],
700 b_entry->cnt_out_edges.cnt[0],
701 (double)b_entry->cnt_edges.cnt[0] / (double)b_entry->cnt_nodes.cnt[0]
708 * initialise the simple dumper
710 static void simple_init(dumper_t *dmp, const char *name)
714 snprintf(fname, sizeof(fname), "%s.txt", name);
715 dmp->f = fopen(fname, "w");
719 * finishes the simple dumper
721 static void simple_finish(dumper_t *dmp)
728 * the simple human readable dumper
730 static dumper_t simple_dumper = {
738 /* ---------------------------------------------------------------------- */
741 * count the nodes as needed:
743 * 1 normal (data) Phi's
748 static void csv_count_nodes(graph_entry_t *graph, counter_t cnt[])
753 for (i = 0; i < 4; ++i)
756 for (entry = pset_first(graph->opcode_hash); entry; entry = pset_next(graph->opcode_hash)) {
757 if (entry->op == op_Phi) {
759 cnt_add(&cnt[1], &entry->cnt_alive);
761 else if (entry->op == status->op_PhiM) {
763 cnt_add(&cnt[2], &entry->cnt_alive);
765 else if (entry->op == op_Proj) {
767 cnt_add(&cnt[3], &entry->cnt_alive);
770 /* all other nodes */
771 cnt_add(&cnt[0], &entry->cnt_alive);
779 static void csv_dump_graph(dumper_t *dmp, graph_entry_t *entry)
785 if (entry->irg && !entry->is_deleted) {
786 ir_graph *const_irg = get_const_code_irg();
788 if (entry->irg == const_irg) {
789 name = "<Const code Irg>";
794 name = get_entity_name(entry->ent);
796 name = "<UNKNOWN IRG>";
799 csv_count_nodes(entry, cnt);
801 fprintf(dmp->f, "%-40s, %p, %d, %d, %d, %d\n",
813 * initialise the simple dumper
815 static void csv_init(dumper_t *dmp, const char *name)
819 snprintf(fname, sizeof(fname), "%s.csv", name);
820 dmp->f = fopen(fname, "a");
824 * finishes the simple dumper
826 static void csv_finish(dumper_t *dmp)
833 * the simple human readable dumper
835 static dumper_t csv_dumper = {
844 /* ---------------------------------------------------------------------- */
847 * helper: get an ir_op from an opcode
849 ir_op *stat_get_op_from_opcode(opcode code)
851 return opcode_find_entry(code, status->ir_op_hash);
854 /* initialize the statistics module. */
855 void init_stat(unsigned enable_options)
857 #define X(a) a, sizeof(a)-1
861 /* enable statistics */
862 status->enable = enable_options & FIRMSTAT_ENABLED;
864 if (! status->enable)
867 obstack_init(&status->cnts);
869 /* build the pseudo-ops */
870 _op_Phi0.code = --pseudo_id;
871 _op_Phi0.name = new_id_from_chars(X("Phi0"));
873 _op_PhiM.code = --pseudo_id;
874 _op_PhiM.name = new_id_from_chars(X("PhiM"));
876 _op_MulC.code = --pseudo_id;
877 _op_MulC.name = new_id_from_chars(X("MulC"));
879 _op_DivC.code = --pseudo_id;
880 _op_DivC.name = new_id_from_chars(X("DivC"));
882 _op_ModC.code = --pseudo_id;
883 _op_ModC.name = new_id_from_chars(X("ModC"));
885 _op_DivModC.code = --pseudo_id;
886 _op_DivModC.name = new_id_from_chars(X("DivModC"));
888 /* create the hash-tables */
889 status->irg_hash = new_pset(graph_cmp, 8);
890 status->ir_op_hash = new_pset(opcode_cmp_2, 1);
892 status->op_Phi0 = &_op_Phi0;
893 status->op_PhiM = &_op_PhiM;
895 if (enable_options & FIRMSTAT_COUNT_STRONG_OP) {
896 status->op_MulC = &_op_MulC;
897 status->op_DivC = &_op_DivC;
898 status->op_ModC = &_op_ModC;
899 status->op_DivModC = &_op_DivModC;
902 status->op_MulC = NULL;
903 status->op_DivC = NULL;
904 status->op_ModC = NULL;
905 status->op_DivModC = NULL;
908 stat_register_dumper(&simple_dumper);
910 if (enable_options & FIRMSTAT_CSV_OUTPUT)
911 stat_register_dumper(&csv_dumper);
913 /* initialize the pattern hash */
914 stat_init_pattern_history(enable_options & FIRMSTAT_PATTERN_ENABLED);
918 /* A new IR op is registered. */
919 void stat_new_ir_op(const ir_op *op)
921 if (! status->enable)
926 graph_entry_t *graph = graph_get_entry(NULL, status->irg_hash);
928 /* execute for side effect :-) */
929 opcode_get_entry(op, graph->opcode_hash);
931 pset_insert(status->ir_op_hash, op, op->code);
936 /* An IR op is freed. */
937 void stat_free_ir_op(const ir_op *op)
939 if (! status->enable)
948 /* A new node is created. */
949 void stat_new_node(ir_node *node)
951 if (! status->enable)
954 /* do NOT count during dead node elimination */
955 if (status->in_dead_node_elim > 0)
961 graph_entry_t *graph;
962 ir_op *op = stat_get_irn_op(node);
964 /* increase global value */
965 graph = graph_get_entry(NULL, status->irg_hash);
966 entry = opcode_get_entry(op, graph->opcode_hash);
967 cnt_inc(&entry->new_node);
969 /* increase local value */
970 graph = graph_get_entry(current_ir_graph, status->irg_hash);
971 entry = opcode_get_entry(op, graph->opcode_hash);
972 cnt_inc(&entry->new_node);
977 /* A node is changed into a Id node */
978 void stat_turn_into_id(ir_node *node)
980 if (! status->enable)
986 graph_entry_t *graph;
987 ir_op *op = stat_get_irn_op(node);
989 /* increase global value */
990 graph = graph_get_entry(NULL, status->irg_hash);
991 entry = opcode_get_entry(op, graph->opcode_hash);
992 cnt_inc(&entry->into_Id);
994 /* increase local value */
995 graph = graph_get_entry(current_ir_graph, status->irg_hash);
996 entry = opcode_get_entry(op, graph->opcode_hash);
997 cnt_inc(&entry->into_Id);
1002 /* A new graph was created */
1003 void stat_new_graph(ir_graph *irg, entity *ent)
1005 if (! status->enable)
1010 /* execute for side effect :-) */
1011 graph_entry_t * graph = graph_get_entry(irg, status->irg_hash);
1014 graph->is_deleted = 0;
1016 graph->is_recursive = 0;
1017 graph->is_chain_call = 0;
1023 * A graph will be deleted
1025 void stat_free_graph(ir_graph *irg)
1027 if (! status->enable)
1032 graph_entry_t *graph = graph_get_entry(irg, status->irg_hash);
1033 graph_entry_t *global = graph_get_entry(NULL, status->irg_hash);
1035 graph->is_deleted = 1;
1037 /* count the nodes of the graph yet, it will be destroyed later */
1038 update_graph_stat(global, graph);
1040 /* count the DAG's */
1041 // count_dags_in_graph(global, graph);
1043 /* calculate the pattern */
1044 stat_calc_pattern_history(irg);
1050 * A walk over a graph is initiated. Do not count walks from statistic code.
1052 void stat_irg_walk(ir_graph *irg, void *pre, void *post)
1054 if (! status->enable)
1059 graph_entry_t *graph = graph_get_entry(irg, status->irg_hash);
1061 cnt_inc(&graph->cnt_walked);
1067 * A walk over a graph in block-wise order is initiated. Do not count walks from statistic code.
1069 void stat_irg_walk_blkwise(ir_graph *irg, void *pre, void *post)
1071 /* for now, do NOT differentiate between blockwise and normal */
1072 stat_irg_walk(irg, pre, post);
1076 * A walk over the graph's blocks is initiated. Do not count walks from statistic code.
1078 void stat_irg_block_walk(ir_graph *irg, const ir_node *node, void *pre, void *post)
1080 if (! status->enable)
1085 graph_entry_t *graph = graph_get_entry(irg, status->irg_hash);
1087 cnt_inc(&graph->cnt_walked_blocks);
1093 * called for every node that is removed due to an optimization
1095 static void removed_due_opt(ir_node *n, pset *set)
1097 ir_op *op = stat_get_irn_op(n);
1098 opt_entry_t *entry = opt_get_entry(op, set);
1100 /* increase global value */
1101 cnt_inc(&entry->count);
1105 * Some nodes were optimized into some others due to an optimization
1107 void stat_merge_nodes(
1108 ir_node **new_node_array, int new_num_entries,
1109 ir_node **old_node_array, int old_num_entries,
1112 if (! status->enable)
1118 graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash);
1120 if (status->reassoc_run)
1121 opt = STAT_OPT_REASSOC;
1123 for (i = 0; i < old_num_entries; ++i) {
1124 for (j = 0; j < new_num_entries; ++j)
1125 if (old_node_array[i] == new_node_array[j])
1128 /* nodes might be in new and old, these are NOT removed */
1129 if (j >= new_num_entries) {
1130 removed_due_opt(old_node_array[i], graph->opt_hash[opt]);
1138 * reassociation started/stopped.
1140 void stat_reassociate(int flag)
1142 if (! status->enable)
1147 status->reassoc_run = flag;
1153 * A node was lowered into other nodes
1155 void stat_lower(ir_node *node)
1157 if (! status->enable)
1162 graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash);
1164 removed_due_opt(node, graph->opt_hash[STAT_LOWERED]);
1170 * A graph was inlined
1172 void stat_inline(ir_node *call, ir_graph *called_irg)
1174 if (! status->enable)
1179 ir_graph *irg = get_irn_irg(call);
1180 graph_entry_t *i_graph = graph_get_entry(called_irg, status->irg_hash);
1181 graph_entry_t *graph = graph_get_entry(irg, status->irg_hash);
1183 cnt_inc(&graph->cnt_got_inlined);
1184 cnt_inc(&i_graph->cnt_was_inlined);
1190 * A graph with tail-recursions was optimized.
1192 void stat_tail_rec(ir_graph *irg)
1194 if (! status->enable)
1204 * Strength reduction was performed on an iteration variable.
1206 void stat_strength_red(ir_graph *irg, ir_node *strong, ir_node *cmp)
1208 if (! status->enable)
1213 graph_entry_t *graph = graph_get_entry(irg, status->irg_hash);
1214 cnt_inc(&graph->cnt_strength_red);
1216 removed_due_opt(strong, graph->opt_hash[STAT_OPT_STRENGTH_RED]);
1222 * Start the dead node elimination.
1224 void stat_dead_node_elim_start(ir_graph *irg)
1226 if (! status->enable)
1229 ++status->in_dead_node_elim;
1233 * Stops the dead node elimination.
1235 void stat_dead_node_elim_stop(ir_graph *irg)
1237 if (! status->enable)
1240 --status->in_dead_node_elim;
1244 * A multiply was replaced by a series of Shifts/Adds/Subs
1246 void stat_arch_dep_replace_mul_with_shifts(ir_node *mul)
1248 if (! status->enable)
1253 graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash);
1254 removed_due_opt(mul, graph->opt_hash[STAT_OPT_ARCH_DEP]);
1260 * A division was replaced by a series of Shifts/Muls
1262 void stat_arch_dep_replace_div_by_const(ir_node *div)
1264 if (! status->enable)
1269 graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash);
1270 removed_due_opt(div, graph->opt_hash[STAT_OPT_ARCH_DEP]);
1276 * A modulo was replaced by a series of Shifts/Muls
1278 void stat_arch_dep_replace_mod_by_const(ir_node *mod)
1280 if (! status->enable)
1285 graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash);
1286 removed_due_opt(mod, graph->opt_hash[STAT_OPT_ARCH_DEP]);
1292 * A DivMod was replaced by a series of Shifts/Muls
1294 void stat_arch_dep_replace_DivMod_by_const(ir_node *divmod)
1296 if (! status->enable)
1301 graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash);
1302 removed_due_opt(divmod, graph->opt_hash[STAT_OPT_ARCH_DEP]);
1307 /* Finish the statistics */
1308 void stat_finish(const char *name)
1310 if (! status->enable)
1315 graph_entry_t *entry;
1316 graph_entry_t *global = graph_get_entry(NULL, status->irg_hash);
1320 /* dump per graph */
1321 for (entry = pset_first(status->irg_hash); entry; entry = pset_next(status->irg_hash)) {
1323 if (entry->irg == NULL) {
1324 /* special entry for the global count */
1328 if (! entry->is_deleted) {
1329 /* the graph is still alive, count the nodes on it */
1330 update_graph_stat(global, entry);
1332 /* count the DAG's */
1333 // count_dags_in_graph(global, entry);
1335 /* calculate the pattern */
1336 stat_calc_pattern_history(entry->irg);
1341 /* clear the counter */
1342 graph_clear_entry(entry);
1349 stat_finish_pattern_history();
1351 /* clear the global counter here */
1353 node_entry_t *entry;
1355 for (entry = pset_first(global->opcode_hash); entry; entry = pset_next(global->opcode_hash)) {
1356 opcode_clear_entry(entry);
1358 graph_clear_entry(global);
1362 // status->enable = 0;
1369 /* need this for prototypes */
1370 #define FIRM_STATISTICS
1371 #include "firmstat.h"
1373 void init_stat(unsigned enable_options) {}
1375 void stat_finish(const char *name) {}
1377 void stat_new_ir_op(const ir_op *op) {}
1379 void stat_free_ir_op(const ir_op *op) {}
1381 void stat_new_node(ir_node *node) {}
1383 void stat_turn_into_id(ir_node *node) {}
1385 void stat_new_graph(ir_graph *irg, entity *ent) {}
1387 void stat_free_graph(ir_graph *irg) {}
1389 void stat_irg_walk(ir_graph *irg, void *pre, void *post) {}
1391 void stat_irg_block_walk(ir_graph *irg, const ir_node *node, void *pre, void *post) {}
1393 void stat_merge_nodes(
1394 ir_node **new_node_array, int new_num_entries,
1395 ir_node **old_node_array, int old_num_entries,
1396 stat_opt_kind opt) {}
1398 void stat_reassociate(int start) {}
1400 void stat_lower(ir_node *node) {}
1402 void stat_inline(ir_node *call, ir_graph *irg) {}
1404 void stat_tail_rec(ir_graph *irg) {}
1406 void stat_strength_red(ir_graph *irg, ir_node *strong, ir_node *cmp) {}
1408 void stat_dead_node_elim_start(ir_graph *irg) {}
1410 void stat_dead_node_elim_stop(ir_graph *irg) {}
1412 void stat_arch_dep_replace_mul_with_shifts(ir_node *mul) {}
1414 void stat_arch_dep_replace_div_by_const(ir_node *div) {}
1416 void stat_arch_dep_replace_mod_by_const(ir_node *mod) {}
1418 void stat_arch_dep_replace_DivMod_by_const(ir_node *divmod) {}