added new acceessers
[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 "irouts.h"
23 #include "irdump.h"
24 #include "hashptr.h"
25 #include "firmstat_t.h"
26 #include "pattern.h"
27 #include "dags.h"
28 #include "stat_dmp.h"
29
30 /*
31  * need this to be static:
32  * Special pseudo Opcodes that we need to count some interesting cases
33  */
34
35 /**
36  * The Phi0, a node that is created during SSA construction
37  */
38 static ir_op _op_Phi0;
39
40 /** The PhiM, just to count memorty Phi's. */
41 static ir_op _op_PhiM;
42
43 /** The Mul by Const node. */
44 static ir_op _op_MulC;
45
46 /** The Div by Const node. */
47 static ir_op _op_DivC;
48
49 /** The Div by Const node. */
50 static ir_op _op_ModC;
51
52 /** The Div by Const node. */
53 static ir_op _op_DivModC;
54
55 /* ---------------------------------------------------------------------------------- */
56
57 #define STAT_ENTER              ++status->recursive
58 #define STAT_LEAVE              --status->recursive
59 #define STAT_ENTER_SINGLE       do { if (status->recursive > 0) return; ++status->recursive; } while (0)
60
61 /**
62  * global status
63  */
64 static stat_info_t _status, *status = &_status;
65
66 /**
67  * compare two elements of the opcode hash
68  */
69 static int opcode_cmp(const void *elt, const void *key)
70 {
71   const node_entry_t *e1 = elt;
72   const node_entry_t *e2 = key;
73
74   return e1->op->code - e2->op->code;
75 }
76
77 /**
78  * compare two elements of the graph hash
79  */
80 static int graph_cmp(const void *elt, const void *key)
81 {
82   const graph_entry_t *e1 = elt;
83   const graph_entry_t *e2 = key;
84
85   return e1->irg != e2->irg;
86 }
87
88 /**
89  * compare two elements of the optimization hash
90  */
91 static int opt_cmp(const void *elt, const void *key)
92 {
93   const opt_entry_t *e1 = elt;
94   const opt_entry_t *e2 = key;
95
96   return e1->op->code != e2->op->code;
97 }
98
99 /**
100  * compare two elements of the block hash
101  */
102 static int block_cmp(const void *elt, const void *key)
103 {
104   const block_entry_t *e1 = elt;
105   const block_entry_t *e2 = key;
106
107   return e1->block_nr != e2->block_nr;
108 }
109
110 /**
111  * compare two elements of the ir_op hash
112  */
113 static int opcode_cmp_2(const void *elt, const void *key)
114 {
115   const ir_op *e1 = elt;
116   const ir_op *e2 = key;
117
118   return e1->code != e2->code;
119 }
120
121 /**
122  * compare two elements of the address_mark set
123  */
124 static int address_mark_cmp(const void *elt, const void *key, size_t size)
125 {
126   const address_mark_entry_t *e1 = elt;
127   const address_mark_entry_t *e2 = key;
128
129   /* compare only the nodes, the rest is used as data container */
130   return e1->node != e2->node;
131 }
132
133 /**
134  * clears all counter in a node_entry_t
135  */
136 static void opcode_clear_entry(node_entry_t *elem)
137 {
138   cnt_clr(&elem->cnt_alive);
139   cnt_clr(&elem->new_node);
140   cnt_clr(&elem->into_Id);
141 }
142
143 /**
144  * Returns the associates node_entry_t for an ir_op
145  */
146 static node_entry_t *opcode_get_entry(const ir_op *op, pset *set)
147 {
148   node_entry_t key;
149   node_entry_t *elem;
150
151   key.op = op;
152
153   elem = pset_find(set, &key, op->code);
154   if (elem)
155     return elem;
156
157   elem = obstack_alloc(&status->cnts, sizeof(*elem));
158
159   /* clear counter */
160   opcode_clear_entry(elem);
161
162   elem->op = op;
163
164   return pset_insert(set, elem, op->code);
165 }
166
167 /**
168  * Returns the associates ir_op for an opcode
169  */
170 static ir_op *opcode_find_entry(opcode code, pset *set)
171 {
172   ir_op key;
173
174   key.code = code;
175   return pset_find(set, &key, code);
176 }
177
178 /**
179  * clears all counter in a graph_entry_t
180  */
181 static void graph_clear_entry(graph_entry_t *elem, int all)
182 {
183   if (all) {
184     cnt_clr(&elem->cnt_walked);
185     cnt_clr(&elem->cnt_walked_blocks);
186     cnt_clr(&elem->cnt_was_inlined);
187     cnt_clr(&elem->cnt_got_inlined);
188     cnt_clr(&elem->cnt_strength_red);
189   }
190   cnt_clr(&elem->cnt_edges);
191   cnt_clr(&elem->cnt_all_calls);
192   cnt_clr(&elem->cnt_indirect_calls);
193 }
194
195 /**
196  * Returns the acssociates graph_entry_t for an irg
197  */
198 static graph_entry_t *graph_get_entry(ir_graph *irg, pset *set)
199 {
200   graph_entry_t key;
201   graph_entry_t *elem;
202   int i;
203
204   key.irg = irg;
205
206   elem = pset_find(set, &key, HASH_PTR(irg));
207   if (elem)
208     return elem;
209
210   /* allocate a new one */
211   elem = obstack_alloc(&status->cnts, sizeof(*elem));
212
213   /* clear counter */
214   graph_clear_entry(elem, 1);
215
216   /* new hash table for opcodes here  */
217   elem->opcode_hash  = new_pset(opcode_cmp, 5);
218   elem->block_hash   = new_pset(block_cmp, 5);
219   elem->address_mark = new_set(address_mark_cmp, 5);
220   elem->irg          = irg;
221
222   for (i = 0; i < sizeof(elem->opt_hash)/sizeof(elem->opt_hash[0]); ++i)
223     elem->opt_hash[i] = new_pset(opt_cmp, 4);
224
225   return pset_insert(set, elem, HASH_PTR(irg));
226 }
227
228 /**
229  * clears all counter in an opt_entry_t
230  */
231 static void opt_clear_entry(opt_entry_t *elem)
232 {
233   cnt_clr(&elem->count);
234 }
235
236 /**
237  * Returns the associates opt_entry_t for an ir_op
238  */
239 static opt_entry_t *opt_get_entry(const ir_op *op, pset *set)
240 {
241   opt_entry_t key;
242   opt_entry_t *elem;
243
244   key.op = op;
245
246   elem = pset_find(set, &key, op->code);
247   if (elem)
248     return elem;
249
250   elem = obstack_alloc(&status->cnts, sizeof(*elem));
251
252   /* clear new counter */
253   opt_clear_entry(elem);
254
255   elem->op = op;
256
257   return pset_insert(set, elem, op->code);
258 }
259
260 /**
261  * clears all counter in a block_entry_t
262  */
263 static void block_clear_entry(block_entry_t *elem)
264 {
265   cnt_clr(&elem->cnt_nodes);
266   cnt_clr(&elem->cnt_edges);
267   cnt_clr(&elem->cnt_in_edges);
268   cnt_clr(&elem->cnt_out_edges);
269 }
270
271 /**
272  * Returns the associates block_entry_t for an block
273  */
274 static block_entry_t *block_get_entry(long block_nr, pset *set)
275 {
276   block_entry_t key;
277   block_entry_t *elem;
278
279   key.block_nr = block_nr;
280
281   elem = pset_find(set, &key, block_nr);
282   if (elem)
283     return elem;
284
285   elem = obstack_alloc(&status->cnts, sizeof(*elem));
286
287   /* clear new counter */
288   block_clear_entry(elem);
289
290   elem->block_nr = block_nr;
291
292   return pset_insert(set, elem, block_nr);
293 }
294
295
296 /**
297  * Returns the ir_op for an IR-node,
298  * handles special cases and return pseudo op codes
299  */
300 static ir_op *stat_get_irn_op(ir_node *node)
301 {
302   ir_op *op = get_irn_op(node);
303
304   if (op->code == iro_Phi && get_irn_arity(node) == 0) {
305     /* special case, a Phi0 node, count on extra counter */
306     op = status->op_Phi0;
307   }
308   else if (op->code == iro_Phi && get_irn_mode(node) == mode_M) {
309     /* special case, a Memory Phi node, count on extra counter */
310     op = status->op_PhiM;
311   }
312   else if (op->code == iro_Mul &&
313            (get_irn_op(get_Mul_left(node)) == op_Const || get_irn_op(get_Mul_right(node)) == op_Const)) {
314     /* special case, a Multiply by a const, count on extra counter */
315     op = status->op_MulC ? status->op_MulC : op_Mul;
316   }
317   else if (op->code == iro_Div && get_irn_op(get_Div_right(node)) == op_Const) {
318     /* special case, a division by a const, count on extra counter */
319     op = status->op_DivC ? status->op_DivC : op_Div;
320   }
321   else if (op->code == iro_Mod && get_irn_op(get_Mod_right(node)) == op_Const) {
322     /* special case, a module by a const, count on extra counter */
323     op = status->op_ModC ? status->op_ModC : op_Mod;
324   }
325   else if (op->code == iro_DivMod && get_irn_op(get_DivMod_right(node)) == op_Const) {
326     /* special case, a division/modulo by a const, count on extra counter */
327     op = status->op_DivModC ? status->op_DivModC : op_DivMod;
328   }
329
330   return op;
331 }
332
333 /**
334  * update the block counter
335  */
336 static void count_block_info(ir_node *node, graph_entry_t *graph)
337 {
338   ir_op *op = get_irn_op(node);
339   ir_node *block;
340   block_entry_t *b_entry;
341   int i, arity;
342
343   /* check for block */
344   if (op == op_Block) {
345     arity = get_irn_arity(node);
346     b_entry = block_get_entry(get_irn_node_nr(node), graph->block_hash);
347
348     /* count all incoming edges */
349     for (i = 0; i < arity; ++i) {
350       ir_node *pred = get_irn_n(node, i);
351       ir_node *other_block = get_nodes_block(pred);
352       block_entry_t *b_entry_other = block_get_entry(get_irn_node_nr(other_block), graph->block_hash);
353
354       cnt_inc(&b_entry->cnt_in_edges);  /* an edge coming from another block */
355       cnt_inc(&b_entry_other->cnt_out_edges);
356     }
357     return;
358   }
359
360   block   = get_nodes_block(node);
361   b_entry = block_get_entry(get_irn_node_nr(block), graph->block_hash);
362
363   /* we have a new nodes */
364   cnt_inc(&b_entry->cnt_nodes);
365
366   arity = get_irn_arity(node);
367
368   for (i = 0; i < arity; ++i) {
369     ir_node *pred = get_irn_n(node, i);
370     ir_node *other_block;
371
372     if (get_irn_op(pred) == op_Block)
373       continue;
374
375     other_block = get_nodes_block(pred);
376
377     if (other_block == block)
378       cnt_inc(&b_entry->cnt_edges);     /* a in block edge */
379     else {
380       block_entry_t *b_entry_other = block_get_entry(get_irn_node_nr(other_block), graph->block_hash);
381
382       cnt_inc(&b_entry->cnt_in_edges);  /* an edge coming from another block */
383       cnt_inc(&b_entry_other->cnt_out_edges);
384     }
385   }
386 }
387
388 /**
389  * update info on calls
390  */
391 static void update_call_stat(ir_node *call, graph_entry_t *graph)
392 {
393   ir_node *block = get_nodes_block(call);
394   ir_node *ptr = get_Call_ptr(call);
395   entity *ent = NULL;
396
397   /*
398    * If the block is bad, the whole subgraph will colabse later
399    * so do not count this call.
400    * This happens in dead code
401    */
402   if (is_Bad(block))
403     return;
404
405   cnt_inc(&graph->cnt_all_calls);
406
407   /* found a call, is not a leaf function */
408   graph->is_leaf = 0;
409
410   if (get_irn_op(ptr) == op_SymConst) {
411     if (get_SymConst_kind(ptr) == symconst_addr_ent) {
412       /* ok, we seems to know the entity */
413       ent = get_SymConst_entity(ptr);
414
415       if (get_entity_irg(ent) == graph->irg)
416         graph->is_recursive = 1;
417     }
418   }
419   else {
420     /* indirect call */
421     cnt_inc(&graph->cnt_indirect_calls);
422   }
423
424   /* check, if it's a chain-call: Then, the call-block
425    * must dominate the end block. */
426   {
427     ir_node *curr = get_irg_end_block(graph->irg);
428     int depth = get_Block_dom_depth(block);
429
430     for (; curr != block && get_Block_dom_depth(curr) > depth;) {
431       curr = get_Block_idom(curr);
432
433       if (! curr || is_no_Block(curr))
434         break;
435     }
436
437     if (curr != block)
438       graph->is_chain_call = 0;
439   }
440 }
441
442 /**
443  * walker for reachable nodes count
444  */
445 static void update_node_stat(ir_node *node, void *env)
446 {
447   graph_entry_t *graph = env;
448   node_entry_t *entry;
449
450   ir_op *op = stat_get_irn_op(node);
451   int arity = get_irn_arity(node);
452
453   entry = opcode_get_entry(op, graph->opcode_hash);
454
455   cnt_inc(&entry->cnt_alive);
456   cnt_add_i(&graph->cnt_edges, arity);
457
458   /* count block edges */
459   count_block_info(node, graph);
460
461   /* check for properties that depends on calls like recursion/leaf/indirect call */
462   if (get_irn_op(node) == op_Call)
463     update_call_stat(node, graph);
464 }
465
466 /**
467  * get the current address mark
468  */
469 static unsigned get_adr_mark(graph_entry_t *graph, ir_node *node)
470 {
471   address_mark_entry_t *value = set_find(graph->address_mark, &node, sizeof(*value), HASH_PTR(node));
472
473   return value ? value->mark : 0;
474 }
475
476 /**
477  * set the current address mark
478  */
479 static void set_adr_mark(graph_entry_t *graph, ir_node *node, unsigned val)
480 {
481   address_mark_entry_t *value = set_insert(graph->address_mark, &node, sizeof(*value), HASH_PTR(node));
482
483   value->mark = val;
484 }
485
486 /**
487  * a vcg attribute hook
488  */
489 static int stat_adr_mark_hook(FILE *F, ir_node *n)
490 {
491   ir_graph *irg        = get_irn_irg(n);
492   graph_entry_t *graph = graph_get_entry(irg, status->irg_hash);
493   unsigned mark        = get_adr_mark(graph, n);
494
495   if (mark & MARK_ADDRESS_CALC)
496     fprintf(F, "color: purple");
497   else if ((mark & (MARK_REF_ADR | MARK_REF_NON_ADR)) == MARK_REF_ADR)
498     fprintf(F, "color: lightblue");
499   else
500     return 0;
501
502   /* I know the color! */
503   return 1;
504 }
505
506 /**
507  * walker that marks every node that is an address calculation
508  *
509  * predecessor nodes must be visited first. We ensure this by
510  * calling in in the post of an outs walk. This should work even in cycles,
511  * while the pre in a normal walk will not.
512  */
513 static void mark_address_calc(ir_node *node, void *env)
514 {
515   graph_entry_t *graph = env;
516   ir_mode *mode = get_irn_mode(node);
517   int i, n;
518   unsigned mark_preds = MARK_REF_NON_ADR;
519
520   if (! mode_is_numP(mode))
521     return;
522
523   if (mode_is_reference(mode)) {
524     /* a reference is calculated here, we are sure */
525     set_adr_mark(graph, node, MARK_ADDRESS_CALC);
526
527     mark_preds = MARK_REF_ADR;
528   }
529   else {
530     unsigned mark = get_adr_mark(graph, node);
531
532     if ((mark & (MARK_REF_ADR | MARK_REF_NON_ADR)) == MARK_REF_ADR) {
533       /*
534        * this node has not an reference mode, but is only
535        * referenced by address calculations
536        */
537       mark_preds = MARK_REF_ADR;
538     }
539   }
540
541   /* makr all predecessors */
542   for (i = 0, n = get_irn_arity(node); i < n; ++i) {
543     ir_node *pred = get_irn_n(node, i);
544
545     set_adr_mark(graph, pred, get_adr_mark(graph, pred) | mark_preds);
546   }
547 }
548
549 /**
550  * called for every graph when the graph is either deleted or stat_finish()
551  * is called, must recalculate all statistic info
552  */
553 static void update_graph_stat(graph_entry_t *global, graph_entry_t *graph)
554 {
555   node_entry_t *entry;
556
557   /* clear first the alive counter in the graph */
558   for (entry = pset_first(graph->opcode_hash); entry; entry = pset_next(graph->opcode_hash)) {
559     cnt_clr(&entry->cnt_alive);
560   }
561
562   /* set pessimistic values */
563   graph->is_leaf       = 1;
564   graph->is_recursive  = 0;
565   graph->is_chain_call = 1;
566
567   /* we need dominator info */
568   if (graph->irg != get_const_code_irg())
569     if (get_irg_dom_state(graph->irg) != dom_consistent)
570       compute_doms(graph->irg);
571
572   /* count the nodes in the graph */
573   irg_walk_graph(graph->irg, update_node_stat, NULL, graph);
574
575 #if 0
576   entry = opcode_get_entry(op_Call, graph->opcode_hash);
577
578   /* check if we have more than 1 call */
579   if (cnt_gt(entry->cnt_alive, 1))
580     graph->is_chain_call = 0;
581 #endif
582
583   /* recursive functions are never chain calls, leafs don't have calls */
584   if (graph->is_recursive || graph->is_leaf)
585     graph->is_chain_call = 0;
586
587   /* assume we walk every graph only ONCE, we could sum here the global count */
588   for (entry = pset_first(graph->opcode_hash); entry; entry = pset_next(graph->opcode_hash)) {
589     node_entry_t *g_entry = opcode_get_entry(entry->op, global->opcode_hash);
590
591     /* update the node counter */
592     cnt_add(&g_entry->cnt_alive, &entry->cnt_alive);
593   }
594
595   /* update the edge counter */
596   cnt_add(&global->cnt_edges, &graph->cnt_edges);
597
598   /* count the number of address calculation */
599   if (graph->irg != get_const_code_irg()) {
600     ir_graph *rem = current_ir_graph;
601
602     if (get_irg_outs_state(graph->irg) != outs_consistent)
603       compute_outs(graph->irg);
604
605     /* Must be done an the outs graph */
606     current_ir_graph = graph->irg;
607     irg_out_walk(get_irg_start(graph->irg), NULL, mark_address_calc, graph);
608     current_ir_graph = rem;
609
610     set_dump_node_vcgattr_hook(stat_adr_mark_hook);
611     dump_ir_block_graph(graph->irg, "-adr");
612     set_dump_node_vcgattr_hook(NULL);
613   }
614 }
615
616 /**
617  * register a dumper
618  */
619 static void stat_register_dumper(const dumper_t *dumper)
620 {
621   dumper_t *p = malloc(sizeof(*p));
622
623   if (p) {
624     *p = *dumper;
625
626     p->next        = status->dumper;
627     p->status      = status;
628     status->dumper = p;
629   }
630
631   /* FIXME: memory leak */
632 }
633
634 /**
635  * dumps an irg
636  */
637 static void dump_graph(graph_entry_t *entry)
638 {
639   dumper_t *dumper;
640
641   for (dumper = status->dumper; dumper; dumper = dumper->next) {
642     if (dumper->dump_graph)
643       dumper->dump_graph(dumper, entry);
644   }
645 }
646
647 /**
648  * initialise the dumper
649  */
650 static void dump_init(const char *name)
651 {
652   dumper_t *dumper;
653
654   for (dumper = status->dumper; dumper; dumper = dumper->next) {
655     if (dumper->init)
656       dumper->init(dumper, name);
657   }
658 }
659
660 /**
661  * finish the dumper
662  */
663 static void dump_finish(void)
664 {
665   dumper_t *dumper;
666
667   for (dumper = status->dumper; dumper; dumper = dumper->next) {
668     if (dumper->finish)
669       dumper->finish(dumper);
670   }
671 }
672
673 /* ---------------------------------------------------------------------- */
674
675 /*
676  * helper: get an ir_op from an opcode
677  */
678 ir_op *stat_get_op_from_opcode(opcode code)
679 {
680   return opcode_find_entry(code, status->ir_op_hash);
681 }
682
683 /* initialize the statistics module. */
684 void init_stat(unsigned enable_options)
685 {
686 #define X(a)  a, sizeof(a)-1
687
688   /* enable statistics */
689   status->enable = enable_options & FIRMSTAT_ENABLED;
690
691   if (! status->enable)
692    return;
693
694   obstack_init(&status->cnts);
695
696   /* create the hash-tables */
697   status->irg_hash   = new_pset(graph_cmp, 8);
698   status->ir_op_hash = new_pset(opcode_cmp_2, 1);
699
700   status->op_Phi0    = &_op_Phi0;
701   status->op_PhiM    = &_op_PhiM;
702
703   if (enable_options & FIRMSTAT_COUNT_STRONG_OP) {
704     /* build the pseudo-ops */
705     _op_Phi0.code    = get_next_ir_opcode();
706     _op_Phi0.name    = new_id_from_chars(X("Phi0"));
707
708     _op_PhiM.code    = get_next_ir_opcode();
709     _op_PhiM.name    = new_id_from_chars(X("PhiM"));
710
711     _op_MulC.code    = get_next_ir_opcode();
712     _op_MulC.name    = new_id_from_chars(X("MulC"));
713
714     _op_DivC.code    = get_next_ir_opcode();
715     _op_DivC.name    = new_id_from_chars(X("DivC"));
716
717     _op_ModC.code    = get_next_ir_opcode();
718     _op_ModC.name    = new_id_from_chars(X("ModC"));
719
720     _op_DivModC.code = get_next_ir_opcode();
721     _op_DivModC.name = new_id_from_chars(X("DivModC"));
722
723     status->op_MulC    = &_op_MulC;
724     status->op_DivC    = &_op_DivC;
725     status->op_ModC    = &_op_ModC;
726     status->op_DivModC = &_op_DivModC;
727   }
728   else {
729     status->op_MulC    = NULL;
730     status->op_DivC    = NULL;
731     status->op_ModC    = NULL;
732     status->op_DivModC = NULL;
733   }
734
735   /* register the dumper */
736   stat_register_dumper(&simple_dumper);
737
738   if (enable_options & FIRMSTAT_CSV_OUTPUT)
739     stat_register_dumper(&csv_dumper);
740
741   /* initialize the pattern hash */
742   stat_init_pattern_history(enable_options & FIRMSTAT_PATTERN_ENABLED);
743 #undef X
744 }
745
746 /* A new IR op is registered. */
747 void stat_new_ir_op(const ir_op *op)
748 {
749   if (! status->enable)
750     return;
751
752   STAT_ENTER;
753   {
754     graph_entry_t *graph = graph_get_entry(NULL, status->irg_hash);
755
756     /* execute for side effect :-) */
757     opcode_get_entry(op, graph->opcode_hash);
758
759     pset_insert(status->ir_op_hash, op, op->code);
760   }
761   STAT_LEAVE;
762 }
763
764 /* An IR op is freed. */
765 void stat_free_ir_op(const ir_op *op)
766 {
767   if (! status->enable)
768     return;
769
770   STAT_ENTER;
771   {
772   }
773   STAT_LEAVE;
774 }
775
776 /* A new node is created. */
777 void stat_new_node(ir_node *node)
778 {
779   if (! status->enable)
780     return;
781
782   /* do NOT count during dead node elimination */
783   if (status->in_dead_node_elim > 0)
784     return;
785
786   STAT_ENTER;
787   {
788     node_entry_t *entry;
789     graph_entry_t *graph;
790     ir_op *op = stat_get_irn_op(node);
791
792     /* increase global value */
793     graph = graph_get_entry(NULL, status->irg_hash);
794     entry = opcode_get_entry(op, graph->opcode_hash);
795     cnt_inc(&entry->new_node);
796
797     /* increase local value */
798     graph = graph_get_entry(current_ir_graph, status->irg_hash);
799     entry = opcode_get_entry(op, graph->opcode_hash);
800     cnt_inc(&entry->new_node);
801   }
802   STAT_LEAVE;
803 }
804
805 /* A node is changed into a Id node */
806 void stat_turn_into_id(ir_node *node)
807 {
808   if (! status->enable)
809     return;
810
811   STAT_ENTER;
812   {
813     node_entry_t *entry;
814     graph_entry_t *graph;
815     ir_op *op = stat_get_irn_op(node);
816
817     /* increase global value */
818     graph = graph_get_entry(NULL, status->irg_hash);
819     entry = opcode_get_entry(op, graph->opcode_hash);
820     cnt_inc(&entry->into_Id);
821
822     /* increase local value */
823     graph = graph_get_entry(current_ir_graph, status->irg_hash);
824     entry = opcode_get_entry(op, graph->opcode_hash);
825     cnt_inc(&entry->into_Id);
826   }
827   STAT_LEAVE;
828 }
829
830 /* A new graph was created */
831 void stat_new_graph(ir_graph *irg, entity *ent)
832 {
833   if (! status->enable)
834     return;
835
836   STAT_ENTER;
837   {
838     /* execute for side effect :-) */
839     graph_entry_t * graph = graph_get_entry(irg, status->irg_hash);
840
841     graph->ent           = ent;
842     graph->is_deleted    = 0;
843     graph->is_leaf       = 0;
844     graph->is_recursive  = 0;
845     graph->is_chain_call = 0;
846   }
847   STAT_LEAVE;
848 }
849
850 /*
851  * A graph will be deleted
852  */
853 void stat_free_graph(ir_graph *irg)
854 {
855   if (! status->enable)
856     return;
857
858   STAT_ENTER;
859   {
860     graph_entry_t *graph  = graph_get_entry(irg, status->irg_hash);
861     graph_entry_t *global = graph_get_entry(NULL, status->irg_hash);
862
863     graph->is_deleted = 1;
864
865     /* count the nodes of the graph yet, it will be destroyed later */
866     update_graph_stat(global, graph);
867
868     /* count the DAG's */
869 //    count_dags_in_graph(global, graph);
870
871     /* calculate the pattern */
872     stat_calc_pattern_history(irg);
873   }
874   STAT_LEAVE;
875 }
876
877 /*
878  * A walk over a graph is initiated. Do not count walks from statistic code.
879  */
880 void stat_irg_walk(ir_graph *irg, void *pre, void *post)
881 {
882   if (! status->enable)
883     return;
884
885   STAT_ENTER_SINGLE;
886   {
887     graph_entry_t *graph = graph_get_entry(irg, status->irg_hash);
888
889     cnt_inc(&graph->cnt_walked);
890   }
891   STAT_LEAVE;
892 }
893
894 /*
895  * A walk over a graph in block-wise order is initiated. Do not count walks from statistic code.
896  */
897 void stat_irg_walk_blkwise(ir_graph *irg, void *pre, void *post)
898 {
899   /* for now, do NOT differentiate between blockwise and normal */
900   stat_irg_walk(irg, pre, post);
901 }
902
903 /*
904  * A walk over the graph's blocks is initiated. Do not count walks from statistic code.
905  */
906 void stat_irg_block_walk(ir_graph *irg, const ir_node *node, void *pre, void *post)
907 {
908   if (! status->enable)
909     return;
910
911   STAT_ENTER_SINGLE;
912   {
913     graph_entry_t *graph = graph_get_entry(irg, status->irg_hash);
914
915     cnt_inc(&graph->cnt_walked_blocks);
916   }
917   STAT_LEAVE;
918 }
919
920 /**
921  * called for every node that is removed due to an optimization
922  */
923 static void removed_due_opt(ir_node *n, pset *set)
924 {
925   ir_op *op          = stat_get_irn_op(n);
926   opt_entry_t *entry = opt_get_entry(op, set);
927
928   /* increase global value */
929   cnt_inc(&entry->count);
930 }
931
932 /*
933  * Some nodes were optimized into some others due to an optimization
934  */
935 void stat_merge_nodes(
936     ir_node **new_node_array, int new_num_entries,
937     ir_node **old_node_array, int old_num_entries,
938     stat_opt_kind opt)
939 {
940   if (! status->enable)
941     return;
942
943   STAT_ENTER;
944   {
945     int i, j;
946     graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash);
947
948     if (status->reassoc_run)
949       opt = STAT_OPT_REASSOC;
950
951     for (i = 0; i < old_num_entries; ++i) {
952       for (j = 0; j < new_num_entries; ++j)
953         if (old_node_array[i] == new_node_array[j])
954           break;
955
956       /* nodes might be in new and old, these are NOT removed */
957       if (j >= new_num_entries) {
958         removed_due_opt(old_node_array[i], graph->opt_hash[opt]);
959       }
960     }
961   }
962   STAT_LEAVE;
963 }
964
965 /*
966  * reassociation started/stopped.
967  */
968 void stat_reassociate(int flag)
969 {
970   if (! status->enable)
971     return;
972
973   STAT_ENTER;
974   {
975     status->reassoc_run = flag;
976   }
977   STAT_LEAVE;
978 }
979
980 /*
981  * A node was lowered into other nodes
982  */
983 void stat_lower(ir_node *node)
984 {
985   if (! status->enable)
986     return;
987
988   STAT_ENTER;
989   {
990     graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash);
991
992     removed_due_opt(node, graph->opt_hash[STAT_LOWERED]);
993   }
994   STAT_LEAVE;
995 }
996
997 /*
998  * A graph was inlined
999  */
1000 void stat_inline(ir_node *call, ir_graph *called_irg)
1001 {
1002   if (! status->enable)
1003     return;
1004
1005   STAT_ENTER;
1006   {
1007     ir_graph *irg = get_irn_irg(call);
1008     graph_entry_t *i_graph = graph_get_entry(called_irg, status->irg_hash);
1009     graph_entry_t *graph   = graph_get_entry(irg, status->irg_hash);
1010
1011     cnt_inc(&graph->cnt_got_inlined);
1012     cnt_inc(&i_graph->cnt_was_inlined);
1013   }
1014   STAT_LEAVE;
1015 }
1016
1017 /*
1018  * A graph with tail-recursions was optimized.
1019  */
1020 void stat_tail_rec(ir_graph *irg)
1021 {
1022   if (! status->enable)
1023     return;
1024
1025   STAT_ENTER;
1026   {
1027   }
1028   STAT_LEAVE;
1029 }
1030
1031 /*
1032  * Strength reduction was performed on an iteration variable.
1033  */
1034 void stat_strength_red(ir_graph *irg, ir_node *strong, ir_node *cmp)
1035 {
1036   if (! status->enable)
1037     return;
1038
1039   STAT_ENTER;
1040   {
1041     graph_entry_t *graph = graph_get_entry(irg, status->irg_hash);
1042     cnt_inc(&graph->cnt_strength_red);
1043
1044     removed_due_opt(strong, graph->opt_hash[STAT_OPT_STRENGTH_RED]);
1045   }
1046   STAT_LEAVE;
1047 }
1048
1049 /*
1050  * Start the dead node elimination.
1051  */
1052 void stat_dead_node_elim_start(ir_graph *irg)
1053 {
1054   if (! status->enable)
1055     return;
1056
1057   ++status->in_dead_node_elim;
1058 }
1059
1060 /*
1061  * Stops the dead node elimination.
1062  */
1063 void stat_dead_node_elim_stop(ir_graph *irg)
1064 {
1065   if (! status->enable)
1066     return;
1067
1068   --status->in_dead_node_elim;
1069 }
1070
1071 /*
1072  * A multiply was replaced by a series of Shifts/Adds/Subs
1073  */
1074 void stat_arch_dep_replace_mul_with_shifts(ir_node *mul)
1075 {
1076   if (! status->enable)
1077     return;
1078
1079   STAT_ENTER;
1080   {
1081     graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash);
1082     removed_due_opt(mul, graph->opt_hash[STAT_OPT_ARCH_DEP]);
1083   }
1084   STAT_LEAVE;
1085 }
1086
1087 /**
1088  * A division was replaced by a series of Shifts/Muls
1089  */
1090 void stat_arch_dep_replace_div_by_const(ir_node *div)
1091 {
1092   if (! status->enable)
1093     return;
1094
1095   STAT_ENTER;
1096   {
1097     graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash);
1098     removed_due_opt(div, graph->opt_hash[STAT_OPT_ARCH_DEP]);
1099   }
1100   STAT_LEAVE;
1101 }
1102
1103 /**
1104  * A modulo was replaced by a series of Shifts/Muls
1105  */
1106 void stat_arch_dep_replace_mod_by_const(ir_node *mod)
1107 {
1108   if (! status->enable)
1109     return;
1110
1111   STAT_ENTER;
1112   {
1113     graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash);
1114     removed_due_opt(mod, graph->opt_hash[STAT_OPT_ARCH_DEP]);
1115   }
1116   STAT_LEAVE;
1117 }
1118
1119 /**
1120  * A DivMod was replaced by a series of Shifts/Muls
1121  */
1122 void stat_arch_dep_replace_DivMod_by_const(ir_node *divmod)
1123 {
1124   if (! status->enable)
1125     return;
1126
1127   STAT_ENTER;
1128   {
1129     graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash);
1130     removed_due_opt(divmod, graph->opt_hash[STAT_OPT_ARCH_DEP]);
1131   }
1132   STAT_LEAVE;
1133 }
1134
1135 /* Finish the statistics */
1136 void stat_finish(const char *name)
1137 {
1138   if (! status->enable)
1139     return;
1140
1141   STAT_ENTER;
1142   {
1143     graph_entry_t *entry;
1144     graph_entry_t *global = graph_get_entry(NULL, status->irg_hash);
1145
1146     dump_init(name);
1147
1148     /* dump per graph */
1149     for (entry = pset_first(status->irg_hash); entry; entry = pset_next(status->irg_hash)) {
1150
1151       if (entry->irg == NULL) {
1152         /* special entry for the global count */
1153         continue;
1154       }
1155
1156       if (! entry->is_deleted) {
1157         /* the graph is still alive, count the nodes on it */
1158         update_graph_stat(global, entry);
1159
1160         /* count the DAG's */
1161 //        count_dags_in_graph(global, entry);
1162
1163         /* calculate the pattern */
1164         stat_calc_pattern_history(entry->irg);
1165       }
1166
1167       dump_graph(entry);
1168
1169       /* clear the counter that are not accumulated */
1170       graph_clear_entry(entry, 0);
1171     }
1172
1173     /* dump global */
1174     dump_graph(global);
1175     dump_finish();
1176
1177     stat_finish_pattern_history();
1178
1179     /* clear the global counter here */
1180     {
1181       node_entry_t *entry;
1182
1183       for (entry = pset_first(global->opcode_hash); entry; entry = pset_next(global->opcode_hash)) {
1184         opcode_clear_entry(entry);
1185       }
1186       /* clear all global counter */
1187       graph_clear_entry(global, 1);
1188     }
1189
1190     /* finished */
1191 //    status->enable = 0;
1192   }
1193   STAT_LEAVE;
1194 }
1195
1196 #else
1197
1198 /* need this for prototypes */
1199 #define FIRM_STATISTICS
1200 #include "firmstat.h"
1201
1202 void init_stat(unsigned enable_options) {}
1203
1204 void stat_finish(const char *name) {}
1205
1206 void stat_new_ir_op(const ir_op *op) {}
1207
1208 void stat_free_ir_op(const ir_op *op) {}
1209
1210 void stat_new_node(ir_node *node) {}
1211
1212 void stat_turn_into_id(ir_node *node) {}
1213
1214 void stat_new_graph(ir_graph *irg, entity *ent) {}
1215
1216 void stat_free_graph(ir_graph *irg) {}
1217
1218 void stat_irg_walk(ir_graph *irg, void *pre, void *post) {}
1219
1220 void stat_irg_block_walk(ir_graph *irg, const ir_node *node, void *pre, void *post) {}
1221
1222 void stat_merge_nodes(
1223     ir_node **new_node_array, int new_num_entries,
1224     ir_node **old_node_array, int old_num_entries,
1225     stat_opt_kind opt) {}
1226
1227 void stat_reassociate(int start) {}
1228
1229 void stat_lower(ir_node *node) {}
1230
1231 void stat_inline(ir_node *call, ir_graph *irg) {}
1232
1233 void stat_tail_rec(ir_graph *irg) {}
1234
1235 void stat_strength_red(ir_graph *irg, ir_node *strong, ir_node *cmp) {}
1236
1237 void stat_dead_node_elim_start(ir_graph *irg) {}
1238
1239 void stat_dead_node_elim_stop(ir_graph *irg) {}
1240
1241 void stat_arch_dep_replace_mul_with_shifts(ir_node *mul) {}
1242
1243 void stat_arch_dep_replace_div_by_const(ir_node *div) {}
1244
1245 void stat_arch_dep_replace_mod_by_const(ir_node *mod) {}
1246
1247 void stat_arch_dep_replace_DivMod_by_const(ir_node *divmod) {}
1248
1249 #endif