410dac0c9ff7142e0ef6279aedfc7d3ea4687da0
[libfirm] / ir / stat / firmstat.c
1 /*
2  * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19
20 /**
21  * @file
22  * @brief   Statistics for Firm.
23  * @author  Michael Beck
24  * @version $Id$
25  */
26 #include "config.h"
27
28 #ifdef FIRM_STATISTICS
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include "irouts.h"
35 #include "irdump.h"
36 #include "hashptr.h"
37 #include "firmstat_t.h"
38 #include "pattern.h"
39 #include "dags.h"
40 #include "stat_dmp.h"
41 #include "xmalloc.h"
42 #include "irhooks.h"
43
44 /*
45  * need this to be static:
46  * Special pseudo Opcodes that we need to count some interesting cases
47  */
48
49 /**
50  * The Phi0, a node that is created during SSA construction
51  */
52 static ir_op _op_Phi0;
53
54 /** The PhiM, just to count memory Phi's. */
55 static ir_op _op_PhiM;
56
57 /** The Mul by Const node. */
58 static ir_op _op_MulC;
59
60 /** The Div by Const node. */
61 static ir_op _op_DivC;
62
63 /** The Div by Const node. */
64 static ir_op _op_ModC;
65
66 /** The Div by Const node. */
67 static ir_op _op_DivModC;
68
69 /** The Quot by Const node. */
70 static ir_op _op_QuotC;
71
72 /** The memory Proj node. */
73 static ir_op _op_ProjM;
74
75 /** A Sel of a Sel */
76 static ir_op _op_SelSel;
77
78 /** A Sel of a Sel of a Sel */
79 static ir_op _op_SelSelSel;
80
81 /* ---------------------------------------------------------------------------------- */
82
83 /** Marks the begin of a statistic (hook) function. */
84 #define STAT_ENTER              ++status->recursive
85
86 /** Marks the end of a statistic (hook) functions. */
87 #define STAT_LEAVE              --status->recursive
88
89 /** Allows to enter a statistic function only when we are not already in a hook. */
90 #define STAT_ENTER_SINGLE       do { if (status->recursive > 0) return; ++status->recursive; } while (0)
91
92 /**
93  * global status
94  */
95 static const unsigned status_disable = 0;
96 static stat_info_t *status = (stat_info_t *)&status_disable;
97
98 /**
99  * Compare two elements of the opcode hash.
100  */
101 static int opcode_cmp(const void *elt, const void *key) {
102         const node_entry_t *e1 = elt;
103         const node_entry_t *e2 = key;
104
105         return e1->op->code - e2->op->code;
106 }  /* opcode_cmp */
107
108 /**
109  * Compare two elements of the graph hash.
110  */
111 static int graph_cmp(const void *elt, const void *key) {
112         const graph_entry_t *e1 = elt;
113         const graph_entry_t *e2 = key;
114
115         return e1->irg != e2->irg;
116 }  /* graph_cmp */
117
118 /**
119  * Compare two elements of the optimization hash.
120  */
121 static int opt_cmp(const void *elt, const void *key) {
122         const opt_entry_t *e1 = elt;
123         const opt_entry_t *e2 = key;
124
125         return e1->op->code != e2->op->code;
126 }  /* opt_cmp */
127
128 /**
129  * Compare two elements of the block/extbb hash.
130  */
131 static int block_cmp(const void *elt, const void *key) {
132         const block_entry_t *e1 = elt;
133         const block_entry_t *e2 = key;
134
135         /* it's enough to compare the block number */
136         return e1->block_nr != e2->block_nr;
137 }  /* block_cmp */
138
139 /**
140  * Compare two elements of the be_block hash.
141  */
142 static int be_block_cmp(const void *elt, const void *key) {
143         const be_block_entry_t *e1 = elt;
144         const be_block_entry_t *e2 = key;
145
146         return e1->block_nr != e2->block_nr;
147 }  /* be_block_cmp */
148
149 /**
150  * Compare two elements of reg pressure hash.
151  */
152 static int reg_pressure_cmp(const void *elt, const void *key) {
153         const reg_pressure_entry_t *e1 = elt;
154         const reg_pressure_entry_t *e2 = key;
155
156         return e1->class_name != e2->class_name;
157 }  /* reg_pressure_cmp */
158
159 /**
160  * Compare two elements of the perm_stat hash.
161  */
162 static int perm_stat_cmp(const void *elt, const void *key) {
163         const perm_stat_entry_t *e1 = elt;
164         const perm_stat_entry_t *e2 = key;
165
166         return e1->perm != e2->perm;
167 }  /* perm_stat_cmp */
168
169 /**
170  * Compare two elements of the perm_class hash.
171  */
172 static int perm_class_cmp(const void *elt, const void *key) {
173         const perm_class_entry_t *e1 = elt;
174         const perm_class_entry_t *e2 = key;
175
176         return e1->class_name != e2->class_name;
177 }  /* perm_class_cmp */
178
179 /**
180  * Compare two elements of the ir_op hash.
181  */
182 static int opcode_cmp_2(const void *elt, const void *key) {
183         const ir_op *e1 = elt;
184         const ir_op *e2 = key;
185
186         return e1->code != e2->code;
187 }  /* opcode_cmp_2 */
188
189 /**
190  * Compare two elements of the address_mark set.
191  */
192 static int address_mark_cmp(const void *elt, const void *key, size_t size) {
193         const address_mark_entry_t *e1 = elt;
194         const address_mark_entry_t *e2 = key;
195         (void) size;
196
197         /* compare only the nodes, the rest is used as data container */
198         return e1->node != e2->node;
199 }  /* address_mark_cmp */
200
201 /**
202  * Clear all counter in a node_entry_t.
203  */
204 static void opcode_clear_entry(node_entry_t *elem) {
205         cnt_clr(&elem->cnt_alive);
206         cnt_clr(&elem->new_node);
207         cnt_clr(&elem->into_Id);
208         cnt_clr(&elem->normalized);
209 }  /* opcode_clear_entry */
210
211 /**
212  * Returns the associates node_entry_t for an ir_op (and allocates
213  * one if not yet available).
214  *
215  * @param op    the IR operation
216  * @param hmap  a hash map containing ir_op* -> node_entry_t*
217  */
218 static node_entry_t *opcode_get_entry(const ir_op *op, hmap_node_entry_t *hmap) {
219         node_entry_t key;
220         node_entry_t *elem;
221
222         key.op = op;
223
224         elem = pset_find(hmap, &key, op->code);
225         if (elem)
226                 return elem;
227
228         elem = obstack_alloc(&status->cnts, sizeof(*elem));
229         memset(elem, 0, sizeof(*elem));
230
231         /* clear counter */
232         opcode_clear_entry(elem);
233
234         elem->op = op;
235
236         return pset_insert(hmap, elem, op->code);
237 }  /* opcode_get_entry */
238
239 /**
240  * Returns the associates ir_op for an opcode
241  *
242  * @param code  the IR opcode
243  * @param hmap  the hash map containing opcode -> ir_op*
244  */
245 static ir_op *opcode_find_entry(ir_opcode code, hmap_ir_op *hmap) {
246         ir_op key;
247
248         key.code = code;
249         return pset_find(hmap, &key, code);
250 }  /* opcode_find_entry */
251
252 /**
253  * Clears all counter in a graph_entry_t.
254  *
255  * @param elem  the graph entry
256  * @param all   if non-zero, clears all counters, else leave accumulated ones
257  */
258 static void graph_clear_entry(graph_entry_t *elem, int all) {
259         int i;
260
261         /* clear accumulated / non-accumulated counter */
262         for (i = all ? 0 : _gcnt_non_acc; i < _gcnt_last; ++i) {
263                 cnt_clr(&elem->cnt[i]);
264         }  /* for */
265
266         if (elem->block_hash) {
267                 del_pset(elem->block_hash);
268                 elem->block_hash = NULL;
269         }  /* if */
270
271         if (elem->extbb_hash) {
272                 del_pset(elem->extbb_hash);
273                 elem->extbb_hash = NULL;
274         }  /* if */
275
276         obstack_free(&elem->recalc_cnts, NULL);
277         obstack_init(&elem->recalc_cnts);
278 }  /* graph_clear_entry */
279
280 /**
281  * Returns the associated graph_entry_t for an IR graph.
282  *
283  * @param irg   the IR graph, NULL for the global counter
284  * @param hmap  the hash map containing ir_graph* -> graph_entry_t*
285  */
286 static graph_entry_t *graph_get_entry(ir_graph *irg, hmap_graph_entry_t *hmap)
287 {
288         graph_entry_t key;
289         graph_entry_t *elem;
290         size_t i;
291
292         key.irg = irg;
293
294         elem = pset_find(hmap, &key, HASH_PTR(irg));
295
296         if (elem) {
297                 /* create hash map backend block information */
298                 if (! elem->be_block_hash)
299                         elem->be_block_hash = new_pset(be_block_cmp, 5);
300
301                 return elem;
302         }  /* if */
303
304         /* allocate a new one */
305         elem = obstack_alloc(&status->cnts, sizeof(*elem));
306         memset(elem, 0, sizeof(*elem));
307         obstack_init(&elem->recalc_cnts);
308
309         /* clear counter */
310         graph_clear_entry(elem, 1);
311
312         /* new hash table for opcodes here  */
313         elem->opcode_hash   = new_pset(opcode_cmp, 5);
314         elem->address_mark  = new_set(address_mark_cmp, 5);
315         elem->irg           = irg;
316
317         /* these hash tables are created on demand */
318         elem->block_hash = NULL;
319         elem->extbb_hash = NULL;
320
321         for (i = 0; i < sizeof(elem->opt_hash)/sizeof(elem->opt_hash[0]); ++i)
322                 elem->opt_hash[i] = new_pset(opt_cmp, 4);
323
324         return pset_insert(hmap, elem, HASH_PTR(irg));
325 }  /* graph_get_entry */
326
327 /**
328  * Clear all counter in an opt_entry_t.
329  */
330 static void opt_clear_entry(opt_entry_t *elem) {
331         cnt_clr(&elem->count);
332 }  /* opt_clear_entry */
333
334 /**
335  * Returns the associated opt_entry_t for an IR operation.
336  *
337  * @param op    the IR operation
338  * @param hmap  the hash map containing ir_op* -> opt_entry_t*
339  */
340 static opt_entry_t *opt_get_entry(const ir_op *op, hmap_opt_entry_t *hmap)
341 {
342         opt_entry_t key;
343         opt_entry_t *elem;
344
345         key.op = op;
346
347         elem = pset_find(hmap, &key, op->code);
348         if (elem)
349                 return elem;
350
351         elem = obstack_alloc(&status->cnts, sizeof(*elem));
352         memset(elem, 0, sizeof(*elem));
353
354         /* clear new counter */
355         opt_clear_entry(elem);
356
357         elem->op = op;
358
359         return pset_insert(hmap, elem, op->code);
360 }  /* opt_get_entry */
361
362 /**
363  * clears all counter in a block_entry_t
364  */
365 static void block_clear_entry(block_entry_t *elem) {
366         int i;
367
368         for (i = 0; i < _bcnt_last; ++i)
369                 cnt_clr(&elem->cnt[i]);
370 }  /* block_clear_entry */
371
372 /**
373  * Returns the associated block_entry_t for an block.
374  *
375  * @param block_nr  an IR  block number
376  * @param hmap      a hash map containing long -> block_entry_t
377  */
378 static block_entry_t *block_get_entry(struct obstack *obst, long block_nr, hmap_block_entry_t *hmap)
379 {
380         block_entry_t key;
381         block_entry_t *elem;
382
383         key.block_nr = block_nr;
384
385         elem = pset_find(hmap, &key, block_nr);
386         if (elem)
387                 return elem;
388
389         elem = obstack_alloc(obst, sizeof(*elem));
390         memset(elem, 0, sizeof(*elem));
391
392         /* clear new counter */
393         block_clear_entry(elem);
394
395         elem->block_nr = block_nr;
396
397         return pset_insert(hmap, elem, block_nr);
398 }  /* block_get_entry */
399
400 /**
401  * Clear all sets in be_block_entry_t.
402  */
403 static void be_block_clear_entry(be_block_entry_t *elem)
404 {
405         if (elem->reg_pressure)
406                 del_pset(elem->reg_pressure);
407
408         if (elem->sched_ready)
409                 stat_delete_distrib_tbl(elem->sched_ready);
410
411         if (elem->perm_class_stat)
412                 del_pset(elem->perm_class_stat);
413
414         elem->reg_pressure    = new_pset(reg_pressure_cmp, 5);
415         elem->sched_ready     = stat_new_int_distrib_tbl();
416         elem->perm_class_stat = new_pset(perm_class_cmp, 5);
417 }  /* be_block_clear_entry */
418
419 /**
420  * Returns the associated be_block_entry_t for an block.
421  *
422  * @param block_nr  an IR  block number
423  * @param hmap      a hash map containing long -> be_block_entry_t
424  */
425 static be_block_entry_t *be_block_get_entry(struct obstack *obst, long block_nr, hmap_be_block_entry_t *hmap)
426 {
427         be_block_entry_t key;
428         be_block_entry_t *elem;
429
430         key.block_nr = block_nr;
431
432         elem = pset_find(hmap, &key, block_nr);
433         if (elem)
434                 return elem;
435
436         elem = obstack_alloc(obst, sizeof(*elem));
437         memset(elem, 0, sizeof(*elem));
438
439         /* clear new counter */
440         be_block_clear_entry(elem);
441
442         elem->block_nr = block_nr;
443
444         return pset_insert(hmap, elem, block_nr);
445 }  /* be_block_get_entry */
446
447 /**
448  * clears all sets in perm_class_entry_t
449  */
450 static void perm_class_clear_entry(perm_class_entry_t *elem) {
451         if (elem->perm_stat)
452                 del_pset(elem->perm_stat);
453
454         elem->perm_stat = new_pset(perm_stat_cmp, 5);
455 }  /* perm_class_clear_entry */
456
457 /**
458  * Returns the associated perm_class entry for a register class.
459  *
460  * @param class_name  the register class name
461  * @param hmap        a hash map containing class_name -> perm_class_entry_t
462  */
463 static perm_class_entry_t *perm_class_get_entry(struct obstack *obst, const char *class_name,
464                                                 hmap_perm_class_entry_t *hmap)
465 {
466         perm_class_entry_t key;
467         perm_class_entry_t *elem;
468
469         key.class_name = class_name;
470
471         elem = pset_find(hmap, &key, HASH_PTR(class_name));
472         if (elem)
473                 return elem;
474
475         elem = obstack_alloc(obst, sizeof(*elem));
476         memset(elem, 0, sizeof(*elem));
477
478         /* clear new counter */
479         perm_class_clear_entry(elem);
480
481         elem->class_name = class_name;
482
483         return pset_insert(hmap, elem, HASH_PTR(class_name));
484 }  /* perm_class_get_entry */
485
486 /**
487  * clears all sets in perm_stat_entry_t
488  */
489 static void perm_stat_clear_entry(perm_stat_entry_t *elem) {
490         if (elem->chains)
491                 stat_delete_distrib_tbl(elem->chains);
492
493         if (elem->cycles)
494                 stat_delete_distrib_tbl(elem->cycles);
495
496         elem->chains = stat_new_int_distrib_tbl();
497         elem->cycles = stat_new_int_distrib_tbl();
498 }  /* perm_stat_clear_entry */
499
500 /**
501  * Returns the associated perm_stat entry for a perm.
502  *
503  * @param perm      the perm node
504  * @param hmap      a hash map containing perm -> perm_stat_entry_t
505  */
506 static perm_stat_entry_t *perm_stat_get_entry(struct obstack *obst, ir_node *perm, hmap_perm_stat_entry_t *hmap)
507 {
508         perm_stat_entry_t key;
509         perm_stat_entry_t *elem;
510
511         key.perm = perm;
512
513         elem = pset_find(hmap, &key, HASH_PTR(perm));
514         if (elem)
515                 return elem;
516
517         elem = obstack_alloc(obst, sizeof(*elem));
518         memset(elem, 0, sizeof(*elem));
519
520         /* clear new counter */
521         perm_stat_clear_entry(elem);
522
523         elem->perm = perm;
524
525         return pset_insert(hmap, elem, HASH_PTR(perm));
526 }  /* perm_stat_get_entry */
527
528 /**
529  * Clear optimizations counter,
530  */
531 static void clear_optimization_counter(void)  {
532         int i;
533         for (i = 0; i < FS_OPT_MAX; ++i)
534                 cnt_clr(&status->num_opts[i]);
535 }
536
537 /**
538  * Returns the ir_op for an IR-node,
539  * handles special cases and return pseudo op codes.
540  *
541  * @param none  an IR node
542  */
543 static ir_op *stat_get_irn_op(ir_node *node)
544 {
545         ir_op *op = get_irn_op(node);
546         ir_opcode opc = op->code;
547
548         switch (opc) {
549         case iro_Phi:
550                 if (get_irn_arity(node) == 0) {
551                         /* special case, a Phi0 node, count on extra counter */
552                         op = status->op_Phi0 ? status->op_Phi0 : op;
553                 } else if (get_irn_mode(node) == mode_M) {
554                         /* special case, a Memory Phi node, count on extra counter */
555                         op = status->op_PhiM ? status->op_PhiM : op;
556                 }  /* if */
557                 break;
558         case iro_Proj:
559                 if (get_irn_mode(node) == mode_M) {
560                         /* special case, a Memory Proj node, count on extra counter */
561                         op = status->op_ProjM ? status->op_ProjM : op;
562                 }  /* if */
563                 break;
564         case iro_Mul:
565                 if (is_Const(get_Mul_left(node)) || is_Const(get_Mul_right(node))) {
566                         /* special case, a Multiply by a const, count on extra counter */
567                         op = status->op_MulC ? status->op_MulC : op;
568                 }  /* if */
569                 break;
570         case iro_Div:
571                 if (is_Const(get_Div_right(node))) {
572                         /* special case, a division by a const, count on extra counter */
573                         op = status->op_DivC ? status->op_DivC : op;
574                 }  /* if */
575                 break;
576         case iro_Mod:
577                 if (is_Const(get_Mod_right(node))) {
578                         /* special case, a module by a const, count on extra counter */
579                         op = status->op_ModC ? status->op_ModC : op;
580                 }  /* if */
581                 break;
582         case iro_DivMod:
583                 if (is_Const(get_DivMod_right(node))) {
584                         /* special case, a division/modulo by a const, count on extra counter */
585                         op = status->op_DivModC ? status->op_DivModC : op;
586                 }  /* if */
587                 break;
588         case iro_Quot:
589                 if (is_Const(get_Quot_right(node))) {
590                         /* special case, a floating point division by a const, count on extra counter */
591                         op = status->op_QuotC ? status->op_QuotC : op;
592                 }  /* if */
593                 break;
594         case iro_Sel:
595                 if (is_Sel(get_Sel_ptr(node))) {
596                         /* special case, a Sel of a Sel, count on extra counter */
597                         op = status->op_SelSel ? status->op_SelSel : op;
598                         if (is_Sel(get_Sel_ptr(get_Sel_ptr(node)))) {
599                                 /* special case, a Sel of a Sel of a Sel, count on extra counter */
600                                 op = status->op_SelSelSel ? status->op_SelSelSel : op;
601                         }  /* if */
602                 }  /* if */
603                 break;
604         default:
605                 ;
606         }  /* switch */
607
608         return op;
609 }  /* stat_get_irn_op */
610
611 /**
612  * update the block counter
613  */
614 static void undate_block_info(ir_node *node, graph_entry_t *graph)
615 {
616         ir_op *op = get_irn_op(node);
617         ir_node *block;
618         block_entry_t *b_entry;
619         int i, arity;
620
621         /* check for block */
622         if (op == op_Block) {
623                 arity = get_irn_arity(node);
624                 b_entry = block_get_entry(&graph->recalc_cnts, get_irn_node_nr(node), graph->block_hash);
625                 /* mark start end block to allow to filter them out */
626                 if (node == get_irg_start_block(graph->irg))
627                         b_entry->is_start = 1;
628                 else if (node == get_irg_end_block(graph->irg))
629                         b_entry->is_end = 1;
630
631                 /* count all incoming edges */
632                 for (i = 0; i < arity; ++i) {
633                         ir_node *pred = get_irn_n(node, i);
634                         ir_node *other_block = get_nodes_block(pred);
635                         block_entry_t *b_entry_other = block_get_entry(&graph->recalc_cnts, get_irn_node_nr(other_block), graph->block_hash);
636
637                         cnt_inc(&b_entry->cnt[bcnt_in_edges]);  /* an edge coming from another block */
638                         cnt_inc(&b_entry_other->cnt[bcnt_out_edges]);
639                 }  /* for */
640                 return;
641         }  /* if */
642
643         block   = get_nodes_block(node);
644         b_entry = block_get_entry(&graph->recalc_cnts, get_irn_node_nr(block), graph->block_hash);
645
646         if (op == op_Phi && mode_is_datab(get_irn_mode(node))) {
647                 /* count data Phi per block */
648                 cnt_inc(&b_entry->cnt[bcnt_phi_data]);
649         }  /* if */
650
651         /* we have a new node in our block */
652         cnt_inc(&b_entry->cnt[bcnt_nodes]);
653
654         /* don't count keep-alive edges */
655         if (is_End(node))
656                 return;
657
658         arity = get_irn_arity(node);
659
660         for (i = 0; i < arity; ++i) {
661                 ir_node *pred = get_irn_n(node, i);
662                 ir_node *other_block;
663
664                 other_block = get_nodes_block(pred);
665
666                 if (other_block == block)
667                         cnt_inc(&b_entry->cnt[bcnt_edges]);     /* a in block edge */
668                 else {
669                         block_entry_t *b_entry_other = block_get_entry(&graph->recalc_cnts, get_irn_node_nr(other_block), graph->block_hash);
670
671                         cnt_inc(&b_entry->cnt[bcnt_in_edges]);  /* an edge coming from another block */
672                         cnt_inc(&b_entry_other->cnt[bcnt_out_edges]);
673                 }  /* if */
674         }  /* for */
675 }  /* undate_block_info */
676
677 /**
678  * Update the extended block counter.
679  */
680 static void update_extbb_info(ir_node *node, graph_entry_t *graph)
681 {
682         ir_op *op = get_irn_op(node);
683         ir_extblk *extbb;
684         extbb_entry_t *eb_entry;
685         int i, arity;
686
687         /* check for block */
688         if (op == op_Block) {
689                 extbb = get_nodes_extbb(node);
690                 arity = get_irn_arity(node);
691                 eb_entry = block_get_entry(&graph->recalc_cnts, get_extbb_node_nr(extbb), graph->extbb_hash);
692
693                 /* count all incoming edges */
694                 for (i = 0; i < arity; ++i) {
695                         ir_node *pred = get_irn_n(node, i);
696                         ir_extblk *other_extbb = get_nodes_extbb(pred);
697
698                         if (extbb != other_extbb) {
699                                 extbb_entry_t *eb_entry_other = block_get_entry(&graph->recalc_cnts, get_extbb_node_nr(other_extbb), graph->extbb_hash);
700
701                                 cnt_inc(&eb_entry->cnt[bcnt_in_edges]); /* an edge coming from another extbb */
702                                 cnt_inc(&eb_entry_other->cnt[bcnt_out_edges]);
703                         }  /* if */
704                 }  /* for */
705                 return;
706         }  /* if */
707
708         extbb    = get_nodes_extbb(node);
709         eb_entry = block_get_entry(&graph->recalc_cnts, get_extbb_node_nr(extbb), graph->extbb_hash);
710
711         if (op == op_Phi && mode_is_datab(get_irn_mode(node))) {
712                 /* count data Phi per extbb */
713                 cnt_inc(&eb_entry->cnt[bcnt_phi_data]);
714         }  /* if */
715
716         /* we have a new node in our block */
717         cnt_inc(&eb_entry->cnt[bcnt_nodes]);
718
719         /* don't count keep-alive edges */
720         if (is_End(node))
721                 return;
722
723         arity = get_irn_arity(node);
724
725         for (i = 0; i < arity; ++i) {
726                 ir_node *pred = get_irn_n(node, i);
727                 ir_extblk *other_extbb = get_nodes_extbb(pred);
728
729                 if (other_extbb == extbb)
730                         cnt_inc(&eb_entry->cnt[bcnt_edges]);    /* a in extbb edge */
731                 else {
732                         extbb_entry_t *eb_entry_other = block_get_entry(&graph->recalc_cnts, get_extbb_node_nr(other_extbb), graph->extbb_hash);
733
734                         cnt_inc(&eb_entry->cnt[bcnt_in_edges]); /* an edge coming from another extbb */
735                         cnt_inc(&eb_entry_other->cnt[bcnt_out_edges]);
736                 }  /* if */
737         }  /* for */
738 }  /* update_extbb_info */
739
740 /**
741  * Calculates how many arguments of the call are const, updates
742  * param distribution.
743  */
744 static void analyse_params_of_Call(graph_entry_t *graph, ir_node *call) {
745         int i, num_const_args = 0, num_local_adr = 0;
746         int n = get_Call_n_params(call);
747
748         for (i = 0; i < n; ++i) {
749                 ir_node *param = get_Call_param(call, i);
750
751                 if (is_irn_constlike(param))
752                         ++num_const_args;
753                 else if (is_Sel(param)) {
754                         ir_node *base = param;
755
756                         do {
757                                 base = get_Sel_ptr(base);
758                         } while (is_Sel(base));
759
760                         if (base == get_irg_frame(current_ir_graph))
761                                 ++num_local_adr;
762                 }
763
764         }  /* for */
765
766         if (num_const_args > 0)
767                 cnt_inc(&graph->cnt[gcnt_call_with_cnst_arg]);
768         if (num_const_args == n)
769                 cnt_inc(&graph->cnt[gcnt_call_with_all_cnst_arg]);
770         if (num_local_adr > 0)
771                 cnt_inc(&graph->cnt[gcnt_call_with_local_adr]);
772
773         stat_inc_int_distrib_tbl(status->dist_param_cnt, n);
774 }  /* analyse_params_of_Call */
775
776 /**
777  * Update info on calls.
778  *
779  * @param call   The call
780  * @param graph  The graph entry containing the call
781  */
782 static void stat_update_call(ir_node *call, graph_entry_t *graph)
783 {
784         ir_node   *block = get_nodes_block(call);
785         ir_node   *ptr = get_Call_ptr(call);
786         ir_entity *ent = NULL;
787         ir_graph  *callee = NULL;
788
789         /*
790          * If the block is bad, the whole subgraph will collapse later
791          * so do not count this call.
792          * This happens in dead code.
793          */
794         if (is_Bad(block))
795                 return;
796
797         cnt_inc(&graph->cnt[gcnt_all_calls]);
798
799         /* found a call, this function is not a leaf */
800         graph->is_leaf = 0;
801
802         if (is_SymConst(ptr)) {
803                 if (get_SymConst_kind(ptr) == symconst_addr_ent) {
804                         /* ok, we seems to know the entity */
805                         ent = get_SymConst_entity(ptr);
806                         callee = get_entity_irg(ent);
807
808                         /* it is recursive, if it calls at least once */
809                         if (callee == graph->irg)
810                                 graph->is_recursive = 1;
811                         if (callee == NULL)
812                                 cnt_inc(&graph->cnt[gcnt_external_calls]);
813                 }  /* if */
814         } else {
815                 /* indirect call, be could not predict */
816                 cnt_inc(&graph->cnt[gcnt_indirect_calls]);
817
818                 /* NOT a leaf call */
819                 graph->is_leaf_call = LCS_NON_LEAF_CALL;
820         }  /* if */
821
822         /* check, if it's a chain-call: Then, the call-block
823          * must dominate the end block. */
824         {
825                 ir_node *curr = get_irg_end_block(graph->irg);
826                 int depth = get_Block_dom_depth(block);
827
828                 for (; curr != block && get_Block_dom_depth(curr) > depth;) {
829                         curr = get_Block_idom(curr);
830
831                         if (! curr || is_no_Block(curr))
832                                 break;
833                 }  /* for */
834
835                 if (curr != block)
836                         graph->is_chain_call = 0;
837         }
838
839         /* check, if the callee is a leaf */
840         if (callee) {
841                 graph_entry_t *called = graph_get_entry(callee, status->irg_hash);
842
843                 if (called->is_analyzed) {
844                         if (! called->is_leaf)
845                                 graph->is_leaf_call = LCS_NON_LEAF_CALL;
846                 }  /* if */
847         }  /* if */
848
849         analyse_params_of_Call(graph, call);
850 }  /* stat_update_call */
851
852 /**
853  * Update info on calls for graphs on the wait queue.
854  */
855 static void stat_update_call_2(ir_node *call, graph_entry_t *graph)
856 {
857         ir_node   *block = get_nodes_block(call);
858         ir_node   *ptr = get_Call_ptr(call);
859         ir_entity *ent = NULL;
860         ir_graph  *callee = NULL;
861
862         /*
863          * If the block is bad, the whole subgraph will collapse later
864          * so do not count this call.
865          * This happens in dead code.
866          */
867         if (is_Bad(block))
868                 return;
869
870         if (is_SymConst(ptr)) {
871                 if (get_SymConst_kind(ptr) == symconst_addr_ent) {
872                         /* ok, we seems to know the entity */
873                         ent = get_SymConst_entity(ptr);
874                         callee = get_entity_irg(ent);
875                 }  /* if */
876         }  /* if */
877
878         /* check, if the callee is a leaf */
879         if (callee) {
880                 graph_entry_t *called = graph_get_entry(callee, status->irg_hash);
881
882                 assert(called->is_analyzed);
883
884                 if (! called->is_leaf)
885                         graph->is_leaf_call = LCS_NON_LEAF_CALL;
886         } else
887                 graph->is_leaf_call = LCS_NON_LEAF_CALL;
888 }  /* stat_update_call_2 */
889
890 /**
891  * Find the base address and entity of an Sel node.
892  *
893  * @param sel  the node
894  *
895  * @return the base address.
896  */
897 static ir_node *find_base_adr(ir_node *sel) {
898         ir_node *ptr = get_Sel_ptr(sel);
899
900         while (is_Sel(ptr)) {
901                 sel = ptr;
902                 ptr = get_Sel_ptr(sel);
903         }
904         return ptr;
905 }  /* find_base_adr */
906
907 /**
908  * Update info on Load/Store address statistics.
909  */
910 static void stat_update_address(ir_node *node, graph_entry_t *graph) {
911         ir_opcode opc = get_irn_opcode(node);
912         ir_node *base;
913         ir_graph *irg;
914
915         switch (opc) {
916         case iro_SymConst:
917                 /* a global address */
918                 cnt_inc(&graph->cnt[gcnt_global_adr]);
919                 break;
920         case iro_Sel:
921                 base = find_base_adr(node);
922                 irg = current_ir_graph;
923                 if (base == get_irg_tls(irg)) {
924                         /* a TLS variable, like a global. */
925                         cnt_inc(&graph->cnt[gcnt_global_adr]);
926                 } else if (base == get_irg_frame(irg)) {
927                         /* a local Variable. */
928                         cnt_inc(&graph->cnt[gcnt_local_adr]);
929                 } else {
930                         /* Pointer access */
931                         if (is_Proj(base) && skip_Proj(get_Proj_pred(base)) == get_irg_start(irg)) {
932                                 /* pointer access through parameter, check for THIS */
933                                 ir_entity *ent = get_irg_entity(irg);
934
935                                 if (ent != NULL) {
936                                         ir_type *ent_tp = get_entity_type(ent);
937
938                                         if (get_method_calling_convention(ent_tp) & cc_this_call) {
939                                                 if (get_Proj_proj(base) == 0) {
940                                                         /* THIS pointer */
941                                                         cnt_inc(&graph->cnt[gcnt_this_adr]);
942                                                         goto end_parameter;
943                                                 }  /* if */
944                                         }  /* if */
945                                 }  /* if */
946                                 /* other parameter */
947                                 cnt_inc(&graph->cnt[gcnt_param_adr]);
948 end_parameter:  ;
949                         } else {
950                                 /* unknown Pointer access */
951                                 cnt_inc(&graph->cnt[gcnt_other_adr]);
952                         }  /* if */
953                 }  /* if */
954         default:
955                 ;
956         }  /* switch */
957 }  /* stat_update_address */
958
959 /**
960  * Walker for reachable nodes count.
961  */
962 static void update_node_stat(ir_node *node, void *env)
963 {
964         graph_entry_t *graph = env;
965         node_entry_t *entry;
966
967         ir_op *op = stat_get_irn_op(node);
968         int i, arity = get_irn_arity(node);
969
970         entry = opcode_get_entry(op, graph->opcode_hash);
971
972         cnt_inc(&entry->cnt_alive);
973         cnt_add_i(&graph->cnt[gcnt_edges], arity);
974
975         /* count block edges */
976         undate_block_info(node, graph);
977
978         /* count extended block edges */
979         if (status->stat_options & FIRMSTAT_COUNT_EXTBB) {
980                 if (graph->irg != get_const_code_irg())
981                         update_extbb_info(node, graph);
982         }  /* if */
983
984         /* handle statistics for special node types */
985
986         switch (op->code) {
987         case iro_Call:
988                 /* check for properties that depends on calls like recursion/leaf/indirect call */
989                 stat_update_call(node, graph);
990                 break;
991         case iro_Load:
992                 /* check address properties */
993                 stat_update_address(get_Load_ptr(node), graph);
994                 break;
995         case iro_Store:
996                 /* check address properties */
997                 stat_update_address(get_Store_ptr(node), graph);
998                 break;
999         case iro_Phi:
1000                 /* check for non-strict Phi nodes */
1001                 for (i = arity - 1; i >= 0; --i) {
1002                         ir_node *pred = get_Phi_pred(node, i);
1003                         if (is_Unknown(pred)) {
1004                                 /* found an Unknown predecessor, graph is not strict */
1005                                 graph->is_strict = 0;
1006                                 break;
1007                         }
1008                 }
1009         default:
1010                 ;
1011         }  /* switch */
1012
1013         /* we want to count the constant IN nodes, not the CSE'ed constant's itself */
1014         if (status->stat_options & FIRMSTAT_COUNT_CONSTS) {
1015                 int i;
1016
1017                 for (i = get_irn_arity(node) - 1; i >= 0; --i) {
1018                         ir_node *pred = get_irn_n(node, i);
1019
1020                         if (is_Const(pred)) {
1021                                 /* check properties of constants */
1022                                 stat_update_const(status, pred, graph);
1023                         }  /* if */
1024                 }  /* for */
1025         }  /* if */
1026 }  /* update_node_stat */
1027
1028 /**
1029  * Walker for reachable nodes count for graphs on the wait_q.
1030  */
1031 static void update_node_stat_2(ir_node *node, void *env) {
1032         graph_entry_t *graph = env;
1033
1034         /* check for properties that depends on calls like recursion/leaf/indirect call */
1035         if (is_Call(node))
1036                 stat_update_call_2(node, graph);
1037 }  /* update_node_stat_2 */
1038
1039 /**
1040  * Get the current address mark.
1041  */
1042 static unsigned get_adr_mark(graph_entry_t *graph, ir_node *node) {
1043         address_mark_entry_t *value = set_find(graph->address_mark, &node, sizeof(*value), HASH_PTR(node));
1044
1045         return value ? value->mark : 0;
1046 }  /* get_adr_mark */
1047
1048 /**
1049  * Set the current address mark.
1050  */
1051 static void set_adr_mark(graph_entry_t *graph, ir_node *node, unsigned val) {
1052         address_mark_entry_t *value = set_insert(graph->address_mark, &node, sizeof(*value), HASH_PTR(node));
1053
1054         value->mark = val;
1055 }  /* set_adr_mark */
1056
1057 #undef DUMP_ADR_MODE
1058
1059 #ifdef DUMP_ADR_MODE
1060 /**
1061  * a vcg attribute hook: Color a node with a different color if
1062  * it's identified as a part of an address expression or at least referenced
1063  * by an address expression.
1064  */
1065 static int stat_adr_mark_hook(FILE *F, ir_node *node, ir_node *local)
1066 {
1067         ir_node *n           = local ? local : node;
1068         ir_graph *irg        = get_irn_irg(n);
1069         graph_entry_t *graph = graph_get_entry(irg, status->irg_hash);
1070         unsigned mark        = get_adr_mark(graph, n);
1071
1072         if (mark & MARK_ADDRESS_CALC)
1073                 fprintf(F, "color: purple");
1074         else if ((mark & (MARK_REF_ADR | MARK_REF_NON_ADR)) == MARK_REF_ADR)
1075                 fprintf(F, "color: pink");
1076         else if ((mark & (MARK_REF_ADR | MARK_REF_NON_ADR)) == (MARK_REF_ADR|MARK_REF_NON_ADR))
1077                 fprintf(F, "color: lightblue");
1078         else
1079                 return 0;
1080
1081         /* I know the color! */
1082         return 1;
1083 }  /* stat_adr_mark_hook */
1084 #endif /* DUMP_ADR_MODE */
1085
1086 /**
1087  * Return the "operational" mode of a Firm node.
1088  */
1089 static ir_mode *get_irn_op_mode(ir_node *node) {
1090         switch (get_irn_opcode(node)) {
1091         case iro_Load:
1092                 return get_Load_mode(node);
1093         case iro_Store:
1094                 return get_irn_mode(get_Store_value(node));
1095         case iro_DivMod:
1096                 return get_irn_mode(get_DivMod_left(node));
1097         case iro_Div:
1098                 return get_irn_mode(get_Div_left(node));
1099         case iro_Mod:
1100                 return get_irn_mode(get_Mod_left(node));
1101         case iro_Cmp:
1102                 /* Cmp is no address calculation, or is it? */
1103         default:
1104                 return get_irn_mode(node);
1105         }  /* switch */
1106 }  /* get_irn_op_mode */
1107
1108 /**
1109  * Post-walker that marks every node that is an address calculation.
1110  *
1111  * Users of a node must be visited first. We ensure this by
1112  * calling it in the post of an outs walk. This should work even in cycles,
1113  * while the normal pre-walk will not.
1114  */
1115 static void mark_address_calc(ir_node *node, void *env) {
1116         graph_entry_t *graph = env;
1117         ir_mode *mode = get_irn_op_mode(node);
1118         int i, n;
1119         unsigned mark_preds = MARK_REF_NON_ADR;
1120
1121         if (! mode_is_data(mode))
1122                 return;
1123
1124         if (mode_is_reference(mode)) {
1125                 /* a reference is calculated here, we are sure */
1126                 set_adr_mark(graph, node, MARK_ADDRESS_CALC);
1127
1128                 mark_preds = MARK_REF_ADR;
1129         } else {
1130                 unsigned mark = get_adr_mark(graph, node);
1131
1132                 if ((mark & (MARK_REF_ADR | MARK_REF_NON_ADR)) == MARK_REF_ADR) {
1133                         /*
1134                          * this node has no reference mode, but is only
1135                          * referenced by address calculations
1136                          */
1137                         mark_preds = MARK_REF_ADR;
1138                 }  /* if */
1139         }  /* if */
1140
1141         /* mark all predecessors */
1142         for (i = 0, n = get_irn_arity(node); i < n; ++i) {
1143                 ir_node *pred = get_irn_n(node, i);
1144
1145                 mode = get_irn_op_mode(pred);
1146                 if (! mode_is_data(mode))
1147                         continue;
1148
1149                 set_adr_mark(graph, pred, get_adr_mark(graph, pred) | mark_preds);
1150         }  /* for */
1151 }  /* mark_address_calc */
1152
1153 /**
1154  * Post-walker that marks every node that is an address calculation.
1155  *
1156  * Users of a node must be visited first. We ensure this by
1157  * calling it in the post of an outs walk. This should work even in cycles,
1158  * while the normal pre-walk will not.
1159  */
1160 static void count_adr_ops(ir_node *node, void *env) {
1161         graph_entry_t *graph = env;
1162         unsigned mark        = get_adr_mark(graph, node);
1163
1164         if (mark & MARK_ADDRESS_CALC)
1165                 cnt_inc(&graph->cnt[gcnt_pure_adr_ops]);
1166         else if ((mark & (MARK_REF_ADR | MARK_REF_NON_ADR)) == MARK_REF_ADR)
1167                 cnt_inc(&graph->cnt[gcnt_pure_adr_ops]);
1168         else if ((mark & (MARK_REF_ADR | MARK_REF_NON_ADR)) == (MARK_REF_ADR|MARK_REF_NON_ADR))
1169                 cnt_inc(&graph->cnt[gcnt_all_adr_ops]);
1170 }  /* count_adr_ops */
1171
1172 /**
1173  * Called for every graph when the graph is either deleted or stat_dump_snapshot()
1174  * is called, must recalculate all statistic info.
1175  *
1176  * @param global    The global entry
1177  * @param graph     The current entry
1178  */
1179 static void update_graph_stat(graph_entry_t *global, graph_entry_t *graph)
1180 {
1181         node_entry_t *entry;
1182         int i;
1183
1184         /* clear first the alive counter in the graph */
1185         foreach_pset(graph->opcode_hash, entry) {
1186                 cnt_clr(&entry->cnt_alive);
1187         }  /* foreach_pset */
1188
1189         /* set pessimistic values */
1190         graph->is_leaf       = 1;
1191         graph->is_leaf_call  = LCS_UNKNOWN;
1192         graph->is_recursive  = 0;
1193         graph->is_chain_call = 1;
1194         graph->is_strict     = 1;
1195
1196         /* create new block counter */
1197         graph->block_hash = new_pset(block_cmp, 5);
1198
1199         /* we need dominator info */
1200         if (graph->irg != get_const_code_irg()) {
1201                 assure_doms(graph->irg);
1202
1203                 if (status->stat_options & FIRMSTAT_COUNT_EXTBB) {
1204                         /* we need extended basic blocks */
1205                         compute_extbb(graph->irg);
1206
1207                         /* create new extbb counter */
1208                         graph->extbb_hash = new_pset(block_cmp, 5);
1209                 }  /* if */
1210         }  /* if */
1211
1212         /* count the nodes in the graph */
1213         irg_walk_graph(graph->irg, update_node_stat, NULL, graph);
1214
1215 #if 0
1216         /* Uncomment this code if chain-call means call exact one. */
1217         entry = opcode_get_entry(op_Call, graph->opcode_hash);
1218
1219         /* check if we have more than 1 call */
1220         if (cnt_gt(entry->cnt_alive, 1))
1221                 graph->is_chain_call = 0;
1222 #endif
1223
1224         /* recursive functions are never chain calls, leafs don't have calls */
1225         if (graph->is_recursive || graph->is_leaf)
1226                 graph->is_chain_call = 0;
1227
1228         /* assume we walk every graph only ONCE, we could sum here the global count */
1229         foreach_pset(graph->opcode_hash, entry) {
1230                 node_entry_t *g_entry = opcode_get_entry(entry->op, global->opcode_hash);
1231
1232                 /* update the node counter */
1233                 cnt_add(&g_entry->cnt_alive, &entry->cnt_alive);
1234         }  /* foreach_pset */
1235
1236         /* count the number of address calculation */
1237         if (graph->irg != get_const_code_irg()) {
1238                 ir_graph *rem = current_ir_graph;
1239
1240                 assure_irg_outs(graph->irg);
1241
1242                 /* Must be done an the outs graph */
1243                 current_ir_graph = graph->irg;
1244                 irg_out_walk(get_irg_start(graph->irg), NULL, mark_address_calc, graph);
1245                 current_ir_graph = rem;
1246
1247 #ifdef DUMP_ADR_MODE
1248                 /* register the vcg hook and dump the graph for test */
1249                 set_dump_node_vcgattr_hook(stat_adr_mark_hook);
1250                 dump_ir_block_graph(graph->irg, "-adr");
1251                 set_dump_node_vcgattr_hook(NULL);
1252 #endif /* DUMP_ADR_MODE */
1253
1254                 irg_walk_graph(graph->irg, NULL, count_adr_ops, graph);
1255         }  /* if */
1256
1257         /* count the DAG's */
1258         if (status->stat_options & FIRMSTAT_COUNT_DAG)
1259                 count_dags_in_graph(global, graph);
1260
1261         /* calculate the patterns of this graph */
1262         stat_calc_pattern_history(graph->irg);
1263
1264         /* leaf function did not call others */
1265         if (graph->is_leaf)
1266                 graph->is_leaf_call = LCS_NON_LEAF_CALL;
1267         else if (graph->is_leaf_call == LCS_UNKNOWN) {
1268                 /* we still don't know if this graph calls leaf-functions, so enqueue */
1269                 pdeq_putl(status->wait_q, graph);
1270         }  /* if */
1271
1272         /* we have analyzed this graph */
1273         graph->is_analyzed = 1;
1274
1275         /* accumulate all counter's */
1276         for (i = 0; i < _gcnt_last; ++i)
1277                 cnt_add(&global->cnt[i], &graph->cnt[i]);
1278 }  /* update_graph_stat */
1279
1280 /**
1281  * Called for every graph that was on the wait_q in stat_dump_snapshot()
1282  * must finish all statistic info calculations.
1283  *
1284  * @param global    The global entry
1285  * @param graph     The current entry
1286  */
1287 static void update_graph_stat_2(graph_entry_t *global, graph_entry_t *graph)
1288 {
1289         (void) global;
1290         if (graph->is_deleted) {
1291                 /* deleted, ignore */
1292                 return;
1293         }
1294
1295         if (graph->irg) {
1296                 /* count the nodes in the graph */
1297                 irg_walk_graph(graph->irg, update_node_stat_2, NULL, graph);
1298
1299                 if (graph->is_leaf_call == LCS_UNKNOWN)
1300                         graph->is_leaf_call = LCS_LEAF_CALL;
1301         }  /* if */
1302 }  /* update_graph_stat_2 */
1303
1304 /**
1305  * Register a dumper.
1306  */
1307 static void stat_register_dumper(const dumper_t *dumper) {
1308         dumper_t *p = XMALLOC(dumper_t);
1309
1310         memcpy(p, dumper, sizeof(*p));
1311
1312         p->next        = status->dumper;
1313         p->status      = status;
1314         status->dumper = p;
1315
1316         /* FIXME: memory leak */
1317 }  /* stat_register_dumper */
1318
1319 /**
1320  * Dumps the statistics of an IR graph.
1321  */
1322 static void stat_dump_graph(graph_entry_t *entry) {
1323         dumper_t *dumper;
1324
1325         for (dumper = status->dumper; dumper; dumper = dumper->next) {
1326                 if (dumper->dump_graph)
1327                         dumper->dump_graph(dumper, entry);
1328         }  /* for */
1329 }  /* stat_dump_graph */
1330
1331 /**
1332  * Calls all registered dumper functions.
1333  */
1334 static void stat_dump_registered(graph_entry_t *entry) {
1335         dumper_t *dumper;
1336
1337         for (dumper = status->dumper; dumper; dumper = dumper->next) {
1338                 if (dumper->func_map) {
1339                         dump_graph_FUNC func;
1340
1341                         foreach_pset(dumper->func_map, func)
1342                                 func(dumper, entry);
1343                 }  /* if */
1344         }  /* for */
1345 }  /* stat_dump_registered */
1346
1347 /**
1348  * Dumps a constant table.
1349  */
1350 static void stat_dump_consts(const constant_info_t *tbl) {
1351         dumper_t *dumper;
1352
1353         for (dumper = status->dumper; dumper; dumper = dumper->next) {
1354                 if (dumper->dump_const_tbl)
1355                         dumper->dump_const_tbl(dumper, tbl);
1356         }  /* for */
1357 }  /* stat_dump_consts */
1358
1359 /**
1360  * Dumps the parameter distribution
1361  */
1362 static void stat_dump_param_tbl(const distrib_tbl_t *tbl, graph_entry_t *global) {
1363         dumper_t *dumper;
1364
1365         for (dumper = status->dumper; dumper; dumper = dumper->next) {
1366                 if (dumper->dump_param_tbl)
1367                         dumper->dump_param_tbl(dumper, tbl, global);
1368         }  /* for */
1369 }  /* stat_dump_param_tbl */
1370
1371 /**
1372  * Dumps the optimization counter
1373  */
1374 static void stat_dump_opt_cnt(const counter_t *tbl, unsigned len) {
1375         dumper_t *dumper;
1376
1377         for (dumper = status->dumper; dumper; dumper = dumper->next) {
1378                 if (dumper->dump_opt_cnt)
1379                         dumper->dump_opt_cnt(dumper, tbl, len);
1380         }  /* for */
1381 }  /* stat_dump_opt_cnt */
1382
1383 /**
1384  * Initialize the dumper.
1385  */
1386 static void stat_dump_init(const char *name) {
1387         dumper_t *dumper;
1388
1389         for (dumper = status->dumper; dumper; dumper = dumper->next) {
1390                 if (dumper->init)
1391                         dumper->init(dumper, name);
1392         }  /* for */
1393 }  /* stat_dump_init */
1394
1395 /**
1396  * Finish the dumper.
1397  */
1398 static void stat_dump_finish(void) {
1399         dumper_t *dumper;
1400
1401         for (dumper = status->dumper; dumper; dumper = dumper->next) {
1402                 if (dumper->finish)
1403                         dumper->finish(dumper);
1404         }  /* for */
1405 }  /* stat_dump_finish */
1406
1407 /**
1408  * Register an additional function for all dumper.
1409  */
1410 void stat_register_dumper_func(dump_graph_FUNC func) {
1411         dumper_t *dumper;
1412
1413         for (dumper = status->dumper; dumper; dumper = dumper->next) {
1414                 if (! dumper->func_map)
1415                         dumper->func_map = pset_new_ptr(3);
1416                 pset_insert_ptr(dumper->func_map, func);
1417         }  /* for */
1418 }  /* stat_register_dumper_func */
1419
1420 /* ---------------------------------------------------------------------- */
1421
1422 /*
1423  * Helper: get an ir_op from an opcode.
1424  */
1425 ir_op *stat_get_op_from_opcode(ir_opcode code) {
1426         return opcode_find_entry(code, status->ir_op_hash);
1427 }  /* stat_get_op_from_opcode */
1428
1429 /**
1430  * Hook: A new IR op is registered.
1431  *
1432  * @param ctx  the hook context
1433  * @param op   the new IR opcode that was created.
1434  */
1435 static void stat_new_ir_op(void *ctx, ir_op *op) {
1436         (void) ctx;
1437         if (! status->stat_options)
1438                 return;
1439
1440         STAT_ENTER;
1441         {
1442                 graph_entry_t *graph = graph_get_entry(NULL, status->irg_hash);
1443
1444                 /* execute for side effect :-) */
1445                 (void)opcode_get_entry(op, graph->opcode_hash);
1446
1447                 pset_insert(status->ir_op_hash, op, op->code);
1448         }
1449         STAT_LEAVE;
1450 }  /* stat_new_ir_op */
1451
1452 /**
1453  * Hook: An IR op is freed.
1454  *
1455  * @param ctx  the hook context
1456  * @param op   the IR opcode that is freed
1457  */
1458 static void stat_free_ir_op(void *ctx, ir_op *op) {
1459         (void) ctx;
1460         (void) op;
1461         if (! status->stat_options)
1462                 return;
1463
1464         STAT_ENTER;
1465         {
1466         }
1467         STAT_LEAVE;
1468 }  /* stat_free_ir_op */
1469
1470 /**
1471  * Hook: A new node is created.
1472  *
1473  * @param ctx   the hook context
1474  * @param irg   the IR graph on which the node is created
1475  * @param node  the new IR node that was created
1476  */
1477 static void stat_new_node(void *ctx, ir_graph *irg, ir_node *node) {
1478         (void) ctx;
1479         (void) irg;
1480         if (! status->stat_options)
1481                 return;
1482
1483         /* do NOT count during dead node elimination */
1484         if (status->in_dead_node_elim)
1485                 return;
1486
1487         STAT_ENTER;
1488         {
1489                 node_entry_t *entry;
1490                 graph_entry_t *graph;
1491                 ir_op *op = stat_get_irn_op(node);
1492
1493                 /* increase global value */
1494                 graph = graph_get_entry(NULL, status->irg_hash);
1495                 entry = opcode_get_entry(op, graph->opcode_hash);
1496                 cnt_inc(&entry->new_node);
1497
1498                 /* increase local value */
1499                 graph = graph_get_entry(current_ir_graph, status->irg_hash);
1500                 entry = opcode_get_entry(op, graph->opcode_hash);
1501                 cnt_inc(&entry->new_node);
1502         }
1503         STAT_LEAVE;
1504 }  /* stat_new_node */
1505
1506 /**
1507  * Hook: A node is changed into a Id node
1508  *
1509  * @param ctx   the hook context
1510  * @param node  the IR node that will be turned into an ID
1511  */
1512 static void stat_turn_into_id(void *ctx, ir_node *node) {
1513         (void) ctx;
1514         if (! status->stat_options)
1515                 return;
1516
1517         STAT_ENTER;
1518         {
1519                 node_entry_t *entry;
1520                 graph_entry_t *graph;
1521                 ir_op *op = stat_get_irn_op(node);
1522
1523                 /* increase global value */
1524                 graph = graph_get_entry(NULL, status->irg_hash);
1525                 entry = opcode_get_entry(op, graph->opcode_hash);
1526                 cnt_inc(&entry->into_Id);
1527
1528                 /* increase local value */
1529                 graph = graph_get_entry(current_ir_graph, status->irg_hash);
1530                 entry = opcode_get_entry(op, graph->opcode_hash);
1531                 cnt_inc(&entry->into_Id);
1532         }
1533         STAT_LEAVE;
1534 }  /* stat_turn_into_id */
1535
1536 /**
1537  * Hook: A node is normalized
1538  *
1539  * @param ctx   the hook context
1540  * @param node  the IR node that was normalized
1541  */
1542 static void stat_normalize(void *ctx, ir_node *node) {
1543         (void) ctx;
1544         if (! status->stat_options)
1545                 return;
1546
1547         STAT_ENTER;
1548         {
1549                 node_entry_t *entry;
1550                 graph_entry_t *graph;
1551                 ir_op *op = stat_get_irn_op(node);
1552
1553                 /* increase global value */
1554                 graph = graph_get_entry(NULL, status->irg_hash);
1555                 entry = opcode_get_entry(op, graph->opcode_hash);
1556                 cnt_inc(&entry->normalized);
1557
1558                 /* increase local value */
1559                 graph = graph_get_entry(current_ir_graph, status->irg_hash);
1560                 entry = opcode_get_entry(op, graph->opcode_hash);
1561                 cnt_inc(&entry->normalized);
1562         }
1563         STAT_LEAVE;
1564 }  /* stat_normalize */
1565
1566 /**
1567  * Hook: A new graph was created
1568  *
1569  * @param ctx  the hook context
1570  * @param irg  the new IR graph that was created
1571  * @param ent  the entity of this graph
1572  */
1573 static void stat_new_graph(void *ctx, ir_graph *irg, ir_entity *ent) {
1574         (void) ctx;
1575         if (! status->stat_options)
1576                 return;
1577
1578         STAT_ENTER;
1579         {
1580                 /* execute for side effect :-) */
1581                 graph_entry_t * graph = graph_get_entry(irg, status->irg_hash);
1582
1583                 graph->ent           = ent;
1584                 graph->is_deleted    = 0;
1585                 graph->is_leaf       = 0;
1586                 graph->is_leaf_call  = 0;
1587                 graph->is_recursive  = 0;
1588                 graph->is_chain_call = 0;
1589                 graph->is_strict     = 1;
1590                 graph->is_analyzed   = 0;
1591         }
1592         STAT_LEAVE;
1593 }  /* stat_new_graph */
1594
1595 /**
1596  * Hook: A graph will be deleted
1597  *
1598  * @param ctx  the hook context
1599  * @param irg  the IR graph that will be deleted
1600  *
1601  * Note that we still hold the information for this graph
1602  * in our hash maps, only a flag is set which prevents this
1603  * information from being changed, it's "frozen" from now.
1604  */
1605 static void stat_free_graph(void *ctx, ir_graph *irg) {
1606         (void) ctx;
1607         if (! status->stat_options)
1608                 return;
1609
1610         STAT_ENTER;
1611         {
1612                 graph_entry_t *graph  = graph_get_entry(irg, status->irg_hash);
1613                 graph_entry_t *global = graph_get_entry(NULL, status->irg_hash);
1614
1615                 graph->is_deleted = 1;
1616
1617                 if (status->stat_options & FIRMSTAT_COUNT_DELETED) {
1618                         /* count the nodes of the graph yet, it will be destroyed later */
1619                         update_graph_stat(global, graph);
1620                 }  /* if */
1621         }
1622         STAT_LEAVE;
1623 }  /* stat_free_graph */
1624
1625 /**
1626  * Hook: A walk over a graph is initiated. Do not count walks from statistic code.
1627  *
1628  * @param ctx  the hook context
1629  * @param irg  the IR graph that will be walked
1630  * @param pre  the pre walker
1631  * @param post the post walker
1632  */
1633 static void stat_irg_walk(void *ctx, ir_graph *irg, generic_func *pre, generic_func *post)
1634 {
1635         (void) ctx;
1636         (void) pre;
1637         (void) post;
1638         if (! status->stat_options)
1639                 return;
1640
1641         STAT_ENTER_SINGLE;
1642         {
1643                 graph_entry_t *graph = graph_get_entry(irg, status->irg_hash);
1644
1645                 cnt_inc(&graph->cnt[gcnt_acc_walked]);
1646         }
1647         STAT_LEAVE;
1648 }  /* stat_irg_walk */
1649
1650 /**
1651  * Hook: A walk over a graph in block-wise order is initiated. Do not count walks from statistic code.
1652  *
1653  * @param ctx  the hook context
1654  * @param irg  the IR graph that will be walked
1655  * @param pre  the pre walker
1656  * @param post the post walker
1657  */
1658 static void stat_irg_walk_blkwise(void *ctx, ir_graph *irg, generic_func *pre, generic_func *post)
1659 {
1660         /* for now, do NOT differentiate between blockwise and normal */
1661         stat_irg_walk(ctx, irg, pre, post);
1662 }  /* stat_irg_walk_blkwise */
1663
1664 /**
1665  * Hook: A walk over the graph's blocks is initiated. Do not count walks from statistic code.
1666  *
1667  * @param ctx  the hook context
1668  * @param irg  the IR graph that will be walked
1669  * @param node the IR node
1670  * @param pre  the pre walker
1671  * @param post the post walker
1672  */
1673 static void stat_irg_block_walk(void *ctx, ir_graph *irg, ir_node *node, generic_func *pre, generic_func *post)
1674 {
1675         (void) ctx;
1676         (void) node;
1677         (void) pre;
1678         (void) post;
1679         if (! status->stat_options)
1680                 return;
1681
1682         STAT_ENTER_SINGLE;
1683         {
1684                 graph_entry_t *graph = graph_get_entry(irg, status->irg_hash);
1685
1686                 cnt_inc(&graph->cnt[gcnt_acc_walked_blocks]);
1687         }
1688         STAT_LEAVE;
1689 }  /* stat_irg_block_walk */
1690
1691 /**
1692  * Called for every node that is removed due to an optimization.
1693  *
1694  * @param n     the IR node that will be removed
1695  * @param hmap  the hash map containing ir_op* -> opt_entry_t*
1696  * @param kind  the optimization kind
1697  */
1698 static void removed_due_opt(ir_node *n, hmap_opt_entry_t *hmap, hook_opt_kind kind) {
1699         opt_entry_t *entry;
1700         ir_op *op = stat_get_irn_op(n);
1701
1702         /* ignore CSE for Constants */
1703         if (kind == HOOK_OPT_CSE && (is_Const(n) || is_SymConst(n)))
1704                 return;
1705
1706         /* increase global value */
1707         entry = opt_get_entry(op, hmap);
1708         cnt_inc(&entry->count);
1709 }  /* removed_due_opt */
1710
1711 /**
1712  * Hook: Some nodes were optimized into some others due to an optimization.
1713  *
1714  * @param ctx  the hook context
1715  */
1716 static void stat_merge_nodes(
1717     void *ctx,
1718     ir_node **new_node_array, int new_num_entries,
1719     ir_node **old_node_array, int old_num_entries,
1720     hook_opt_kind opt)
1721 {
1722         (void) ctx;
1723         if (! status->stat_options)
1724                 return;
1725
1726         STAT_ENTER;
1727         {
1728                 int i, j;
1729                 graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash);
1730
1731                 cnt_inc(&status->num_opts[opt]);
1732                 if (status->reassoc_run)
1733                         opt = HOOK_OPT_REASSOC;
1734
1735                 for (i = 0; i < old_num_entries; ++i) {
1736                         /* nodes might be in new and old, so if we found a node
1737                            in both sets, this one  is NOT removed */
1738                         for (j = 0; j < new_num_entries; ++j) {
1739                                 if (old_node_array[i] == new_node_array[j])
1740                                         break;
1741                         }  /* for */
1742                         if (j >= new_num_entries) {
1743                                 int xopt = opt;
1744
1745                                 /* sometimes we did not detect, that it is replaced by a Const */
1746                                 if (opt == HOOK_OPT_CONFIRM && new_num_entries == 1) {
1747                                         ir_op *op = get_irn_op(new_node_array[0]);
1748
1749                                         if (op == op_Const || op == op_SymConst)
1750                                                 xopt = HOOK_OPT_CONFIRM_C;
1751                                 }  /* if */
1752
1753                                 removed_due_opt(old_node_array[i], graph->opt_hash[xopt], xopt);
1754                         }  /* if */
1755                 }  /* for */
1756         }
1757         STAT_LEAVE;
1758 }  /* stat_merge_nodes */
1759
1760 /**
1761  * Hook: Reassociation is started/stopped.
1762  *
1763  * @param ctx   the hook context
1764  * @param flag  if non-zero, reassociation is started else stopped
1765  */
1766 static void stat_reassociate(void *ctx, int flag) {
1767         (void) ctx;
1768         if (! status->stat_options)
1769                 return;
1770
1771         STAT_ENTER;
1772         {
1773                 status->reassoc_run = flag;
1774         }
1775         STAT_LEAVE;
1776 }  /* stat_reassociate */
1777
1778 /**
1779  * Hook: A node was lowered into other nodes
1780  *
1781  * @param ctx  the hook context
1782  * @param node the IR node that will be lowered
1783  */
1784 static void stat_lower(void *ctx, ir_node *node) {
1785         (void) ctx;
1786         if (! status->stat_options)
1787                 return;
1788
1789         STAT_ENTER;
1790         {
1791                 graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash);
1792
1793                 removed_due_opt(node, graph->opt_hash[HOOK_LOWERED], HOOK_LOWERED);
1794         }
1795         STAT_LEAVE;
1796 }  /* stat_lower */
1797
1798 /**
1799  * Hook: A graph was inlined.
1800  *
1801  * @param ctx  the hook context
1802  * @param call the IR call that will re changed into the body of
1803  *             the called IR graph
1804  * @param called_irg  the IR graph representing the called routine
1805  */
1806 static void stat_inline(void *ctx, ir_node *call, ir_graph *called_irg)
1807 {
1808         (void) ctx;
1809         if (! status->stat_options)
1810                 return;
1811
1812         STAT_ENTER;
1813         {
1814                 ir_graph *irg = get_irn_irg(call);
1815                 graph_entry_t *i_graph = graph_get_entry(called_irg, status->irg_hash);
1816                 graph_entry_t *graph   = graph_get_entry(irg, status->irg_hash);
1817
1818                 cnt_inc(&graph->cnt[gcnt_acc_got_inlined]);
1819                 cnt_inc(&i_graph->cnt[gcnt_acc_was_inlined]);
1820         }
1821         STAT_LEAVE;
1822 }  /* stat_inline */
1823
1824 /**
1825  * Hook: A graph with tail-recursions was optimized.
1826  *
1827  * @param ctx  the hook context
1828  */
1829 static void stat_tail_rec(void *ctx, ir_graph *irg, int n_calls) {
1830         (void) ctx;
1831         if (! status->stat_options)
1832                 return;
1833
1834         STAT_ENTER;
1835         {
1836                 graph_entry_t *graph = graph_get_entry(irg, status->irg_hash);
1837
1838                 graph->num_tail_recursion += n_calls;
1839         }
1840         STAT_LEAVE;
1841 }  /* stat_tail_rec */
1842
1843 /**
1844  * Strength reduction was performed on an iteration variable.
1845  *
1846  * @param ctx  the hook context
1847  */
1848 static void stat_strength_red(void *ctx, ir_graph *irg, ir_node *strong) {
1849         (void) ctx;
1850         if (! status->stat_options)
1851                 return;
1852
1853         STAT_ENTER;
1854         {
1855                 graph_entry_t *graph = graph_get_entry(irg, status->irg_hash);
1856                 cnt_inc(&graph->cnt[gcnt_acc_strength_red]);
1857
1858                 removed_due_opt(strong, graph->opt_hash[HOOK_OPT_STRENGTH_RED], HOOK_OPT_STRENGTH_RED);
1859         }
1860         STAT_LEAVE;
1861 }  /* stat_strength_red */
1862
1863 /**
1864  * Hook: Start/Stop the dead node elimination.
1865  *
1866  * @param ctx  the hook context
1867  */
1868 static void stat_dead_node_elim(void *ctx, ir_graph *irg, int start) {
1869         (void) ctx;
1870         (void) irg;
1871         if (! status->stat_options)
1872                 return;
1873
1874         status->in_dead_node_elim = (start != 0);
1875 }  /* stat_dead_node_elim */
1876
1877 /**
1878  * Hook: if-conversion was tried.
1879  */
1880 static void stat_if_conversion(void *context, ir_graph *irg, ir_node *phi,
1881                                int pos, ir_node *mux, if_result_t reason)
1882 {
1883         (void) context;
1884         (void) phi;
1885         (void) pos;
1886         (void) mux;
1887         if (! status->stat_options)
1888                 return;
1889
1890         STAT_ENTER;
1891         {
1892                 graph_entry_t *graph = graph_get_entry(irg, status->irg_hash);
1893
1894                 cnt_inc(&graph->cnt[gcnt_if_conv + reason]);
1895         }
1896         STAT_LEAVE;
1897 }  /* stat_if_conversion */
1898
1899 /**
1900  * Hook: real function call was optimized.
1901  */
1902 static void stat_func_call(void *context, ir_graph *irg, ir_node *call)
1903 {
1904         (void) context;
1905         (void) call;
1906         if (! status->stat_options)
1907                 return;
1908
1909         STAT_ENTER;
1910         {
1911                 graph_entry_t *graph = graph_get_entry(irg, status->irg_hash);
1912
1913                 cnt_inc(&graph->cnt[gcnt_acc_real_func_call]);
1914         }
1915         STAT_LEAVE;
1916 }  /* stat_func_call */
1917
1918 /**
1919  * Hook: A multiply was replaced by a series of Shifts/Adds/Subs.
1920  *
1921  * @param ctx  the hook context
1922  */
1923 static void stat_arch_dep_replace_mul_with_shifts(void *ctx, ir_node *mul) {
1924         (void) ctx;
1925         if (! status->stat_options)
1926                 return;
1927
1928         STAT_ENTER;
1929         {
1930                 graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash);
1931                 removed_due_opt(mul, graph->opt_hash[HOOK_OPT_ARCH_DEP], HOOK_OPT_ARCH_DEP);
1932         }
1933         STAT_LEAVE;
1934 }  /* stat_arch_dep_replace_mul_with_shifts */
1935
1936 /**
1937  * Hook: A division by const was replaced.
1938  *
1939  * @param ctx   the hook context
1940  * @param node  the division node that will be optimized
1941  */
1942 static void stat_arch_dep_replace_division_by_const(void *ctx, ir_node *node) {
1943         (void) ctx;
1944         if (! status->stat_options)
1945                 return;
1946
1947         STAT_ENTER;
1948         {
1949                 graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash);
1950                 removed_due_opt(node, graph->opt_hash[HOOK_OPT_ARCH_DEP], HOOK_OPT_ARCH_DEP);
1951         }
1952         STAT_LEAVE;
1953 }  /* stat_arch_dep_replace_division_by_const */
1954
1955 /*
1956  * Update the register pressure of a block.
1957  *
1958  * @param irg        the irg containing the block
1959  * @param block      the block for which the reg pressure should be set
1960  * @param pressure   the pressure
1961  * @param class_name the name of the register class
1962  */
1963 void stat_be_block_regpressure(ir_graph *irg, ir_node *block, int pressure, const char *class_name)
1964 {
1965         if (! status->stat_options)
1966                 return;
1967
1968         STAT_ENTER;
1969         {
1970                 graph_entry_t        *graph = graph_get_entry(irg, status->irg_hash);
1971                 be_block_entry_t     *block_ent;
1972                 reg_pressure_entry_t *rp_ent;
1973
1974                 block_ent = be_block_get_entry(&status->be_data, get_irn_node_nr(block), graph->be_block_hash);
1975                 rp_ent    = obstack_alloc(&status->be_data, sizeof(*rp_ent));
1976                 memset(rp_ent, 0, sizeof(*rp_ent));
1977
1978                 rp_ent->class_name = class_name;
1979                 rp_ent->pressure   = pressure;
1980
1981                 pset_insert(block_ent->reg_pressure, rp_ent, HASH_PTR(class_name));
1982         }
1983         STAT_LEAVE;
1984 }  /* stat_be_block_regpressure */
1985
1986 /**
1987  * Update the distribution of ready nodes of a block
1988  *
1989  * @param irg        the irg containing the block
1990  * @param block      the block for which the reg pressure should be set
1991  * @param num_ready  the number of ready nodes
1992  */
1993 void stat_be_block_sched_ready(ir_graph *irg, ir_node *block, int num_ready)
1994 {
1995         if (! status->stat_options)
1996                 return;
1997
1998         STAT_ENTER;
1999         {
2000                 graph_entry_t    *graph = graph_get_entry(irg, status->irg_hash);
2001                 be_block_entry_t *block_ent;
2002
2003                 block_ent = be_block_get_entry(&status->be_data, get_irn_node_nr(block), graph->be_block_hash);
2004
2005                 /* increase the counter of corresponding number of ready nodes */
2006                 stat_inc_int_distrib_tbl(block_ent->sched_ready, num_ready);
2007         }
2008         STAT_LEAVE;
2009 }  /* stat_be_block_sched_ready */
2010
2011 /**
2012  * Update the permutation statistic of a block.
2013  *
2014  * @param class_name the name of the register class
2015  * @param n_regs     number of registers in the register class
2016  * @param perm       the perm node
2017  * @param block      the block containing the perm
2018  * @param size       the size of the perm
2019  * @param real_size  number of pairs with different registers
2020  */
2021 void stat_be_block_stat_perm(const char *class_name, int n_regs, ir_node *perm, ir_node *block,
2022                              int size, int real_size)
2023 {
2024         if (! status->stat_options)
2025                 return;
2026
2027         STAT_ENTER;
2028         {
2029                 graph_entry_t      *graph = graph_get_entry(get_irn_irg(block), status->irg_hash);
2030                 be_block_entry_t   *block_ent;
2031                 perm_class_entry_t *pc_ent;
2032                 perm_stat_entry_t  *ps_ent;
2033
2034                 block_ent = be_block_get_entry(&status->be_data, get_irn_node_nr(block), graph->be_block_hash);
2035                 pc_ent    = perm_class_get_entry(&status->be_data, class_name, block_ent->perm_class_stat);
2036                 ps_ent    = perm_stat_get_entry(&status->be_data, perm, pc_ent->perm_stat);
2037
2038                 pc_ent->n_regs = n_regs;
2039
2040                 /* update information */
2041                 ps_ent->size      = size;
2042                 ps_ent->real_size = real_size;
2043         }
2044         STAT_LEAVE;
2045 }  /* stat_be_block_stat_perm */
2046
2047 /**
2048  * Update the permutation statistic of a single perm.
2049  *
2050  * @param class_name the name of the register class
2051  * @param perm       the perm node
2052  * @param block      the block containing the perm
2053  * @param is_chain   1 if chain, 0 if cycle
2054  * @param size       length of the cycle/chain
2055  * @param n_ops      the number of ops representing this cycle/chain after lowering
2056  */
2057 void stat_be_block_stat_permcycle(const char *class_name, ir_node *perm, ir_node *block,
2058                                   int is_chain, int size, int n_ops)
2059 {
2060         if (! status->stat_options)
2061                 return;
2062
2063         STAT_ENTER;
2064         {
2065                 graph_entry_t      *graph = graph_get_entry(get_irn_irg(block), status->irg_hash);
2066                 be_block_entry_t   *block_ent;
2067                 perm_class_entry_t *pc_ent;
2068                 perm_stat_entry_t  *ps_ent;
2069
2070                 block_ent = be_block_get_entry(&status->be_data, get_irn_node_nr(block), graph->be_block_hash);
2071                 pc_ent    = perm_class_get_entry(&status->be_data, class_name, block_ent->perm_class_stat);
2072                 ps_ent    = perm_stat_get_entry(&status->be_data, perm, pc_ent->perm_stat);
2073
2074                 if (is_chain) {
2075                         ps_ent->n_copies += n_ops;
2076                         stat_inc_int_distrib_tbl(ps_ent->chains, size);
2077                 } else {
2078                         ps_ent->n_exchg += n_ops;
2079                         stat_inc_int_distrib_tbl(ps_ent->cycles, size);
2080                 }  /* if */
2081         }
2082         STAT_LEAVE;
2083 }  /* stat_be_block_stat_permcycle */
2084
2085 /* Dumps a statistics snapshot. */
2086 void stat_dump_snapshot(const char *name, const char *phase)
2087 {
2088         char fname[2048];
2089         const char *p;
2090         int l;
2091
2092         if (! status->stat_options)
2093                 return;
2094
2095         STAT_ENTER;
2096         {
2097                 graph_entry_t *entry;
2098                 graph_entry_t *global = graph_get_entry(NULL, status->irg_hash);
2099
2100                 /*
2101                  * The constant counter is only global, so we clear it here.
2102                  * Note that it does NOT contain the constants in DELETED
2103                  * graphs due to this.
2104                  */
2105                 if (status->stat_options & FIRMSTAT_COUNT_CONSTS)
2106                         stat_const_clear(status);
2107
2108                 /* build the name */
2109                 p = strrchr(name, '/');
2110 #ifdef _WIN32
2111                 {
2112                         const char *q;
2113
2114                         q = strrchr(name, '\\');
2115
2116                         /* NULL might be not the smallest pointer */
2117                         if (q && (!p || q > p))
2118                                 p = q;
2119                 }
2120 #endif /* _WIN32 */
2121                 if (p) {
2122                         ++p;
2123                         l = p - name;
2124
2125                         if (l > (int) (sizeof(fname) - 1))
2126                                 l = sizeof(fname) - 1;
2127
2128                         memcpy(fname, name, l);
2129                         fname[l] = '\0';
2130                 } else {
2131                         fname[0] = '\0';
2132                         p = name;
2133                 }  /* if */
2134                 strncat(fname, "firmstat-", sizeof(fname)-1);
2135                 strncat(fname, phase, sizeof(fname)-1);
2136                 strncat(fname, "-", sizeof(fname)-1);
2137                 strncat(fname, p, sizeof(fname)-1);
2138
2139                 stat_dump_init(fname);
2140
2141                 /* calculate the graph statistics */
2142                 for (entry = pset_first(status->irg_hash); entry; entry = pset_next(status->irg_hash)) {
2143                         if (entry->irg == NULL) {
2144                                 /* special entry for the global count */
2145                                 continue;
2146                         }  /* if */
2147                         if (! entry->is_deleted) {
2148                                 /* the graph is still alive, count the nodes on it */
2149                                 update_graph_stat(global, entry);
2150                         }  /* if */
2151                 }  /* for */
2152
2153                 /* some calculations are dependent, we pushed them on the wait_q */
2154                 while (! pdeq_empty(status->wait_q)) {
2155                         entry = pdeq_getr(status->wait_q);
2156
2157                         update_graph_stat_2(global, entry);
2158                 }  /* while */
2159
2160                 /* dump per graph */
2161                 for (entry = pset_first(status->irg_hash); entry; entry = pset_next(status->irg_hash)) {
2162                         if (entry->irg == NULL) {
2163                                 /* special entry for the global count */
2164                                 continue;
2165                         }  /* if */
2166
2167                         if (! entry->is_deleted || status->stat_options & FIRMSTAT_COUNT_DELETED) {
2168                                 stat_dump_graph(entry);
2169                                 stat_dump_registered(entry);
2170                         }  /* if */
2171
2172                         if (! entry->is_deleted) {
2173                                 /* clear the counter that are not accumulated */
2174                                 graph_clear_entry(entry, 0);
2175                         }  /* if */
2176                 }  /* for */
2177
2178                 /* dump global */
2179                 stat_dump_graph(global);
2180
2181                 /* dump the const info */
2182                 if (status->stat_options & FIRMSTAT_COUNT_CONSTS)
2183                         stat_dump_consts(&status->const_info);
2184
2185                 /* dump the parameter distribution */
2186                 stat_dump_param_tbl(status->dist_param_cnt, global);
2187
2188                 /* dump the optimization counter and clear them */
2189                 stat_dump_opt_cnt(status->num_opts, ARR_SIZE(status->num_opts));
2190                 clear_optimization_counter();
2191
2192                 stat_dump_finish();
2193
2194                 stat_finish_pattern_history(fname);
2195
2196                 /* clear the global counters here */
2197                 {
2198                         node_entry_t *entry;
2199
2200                         for (entry = pset_first(global->opcode_hash); entry; entry = pset_next(global->opcode_hash)) {
2201                                 opcode_clear_entry(entry);
2202                         }  /* for */
2203                         /* clear all global counter */
2204                         graph_clear_entry(global, /*all=*/1);
2205                 }
2206         }
2207         STAT_LEAVE;
2208 }  /* stat_dump_snapshot */
2209
2210 /** the hook entries for the Firm statistics module */
2211 static hook_entry_t stat_hooks[hook_last];
2212
2213 /* initialize the statistics module. */
2214 void firm_init_stat(unsigned enable_options)
2215 {
2216 #define X(a)  a, sizeof(a)-1
2217 #define HOOK(h, fkt) \
2218         stat_hooks[h].hook._##h = fkt; register_hook(h, &stat_hooks[h])
2219         unsigned num = 0;
2220
2221         if (! (enable_options & FIRMSTAT_ENABLED))
2222                 return;
2223
2224         status = XMALLOCZ(stat_info_t);
2225
2226         /* enable statistics */
2227         status->stat_options = enable_options & FIRMSTAT_ENABLED ? enable_options : 0;
2228
2229         /* register all hooks */
2230         HOOK(hook_new_ir_op,                          stat_new_ir_op);
2231         HOOK(hook_free_ir_op,                         stat_free_ir_op);
2232         HOOK(hook_new_node,                           stat_new_node);
2233         HOOK(hook_turn_into_id,                       stat_turn_into_id);
2234         HOOK(hook_normalize,                          stat_normalize);
2235         HOOK(hook_new_graph,                          stat_new_graph);
2236         HOOK(hook_free_graph,                         stat_free_graph);
2237         HOOK(hook_irg_walk,                           stat_irg_walk);
2238         HOOK(hook_irg_walk_blkwise,                   stat_irg_walk_blkwise);
2239         HOOK(hook_irg_block_walk,                     stat_irg_block_walk);
2240         HOOK(hook_merge_nodes,                        stat_merge_nodes);
2241         HOOK(hook_reassociate,                        stat_reassociate);
2242         HOOK(hook_lower,                              stat_lower);
2243         HOOK(hook_inline,                             stat_inline);
2244         HOOK(hook_tail_rec,                           stat_tail_rec);
2245         HOOK(hook_strength_red,                       stat_strength_red);
2246         HOOK(hook_dead_node_elim,                     stat_dead_node_elim);
2247         HOOK(hook_if_conversion,                      stat_if_conversion);
2248         HOOK(hook_func_call,                          stat_func_call);
2249         HOOK(hook_arch_dep_replace_mul_with_shifts,   stat_arch_dep_replace_mul_with_shifts);
2250         HOOK(hook_arch_dep_replace_division_by_const, stat_arch_dep_replace_division_by_const);
2251
2252         obstack_init(&status->cnts);
2253         obstack_init(&status->be_data);
2254
2255         /* create the hash-tables */
2256         status->irg_hash   = new_pset(graph_cmp, 8);
2257         status->ir_op_hash = new_pset(opcode_cmp_2, 1);
2258
2259         /* create the wait queue */
2260         status->wait_q     = new_pdeq();
2261
2262         if (enable_options & FIRMSTAT_COUNT_STRONG_OP) {
2263                 /* build the pseudo-ops */
2264
2265                 _op_Phi0.code    = --num;
2266                 _op_Phi0.name    = new_id_from_chars(X("Phi0"));
2267
2268                 _op_PhiM.code    = --num;
2269                 _op_PhiM.name    = new_id_from_chars(X("PhiM"));
2270
2271                 _op_ProjM.code   = --num;
2272                 _op_ProjM.name   = new_id_from_chars(X("ProjM"));
2273
2274                 _op_MulC.code    = --num;
2275                 _op_MulC.name    = new_id_from_chars(X("MulC"));
2276
2277                 _op_DivC.code    = --num;
2278                 _op_DivC.name    = new_id_from_chars(X("DivC"));
2279
2280                 _op_ModC.code    = --num;
2281                 _op_ModC.name    = new_id_from_chars(X("ModC"));
2282
2283                 _op_DivModC.code = --num;
2284                 _op_DivModC.name = new_id_from_chars(X("DivModC"));
2285
2286                 _op_QuotC.code   = --num;
2287                 _op_QuotC.name   = new_id_from_chars(X("QuotC"));
2288
2289                 status->op_Phi0    = &_op_Phi0;
2290                 status->op_PhiM    = &_op_PhiM;
2291                 status->op_ProjM   = &_op_ProjM;
2292                 status->op_MulC    = &_op_MulC;
2293                 status->op_DivC    = &_op_DivC;
2294                 status->op_ModC    = &_op_ModC;
2295                 status->op_DivModC = &_op_DivModC;
2296                 status->op_QuotC   = &_op_QuotC;
2297         } else {
2298                 status->op_Phi0    = NULL;
2299                 status->op_PhiM    = NULL;
2300                 status->op_ProjM   = NULL;
2301                 status->op_MulC    = NULL;
2302                 status->op_DivC    = NULL;
2303                 status->op_ModC    = NULL;
2304                 status->op_DivModC = NULL;
2305                 status->op_QuotC   = NULL;
2306         }  /* if */
2307
2308         /* for Florian: count the Sel depth */
2309         if (enable_options & FIRMSTAT_COUNT_SELS) {
2310                 _op_SelSel.code    = --num;
2311                 _op_SelSel.name    = new_id_from_chars(X("Sel(Sel)"));
2312
2313                 _op_SelSelSel.code = --num;
2314                 _op_SelSelSel.name = new_id_from_chars(X("Sel(Sel(Sel))"));
2315
2316                 status->op_SelSel    = &_op_SelSel;
2317                 status->op_SelSelSel = &_op_SelSelSel;
2318         } else {
2319                 status->op_SelSel    = NULL;
2320                 status->op_SelSelSel = NULL;
2321         }  /* if */
2322
2323         /* register the dumper */
2324         stat_register_dumper(&simple_dumper);
2325
2326         if (enable_options & FIRMSTAT_CSV_OUTPUT)
2327                 stat_register_dumper(&csv_dumper);
2328
2329         /* initialize the pattern hash */
2330         stat_init_pattern_history(enable_options & FIRMSTAT_PATTERN_ENABLED);
2331
2332         /* initialize the Const options */
2333         if (enable_options & FIRMSTAT_COUNT_CONSTS)
2334                 stat_init_const_cnt(status);
2335
2336         /* distribution table for parameter counts */
2337         status->dist_param_cnt = stat_new_int_distrib_tbl();
2338
2339         clear_optimization_counter();
2340
2341 #undef HOOK
2342 #undef X
2343 }  /* firm_init_stat */
2344
2345 /**
2346  * Frees all dumper structures.
2347  */
2348 static void stat_term_dumper(void) {
2349         dumper_t *dumper, *next_dumper;
2350
2351         for (dumper = status->dumper; dumper; /* iteration done in loop body */ ) {
2352                 if (dumper->func_map)
2353                         del_pset(dumper->func_map);
2354
2355                 next_dumper = dumper->next;
2356                 free(dumper);
2357                 dumper = next_dumper;
2358         }  /* for */
2359 }  /* stat_term_dumper */
2360
2361
2362 /* Terminates the statistics module, frees all memory. */
2363 void stat_term(void) {
2364         if (status != (stat_info_t *)&status_disable) {
2365                 obstack_free(&status->be_data, NULL);
2366                 obstack_free(&status->cnts, NULL);
2367
2368                 stat_term_dumper();
2369
2370                 xfree(status);
2371                 status = (stat_info_t *)&status_disable;
2372         }
2373 }  /* stat_term */
2374
2375 /* returns 1 if statistics were initialized, 0 otherwise */
2376 int stat_is_active(void) {
2377         return status != (stat_info_t *)&status_disable;
2378 }  /* stat_is_active */
2379
2380 #else
2381
2382 /* initialize the statistics module. */
2383 void firm_init_stat(unsigned enable_options) {}
2384
2385 /* Dumps a statistics snapshot */
2386 void stat_dump_snapshot(const char *name, const char *phase) {}
2387
2388 /* terminates the statistics module, frees all memory */
2389 void stat_term(void);
2390
2391 #endif /* FIRM_STATISTICS */