Fixed compiling without statistics
[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 # include <string.h>
17
18 # include "irop_t.h"
19 # include "irnode_t.h"
20 # include "irgraph_t.h"
21 # include "pset.h"
22 # include "irprog.h"
23
24 #include <stdio.h>
25 #include <stdlib.h>
26
27 #undef obstack_chunk_alloc
28 #undef obstack_chunk_free
29 #define obstack_chunk_alloc     malloc
30 #define obstack_chunk_free      free
31 #include <obstack.h>
32
33 #ifdef FIRM_STATISTICS
34
35 #include "firmstat.h"
36
37 /*
38  * 64 bit should be enough for now
39  */
40 #define STAT_CNT_NUM 2
41
42 typedef struct _counter_t {
43   unsigned cnt[STAT_CNT_NUM];
44 } counter_t;
45
46 /*
47  * An entry for ir_nodes
48  */
49 typedef struct _node_entry_t {
50   counter_t   new_node;         /**< amount of new nodes for this entry */
51   counter_t   into_Id;          /**< amount of nodes that turned into Id's for this entry */
52   const ir_op *op;              /**< the op for this entry */
53 } node_entry_t;
54
55 /*
56  * An entry for ir_graphs
57  */
58 typedef struct _graph_entry_t {
59   pset           *opcode_hash;                  /**< hash map containing the opcode counter */
60   counter_t      walked;                        /**< walker walked over the graph */
61   counter_t      walked_blocks;                 /**< walker walked over the graph blocks */
62   pset           *opt_hash[STAT_OPT_MAX];       /**< hash maps containing opcode counter for optimizations */
63   const ir_graph *irg;                          /**< the graph of this object */
64   entity         *ent;                          /**< the entity of this graph if one exists */
65   int            deleted;                       /**< set if this irg was deleted */
66 } graph_entry_t;
67
68 /**
69  * An entry for optimized ir_nodes
70  */
71 typedef struct _opt_entry_t {
72   counter_t   count;            /**< optimization counter */
73   const ir_op *op;              /**< the op for this entry */
74 } opt_entry_t;
75
76 /**
77  * statistics info
78  */
79 typedef struct _statistic_info_t {
80   struct obstack cnts;          /**< obstack containing the counters */
81   pset           *opcode_hash;  /**< hash map containing the opcode counter */
82   pset           *irg_hash;     /**< hash map containing the counter for irgs */
83   FILE           *f;            /**< outputfile */
84   ir_op          *op_Phi0;      /**< needed pseudo op */
85 } stat_info_t;
86
87 /*
88  * global status
89  */
90 static stat_info_t _status, *status = &_status;
91
92 /**
93  * increase a counter
94  */
95 static INLINE void cnt_inc(counter_t *cnt)
96 {
97   int i;
98
99   for (i = 0; i < STAT_CNT_NUM; ++i) {
100     if (++cnt->cnt[i])
101       break;
102   }
103 }
104
105 /**
106  * decreace a counter
107  */
108 static INLINE void cnt_dec(counter_t *cnt)
109 {
110   int i;
111
112   for (i = 0; i < STAT_CNT_NUM; ++i) {
113     if (--cnt->cnt[i] != -1)
114       break;
115   }
116 }
117
118 /**
119  * set a counter to zero
120  */
121 static INLINE void cnt_clr(counter_t *cnt)
122 {
123   memset(cnt->cnt, 0, sizeof(cnt->cnt));
124 }
125
126 /*
127  * compare two elements of the opcode hash
128  */
129 static int opcode_cmp(const void *elt, const void *key)
130 {
131   const node_entry_t *e1 = elt;
132   const node_entry_t *e2 = key;
133
134   return e1->op->code - e2->op->code;
135 }
136
137 /*
138  * compare two elements of the graph hash
139  */
140 static int graph_cmp(const void *elt, const void *key)
141 {
142   const graph_entry_t *e1 = elt;
143   const graph_entry_t *e2 = key;
144
145   return e1->irg != e2->irg;
146 }
147
148 /*
149  * compare two elements of the optimization hash
150  */
151 static int opt_cmp(const void *elt, const void *key)
152 {
153   const opt_entry_t *e1 = elt;
154   const opt_entry_t *e2 = key;
155
156   return e1->op->code != e2->op->code;
157 }
158
159 /**
160  * Returns the associates node_entry_t for an ir_op
161  */
162 static node_entry_t *opcode_get_entry(const ir_op *op, pset *set)
163 {
164   node_entry_t key;
165   node_entry_t *elem;
166
167   key.op = op;
168
169   elem = pset_find(set, &key, op->code);
170   if (elem)
171     return elem;
172
173   elem = obstack_alloc(&status->cnts, sizeof(*elem));
174
175   /* clear new counter */
176   cnt_clr(&elem->new_node);
177   cnt_clr(&elem->into_Id);
178
179   elem->op = op;
180
181   return pset_insert(set, elem, op->code);
182 }
183
184 /**
185  * calculates a hash value for an irg
186  */
187 static INLINE unsigned irg_hash(const ir_graph *irg)
188 {
189   return (unsigned)irg;
190 }
191
192 /**
193  * Returns the acssociates graph_entry_t for an irg
194  */
195 static graph_entry_t *graph_get_entry(const ir_graph *irg, pset *set)
196 {
197   graph_entry_t key;
198   graph_entry_t *elem;
199   int i;
200
201   key.irg = irg;
202
203   elem = pset_find(set, &key, irg_hash(irg));
204   if (elem)
205     return elem;
206
207   elem = obstack_alloc(&status->cnts, sizeof(*elem));
208
209   cnt_clr(&elem->walked);
210   cnt_clr(&elem->walked_blocks);
211
212   /* new hash table for opcodes here  */
213   elem->opcode_hash  = new_pset(opcode_cmp, 5);
214   elem->irg          = irg;
215
216   for (i = 0; i < sizeof(elem->opt_hash)/sizeof(elem->opt_hash[0]); ++i)
217     elem->opt_hash[i] = new_pset(opt_cmp, 4);
218
219   return pset_insert(set, elem, irg_hash(irg));
220 }
221
222 /**
223  * Returns the associates opt_entry_t for an ir_op
224  */
225 static opt_entry_t *opt_get_entry(const ir_op *op, pset *set)
226 {
227   opt_entry_t key;
228   opt_entry_t *elem;
229
230   key.op = op;
231
232   elem = pset_find(set, &key, op->code);
233   if (elem)
234     return elem;
235
236   elem = obstack_alloc(&status->cnts, sizeof(*elem));
237
238   /* clear new counter */
239   cnt_clr(&elem->count);
240
241   elem->op = op;
242
243   return pset_insert(set, elem, op->code);
244 }
245
246 /* ---------------------------------------------------------------------- */
247
248 /* initialize the statistics module. */
249 void stat_init(void)
250 {
251   obstack_init(&status->cnts);
252
253   /* create the hash-tables */
254   status->opcode_hash = new_pset(opcode_cmp, 8);
255   status->irg_hash    = new_pset(graph_cmp, 8);
256
257   status->f           = fopen("firmstat.txt", "w");
258   status->op_Phi0     = NULL;
259 }
260
261 /* A new IR op is registered. */
262 void stat_new_ir_op(const ir_op *op)
263 {
264   /* execute for side effect :-) */
265   opcode_get_entry(op, status->opcode_hash);
266 }
267
268 /* An IR op is freed. */
269 void stat_free_ir_op(const ir_op *op)
270 {
271 }
272
273 /* A new node is created. */
274 void stat_new_node(const ir_node *node)
275 {
276   node_entry_t *entry;
277   graph_entry_t *graph;
278   ir_op *op = get_irn_op(node);
279
280   if (op->code == iro_Phi && get_irn_arity(node) == 0) {
281     /* special case, a Phi0 node, count on extra counter */
282     if (! status->op_Phi0) {
283       ir_op *op_Phi = get_op_Phi();
284
285       status->op_Phi0 = new_ir_op(0xFFFF, "Phi0", op_Phi->pinned, op_Phi->flags, op_Phi->opar, op_Phi->op_index, op_Phi->attr_size);
286     }
287     op = status->op_Phi0;
288   }
289
290   entry = opcode_get_entry(op, status->opcode_hash);
291   graph = graph_get_entry(current_ir_graph, status->irg_hash);
292
293   /* increase global value */
294   cnt_inc(&entry->new_node);
295
296   /* increase local value */
297   entry = opcode_get_entry(op, graph->opcode_hash);
298   cnt_inc(&entry->new_node);
299 }
300
301 /* A node is changed into a Id node */
302 void stat_turn_into_id(const ir_node *node)
303 {
304   node_entry_t *entry;
305   graph_entry_t *graph;
306   ir_op *op = get_irn_op(node);
307
308   if (op->code == iro_Phi && get_irn_arity(node) == 0) {
309     /* special case, a Phi0 node, count on extra counter */
310     if (! status->op_Phi0) {
311       ir_op *op_Phi = get_op_Phi();
312
313       status->op_Phi0 = new_ir_op(0xFFFF, "Phi0", op_Phi->pinned, op_Phi->flags, op_Phi->opar, op_Phi->op_index, op_Phi->attr_size);
314     }
315     op = status->op_Phi0;
316   }
317
318   entry = opcode_get_entry(op, status->opcode_hash);
319   graph = graph_get_entry(current_ir_graph, status->irg_hash);
320
321   /* increase global value */
322   cnt_inc(&entry->into_Id);
323
324   /* increase local value */
325   entry = opcode_get_entry(op, graph->opcode_hash);
326   cnt_inc(&entry->into_Id);
327 }
328
329 /* A new graph was created */
330 void stat_new_graph(const ir_graph *irg, entity *ent)
331 {
332   /* execute for side effect :-) */
333   graph_entry_t * graph = graph_get_entry(irg, status->irg_hash);
334
335   graph->ent     = ent;
336   graph->deleted = 0;
337 }
338
339 /*
340  * A graph was deleted
341  */
342 void stat_free_graph(const ir_graph *irg)
343 {
344   graph_entry_t * graph = graph_get_entry(irg, status->irg_hash);
345
346   graph->deleted = 1;
347 }
348
349 /*
350  * A walk over a graph is initiated
351  */
352 void stat_irg_walk(const ir_graph *irg, void *pre, void *post)
353 {
354   graph_entry_t *graph = graph_get_entry(irg, status->irg_hash);
355
356   cnt_inc(&graph->walked);
357 }
358
359 /*
360  * A walk over the graph's blocks is initiated
361  */
362 void stat_irg_block_walk(const ir_graph *irg, const ir_node *node, void *pre, void *post)
363 {
364   graph_entry_t *graph = graph_get_entry(irg, status->irg_hash);
365
366   cnt_inc(&graph->walked_blocks);
367 }
368
369 /**
370  * called for every node that is removed due to an optimization
371  */
372 static void removed_due_opt(ir_node *n, pset *set)
373 {
374   ir_op *op          = get_irn_op(n);
375   opt_entry_t *entry = opt_get_entry(op, set);
376
377   /* increase global value */
378   cnt_inc(&entry->count);
379 }
380
381 /*
382  * Some nodes were optimized into some others due to an optimization
383  */
384 void stat_merge_nodes(
385     ir_node **new_node_array, int new_num_entries,
386     ir_node **old_node_array, int old_num_entries,
387     stat_opt_kind opt)
388 {
389   int i, j;
390   graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash);
391
392   for (i = 0; i < old_num_entries; ++i) {
393     for (j = 0; j < new_num_entries; ++j)
394       if (old_node_array[i] == new_node_array[j])
395         break;
396
397     /* nodes might be in new and old, these are NOT removed */
398     if (j >= new_num_entries) {
399       removed_due_opt(old_node_array[i], graph->opt_hash[opt]);
400     }
401   }
402 }
403
404 /*
405  * A node was lowered into other nodes
406  */
407 void stat_lower(ir_node *node)
408 {
409   graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash);
410
411   removed_due_opt(node, graph->opt_hash[STAT_LOWERED]);
412 }
413
414 /**
415  * dumps a opcode hash
416  */
417 static void dump_opcode_hash(pset *set)
418 {
419   node_entry_t *entry;
420
421   fprintf(status->f, "%-16s %-8s %-8s\n", "Opcode", "created", "->Id");
422   for (entry = pset_first(set); entry; entry = pset_next(set)) {
423     fprintf(status->f, "%-16s %8d %8d\n",
424         get_id_str(entry->op->name), entry->new_node.cnt[0], entry->into_Id.cnt[0]);
425   }
426 }
427
428 static const char *opt_names[] = {
429   "straightening optimization",
430   "if simplification",
431   "algebraic simplification",
432   "Phi optmization",
433   "Write-After-Write optimization",
434   "Write-After-Read optimization",
435   "Tuple optimization",
436   "ID optimization",
437   "Constant evaluation",
438   "Lowered",
439 };
440
441 /**
442  * dumps a optimization hash
443  */
444 static void dump_opt_hash(pset *set, int index)
445 {
446   opt_entry_t *entry = pset_first(set);
447
448   if (entry) {
449     fprintf(status->f, "\n%s:\n", opt_names[index]);
450     fprintf(status->f, "%-16s %-8s\n", "Opcode", "deref");
451
452     for (; entry; entry = pset_next(set)) {
453       fprintf(status->f, "%-16s %8d\n",
454           get_id_str(entry->op->name), entry->count.cnt[0]);
455     }
456   }
457 }
458
459 /* Finish the statistics */
460 void stat_finish(void)
461 {
462   int i;
463   graph_entry_t *entry;
464   ir_graph *const_irg = get_const_code_irg();
465
466   /* dump global */
467   fprintf(status->f, "\nGlobal counts:\n");
468   dump_opcode_hash(status->opcode_hash);
469
470   for (entry = pset_first(status->irg_hash); entry; entry = pset_next(status->irg_hash)) {
471     entity *ent = entry->ent;
472
473     if (entry->irg == const_irg) {
474       fprintf(status->f, "\nConst code Irg %p", entry->irg);
475     }
476     else {
477       if (ent)
478         fprintf(status->f, "\nEntity %s, Irg %p", get_entity_name(ent), entry->irg);
479       else
480         fprintf(status->f, "\nIrg %p", entry->irg);
481     }
482
483     fprintf(status->f, " %swalked %d over blocks %d:\n",
484         entry->deleted ? "DELETED " : "",
485         entry->walked.cnt[0], entry->walked_blocks.cnt[0]);
486
487     dump_opcode_hash(entry->opcode_hash);
488
489     for (i = 0; i < sizeof(entry->opt_hash)/sizeof(entry->opt_hash[0]); ++i) {
490       dump_opt_hash(entry->opt_hash[i], i);
491     }
492   }
493
494   fclose(status->f);
495 }
496
497 #else
498
499 /* need this for prototypes */
500 #define FIRM_STATISTICS
501 #include "firmstat.h"
502
503 void stat_init(void) {}
504
505 void stat_finish(void) {}
506
507 void stat_new_ir_op(const ir_op *op) {}
508
509 void stat_free_ir_op(const ir_op *op) {}
510
511 void stat_new_node(const ir_node *node) {}
512
513 void stat_turn_into_id(const ir_node *node) {}
514
515 void stat_new_graph(const ir_graph *irg, entity *ent) {}
516
517 void stat_free_graph(const ir_graph *irg) {}
518
519 void stat_irg_walk(const ir_graph *irg, void *pre, void *post) {}
520
521 void stat_irg_block_walk(const ir_graph *irg, const ir_node *node, void *pre, void *post) {}
522
523 void stat_merge_nodes(
524     ir_node **new_node_array, int new_num_entries,
525     ir_node **old_node_array, int old_num_entries,
526     stat_opt_kind opt) {}
527
528 void stat_lower(ir_node *node) {}
529
530 #endif