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