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