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