flag for strength reduction verbosity
[libfirm] / ir / stat / firmstat.c
1 /*
2  * Project:     libFIRM
3  * File name:   ir/ir/firmstat.c
4  * Purpose:     Statistics for Firm.
5  * Author:      Michael Beck
6  * Created:
7  * CVS-ID:      $Id$
8  * Copyright:   (c) 2004 Universität Karlsruhe
9  * Licence:     This file protected by GPL -  GNU GENERAL PUBLIC LICENSE.
10  */
11
12 #ifdef HAVE_CONFIG_H
13 # include "config.h"
14 #endif
15
16 #ifdef FIRM_STATISTICS
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21
22 #include "firmstat_t.h"
23 #include "pattern.h"
24 #include "dags.h"
25
26 /**
27  * names of the optimizations
28  */
29 static const char *opt_names[] = {
30   "straightening optimization",
31   "if simplification",
32   "algebraic simplification",
33   "Phi optmization",
34   "Write-After-Write optimization",
35   "Write-After-Read optimization",
36   "Read-After-Write optimization",
37   "Tuple optimization",
38   "ID optimization",
39   "Constant evaluation",
40   "Lowered",
41 };
42
43 /**
44  * need this to be static
45  */
46 static ir_op _op_Phi0, _op_PhiM;
47
48 /* ---------------------------------------------------------------------------------- */
49
50 #define STAT_ENTER              ++status->recursive
51 #define STAT_LEAVE              --status->recursive
52 #define STAT_ENTER_SINGLE       do { if (status->recursive > 0) return; ++status->recursive; } while (0)
53
54 /**
55  * global status
56  */
57 static stat_info_t _status, *status = &_status;
58
59 /**
60  * compare two elements of the opcode hash
61  */
62 static int opcode_cmp(const void *elt, const void *key)
63 {
64   const node_entry_t *e1 = elt;
65   const node_entry_t *e2 = key;
66
67   return e1->op->code - e2->op->code;
68 }
69
70 /**
71  * compare two elements of the graph hash
72  */
73 static int graph_cmp(const void *elt, const void *key)
74 {
75   const graph_entry_t *e1 = elt;
76   const graph_entry_t *e2 = key;
77
78   return e1->irg != e2->irg;
79 }
80
81 /**
82  * compare two elements of the optimization hash
83  */
84 static int opt_cmp(const void *elt, const void *key)
85 {
86   const opt_entry_t *e1 = elt;
87   const opt_entry_t *e2 = key;
88
89   return e1->op->code != e2->op->code;
90 }
91
92 /**
93  * compare two elements of the block hash
94  */
95 static int block_cmp(const void *elt, const void *key)
96 {
97   const block_entry_t *e1 = elt;
98   const block_entry_t *e2 = key;
99
100   return e1->block_nr != e2->block_nr;
101 }
102
103 /**
104  * compare two elements of the ir_op hash
105  */
106 static int opcode_cmp_2(const void *elt, const void *key)
107 {
108   const ir_op *e1 = elt;
109   const ir_op *e2 = key;
110
111   return e1->code != e2->code;
112 }
113
114 /**
115  * clears all counter in a node_entry_t
116  */
117 static void opcode_clear_entry(node_entry_t *elem)
118 {
119   cnt_clr(&elem->cnt_alive);
120   cnt_clr(&elem->new_node);
121   cnt_clr(&elem->into_Id);
122 }
123
124 /**
125  * Returns the associates node_entry_t for an ir_op
126  */
127 static node_entry_t *opcode_get_entry(const ir_op *op, pset *set)
128 {
129   node_entry_t key;
130   node_entry_t *elem;
131
132   key.op = op;
133
134   elem = pset_find(set, &key, op->code);
135   if (elem)
136     return elem;
137
138   elem = obstack_alloc(&status->cnts, sizeof(*elem));
139
140   /* clear counter */
141   opcode_clear_entry(elem);
142
143   elem->op = op;
144
145   return pset_insert(set, elem, op->code);
146 }
147
148 /**
149  * Returns the associates ir_op for an opcode
150  */
151 static ir_op *opcode_find_entry(opcode code, pset *set)
152 {
153   ir_op key;
154
155   key.code = code;
156   return pset_find(set, &key, code);
157 }
158
159 /**
160  * calculates a hash value for an irg
161  * Addresses are typically aligned at 32bit, so we ignore the lowest bits
162  */
163 static INLINE unsigned irg_hash(const ir_graph *irg)
164 {
165   return (unsigned)irg >> 3;
166 }
167
168 /**
169  * clears all counter in a graph_entry_t
170  */
171 static void graph_clear_entry(graph_entry_t *elem)
172 {
173   cnt_clr(&elem->cnt_walked);
174   cnt_clr(&elem->cnt_walked_blocks);
175   cnt_clr(&elem->cnt_got_inlined);
176   cnt_clr(&elem->cnt_was_inlined);
177   cnt_clr(&elem->cnt_edges);
178 }
179
180 /**
181  * Returns the acssociates graph_entry_t for an irg
182  */
183 static graph_entry_t *graph_get_entry(ir_graph *irg, pset *set)
184 {
185   graph_entry_t key;
186   graph_entry_t *elem;
187   int i;
188
189   key.irg = irg;
190
191   elem = pset_find(set, &key, irg_hash(irg));
192   if (elem)
193     return elem;
194
195   elem = obstack_alloc(&status->cnts, sizeof(*elem));
196
197   /* clear counter */
198   graph_clear_entry(elem);
199
200   /* new hash table for opcodes here  */
201   elem->opcode_hash  = new_pset(opcode_cmp, 5);
202   elem->block_hash   = new_pset(block_cmp, 5);
203   elem->irg          = irg;
204
205   for (i = 0; i < sizeof(elem->opt_hash)/sizeof(elem->opt_hash[0]); ++i)
206     elem->opt_hash[i] = new_pset(opt_cmp, 4);
207
208   return pset_insert(set, elem, irg_hash(irg));
209 }
210
211 /**
212  * clears all counter in an opt_entry_t
213  */
214 static void opt_clear_entry(opt_entry_t *elem)
215 {
216   cnt_clr(&elem->count);
217 }
218
219 /**
220  * Returns the associates opt_entry_t for an ir_op
221  */
222 static opt_entry_t *opt_get_entry(const ir_op *op, pset *set)
223 {
224   opt_entry_t key;
225   opt_entry_t *elem;
226
227   key.op = op;
228
229   elem = pset_find(set, &key, op->code);
230   if (elem)
231     return elem;
232
233   elem = obstack_alloc(&status->cnts, sizeof(*elem));
234
235   /* clear new counter */
236   opt_clear_entry(elem);
237
238   elem->op = op;
239
240   return pset_insert(set, elem, op->code);
241 }
242
243 /**
244  * clears all counter in a block_entry_t
245  */
246 static void block_clear_entry(block_entry_t *elem)
247 {
248   cnt_clr(&elem->cnt_nodes);
249   cnt_clr(&elem->cnt_edges);
250   cnt_clr(&elem->cnt_in_edges);
251   cnt_clr(&elem->cnt_out_edges);
252 }
253
254 /**
255  * Returns the associates block_entry_t for an block
256  */
257 static block_entry_t *block_get_entry(long block_nr, pset *set)
258 {
259   block_entry_t key;
260   block_entry_t *elem;
261
262   key.block_nr = block_nr;
263
264   elem = pset_find(set, &key, block_nr);
265   if (elem)
266     return elem;
267
268   elem = obstack_alloc(&status->cnts, sizeof(*elem));
269
270   /* clear new counter */
271   block_clear_entry(elem);
272
273   elem->block_nr = block_nr;
274
275   return pset_insert(set, elem, block_nr);
276 }
277
278
279 /**
280  * Returns the ir_op for an IR-node,
281  * handles special cases and return pseudo op codes
282  */
283 static ir_op *stat_get_irn_op(const ir_node *node)
284 {
285   ir_op *op = get_irn_op(node);
286
287   if (op->code == iro_Phi && get_irn_arity(node) == 0) {
288     /* special case, a Phi0 node, count on extra counter */
289     op = status->op_Phi0;
290   }
291   else if (op->code == iro_Phi && get_irn_mode(node) == mode_M) {
292     /* special case, a Memory Phi node, count on extra counter */
293     op = status->op_PhiM;
294   }
295   return op;
296 }
297
298 /**
299  * update the block counter
300  */
301 static void count_block_info(ir_node *node, graph_entry_t *graph)
302 {
303   ir_op *op = get_irn_op(node);
304   ir_node *block;
305   block_entry_t *b_entry;
306   int i, arity;
307
308   /* check for block */
309   if (op == op_Block) {
310     arity = get_irn_arity(node);
311     b_entry = block_get_entry(get_irn_node_nr(node), graph->block_hash);
312
313     /* count all incoming edges */
314     for (i = 0; i < arity; ++i) {
315       ir_node *pred = get_irn_n(node, i);
316       ir_node *other_block = get_nodes_block(pred);
317       block_entry_t *b_entry_other = block_get_entry(get_irn_node_nr(other_block), graph->block_hash);
318
319       cnt_inc(&b_entry->cnt_in_edges);  /* an edge coming from another block */
320       cnt_inc(&b_entry_other->cnt_out_edges);
321     }
322     return;
323   }
324   else if (op == op_Call) {
325     // return;
326   }
327
328   block   = get_nodes_block(node);
329   b_entry = block_get_entry(get_irn_node_nr(block), graph->block_hash);
330
331   /* we have a new nodes */
332   cnt_inc(&b_entry->cnt_nodes);
333
334   arity = get_irn_arity(node);
335
336   for (i = 0; i < arity; ++i) {
337     ir_node *pred = get_irn_n(node, i);
338     ir_node *other_block;
339
340     if (get_irn_op(pred) == op_Block)
341       continue;
342
343     other_block = get_nodes_block(pred);
344
345     if (other_block == block)
346       cnt_inc(&b_entry->cnt_edges);     /* a in block edge */
347     else {
348       block_entry_t *b_entry_other = block_get_entry(get_irn_node_nr(other_block), graph->block_hash);
349
350       cnt_inc(&b_entry->cnt_in_edges);  /* an edge coming from another block */
351       cnt_inc(&b_entry_other->cnt_out_edges);
352     }
353   }
354 }
355
356 /**
357  * walker for reachable nodes count
358  */
359 static void count_nodes(ir_node *node, void *env)
360 {
361   graph_entry_t *graph = env;
362   node_entry_t *entry;
363
364   ir_op *op = stat_get_irn_op(node);
365   int arity = get_irn_arity(node);
366
367   entry = opcode_get_entry(op, graph->opcode_hash);
368
369   cnt_inc(&entry->cnt_alive);
370   cnt_add_i(&graph->cnt_edges, arity);
371
372   /* count block edges */
373   count_block_info(node, graph);
374 }
375
376 /**
377  * count all alive nodes and edges in a graph
378  */
379 static void count_nodes_in_graph(graph_entry_t *global, graph_entry_t *graph)
380 {
381   node_entry_t *entry;
382
383   /* clear first the alive counter in the graph */
384   for (entry = pset_first(graph->opcode_hash); entry; entry = pset_next(graph->opcode_hash)) {
385     cnt_clr(&entry->cnt_alive);
386   }
387
388   /* count the nodes in the graph */
389   irg_walk_graph(graph->irg, count_nodes, NULL, graph);
390
391   /* assume we walk every graph only ONCE, we could sum here the global count */
392   for (entry = pset_first(graph->opcode_hash); entry; entry = pset_next(graph->opcode_hash)) {
393     node_entry_t *g_entry = opcode_get_entry(entry->op, global->opcode_hash);
394
395     /* update the node counter */
396     cnt_add(&g_entry->cnt_alive, &entry->cnt_alive);
397   }
398
399   /* update the edge counter */
400   cnt_add(&global->cnt_edges, &graph->cnt_edges);
401 }
402
403 /**
404  * register a dumper
405  */
406 static void stat_register_dumper(dumper_t *dumper)
407 {
408   dumper->next   = status->dumper;
409   status->dumper = dumper;
410 }
411
412 /**
413  * dumps an irg
414  */
415 static void dump_graph(graph_entry_t *entry)
416 {
417   dumper_t *dumper;
418
419   for (dumper = status->dumper; dumper; dumper = dumper->next) {
420     if (dumper->dump_graph)
421       dumper->dump_graph(dumper, entry);
422   }
423 }
424
425 /**
426  * initialise the dumper
427  */
428 static void dump_init(const char *name)
429 {
430   dumper_t *dumper;
431
432   for (dumper = status->dumper; dumper; dumper = dumper->next) {
433     if (dumper->init)
434       dumper->init(dumper, name);
435   }
436 }
437
438 /**
439  * finish the dumper
440  */
441 static void dump_finish(void)
442 {
443   dumper_t *dumper;
444
445   for (dumper = status->dumper; dumper; dumper = dumper->next) {
446     if (dumper->finish)
447       dumper->finish(dumper);
448   }
449 }
450
451 /* ---------------------------------------------------------------------- */
452
453 /**
454  * dumps a opcode hash into human readable form
455  */
456 static void simple_dump_opcode_hash(dumper_t *dmp, pset *set)
457 {
458   node_entry_t *entry;
459   counter_t f_alive;
460   counter_t f_new_node;
461   counter_t f_Id;
462
463   cnt_clr(&f_alive);
464   cnt_clr(&f_new_node);
465   cnt_clr(&f_Id);
466
467   fprintf(dmp->f, "%-16s %-8s %-8s %-8s\n", "Opcode", "alive", "created", "->Id");
468   for (entry = pset_first(set); entry; entry = pset_next(set)) {
469     fprintf(dmp->f, "%-16s %8d %8d %8d\n",
470       get_id_str(entry->op->name), entry->cnt_alive.cnt[0], entry->new_node.cnt[0], entry->into_Id.cnt[0]);
471
472     cnt_add(&f_alive,    &entry->cnt_alive);
473     cnt_add(&f_new_node, &entry->new_node);
474     cnt_add(&f_Id,       &entry->into_Id);
475   }
476   fprintf(dmp->f, "-------------------------------------------\n");
477   fprintf(dmp->f, "%-16s %8d %8d %8d\n", "Sum",
478      f_alive.cnt[0],
479      f_new_node.cnt[0],
480      f_Id.cnt[0]);
481 }
482
483 /**
484  * dumps a optimization hash into human readable form
485  */
486 static void simple_dump_opt_hash(dumper_t *dmp, pset *set, int index)
487 {
488   opt_entry_t *entry = pset_first(set);
489
490   if (entry) {
491     fprintf(dmp->f, "\n%s:\n", opt_names[index]);
492     fprintf(dmp->f, "%-16s %-8s\n", "Opcode", "deref");
493
494     for (; entry; entry = pset_next(set)) {
495       fprintf(dmp->f, "%-16s %8d\n",
496         get_id_str(entry->op->name), entry->count.cnt[0]);
497     }
498   }
499 }
500
501 /**
502  * dumps the endges count
503  */
504 static void simple_dump_edges(dumper_t *dmp, counter_t *cnt)
505 {
506   fprintf(dmp->f, "%-16s %8d\n", "Edges", cnt->cnt[0]);
507 }
508
509 /**
510  * dumps the IRG
511  */
512 static void simple_dump_graph(dumper_t *dmp, graph_entry_t *entry)
513 {
514   int dump_opts = 1;
515   block_entry_t *b_entry;
516
517   if (entry->irg) {
518     ir_graph *const_irg = get_const_code_irg();
519
520     if (entry->irg == const_irg) {
521       fprintf(dmp->f, "\nConst code Irg %p", (void *)entry->irg);
522     }
523     else {
524       if (entry->ent)
525         fprintf(dmp->f, "\nEntity %s, Irg %p", get_entity_name(entry->ent), (void *)entry->irg);
526       else
527         fprintf(dmp->f, "\nIrg %p", (void *)entry->irg);
528     }
529
530     fprintf(dmp->f, " %swalked %d over blocks %d was inlined %d got inlined %d:\n",
531         entry->deleted ? "DELETED " : "",
532         entry->cnt_walked.cnt[0], entry->cnt_walked_blocks.cnt[0],
533         entry->cnt_was_inlined.cnt[0],
534         entry->cnt_got_inlined.cnt[0]
535     );
536   }
537   else {
538     fprintf(dmp->f, "\nGlobals counts:\n");
539     fprintf(dmp->f, "--------------\n");
540     dump_opts = 0;
541   }
542
543   simple_dump_opcode_hash(dmp, entry->opcode_hash);
544   simple_dump_edges(dmp, &entry->cnt_edges);
545
546   /* effects of optimizations */
547   if (dump_opts) {
548     int i;
549
550     for (i = 0; i < sizeof(entry->opt_hash)/sizeof(entry->opt_hash[0]); ++i) {
551       simple_dump_opt_hash(dmp, entry->opt_hash[i], i);
552     }
553
554     /* dump block info */
555     fprintf(dmp->f, "\n%12s %12s %12s %12s %12s %12s\n", "Block Nr", "Nodes", "intern E", "incoming E", "outgoing E", "quot");
556     for (b_entry = pset_first(entry->block_hash);
557          b_entry;
558          b_entry = pset_next(entry->block_hash)) {
559       fprintf(dmp->f, "BLK %12ld %12u %12u %12u %12u %4.8f\n",
560           b_entry->block_nr,
561           b_entry->cnt_nodes.cnt[0],
562           b_entry->cnt_edges.cnt[0],
563           b_entry->cnt_in_edges.cnt[0],
564           b_entry->cnt_out_edges.cnt[0],
565           (double)b_entry->cnt_edges.cnt[0] / (double)b_entry->cnt_nodes.cnt[0]
566       );
567     }
568   }
569 }
570
571 /**
572  * initialise the simple dumper
573  */
574 static void simple_init(dumper_t *dmp, const char *name)
575 {
576   char fname[2048];
577
578   snprintf(fname, sizeof(fname), "%s.txt", name);
579   dmp->f = fopen(fname, "w");
580 }
581
582 /**
583  * finishes the simple dumper
584  */
585 static void simple_finish(dumper_t *dmp)
586 {
587   fclose(dmp->f);
588   dmp->f = NULL;
589 }
590
591 /**
592  * the simple human readable dumper
593  */
594 static dumper_t simple_dumper = {
595   simple_dump_graph,
596   simple_init,
597   simple_finish,
598   NULL,
599   NULL,
600 };
601
602 /* ---------------------------------------------------------------------- */
603
604 /**
605  * count the nodes as needed:
606  *
607  * 1 normal (data) Phi's
608  * 2 memory Phi's
609  * 3 Proj
610  * 0 all other nodes
611  */
612 static void csv_count_nodes(graph_entry_t *graph, counter_t cnt[])
613 {
614   node_entry_t *entry;
615   int i;
616
617   for (i = 0; i < 4; ++i)
618     cnt_clr(&cnt[i]);
619
620   for (entry = pset_first(graph->opcode_hash); entry; entry = pset_next(graph->opcode_hash)) {
621     if (entry->op == op_Phi) {
622       /* normal Phi */
623       cnt_add(&cnt[1], &entry->cnt_alive);
624     }
625     else if (entry->op == status->op_PhiM) {
626       /* memory Phi */
627       cnt_add(&cnt[2], &entry->cnt_alive);
628     }
629     else if (entry->op == op_Proj) {
630       /* Proj */
631       cnt_add(&cnt[3], &entry->cnt_alive);
632     }
633     else {
634       /* all other nodes */
635       cnt_add(&cnt[0], &entry->cnt_alive);
636     }
637   }
638 }
639
640 /**
641  * dumps the IRG
642  */
643 static void csv_dump_graph(dumper_t *dmp, graph_entry_t *entry)
644 {
645   const char *name;
646
647   counter_t cnt[4];
648
649   if (entry->irg) {
650     ir_graph *const_irg = get_const_code_irg();
651
652     if (entry->irg == const_irg) {
653       name = "<Const code Irg>";
654       return;
655     }
656     else {
657       if (entry->ent)
658         name = get_entity_name(entry->ent);
659       else
660         name = "<UNKNOWN IRG>";
661     }
662
663     csv_count_nodes(entry, cnt);
664
665     fprintf(dmp->f, "%-40s, %p, %d, %d, %d, %d\n",
666         name,
667         (void *)entry->irg,
668         cnt[0].cnt[0],
669         cnt[1].cnt[0],
670         cnt[2].cnt[0],
671         cnt[3].cnt[0]
672     );
673   }
674 }
675
676 /**
677  * initialise the simple dumper
678  */
679 static void csv_init(dumper_t *dmp, const char *name)
680 {
681   char fname[2048];
682
683   snprintf(fname, sizeof(fname), "%s.csv", name);
684   dmp->f = fopen(fname, "a");
685 }
686
687 /**
688  * finishes the simple dumper
689  */
690 static void csv_finish(dumper_t *dmp)
691 {
692   fclose(dmp->f);
693   dmp->f = NULL;
694 }
695
696 /**
697  * the simple human readable dumper
698  */
699 static dumper_t csv_dumper = {
700   csv_dump_graph,
701   csv_init,
702   csv_finish,
703   NULL,
704   NULL,
705 };
706
707
708 /* ---------------------------------------------------------------------- */
709
710 /*
711  * helper: get an ir_op from an opcode
712  */
713 ir_op *stat_get_op_from_opcode(opcode code)
714 {
715   return opcode_find_entry(code, status->ir_op_hash);
716 }
717
718 /* initialize the statistics module. */
719 void init_stat(unsigned enable_options)
720 {
721 #define X(a)  a, sizeof(a)-1
722
723   int pseudo_id = 0;
724
725   /* enable statistics */
726   status->enable = enable_options & FIRMSTAT_ENABLED;
727
728   if (! status->enable)
729    return;
730
731   obstack_init(&status->cnts);
732
733   /* build the pseudo-ops */
734   _op_Phi0.code = --pseudo_id;
735   _op_Phi0.name = new_id_from_chars(X("Phi0"));
736
737   _op_PhiM.code = --pseudo_id;
738   _op_PhiM.name = new_id_from_chars(X("PhiM"));
739
740   /* create the hash-tables */
741   status->irg_hash   = new_pset(graph_cmp, 8);
742   status->ir_op_hash = new_pset(opcode_cmp_2, 1);
743
744   status->op_Phi0    = &_op_Phi0;
745   status->op_PhiM    = &_op_PhiM;
746
747   stat_register_dumper(&simple_dumper);
748   stat_register_dumper(&csv_dumper);
749
750   /* initialize the pattern hash */
751   stat_init_pattern_history(enable_options & FIRMSTAT_PATTERN_ENABLED);
752 #undef X
753 }
754
755 /* A new IR op is registered. */
756 void stat_new_ir_op(const ir_op *op)
757 {
758   if (! status->enable)
759     return;
760
761   STAT_ENTER;
762   {
763     graph_entry_t *graph = graph_get_entry(NULL, status->irg_hash);
764
765     /* execute for side effect :-) */
766     opcode_get_entry(op, graph->opcode_hash);
767
768     pset_insert(status->ir_op_hash, op, op->code);
769   }
770   STAT_LEAVE;
771 }
772
773 /* An IR op is freed. */
774 void stat_free_ir_op(const ir_op *op)
775 {
776   if (! status->enable)
777     return;
778
779   STAT_ENTER;
780   {
781   }
782   STAT_LEAVE;
783 }
784
785 /* A new node is created. */
786 void stat_new_node(const ir_node *node)
787 {
788   if (! status->enable)
789     return;
790
791   /* do NOT count during dead node elimination */
792   if (status->in_dead_node_elim > 0)
793     return;
794
795   STAT_ENTER;
796   {
797     node_entry_t *entry;
798     graph_entry_t *graph;
799     ir_op *op = stat_get_irn_op(node);
800
801     /* increase global value */
802     graph = graph_get_entry(NULL, status->irg_hash);
803     entry = opcode_get_entry(op, graph->opcode_hash);
804     cnt_inc(&entry->new_node);
805
806     /* increase local value */
807     graph = graph_get_entry(current_ir_graph, status->irg_hash);
808     entry = opcode_get_entry(op, graph->opcode_hash);
809     cnt_inc(&entry->new_node);
810   }
811   STAT_LEAVE;
812 }
813
814 /* A node is changed into a Id node */
815 void stat_turn_into_id(const ir_node *node)
816 {
817   if (! status->enable)
818     return;
819
820   STAT_ENTER;
821   {
822     node_entry_t *entry;
823     graph_entry_t *graph;
824     ir_op *op = stat_get_irn_op(node);
825
826     /* increase global value */
827     graph = graph_get_entry(NULL, status->irg_hash);
828     entry = opcode_get_entry(op, graph->opcode_hash);
829     cnt_inc(&entry->into_Id);
830
831     /* increase local value */
832     graph = graph_get_entry(current_ir_graph, status->irg_hash);
833     entry = opcode_get_entry(op, graph->opcode_hash);
834     cnt_inc(&entry->into_Id);
835   }
836   STAT_LEAVE;
837 }
838
839 /* A new graph was created */
840 void stat_new_graph(ir_graph *irg, entity *ent)
841 {
842   if (! status->enable)
843     return;
844
845   STAT_ENTER;
846   {
847     /* execute for side effect :-) */
848     graph_entry_t * graph = graph_get_entry(irg, status->irg_hash);
849
850     graph->ent     = ent;
851     graph->deleted = 0;
852   }
853   STAT_LEAVE;
854 }
855
856 /*
857  * A graph was deleted
858  */
859 void stat_free_graph(ir_graph *irg)
860 {
861   if (! status->enable)
862     return;
863
864   STAT_ENTER;
865   {
866     graph_entry_t *graph  = graph_get_entry(irg, status->irg_hash);
867     graph_entry_t *global = graph_get_entry(NULL, status->irg_hash);
868
869     graph->deleted = 1;
870
871     /* count the nodes of the graph yet, it will be destroyed later */
872     count_nodes_in_graph(global, graph);
873
874     /* count the DAG's */
875     count_dags_in_graph(global, graph);
876
877     /* calculate the pattern */
878     stat_calc_pattern_history(irg);
879   }
880   STAT_LEAVE;
881 }
882
883 /*
884  * A walk over a graph is initiated. Do not count walks from statistic code.
885  */
886 void stat_irg_walk(ir_graph *irg, void *pre, void *post)
887 {
888   if (! status->enable)
889     return;
890
891   STAT_ENTER_SINGLE;
892   {
893     graph_entry_t *graph = graph_get_entry(irg, status->irg_hash);
894
895     cnt_inc(&graph->cnt_walked);
896   }
897   STAT_LEAVE;
898 }
899
900 /*
901  * A walk over a graph in block-wise order is initiated. Do not count walks from statistic code.
902  */
903 void stat_irg_walk_blkwise(ir_graph *irg, void *pre, void *post)
904 {
905   /* for now, do NOT differentiate between blockwise and normal */
906   stat_irg_walk(irg, pre, post);
907 }
908
909 /*
910  * A walk over the graph's blocks is initiated. Do not count walks from statistic code.
911  */
912 void stat_irg_block_walk(ir_graph *irg, const ir_node *node, void *pre, void *post)
913 {
914   if (! status->enable)
915     return;
916
917   STAT_ENTER_SINGLE;
918   {
919     graph_entry_t *graph = graph_get_entry(irg, status->irg_hash);
920
921     cnt_inc(&graph->cnt_walked_blocks);
922   }
923   STAT_LEAVE;
924 }
925
926 /**
927  * called for every node that is removed due to an optimization
928  */
929 static void removed_due_opt(ir_node *n, pset *set)
930 {
931   ir_op *op          = get_irn_op(n);
932   opt_entry_t *entry = opt_get_entry(op, set);
933
934   /* increase global value */
935   cnt_inc(&entry->count);
936 }
937
938 /*
939  * Some nodes were optimized into some others due to an optimization
940  */
941 void stat_merge_nodes(
942     ir_node **new_node_array, int new_num_entries,
943     ir_node **old_node_array, int old_num_entries,
944     stat_opt_kind opt)
945 {
946   if (! status->enable)
947     return;
948
949   STAT_ENTER;
950   {
951     int i, j;
952     graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash);
953
954     for (i = 0; i < old_num_entries; ++i) {
955       for (j = 0; j < new_num_entries; ++j)
956         if (old_node_array[i] == new_node_array[j])
957           break;
958
959       /* nodes might be in new and old, these are NOT removed */
960       if (j >= new_num_entries) {
961         removed_due_opt(old_node_array[i], graph->opt_hash[opt]);
962       }
963     }
964   }
965   STAT_LEAVE;
966 }
967
968 /*
969  * A node was lowered into other nodes
970  */
971 void stat_lower(ir_node *node)
972 {
973   if (! status->enable)
974     return;
975
976   STAT_ENTER;
977   {
978     graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash);
979
980     removed_due_opt(node, graph->opt_hash[STAT_LOWERED]);
981   }
982   STAT_LEAVE;
983 }
984
985 /*
986  * A graph was inlined
987  */
988 void stat_inline(ir_node *call, ir_graph *called_irg)
989 {
990   if (! status->enable)
991     return;
992
993   STAT_ENTER;
994   {
995     ir_graph *irg = get_irn_irg(call);
996     graph_entry_t *i_graph = graph_get_entry(called_irg, status->irg_hash);
997     graph_entry_t *graph   = graph_get_entry(irg, status->irg_hash);
998
999     cnt_inc(&graph->cnt_got_inlined);
1000     cnt_inc(&i_graph->cnt_was_inlined);
1001   }
1002   STAT_LEAVE;
1003 }
1004
1005 /*
1006  * Start the dead node elimination.
1007  */
1008 void stat_dead_node_elim_start(ir_graph *irg)
1009 {
1010   if (! status->enable)
1011     return;
1012
1013   ++status->in_dead_node_elim;
1014 }
1015
1016 /*
1017  * Stops the dead node elimination.
1018  */
1019 void stat_dead_node_elim_stop(ir_graph *irg)
1020 {
1021   if (! status->enable)
1022     return;
1023
1024   --status->in_dead_node_elim;
1025 }
1026
1027 /* Finish the statistics */
1028 void stat_finish(const char *name)
1029 {
1030   if (! status->enable)
1031     return;
1032
1033   STAT_ENTER;
1034   {
1035     graph_entry_t *entry;
1036     graph_entry_t *global = graph_get_entry(NULL, status->irg_hash);
1037
1038     dump_init(name);
1039
1040     /* dump per graph */
1041     for (entry = pset_first(status->irg_hash); entry; entry = pset_next(status->irg_hash)) {
1042
1043       if (entry->irg == NULL) {
1044         /* special entry for the global count */
1045         continue;
1046       }
1047
1048       if (! entry->deleted) {
1049         /* the graph is still alive, count the nodes on it */
1050         count_nodes_in_graph(global, entry);
1051
1052         /* count the DAG's */
1053         count_dags_in_graph(global, entry);
1054
1055         /* calculate the pattern */
1056         stat_calc_pattern_history(entry->irg);
1057       }
1058
1059       dump_graph(entry);
1060
1061       /* clear the counter here:
1062        * we need only the edge counter to be cleared, all others are cumulative
1063        */
1064       cnt_clr(&entry->cnt_edges);
1065     }
1066
1067     /* dump global */
1068 //    dump_graph(global);
1069     dump_finish();
1070
1071     stat_finish_pattern_history();
1072
1073     /* clear the global counter here */
1074     {
1075       node_entry_t *entry;
1076
1077       for (entry = pset_first(global->opcode_hash); entry; entry = pset_next(global->opcode_hash)) {
1078         opcode_clear_entry(entry);
1079       }
1080       graph_clear_entry(global);
1081     }
1082
1083     /* finished */
1084 //    status->enable = 0;
1085   }
1086   STAT_LEAVE;
1087 }
1088
1089 #else
1090
1091 /* need this for prototypes */
1092 #define FIRM_STATISTICS
1093 #include "firmstat.h"
1094
1095 void init_stat(unsigned enable_options) {}
1096
1097 void stat_finish(const char *name) {}
1098
1099 void stat_new_ir_op(const ir_op *op) {}
1100
1101 void stat_free_ir_op(const ir_op *op) {}
1102
1103 void stat_new_node(const ir_node *node) {}
1104
1105 void stat_turn_into_id(const ir_node *node) {}
1106
1107 void stat_new_graph(ir_graph *irg, entity *ent) {}
1108
1109 void stat_free_graph(ir_graph *irg) {}
1110
1111 void stat_irg_walk(ir_graph *irg, void *pre, void *post) {}
1112
1113 void stat_irg_block_walk(ir_graph *irg, const ir_node *node, void *pre, void *post) {}
1114
1115 void stat_merge_nodes(
1116     ir_node **new_node_array, int new_num_entries,
1117     ir_node **old_node_array, int old_num_entries,
1118     stat_opt_kind opt) {}
1119
1120 void stat_lower(ir_node *node) {}
1121
1122 void stat_inline(ir_node *call, ir_graph *irg) {}
1123
1124 void stat_dead_node_elim_start(ir_graph *irg) {}
1125
1126 void stat_dead_node_elim_stop(ir_graph *irg) {}
1127
1128 #endif