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