fixes for gcc 4.0: void * and pointer to function are not compatible anymore
[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
20 #ifdef HAVE_STDLIB_H
21 # include <stdlib.h>
22 #endif
23 #ifdef HAVE_STRING_H
24 # include <string.h>
25 #endif
26
27 #include "irouts.h"
28 #include "irdump.h"
29 #include "hashptr.h"
30 #include "firmstat_t.h"
31 #include "pattern.h"
32 #include "dags.h"
33 #include "stat_dmp.h"
34 #include "xmalloc.h"
35 #include "irhooks.h"
36
37 /*
38  * need this to be static:
39  * Special pseudo Opcodes that we need to count some interesting cases
40  */
41
42 /**
43  * The Phi0, a node that is created during SSA construction
44  */
45 static ir_op _op_Phi0;
46
47 /** The PhiM, just to count memory Phi's. */
48 static ir_op _op_PhiM;
49
50 /** The Mul by Const node. */
51 static ir_op _op_MulC;
52
53 /** The Div by Const node. */
54 static ir_op _op_DivC;
55
56 /** The Div by Const node. */
57 static ir_op _op_ModC;
58
59 /** The Div by Const node. */
60 static ir_op _op_DivModC;
61
62 /** The memory Proj node. */
63 static ir_op _op_ProjM;
64
65 /** A Sel of a Sel */
66 static ir_op _op_SelSel;
67
68 /** A Sel of a Sel of a Sel */
69 static ir_op _op_SelSelSel;
70
71 /* ---------------------------------------------------------------------------------- */
72
73 /** Marks the begin of a statistic (hook) function. */
74 #define STAT_ENTER              ++status->recursive
75
76 /** Marks the end of a statistic (hook) functions. */
77 #define STAT_LEAVE              --status->recursive
78
79 /** Allows to enter a statistic function only when we are not already in a hook. */
80 #define STAT_ENTER_SINGLE       do { if (status->recursive > 0) return; ++status->recursive; } while (0)
81
82 /**
83  * global status
84  */
85 static const int status_disable = 0;
86 static stat_info_t *status = (stat_info_t *)&status_disable;
87
88 /**
89  * compare two elements of the opcode hash
90  */
91 static int opcode_cmp(const void *elt, const void *key)
92 {
93   const node_entry_t *e1 = elt;
94   const node_entry_t *e2 = key;
95
96   return e1->op->code - e2->op->code;
97 }
98
99 /**
100  * compare two elements of the graph hash
101  */
102 static int graph_cmp(const void *elt, const void *key)
103 {
104   const graph_entry_t *e1 = elt;
105   const graph_entry_t *e2 = key;
106
107   return e1->irg != e2->irg;
108 }
109
110 /**
111  * compare two elements of the optimization hash
112  */
113 static int opt_cmp(const void *elt, const void *key)
114 {
115   const opt_entry_t *e1 = elt;
116   const opt_entry_t *e2 = key;
117
118   return e1->op->code != e2->op->code;
119 }
120
121 /**
122  * compare two elements of the block hash
123  */
124 static int block_cmp(const void *elt, const void *key)
125 {
126   const block_entry_t *e1 = elt;
127   const block_entry_t *e2 = key;
128
129   return e1->block_nr != e2->block_nr;
130 }
131
132 /**
133  * compare two elements of the ir_op hash
134  */
135 static int opcode_cmp_2(const void *elt, const void *key)
136 {
137   const ir_op *e1 = elt;
138   const ir_op *e2 = key;
139
140   return e1->code != e2->code;
141 }
142
143 /**
144  * compare two elements of the address_mark set
145  */
146 static int address_mark_cmp(const void *elt, const void *key, size_t size)
147 {
148   const address_mark_entry_t *e1 = elt;
149   const address_mark_entry_t *e2 = key;
150
151   /* compare only the nodes, the rest is used as data container */
152   return e1->node != e2->node;
153 }
154
155 /**
156  * clears all counter in a node_entry_t
157  */
158 static void opcode_clear_entry(node_entry_t *elem)
159 {
160   cnt_clr(&elem->cnt_alive);
161   cnt_clr(&elem->new_node);
162   cnt_clr(&elem->into_Id);
163 }
164
165 /**
166  * Returns the associates node_entry_t for an ir_op
167  *
168  * @param op    the IR operation
169  * @param hmap  a hash map containing ir_op* -> node_entry_t*
170  */
171 static node_entry_t *opcode_get_entry(const ir_op *op, hmap_node_entry_t *hmap)
172 {
173   node_entry_t key;
174   node_entry_t *elem;
175
176   key.op = op;
177
178   elem = pset_find(hmap, &key, op->code);
179   if (elem)
180     return elem;
181
182   elem = obstack_alloc(&status->cnts, sizeof(*elem));
183   memset(elem, 0, sizeof(*elem));
184
185   /* clear counter */
186   opcode_clear_entry(elem);
187
188   elem->op = op;
189
190   return pset_insert(hmap, elem, op->code);
191 }
192
193 /**
194  * Returns the associates ir_op for an opcode
195  *
196  * @param code  the IR opcode
197  * @param hmap  the hash map containing opcode -> ir_op*
198  */
199 static ir_op *opcode_find_entry(opcode code, hmap_ir_op *hmap)
200 {
201   ir_op key;
202
203   key.code = code;
204   return pset_find(hmap, &key, code);
205 }
206
207 /**
208  * clears all counter in a graph_entry_t
209  */
210 static void graph_clear_entry(graph_entry_t *elem, int all)
211 {
212   if (all) {
213     cnt_clr(&elem->cnt_walked);
214     cnt_clr(&elem->cnt_walked_blocks);
215     cnt_clr(&elem->cnt_was_inlined);
216     cnt_clr(&elem->cnt_got_inlined);
217     cnt_clr(&elem->cnt_strength_red);
218     cnt_clr(&elem->cnt_real_func_call);
219   }
220   cnt_clr(&elem->cnt_edges);
221   cnt_clr(&elem->cnt_all_calls);
222   cnt_clr(&elem->cnt_call_with_cnst_arg);
223   cnt_clr(&elem->cnt_indirect_calls);
224 }
225
226 /**
227  * Returns the associated graph_entry_t for an IR graph.
228  *
229  * @param irg   the IR graph
230  * @param hmap  the hash map containing ir_graph* -> graph_entry_t*
231  */
232 static graph_entry_t *graph_get_entry(ir_graph *irg, hmap_graph_entry_t *hmap)
233 {
234   graph_entry_t key;
235   graph_entry_t *elem;
236   int i;
237
238   key.irg = irg;
239
240   elem = pset_find(hmap, &key, HASH_PTR(irg));
241   if (elem)
242     return elem;
243
244   /* allocate a new one */
245   elem = obstack_alloc(&status->cnts, sizeof(*elem));
246   memset(elem, 0, sizeof(*elem));
247
248   /* clear counter */
249   graph_clear_entry(elem, 1);
250
251   /* new hash table for opcodes here  */
252   elem->opcode_hash  = new_pset(opcode_cmp, 5);
253   elem->block_hash   = new_pset(block_cmp, 5);
254   elem->address_mark = new_set(address_mark_cmp, 5);
255   elem->irg          = irg;
256
257   for (i = 0; i < sizeof(elem->opt_hash)/sizeof(elem->opt_hash[0]); ++i)
258     elem->opt_hash[i] = new_pset(opt_cmp, 4);
259
260   return pset_insert(hmap, elem, HASH_PTR(irg));
261 }
262
263 /**
264  * clears all counter in an opt_entry_t
265  */
266 static void opt_clear_entry(opt_entry_t *elem)
267 {
268   cnt_clr(&elem->count);
269 }
270
271 /**
272  * Returns the associated opt_entry_t for an IR operation.
273  *
274  * @param op    the IR operation
275  * @param hmap  the hash map containing ir_op* -> opt_entry_t*
276  */
277 static opt_entry_t *opt_get_entry(const ir_op *op, hmap_opt_entry_t *hmap)
278 {
279   opt_entry_t key;
280   opt_entry_t *elem;
281
282   key.op = op;
283
284   elem = pset_find(hmap, &key, op->code);
285   if (elem)
286     return elem;
287
288   elem = obstack_alloc(&status->cnts, sizeof(*elem));
289   memset(elem, 0, sizeof(*elem));
290
291   /* clear new counter */
292   opt_clear_entry(elem);
293
294   elem->op = op;
295
296   return pset_insert(hmap, elem, op->code);
297 }
298
299 /**
300  * clears all counter in a block_entry_t
301  */
302 static void block_clear_entry(block_entry_t *elem)
303 {
304   cnt_clr(&elem->cnt_nodes);
305   cnt_clr(&elem->cnt_edges);
306   cnt_clr(&elem->cnt_in_edges);
307   cnt_clr(&elem->cnt_out_edges);
308   cnt_clr(&elem->cnt_phi_data);
309 }
310
311 /**
312  * Returns the associated block_entry_t for an block.
313  *
314  * @param block_nr  an IR  block number
315  * @param hmap      a hash map containing long -> block_entry_t
316  */
317 static block_entry_t *block_get_entry(long block_nr, hmap_block_entry_t *hmap)
318 {
319   block_entry_t key;
320   block_entry_t *elem;
321
322   key.block_nr = block_nr;
323
324   elem = pset_find(hmap, &key, block_nr);
325   if (elem)
326     return elem;
327
328   elem = obstack_alloc(&status->cnts, sizeof(*elem));
329   memset(elem, 0, sizeof(*elem));
330
331   /* clear new counter */
332   block_clear_entry(elem);
333
334   elem->block_nr = block_nr;
335
336   return pset_insert(hmap, elem, block_nr);
337 }
338
339
340 /**
341  * Returns the ir_op for an IR-node,
342  * handles special cases and return pseudo op codes.
343  *
344  * @param none  an IR node
345  */
346 static ir_op *stat_get_irn_op(ir_node *node)
347 {
348   ir_op *op = get_irn_op(node);
349
350   if (op == op_Phi && get_irn_arity(node) == 0) {
351     /* special case, a Phi0 node, count on extra counter */
352     op = status->op_Phi0 ? status->op_Phi0 : op;
353   }
354   else if (op == op_Phi && get_irn_mode(node) == mode_M) {
355     /* special case, a Memory Phi node, count on extra counter */
356     op = status->op_PhiM ? status->op_PhiM : op;
357   }
358   else if (op == op_Proj && get_irn_mode(node) == mode_M) {
359     /* special case, a Memory Proj node, count on extra counter */
360     op = status->op_ProjM ? status->op_ProjM : op;
361   }
362   else if (op == op_Mul &&
363            (get_irn_op(get_Mul_left(node)) == op_Const || get_irn_op(get_Mul_right(node)) == op_Const)) {
364     /* special case, a Multiply by a const, count on extra counter */
365     op = status->op_MulC ? status->op_MulC : op;
366   }
367   else if (op == op_Div && get_irn_op(get_Div_right(node)) == op_Const) {
368     /* special case, a division by a const, count on extra counter */
369     op = status->op_DivC ? status->op_DivC : op;
370   }
371   else if (op == op_Mod && get_irn_op(get_Mod_right(node)) == op_Const) {
372     /* special case, a module by a const, count on extra counter */
373     op = status->op_ModC ? status->op_ModC : op;
374   }
375   else if (op == op_DivMod && get_irn_op(get_DivMod_right(node)) == op_Const) {
376     /* special case, a division/modulo by a const, count on extra counter */
377     op = status->op_DivModC ? status->op_DivModC : op;
378   }
379   else if (op == op_Sel && get_irn_op(get_Sel_ptr(node)) == op_Sel) {
380     /* special case, a Sel of a Sel, count on extra counter */
381     op = status->op_SelSel ? status->op_SelSel : op;
382
383     if (get_irn_op(get_Sel_ptr(get_Sel_ptr(node))) == op_Sel) {
384       /* special case, a Sel of a Sel of a Sel, count on extra counter */
385       op = status->op_SelSelSel ? status->op_SelSelSel : op;
386     }
387   }
388
389   return op;
390 }
391
392 /**
393  * update the block counter
394  */
395 static void undate_block_info(ir_node *node, graph_entry_t *graph)
396 {
397   ir_op *op = get_irn_op(node);
398   ir_node *block;
399   block_entry_t *b_entry;
400   int i, arity;
401
402   /* check for block */
403   if (op == op_Block) {
404     arity = get_irn_arity(node);
405     b_entry = block_get_entry(get_irn_node_nr(node), graph->block_hash);
406
407     /* count all incoming edges */
408     for (i = 0; i < arity; ++i) {
409       ir_node *pred = get_irn_n(node, i);
410       ir_node *other_block = get_nodes_block(pred);
411       block_entry_t *b_entry_other = block_get_entry(get_irn_node_nr(other_block), graph->block_hash);
412
413       cnt_inc(&b_entry->cnt_in_edges);  /* an edge coming from another block */
414       cnt_inc(&b_entry_other->cnt_out_edges);
415     }
416     return;
417   }
418   else if (op == op_Phi && mode_is_datab(get_irn_mode(node))) {
419     /* count data Phi */
420     ir_node *block = get_nodes_block(node);
421     block_entry_t *b_entry = block_get_entry(get_irn_node_nr(block), graph->block_hash);
422
423     cnt_inc(&b_entry->cnt_phi_data);
424   }
425
426   block   = get_nodes_block(node);
427   b_entry = block_get_entry(get_irn_node_nr(block), graph->block_hash);
428
429   /* we have a new nodes */
430   cnt_inc(&b_entry->cnt_nodes);
431
432   arity = get_irn_arity(node);
433
434   for (i = 0; i < arity; ++i) {
435     ir_node *pred = get_irn_n(node, i);
436     ir_node *other_block;
437
438     if (get_irn_op(pred) == op_Block)
439       continue;
440
441     other_block = get_nodes_block(pred);
442
443     if (other_block == block)
444       cnt_inc(&b_entry->cnt_edges);     /* a in block edge */
445     else {
446       block_entry_t *b_entry_other = block_get_entry(get_irn_node_nr(other_block), graph->block_hash);
447
448       cnt_inc(&b_entry->cnt_in_edges);  /* an edge coming from another block */
449       cnt_inc(&b_entry_other->cnt_out_edges);
450     }
451   }
452 }
453
454 /** calculates how many arguments of the call are const */
455 static int cnt_const_args(ir_node *call)
456 {
457   int  i, res = 0;
458   int  n = get_Call_n_params(call);
459
460   for (i = 0; i < n; ++i) {
461     ir_node *param = get_Call_param(call, i);
462     ir_op   *op = get_irn_op(param);
463
464     if (op == op_Const || op == op_SymConst)
465       ++res;
466   }
467   return res;
468 }
469
470 /**
471  * update info on calls
472  *
473  * @param call   The call
474  * @param graph  The graph entry containing the call
475  */
476 static void stat_update_call(ir_node *call, graph_entry_t *graph)
477 {
478   ir_node  *block = get_nodes_block(call);
479   ir_node  *ptr = get_Call_ptr(call);
480   entity   *ent = NULL;
481   ir_graph *callee = NULL;
482   int      num_const_args;
483
484   /*
485    * If the block is bad, the whole subgraph will collapse later
486    * so do not count this call.
487    * This happens in dead code.
488    */
489   if (is_Bad(block))
490     return;
491
492   cnt_inc(&graph->cnt_all_calls);
493
494   /* found a call, this function is not a leaf */
495   graph->is_leaf = 0;
496
497   if (get_irn_op(ptr) == op_SymConst) {
498     if (get_SymConst_kind(ptr) == symconst_addr_ent) {
499       /* ok, we seems to know the entity */
500       ent = get_SymConst_entity(ptr);
501       callee = get_entity_irg(ent);
502
503       /* it is recursive, if it calls at least once */
504       if (callee == graph->irg)
505         graph->is_recursive = 1;
506     }
507   }
508   else {
509     /* indirect call, be could not predict */
510     cnt_inc(&graph->cnt_indirect_calls);
511
512     /* NOT a leaf call */
513     graph->is_leaf_call = LCS_NON_LEAF_CALL;
514   }
515
516   /* check, if it's a chain-call: Then, the call-block
517    * must dominate the end block. */
518   {
519     ir_node *curr = get_irg_end_block(graph->irg);
520     int depth = get_Block_dom_depth(block);
521
522     for (; curr != block && get_Block_dom_depth(curr) > depth;) {
523       curr = get_Block_idom(curr);
524
525       if (! curr || is_no_Block(curr))
526         break;
527     }
528
529     if (curr != block)
530       graph->is_chain_call = 0;
531   }
532
533   /* check, if the callee is a leaf */
534   if (callee) {
535     graph_entry_t *called = graph_get_entry(callee, status->irg_hash);
536
537     if (called->is_analyzed) {
538       if (! called->is_leaf)
539         graph->is_leaf_call = LCS_NON_LEAF_CALL;
540     }
541   }
542
543   /* check, if arguments of the call are const */
544   num_const_args = cnt_const_args(call);
545
546   if (num_const_args > 0)
547     cnt_inc(&graph->cnt_call_with_cnst_arg);
548 }
549
550 /**
551  * update info on calls for graphs on the wait queue
552  */
553 static void stat_update_call_2(ir_node *call, graph_entry_t *graph)
554 {
555   ir_node  *block = get_nodes_block(call);
556   ir_node  *ptr = get_Call_ptr(call);
557   entity   *ent = NULL;
558   ir_graph *callee = NULL;
559
560   /*
561    * If the block is bad, the whole subgraph will collapse later
562    * so do not count this call.
563    * This happens in dead code.
564    */
565   if (is_Bad(block))
566     return;
567
568   if (get_irn_op(ptr) == op_SymConst) {
569     if (get_SymConst_kind(ptr) == symconst_addr_ent) {
570       /* ok, we seems to know the entity */
571       ent = get_SymConst_entity(ptr);
572       callee = get_entity_irg(ent);
573     }
574   }
575
576   /* check, if the callee is a leaf */
577   if (callee) {
578     graph_entry_t *called = graph_get_entry(callee, status->irg_hash);
579
580     assert(called->is_analyzed);
581
582     if (! called->is_leaf)
583       graph->is_leaf_call = LCS_NON_LEAF_CALL;
584   }
585   else
586     graph->is_leaf_call = LCS_NON_LEAF_CALL;
587 }
588
589 /**
590  * walker for reachable nodes count
591  */
592 static void update_node_stat(ir_node *node, void *env)
593 {
594   graph_entry_t *graph = env;
595   node_entry_t *entry;
596
597   ir_op *op = stat_get_irn_op(node);
598   int arity = get_irn_arity(node);
599
600   entry = opcode_get_entry(op, graph->opcode_hash);
601
602   cnt_inc(&entry->cnt_alive);
603   cnt_add_i(&graph->cnt_edges, arity);
604
605   /* count block edges */
606   undate_block_info(node, graph);
607
608   /* handle statistics for special node types */
609
610   if (op == op_Const) {
611     if (status->stat_options & FIRMSTAT_COUNT_CONSTS) {
612       /* check properties of constants */
613       stat_update_const(status, node, graph);
614     }
615   }
616   else if (op == op_Call) {
617     /* check for properties that depends on calls like recursion/leaf/indirect call */
618     stat_update_call(node, graph);
619   }
620 }
621
622 /**
623  * walker for reachable nodes count for graphs on the wait_q
624  */
625 static void update_node_stat_2(ir_node *node, void *env)
626 {
627   graph_entry_t *graph = env;
628
629   /* check for properties that depends on calls like recursion/leaf/indirect call */
630   if (get_irn_op(node) == op_Call)
631     stat_update_call_2(node, graph);
632 }
633
634 /**
635  * get the current address mark
636  */
637 static unsigned get_adr_mark(graph_entry_t *graph, ir_node *node)
638 {
639   address_mark_entry_t *value = set_find(graph->address_mark, &node, sizeof(*value), HASH_PTR(node));
640
641   return value ? value->mark : 0;
642 }
643
644 /**
645  * set the current address mark
646  */
647 static void set_adr_mark(graph_entry_t *graph, ir_node *node, unsigned val)
648 {
649   address_mark_entry_t *value = set_insert(graph->address_mark, &node, sizeof(*value), HASH_PTR(node));
650
651   value->mark = val;
652 }
653
654 /**
655  * a vcg attribute hook: Color a node with a different color if
656  * it's identified as a part of an address expression or at least referenced
657  * by an address expression.
658  */
659 static int stat_adr_mark_hook(FILE *F, ir_node *node, ir_node *local)
660 {
661   ir_node *n           = local ? local : node;
662   ir_graph *irg        = get_irn_irg(n);
663   graph_entry_t *graph = graph_get_entry(irg, status->irg_hash);
664   unsigned mark        = get_adr_mark(graph, n);
665
666   if (mark & MARK_ADDRESS_CALC)
667     fprintf(F, "color: purple");
668   else if ((mark & (MARK_REF_ADR | MARK_REF_NON_ADR)) == MARK_REF_ADR)
669     fprintf(F, "color: pink");
670   else if ((mark & (MARK_REF_ADR | MARK_REF_NON_ADR)) == (MARK_REF_ADR|MARK_REF_NON_ADR))
671     fprintf(F, "color: lightblue");
672   else
673     return 0;
674
675   /* I know the color! */
676   return 1;
677 }
678
679 /**
680  * walker that marks every node that is an address calculation
681  *
682  * predecessor nodes must be visited first. We ensure this by
683  * calling in in the post of an outs walk. This should work even in cycles,
684  * while the pre in a normal walk will not.
685  */
686 static void mark_address_calc(ir_node *node, void *env)
687 {
688   graph_entry_t *graph = env;
689   ir_mode *mode = get_irn_mode(node);
690   int i, n;
691   unsigned mark_preds = MARK_REF_NON_ADR;
692
693   if (! mode_is_numP(mode))
694     return;
695
696   if (mode_is_reference(mode)) {
697     /* a reference is calculated here, we are sure */
698     set_adr_mark(graph, node, MARK_ADDRESS_CALC);
699
700     mark_preds = MARK_REF_ADR;
701   }
702   else {
703     unsigned mark = get_adr_mark(graph, node);
704
705     if ((mark & (MARK_REF_ADR | MARK_REF_NON_ADR)) == MARK_REF_ADR) {
706       /*
707        * this node has not an reference mode, but is only
708        * referenced by address calculations
709        */
710       mark_preds = MARK_REF_ADR;
711     }
712   }
713
714   /* mark all predecessors */
715   for (i = 0, n = get_irn_arity(node); i < n; ++i) {
716     ir_node *pred = get_irn_n(node, i);
717
718     set_adr_mark(graph, pred, get_adr_mark(graph, pred) | mark_preds);
719   }
720 }
721
722 /**
723  * Called for every graph when the graph is either deleted or stat_dump_snapshot()
724  * is called, must recalculate all statistic info.
725  *
726  * @param global    The global entry
727  * @param graph     The current entry
728  */
729 static void update_graph_stat(graph_entry_t *global, graph_entry_t *graph)
730 {
731   node_entry_t *entry;
732
733   /* clear first the alive counter in the graph */
734   for (entry = pset_first(graph->opcode_hash); entry; entry = pset_next(graph->opcode_hash)) {
735     cnt_clr(&entry->cnt_alive);
736   }
737
738   /* set pessimistic values */
739   graph->is_leaf       = 1;
740   graph->is_leaf_call  = LCS_UNKNOWN;
741   graph->is_recursive  = 0;
742   graph->is_chain_call = 1;
743
744   /* we need dominator info */
745   if (graph->irg != get_const_code_irg())
746     if (get_irg_dom_state(graph->irg) != dom_consistent)
747       compute_doms(graph->irg);
748
749   /* count the nodes in the graph */
750   irg_walk_graph(graph->irg, update_node_stat, NULL, graph);
751
752 #if 0
753   entry = opcode_get_entry(op_Call, graph->opcode_hash);
754
755   /* check if we have more than 1 call */
756   if (cnt_gt(entry->cnt_alive, 1))
757     graph->is_chain_call = 0;
758 #endif
759
760   /* recursive functions are never chain calls, leafs don't have calls */
761   if (graph->is_recursive || graph->is_leaf)
762     graph->is_chain_call = 0;
763
764   /* assume we walk every graph only ONCE, we could sum here the global count */
765   for (entry = pset_first(graph->opcode_hash); entry; entry = pset_next(graph->opcode_hash)) {
766     node_entry_t *g_entry = opcode_get_entry(entry->op, global->opcode_hash);
767
768     /* update the node counter */
769     cnt_add(&g_entry->cnt_alive, &entry->cnt_alive);
770   }
771
772   /* update the edge counter */
773   cnt_add(&global->cnt_edges, &graph->cnt_edges);
774
775   /* count the number of address calculation */
776   if (graph->irg != get_const_code_irg()) {
777     ir_graph *rem = current_ir_graph;
778
779     if (get_irg_outs_state(graph->irg) != outs_consistent)
780       compute_irg_outs(graph->irg);
781
782     /* Must be done an the outs graph */
783     current_ir_graph = graph->irg;
784     irg_out_walk(get_irg_start(graph->irg), NULL, mark_address_calc, graph);
785     current_ir_graph = rem;
786
787 #if 0
788     set_dump_node_vcgattr_hook(stat_adr_mark_hook);
789     dump_ir_block_graph(graph->irg, "-adr");
790     set_dump_node_vcgattr_hook(NULL);
791 #endif
792   }
793
794   /* count the DAG's */
795   if (status->stat_options & FIRMSTAT_COUNT_DAG)
796     count_dags_in_graph(global, graph);
797
798   /* calculate the patterns of this graph */
799   stat_calc_pattern_history(graph->irg);
800
801   /* leaf function did not call others */
802   if (graph->is_leaf)
803     graph->is_leaf_call = LCS_NON_LEAF_CALL;
804   else if (graph->is_leaf_call == LCS_UNKNOWN) {
805     /* we still don't know if this graph calls leaf-functions, so enqueue */
806     pdeq_putl(status->wait_q, graph);
807   }
808
809   /* we have analyzed this graph */
810   graph->is_analyzed = 1;
811 }
812
813 /**
814  * Called for every graph that was on the wait_q in stat_dump_snapshot()
815  *  must finish all statistic info calculations.
816  *
817  * @param global    The global entry
818  * @param graph     The current entry
819  */
820 static void update_graph_stat_2(graph_entry_t *global, graph_entry_t *graph)
821 {
822   if (graph->is_deleted) {
823     /* deleted, ignore */
824     return;
825   }
826
827   if (graph->irg) {
828     /* count the nodes in the graph */
829     irg_walk_graph(graph->irg, update_node_stat_2, NULL, graph);
830
831     if (graph->is_leaf_call == LCS_UNKNOWN)
832       graph->is_leaf_call = LCS_LEAF_CALL;
833   }
834 }
835
836 /**
837  * register a dumper
838  */
839 static void stat_register_dumper(const dumper_t *dumper)
840 {
841   dumper_t *p = xmalloc(sizeof(*p));
842
843   if (p) {
844     *p = *dumper;
845
846     p->next        = status->dumper;
847     p->status      = status;
848     status->dumper = p;
849   }
850
851   /* FIXME: memory leak */
852 }
853
854 /**
855  * dumps an IR graph.
856  */
857 static void stat_dump_graph(graph_entry_t *entry)
858 {
859   dumper_t *dumper;
860
861   for (dumper = status->dumper; dumper; dumper = dumper->next) {
862     if (dumper->dump_graph)
863       dumper->dump_graph(dumper, entry);
864   }
865 }
866
867 /**
868  * dumps a constant table
869  */
870 static void stat_dump_consts(const constant_info_t *tbl)
871 {
872   dumper_t *dumper;
873
874   for (dumper = status->dumper; dumper; dumper = dumper->next) {
875     if (dumper->dump_const_tbl)
876       dumper->dump_const_tbl(dumper, tbl);
877   }
878 }
879
880 /**
881  * initialize the dumper
882  */
883 static void stat_dump_init(const char *name)
884 {
885   dumper_t *dumper;
886
887   for (dumper = status->dumper; dumper; dumper = dumper->next) {
888     if (dumper->init)
889       dumper->init(dumper, name);
890   }
891 }
892
893 /**
894  * finish the dumper
895  */
896 static void stat_dump_finish(void)
897 {
898   dumper_t *dumper;
899
900   for (dumper = status->dumper; dumper; dumper = dumper->next) {
901     if (dumper->finish)
902       dumper->finish(dumper);
903   }
904 }
905
906 /* ---------------------------------------------------------------------- */
907
908 /*
909  * helper: get an ir_op from an opcode
910  */
911 ir_op *stat_get_op_from_opcode(opcode code)
912 {
913   return opcode_find_entry(code, status->ir_op_hash);
914 }
915
916 /**
917  * A new IR op is registered.
918  *
919  * @param ctx  the hook context
920  * @param op   the new IR opcode that was created.
921  */
922 static void stat_new_ir_op(void *ctx, ir_op *op)
923 {
924   if (! status->stat_options)
925     return;
926
927   STAT_ENTER;
928   {
929     graph_entry_t *graph = graph_get_entry(NULL, status->irg_hash);
930
931     /* execute for side effect :-) */
932     opcode_get_entry(op, graph->opcode_hash);
933
934     pset_insert(status->ir_op_hash, op, op->code);
935   }
936   STAT_LEAVE;
937 }
938
939 /**
940  * An IR op is freed.
941  *
942  * @param ctx  the hook context
943  * @param op   the IR opcode that is freed
944  */
945 static void stat_free_ir_op(void *ctx, ir_op *op)
946 {
947   if (! status->stat_options)
948     return;
949
950   STAT_ENTER;
951   {
952   }
953   STAT_LEAVE;
954 }
955
956 /**
957  * A new node is created.
958  *
959  * @param ctx   the hook context
960  * @param irg   the IR graph on which the node is created
961  * @param node  the new IR node that was created
962  */
963 static void stat_new_node(void *ctx, ir_graph *irg, ir_node *node)
964 {
965   if (! status->stat_options)
966     return;
967
968   /* do NOT count during dead node elimination */
969   if (status->in_dead_node_elim > 0)
970     return;
971
972   STAT_ENTER;
973   {
974     node_entry_t *entry;
975     graph_entry_t *graph;
976     ir_op *op = stat_get_irn_op(node);
977
978     /* increase global value */
979     graph = graph_get_entry(NULL, status->irg_hash);
980     entry = opcode_get_entry(op, graph->opcode_hash);
981     cnt_inc(&entry->new_node);
982
983     /* increase local value */
984     graph = graph_get_entry(current_ir_graph, status->irg_hash);
985     entry = opcode_get_entry(op, graph->opcode_hash);
986     cnt_inc(&entry->new_node);
987   }
988   STAT_LEAVE;
989 }
990
991 /**
992  * A node is changed into a Id node
993  *
994  * @param ctx   the hook context
995  * @param node  the IR node that will be turned into an ID
996  */
997 static void stat_turn_into_id(void *ctx, ir_node *node)
998 {
999   if (! status->stat_options)
1000     return;
1001
1002   STAT_ENTER;
1003   {
1004     node_entry_t *entry;
1005     graph_entry_t *graph;
1006     ir_op *op = stat_get_irn_op(node);
1007
1008     /* increase global value */
1009     graph = graph_get_entry(NULL, status->irg_hash);
1010     entry = opcode_get_entry(op, graph->opcode_hash);
1011     cnt_inc(&entry->into_Id);
1012
1013     /* increase local value */
1014     graph = graph_get_entry(current_ir_graph, status->irg_hash);
1015     entry = opcode_get_entry(op, graph->opcode_hash);
1016     cnt_inc(&entry->into_Id);
1017   }
1018   STAT_LEAVE;
1019 }
1020
1021 /**
1022  * A new graph was created
1023  *
1024  * @param ctx  the hook context
1025  * @param irg  the new IR graph that was created
1026  * @param ent  the entity of this graph
1027  */
1028 static void stat_new_graph(void *ctx, ir_graph *irg, entity *ent)
1029 {
1030   if (! status->stat_options)
1031     return;
1032
1033   STAT_ENTER;
1034   {
1035     /* execute for side effect :-) */
1036     graph_entry_t * graph = graph_get_entry(irg, status->irg_hash);
1037
1038     graph->ent           = ent;
1039     graph->is_deleted    = 0;
1040     graph->is_leaf       = 0;
1041     graph->is_leaf_call  = 0;
1042     graph->is_recursive  = 0;
1043     graph->is_chain_call = 0;
1044     graph->is_analyzed   = 0;
1045   }
1046   STAT_LEAVE;
1047 }
1048
1049 /**
1050  * A graph will be deleted
1051  *
1052  * @param ctx  the hook context
1053  * @param irg  the IR graph that will be deleted
1054  *
1055  * Note that we still hold the information for this graph
1056  * in our hash maps, only a flag is set which prevents this
1057  * information from being changed, it's "frozen" from now.
1058  */
1059 static void stat_free_graph(void *ctx, ir_graph *irg)
1060 {
1061   if (! status->stat_options)
1062     return;
1063
1064   STAT_ENTER;
1065   {
1066     graph_entry_t *graph  = graph_get_entry(irg, status->irg_hash);
1067     graph_entry_t *global = graph_get_entry(NULL, status->irg_hash);
1068
1069     graph->is_deleted = 1;
1070
1071     if (status->stat_options & FIRMSTAT_COUNT_DELETED) {
1072       /* count the nodes of the graph yet, it will be destroyed later */
1073       update_graph_stat(global, graph);
1074     }
1075   }
1076   STAT_LEAVE;
1077 }
1078
1079 /**
1080  * A walk over a graph is initiated. Do not count walks from statistic code.
1081  *
1082  * @param ctx  the hook context
1083  * @param irg  the IR graph that will be walked
1084  * @param pre  the pre walker
1085  * @param post the post walker
1086  */
1087 static void stat_irg_walk(void *ctx, ir_graph *irg, generic_func *pre, generic_func *post)
1088 {
1089   if (! status->stat_options)
1090     return;
1091
1092   STAT_ENTER_SINGLE;
1093   {
1094     graph_entry_t *graph = graph_get_entry(irg, status->irg_hash);
1095
1096     cnt_inc(&graph->cnt_walked);
1097   }
1098   STAT_LEAVE;
1099 }
1100
1101 /**
1102  * A walk over a graph in block-wise order is initiated. Do not count walks from statistic code.
1103  *
1104  * @param ctx  the hook context
1105  * @param irg  the IR graph that will be walked
1106  * @param pre  the pre walker
1107  * @param post the post walker
1108  */
1109 static void stat_irg_walk_blkwise(void *ctx, ir_graph *irg, generic_func *pre, generic_func *post)
1110 {
1111   /* for now, do NOT differentiate between blockwise and normal */
1112   stat_irg_walk(ctx, irg, pre, post);
1113 }
1114
1115 /**
1116  * A walk over the graph's blocks is initiated. Do not count walks from statistic code.
1117  *
1118  * @param ctx  the hook context
1119  * @param irg  the IR graph that will be walked
1120  * @param node the IR node
1121  * @param pre  the pre walker
1122  * @param post the post walker
1123  */
1124 static void stat_irg_block_walk(void *ctx, ir_graph *irg, ir_node *node, generic_func *pre, generic_func *post)
1125 {
1126   if (! status->stat_options)
1127     return;
1128
1129   STAT_ENTER_SINGLE;
1130   {
1131     graph_entry_t *graph = graph_get_entry(irg, status->irg_hash);
1132
1133     cnt_inc(&graph->cnt_walked_blocks);
1134   }
1135   STAT_LEAVE;
1136 }
1137
1138 /**
1139  * called for every node that is removed due to an optimization.
1140  *
1141  * @param n     the IR node that will be removed
1142  * @param hmap  the hash map containing ir_op* -> opt_entry_t*
1143  */
1144 static void removed_due_opt(ir_node *n, hmap_opt_entry_t *hmap)
1145 {
1146   ir_op *op          = stat_get_irn_op(n);
1147   opt_entry_t *entry = opt_get_entry(op, hmap);
1148
1149   /* increase global value */
1150   cnt_inc(&entry->count);
1151 }
1152
1153 /**
1154  * Some nodes were optimized into some others due to an optimization.
1155  *
1156  * @param ctx  the hook context
1157  */
1158 static void stat_merge_nodes(
1159     void *ctx,
1160     ir_node **new_node_array, int new_num_entries,
1161     ir_node **old_node_array, int old_num_entries,
1162     hook_opt_kind opt)
1163 {
1164   if (! status->stat_options)
1165     return;
1166
1167   STAT_ENTER;
1168   {
1169     int i, j;
1170     graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash);
1171
1172     if (status->reassoc_run)
1173       opt = HOOK_OPT_REASSOC;
1174
1175     for (i = 0; i < old_num_entries; ++i) {
1176       for (j = 0; j < new_num_entries; ++j)
1177         if (old_node_array[i] == new_node_array[j])
1178           break;
1179
1180       /* nodes might be in new and old, these are NOT removed */
1181       if (j >= new_num_entries) {
1182         int xopt = opt;
1183
1184         /* sometimes we did not detect, that it is replaced by a Const */
1185         if (opt == HOOK_OPT_CONFIRM && new_num_entries == 1) {
1186           ir_op *op = get_irn_op(new_node_array[0]);
1187
1188           if (op == op_Const || op == op_SymConst)
1189             xopt = HOOK_OPT_CONFIRM_C;
1190         }
1191
1192         removed_due_opt(old_node_array[i], graph->opt_hash[xopt]);
1193       }
1194     }
1195   }
1196   STAT_LEAVE;
1197 }
1198
1199 /**
1200  * Reassociation is started/stopped.
1201  *
1202  * @param ctx   the hook context
1203  * @param flag  if non-zero, reassociation is started else stopped
1204  */
1205 static void stat_reassociate(void *ctx, int flag)
1206 {
1207   if (! status->stat_options)
1208     return;
1209
1210   STAT_ENTER;
1211   {
1212     status->reassoc_run = flag;
1213   }
1214   STAT_LEAVE;
1215 }
1216
1217 /**
1218  * A node was lowered into other nodes
1219  *
1220  * @param ctx  the hook context
1221  * @param node the IR node that will be lowered
1222  */
1223 static void stat_lower(void *ctx, ir_node *node)
1224 {
1225   if (! status->stat_options)
1226     return;
1227
1228   STAT_ENTER;
1229   {
1230     graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash);
1231
1232     removed_due_opt(node, graph->opt_hash[HOOK_LOWERED]);
1233   }
1234   STAT_LEAVE;
1235 }
1236
1237 /**
1238  * A graph was inlined.
1239  *
1240  * @param ctx  the hook context
1241  * @param call the IR call that will re changed into the body of
1242  *             the called IR graph
1243  * @param called_irg  the IR graph representing the called routine
1244  */
1245 static void stat_inline(void *ctx, ir_node *call, ir_graph *called_irg)
1246 {
1247   if (! status->stat_options)
1248     return;
1249
1250   STAT_ENTER;
1251   {
1252     ir_graph *irg = get_irn_irg(call);
1253     graph_entry_t *i_graph = graph_get_entry(called_irg, status->irg_hash);
1254     graph_entry_t *graph   = graph_get_entry(irg, status->irg_hash);
1255
1256     cnt_inc(&graph->cnt_got_inlined);
1257     cnt_inc(&i_graph->cnt_was_inlined);
1258   }
1259   STAT_LEAVE;
1260 }
1261
1262 /**
1263  * A graph with tail-recursions was optimized.
1264  *
1265  * @param ctx  the hook context
1266  */
1267 static void stat_tail_rec(void *ctx, ir_graph *irg, int n_calls)
1268 {
1269   if (! status->stat_options)
1270     return;
1271
1272   STAT_ENTER;
1273   {
1274     graph_entry_t *graph = graph_get_entry(irg, status->irg_hash);
1275
1276     graph->num_tail_recursion += n_calls;
1277   }
1278   STAT_LEAVE;
1279 }
1280
1281 /**
1282  * Strength reduction was performed on an iteration variable.
1283  *
1284  * @param ctx  the hook context
1285  */
1286 static void stat_strength_red(void *ctx, ir_graph *irg, ir_node *strong, ir_node *cmp)
1287 {
1288   if (! status->stat_options)
1289     return;
1290
1291   STAT_ENTER;
1292   {
1293     graph_entry_t *graph = graph_get_entry(irg, status->irg_hash);
1294     cnt_inc(&graph->cnt_strength_red);
1295
1296     removed_due_opt(strong, graph->opt_hash[HOOK_OPT_STRENGTH_RED]);
1297   }
1298   STAT_LEAVE;
1299 }
1300
1301 /**
1302  * Start the dead node elimination.
1303  *
1304  * @param ctx  the hook context
1305  */
1306 static void stat_dead_node_elim_start(void *ctx, ir_graph *irg)
1307 {
1308   if (! status->stat_options)
1309     return;
1310
1311   ++status->in_dead_node_elim;
1312 }
1313
1314 /**
1315  * Stops the dead node elimination.
1316  *
1317  * @param ctx  the hook context
1318  */
1319 static void stat_dead_node_elim_stop(void *ctx, ir_graph *irg)
1320 {
1321   if (! status->stat_options)
1322     return;
1323
1324   --status->in_dead_node_elim;
1325 }
1326
1327 /**
1328  * if-conversion was tried
1329  */
1330 static void stat_if_conversion(void *context, ir_graph *irg, ir_node *phi,
1331                                int pos, ir_node *mux, if_result_t reason)
1332 {
1333   if (! status->stat_options)
1334     return;
1335
1336   STAT_ENTER;
1337   {
1338     graph_entry_t *graph = graph_get_entry(irg, status->irg_hash);
1339
1340     cnt_inc(&graph->cnt_if_conv[reason]);
1341   }
1342   STAT_LEAVE;
1343 }
1344
1345 /**
1346  * real function call was optimized
1347  */
1348 static void stat_func_call(void *context, ir_graph *irg, ir_node *call)
1349 {
1350   if (! status->stat_options)
1351     return;
1352
1353   STAT_ENTER;
1354   {
1355     graph_entry_t *graph = graph_get_entry(irg, status->irg_hash);
1356
1357     cnt_inc(&graph->cnt_real_func_call);
1358   }
1359   STAT_LEAVE;
1360 }
1361
1362 /**
1363  * A multiply was replaced by a series of Shifts/Adds/Subs
1364  *
1365  * @param ctx  the hook context
1366  */
1367 static void stat_arch_dep_replace_mul_with_shifts(void *ctx, ir_node *mul)
1368 {
1369   if (! status->stat_options)
1370     return;
1371
1372   STAT_ENTER;
1373   {
1374     graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash);
1375     removed_due_opt(mul, graph->opt_hash[HOOK_OPT_ARCH_DEP]);
1376   }
1377   STAT_LEAVE;
1378 }
1379
1380 /**
1381  * A division was replaced by a series of Shifts/Muls
1382  *
1383  * @param ctx  the hook context
1384  * @param div  the div node that will be optimized
1385  */
1386 static void stat_arch_dep_replace_div_by_const(void *ctx, ir_node *div)
1387 {
1388   if (! status->stat_options)
1389     return;
1390
1391   STAT_ENTER;
1392   {
1393     graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash);
1394     removed_due_opt(div, graph->opt_hash[HOOK_OPT_ARCH_DEP]);
1395   }
1396   STAT_LEAVE;
1397 }
1398
1399 /**
1400  * A modulo was replaced by a series of Shifts/Muls
1401  *
1402  * @param ctx  the hook context
1403  * @param mod  the mod node that will be optimized
1404  */
1405 static void stat_arch_dep_replace_mod_by_const(void *ctx, ir_node *mod)
1406 {
1407   if (! status->stat_options)
1408     return;
1409
1410   STAT_ENTER;
1411   {
1412     graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash);
1413     removed_due_opt(mod, graph->opt_hash[HOOK_OPT_ARCH_DEP]);
1414   }
1415   STAT_LEAVE;
1416 }
1417
1418 /**
1419  * A DivMod was replaced by a series of Shifts/Muls
1420  *
1421  * @param ctx     the hook context
1422  * @param divmod  the divmod node that will be optimized
1423  */
1424 static void stat_arch_dep_replace_DivMod_by_const(void *ctx, ir_node *divmod)
1425 {
1426   if (! status->stat_options)
1427     return;
1428
1429   STAT_ENTER;
1430   {
1431     graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash);
1432     removed_due_opt(divmod, graph->opt_hash[HOOK_OPT_ARCH_DEP]);
1433   }
1434   STAT_LEAVE;
1435 }
1436
1437 /* Dumps a statistics snapshot */
1438 void stat_dump_snapshot(const char *name, const char *phase)
1439 {
1440   char fname[2048];
1441   const char *p;
1442   int l;
1443
1444   if (! status->stat_options)
1445     return;
1446
1447   STAT_ENTER;
1448   {
1449     graph_entry_t *entry;
1450     graph_entry_t *global = graph_get_entry(NULL, status->irg_hash);
1451
1452     /*
1453      * The constant counter is only global, so we clear it here.
1454      * Note that it does NOT contain the constants in DELETED
1455      * graphs due to this.
1456      */
1457     if (status->stat_options & FIRMSTAT_COUNT_CONSTS)
1458       stat_const_clear(status);
1459
1460     /* build the name */
1461     p = strrchr(name, '/');
1462 #ifdef _WIN32
1463     {
1464       const char *q;
1465
1466       q = strrchr(name, '\\');
1467
1468       /* NULL might be not the smallest pointer */
1469       if (q && (!p || q > p))
1470         p = q;
1471     }
1472 #endif
1473     if (p) {
1474       ++p;
1475       l = p - name;
1476
1477       if (l > sizeof(fname) - 1)
1478         l = sizeof(fname) - 1;
1479
1480       memcpy(fname, name, l);
1481       fname[l] = '\0';
1482     }
1483     else {
1484       fname[0] = '\0';
1485       p = name;
1486     }
1487     strncat(fname, "firmstat-", sizeof(fname));
1488     strncat(fname, phase, sizeof(fname));
1489     strncat(fname, "-", sizeof(fname));
1490     strncat(fname, p, sizeof(fname));
1491
1492     stat_dump_init(fname);
1493
1494     /* calculate the graph statistics */
1495     for (entry = pset_first(status->irg_hash); entry; entry = pset_next(status->irg_hash)) {
1496
1497       if (entry->irg == NULL) {
1498         /* special entry for the global count */
1499         continue;
1500       }
1501
1502       if (! entry->is_deleted) {
1503         /* the graph is still alive, count the nodes on it */
1504         update_graph_stat(global, entry);
1505       }
1506     }
1507
1508     /* some calculations are dependent, we pushed them on the wait_q */
1509     while (! pdeq_empty(status->wait_q)) {
1510       entry = pdeq_getr(status->wait_q);
1511
1512       update_graph_stat_2(global, entry);
1513     }
1514
1515
1516     /* dump per graph */
1517     for (entry = pset_first(status->irg_hash); entry; entry = pset_next(status->irg_hash)) {
1518
1519       if (entry->irg == NULL) {
1520         /* special entry for the global count */
1521         continue;
1522       }
1523
1524       if (! entry->is_deleted || status->stat_options & FIRMSTAT_COUNT_DELETED)
1525         stat_dump_graph(entry);
1526
1527       if (! entry->is_deleted) {
1528         /* clear the counter that are not accumulated */
1529         graph_clear_entry(entry, 0);
1530       }
1531     }
1532
1533     /* dump global */
1534     stat_dump_graph(global);
1535
1536     /* dump the const info */
1537     if (status->stat_options & FIRMSTAT_COUNT_CONSTS)
1538       stat_dump_consts(&status->const_info);
1539
1540     stat_dump_finish();
1541
1542     stat_finish_pattern_history();
1543
1544     /* clear the global counter here */
1545     {
1546       node_entry_t *entry;
1547
1548       for (entry = pset_first(global->opcode_hash); entry; entry = pset_next(global->opcode_hash)) {
1549         opcode_clear_entry(entry);
1550       }
1551       /* clear all global counter */
1552       graph_clear_entry(global, 1);
1553     }
1554   }
1555   STAT_LEAVE;
1556 }
1557
1558 /** the hook entries for the Firm statistics module */
1559 static hook_entry_t stat_hooks[hook_last];
1560
1561 /* initialize the statistics module. */
1562 void init_stat(unsigned enable_options)
1563 {
1564 #define X(a)  a, sizeof(a)-1
1565 #define HOOK(h, fkt) \
1566   stat_hooks[h].hook._##h = fkt; register_hook(h, &stat_hooks[h])
1567
1568   if (! (enable_options & FIRMSTAT_ENABLED))
1569     return;
1570
1571   status = xmalloc(sizeof(*status));
1572   memset(status, 0, sizeof(*status));
1573
1574   /* enable statistics */
1575   status->stat_options = enable_options & FIRMSTAT_ENABLED ? enable_options : 0;
1576
1577   /* register all hooks */
1578   HOOK(hook_new_ir_op,                        stat_new_ir_op);
1579   HOOK(hook_free_ir_op,                       stat_free_ir_op);
1580   HOOK(hook_new_node,                         stat_new_node);
1581   HOOK(hook_turn_into_id,                     stat_turn_into_id);
1582   HOOK(hook_new_graph,                        stat_new_graph);
1583   HOOK(hook_free_graph,                       stat_free_graph);
1584   HOOK(hook_irg_walk,                         stat_irg_walk);
1585   HOOK(hook_irg_walk_blkwise,                 stat_irg_walk_blkwise);
1586   HOOK(hook_irg_block_walk,                   stat_irg_block_walk);
1587   HOOK(hook_merge_nodes,                      stat_merge_nodes);
1588   HOOK(hook_reassociate,                      stat_reassociate);
1589   HOOK(hook_lower,                            stat_lower);
1590   HOOK(hook_inline,                           stat_inline);
1591   HOOK(hook_tail_rec,                         stat_tail_rec);
1592   HOOK(hook_strength_red,                     stat_strength_red);
1593   HOOK(hook_dead_node_elim_start,             stat_dead_node_elim_start);
1594   HOOK(hook_dead_node_elim_stop,              stat_dead_node_elim_stop);
1595   HOOK(hook_if_conversion,                    stat_if_conversion);
1596   HOOK(hook_func_call,                        stat_func_call);
1597   HOOK(hook_arch_dep_replace_mul_with_shifts, stat_arch_dep_replace_mul_with_shifts);
1598   HOOK(hook_arch_dep_replace_div_by_const,    stat_arch_dep_replace_div_by_const);
1599   HOOK(hook_arch_dep_replace_mod_by_const,    stat_arch_dep_replace_mod_by_const);
1600   HOOK(hook_arch_dep_replace_DivMod_by_const, stat_arch_dep_replace_DivMod_by_const);
1601
1602   obstack_init(&status->cnts);
1603
1604   /* create the hash-tables */
1605   status->irg_hash   = new_pset(graph_cmp, 8);
1606   status->ir_op_hash = new_pset(opcode_cmp_2, 1);
1607
1608   /* create the wait queue */
1609   status->wait_q     = new_pdeq();
1610
1611   if (enable_options & FIRMSTAT_COUNT_STRONG_OP) {
1612     /* build the pseudo-ops */
1613     _op_Phi0.code    = get_next_ir_opcode();
1614     _op_Phi0.name    = new_id_from_chars(X("Phi0"));
1615
1616     _op_PhiM.code    = get_next_ir_opcode();
1617     _op_PhiM.name    = new_id_from_chars(X("PhiM"));
1618
1619     _op_ProjM.code   = get_next_ir_opcode();
1620     _op_ProjM.name   = new_id_from_chars(X("ProjM"));
1621
1622     _op_MulC.code    = get_next_ir_opcode();
1623     _op_MulC.name    = new_id_from_chars(X("MulC"));
1624
1625     _op_DivC.code    = get_next_ir_opcode();
1626     _op_DivC.name    = new_id_from_chars(X("DivC"));
1627
1628     _op_ModC.code    = get_next_ir_opcode();
1629     _op_ModC.name    = new_id_from_chars(X("ModC"));
1630
1631     _op_DivModC.code = get_next_ir_opcode();
1632     _op_DivModC.name = new_id_from_chars(X("DivModC"));
1633
1634     status->op_Phi0    = &_op_Phi0;
1635     status->op_PhiM    = &_op_PhiM;
1636     status->op_ProjM   = &_op_ProjM;
1637     status->op_MulC    = &_op_MulC;
1638     status->op_DivC    = &_op_DivC;
1639     status->op_ModC    = &_op_ModC;
1640     status->op_DivModC = &_op_DivModC;
1641   }
1642   else {
1643     status->op_Phi0    = NULL;
1644     status->op_PhiM    = NULL;
1645     status->op_ProjM   = NULL;
1646     status->op_MulC    = NULL;
1647     status->op_DivC    = NULL;
1648     status->op_ModC    = NULL;
1649     status->op_DivModC = NULL;
1650   }
1651
1652   if (enable_options & FIRMSTAT_COUNT_SELS) {
1653     _op_SelSel.code    = get_next_ir_opcode();
1654     _op_SelSel.name    = new_id_from_chars(X("Sel(Sel)"));
1655
1656     _op_SelSelSel.code = get_next_ir_opcode();
1657     _op_SelSelSel.name = new_id_from_chars(X("Sel(Sel(Sel))"));
1658
1659     status->op_SelSel    = &_op_SelSel;
1660     status->op_SelSelSel = &_op_SelSelSel;
1661   }
1662   else {
1663     status->op_SelSel    = NULL;
1664     status->op_SelSelSel = NULL;
1665   }
1666
1667   /* register the dumper */
1668   stat_register_dumper(&simple_dumper);
1669
1670   if (enable_options & FIRMSTAT_CSV_OUTPUT)
1671     stat_register_dumper(&csv_dumper);
1672
1673   /* initialize the pattern hash */
1674   stat_init_pattern_history(enable_options & FIRMSTAT_PATTERN_ENABLED);
1675
1676   /* initialize the Const options */
1677   if (enable_options & FIRMSTAT_COUNT_CONSTS)
1678     stat_init_const_cnt(status);
1679
1680 #undef HOOK
1681 #undef X
1682 }
1683
1684 /* terminates the statistics module, frees all memory */
1685 void stat_term(void) {
1686   if (status != (stat_info_t *)&status_disable) {
1687     xfree(status);
1688     status = (stat_info_t *)&status_disable;
1689   }
1690 }
1691
1692 #else
1693
1694 /* initialize the statistics module. */
1695 void init_stat(unsigned enable_options) {}
1696
1697 /* Dumps a statistics snapshot */
1698 void stat_dump_snapshot(const char *name, const char *phase) {}
1699
1700 /* terminates the statistics module, frees all memory */
1701 void stat_term(void);
1702
1703 #endif /* FIRM_STATISTICS */