Removed bogus printf
[libfirm] / ir / be / bestat.c
1 /**
2  * This file calls the corresponding statistic functions for
3  * some backend statistics.
4  * @author Christian Wuerdig
5  * $Id$
6  */
7 #ifdef HAVE_CONFIG_H
8 #include "config.h"
9 #endif
10
11 #ifdef FIRM_STATISTICS
12
13 #include "irnode_t.h"
14 #include "irprintf.h"
15 #include "irgwalk.h"
16 #include "irhooks.h"
17 #include "dbginfo_t.h"
18 #include "firmstat_t.h"
19 #include "irtools.h"
20 #include "pset.h"
21
22 #include "bestat.h"
23 #include "belive_t.h"
24 #include "besched.h"
25 #include "benode_t.h"
26
27 typedef struct _be_stat_irg_t {
28         ir_graph         *irg;       /**< the irg, the statistic is about */
29         pset             *phases;    /**< node statistics for each phase  */
30         struct obstack   obst;       /**< the obstack containing the information */
31         const arch_env_t *arch_env;  /**< the current arch env */
32 } be_stat_irg_t;
33
34 typedef struct _be_stat_phase_t {
35         const arch_env_t *arch_env;  /**< the current arch env */
36         const char       *phase;     /**< the name of the phase the statistic is about */
37         unsigned long    num_nodes;  /**< overall number of reachable nodes in the irg */
38         unsigned long    num_data;   /**< number of data nodes ((mode_datab && ! Proj && ! Phi)  || mode_T) */
39         unsigned long    num_proj;   /**< number of Projs */
40         unsigned long    num_phi;    /**< number of Phis */
41         unsigned long    num_load;   /**< number of Loads */
42         unsigned long    num_store;  /**< number of Stores */
43         unsigned long    num_spill;  /**< number of Spills */
44         unsigned long    num_reload; /**< number of Reloads */
45 } be_stat_phase_t;
46
47 static set *be_stat_data = NULL;
48
49 static int cmp_stat_phase(const void *a, const void *b) {
50         const be_stat_phase_t *p1 = a;
51         const be_stat_phase_t *p2 = b;
52
53         return p1->phase != p2->phase;
54 }
55
56 static int cmp_stat_data(const void *a, const void *b, size_t len) {
57         const be_stat_irg_t *p1 = a;
58         const be_stat_irg_t *p2 = b;
59
60         return p1->irg != p2->irg;
61 }
62
63 static be_stat_irg_t *find_stat_irg_entry(ir_graph *irg) {
64         be_stat_irg_t *entry, key;
65
66         if (! be_stat_data)
67                 return NULL;
68
69         key.irg = irg;
70         entry   = set_find(be_stat_data, &key, sizeof(key), HASH_PTR(irg));
71
72         return entry;
73 }
74
75 static be_stat_irg_t *get_stat_irg_entry(ir_graph *irg) {
76         be_stat_irg_t *entry, key;
77
78         if (! be_stat_data)
79                 return NULL;
80
81         entry = find_stat_irg_entry(irg);
82
83         if (! entry) {
84                 key.irg = irg;
85                 entry   = set_insert(be_stat_data, &key, sizeof(key), HASH_PTR(irg));
86         }
87
88         return entry;
89 }
90
91 struct a_pressure_walker {
92         be_irg_t *birg;
93         be_lv_t *lv;
94 };
95
96 /**
97  * Collect reg pressure statistics per block and per class.
98  */
99 static void stat_reg_pressure_block(ir_node *block, void *data) {
100         struct a_pressure_walker *env = data;
101         be_irg_t         *birg = env->birg;
102         const arch_env_t *aenv = birg->main_env->arch_env;
103         int i, n = arch_isa_get_n_reg_class(aenv->isa);
104
105         for (i = 0; i < n; i++) {
106                 const arch_register_class_t *cls = arch_isa_get_reg_class(aenv->isa, i);
107                 ir_node  *irn;
108                 pset     *live_nodes = pset_new_ptr(64);
109                 int       max_live;
110
111                 live_nodes = be_liveness_end_of_block(env->lv, aenv, cls, block, live_nodes);
112                 max_live   = pset_count(live_nodes);
113
114                 sched_foreach_reverse(block, irn) {
115                         int cnt;
116
117                         if(is_Phi(irn))
118                                 break;
119
120                         live_nodes = be_liveness_transfer(aenv, cls, irn, live_nodes);
121                         cnt        = pset_count(live_nodes);
122                         max_live   = cnt < max_live ? max_live : cnt;
123                 }
124
125                 stat_be_block_regpressure(birg->irg, block, max_live, cls->name);
126         }
127 }
128
129 void be_do_stat_reg_pressure(be_irg_t *birg) {
130         if (stat_is_active()) {
131                 struct a_pressure_walker w;
132
133                 w.birg = birg;
134                 w.lv   = be_liveness(birg->irg);
135                 /* Collect register pressure information for each block */
136                 irg_block_walk_graph(birg->irg, stat_reg_pressure_block, NULL, &w);
137                 be_liveness_free(w.lv);
138         }
139 }
140
141 /**
142  * Notify statistic module about amount of ready nodes.
143  */
144 void be_do_stat_sched_ready(ir_node *block, nodeset *ready_set) {
145         if (stat_is_active()) {
146                 stat_be_block_sched_ready(get_irn_irg(block), block, MIN(nodeset_count(ready_set), 5));
147         }
148 }
149
150 /**
151  * Pass information about a perm to the statistic module.
152  */
153 void be_do_stat_perm(const char *class_name, int n_regs, ir_node *perm, ir_node *block, int n, int real_size) {
154         if (stat_is_active()) {
155                 stat_be_block_stat_perm(class_name, n_regs, perm, block, n, real_size);
156         }
157 }
158
159 /**
160  * Pass information about a cycle or chain in a perm to the statistic module.
161  */
162 void be_do_stat_permcycle(const char *class_name, ir_node *perm, ir_node *block, int is_chain, int n_elems, int n_ops) {
163         if (stat_is_active()) {
164                 stat_be_block_stat_permcycle(class_name, perm, block, is_chain, n_elems, n_ops);
165         }
166 }
167
168 /**
169  * Updates nodes statistics.
170  */
171 static void do_nodes_stat(ir_node *irn, void *env) {
172         be_stat_phase_t  *phase = env;
173         ir_mode          *mode;
174         opcode           opc;
175         arch_irn_class_t irn_class;
176
177         if (is_Block(irn))
178                 return;
179
180         mode = get_irn_mode(irn);
181         opc  = get_irn_opcode(irn);
182
183         phase->num_nodes++;
184
185         /* check for nodes we want to ignore */
186         if (be_is_Keep(irn)     ||
187                 be_is_CopyKeep(irn) ||
188                 opc == iro_Start    ||
189                 opc == iro_End)
190                 return;
191
192         if (is_Proj(irn) && (mode != mode_X)) {
193                 phase->num_proj++;
194                 return;
195         }
196         else if (is_Phi(irn)) {
197                 phase->num_phi++;
198                 return;
199         }
200         else if (mode_is_datab(mode) || ((mode == mode_T) && ! is_be_node(irn)) || (is_Proj(irn) && (mode == mode_X)))
201                 phase->num_data++;
202
203         if (opc == iro_Load)
204                 phase->num_load++;
205         else if (opc == iro_Store)
206                 phase->num_store++;
207
208         irn_class = arch_irn_classify(phase->arch_env, irn);
209         if (irn_class & arch_irn_class_spill)
210                 phase->num_spill++;
211         else if (irn_class & arch_irn_class_reload)
212                 phase->num_reload++;
213         else if (irn_class & arch_irn_class_stackparam)
214                 phase->num_load++;
215         else if (irn_class & arch_irn_class_load)
216                 phase->num_load++;
217         else if (irn_class & arch_irn_class_store)
218                 phase->num_store++;
219 }
220
221 /**
222  * Collects node statistics.
223  *
224  * @param irg      the to do statistics for
225  * @param phase    the phase to collect the statistic for
226  */
227 void be_do_stat_nodes(ir_graph *irg, const char *phase) {
228         be_stat_irg_t   *irg_entry;
229         be_stat_phase_t *phase_entry, phase_key;
230
231         irg_entry = find_stat_irg_entry(irg);
232
233         if (! irg_entry)
234                 return;
235
236         phase_key.phase = phase;
237         phase_entry     = pset_find_ptr(irg_entry->phases, &phase_key);
238
239         if (! phase_entry) {
240                 phase_entry = obstack_alloc(&irg_entry->obst, sizeof(*phase_entry));
241                 phase_entry = pset_insert(irg_entry->phases, phase_entry, HASH_PTR(phase));
242         }
243         memset(phase_entry, 0, sizeof(*phase_entry));
244
245         phase_entry->phase    = phase;
246         phase_entry->arch_env = irg_entry->arch_env;
247
248         irg_walk_blkwise_graph(irg_entry->irg, NULL, do_nodes_stat, phase_entry);
249 }
250
251 /**
252  * Dumps statistics about nodes (called from dump_snapshot)
253  */
254 static void be_dump_node_stat(dumper_t *dmp, graph_entry_t *entry) {
255         be_stat_irg_t   *stat_irg = find_stat_irg_entry(entry->irg);
256         be_stat_phase_t *phase;
257
258         if (! stat_irg || ! stat_irg->phases)
259                 return;
260
261         fprintf(dmp->f, "===> BE NODE STATISTIC BEGIN <===\n");
262
263         foreach_pset(stat_irg->phases, phase) {
264                 fprintf(dmp->f, "--> Phase: %s\n", phase->phase);
265                 fprintf(dmp->f, "# nodes:      %ld\n", phase->num_nodes);
266                 fprintf(dmp->f, "# data nodes: %ld\n", phase->num_data);
267                 fprintf(dmp->f, "# Proj:       %ld\n", phase->num_proj);
268                 fprintf(dmp->f, "# Phi:        %ld\n", phase->num_phi);
269                 fprintf(dmp->f, "# Load:       %ld\n", phase->num_load);
270                 fprintf(dmp->f, "# Store:      %ld\n", phase->num_store);
271                 fprintf(dmp->f, "# Spill:      %ld\n", phase->num_spill);
272                 fprintf(dmp->f, "# Reload:     %ld\n", phase->num_reload);
273         }
274
275         fprintf(dmp->f, "===> BE NODE STATISTIC END <===\n");
276 }
277
278 /**
279  * Returns a be statistic object for the given irg.
280  */
281 void be_stat_init_irg(const arch_env_t *arch_env, ir_graph *irg) {
282         static int reg_func  = 1;
283
284         if (stat_is_active()) {
285                 be_stat_irg_t *stat_irg;
286
287                 if (! be_stat_data)
288                         be_stat_data = new_set(cmp_stat_data, 8);
289
290                 stat_irg           = get_stat_irg_entry(irg);
291                 stat_irg->irg      = irg;
292                 stat_irg->phases   = new_pset(cmp_stat_phase, 8);
293                 stat_irg->arch_env = arch_env;
294                 obstack_init(&stat_irg->obst);
295
296                 if (reg_func) {
297                         /* first init: register dumper */
298                         stat_register_dumper_func(be_dump_node_stat);
299                         reg_func = 0;
300                 }
301         }
302 }
303
304 #else
305
306 void (be_stat_init_irg)(const arch_env_t *arch_env, ir_graph *irg) {}
307 void (be_do_stat_nodes)(ir_graph *irg, const char *phase) {}
308 void (be_do_stat_reg_pressure)(be_irg_t *birg) {}
309 void (be_do_stat_sched_ready)(ir_node *block, nodeset *ready_set) {}
310 void (be_do_stat_perm)(const char *class_name, int n_regs, ir_node *perm, ir_node *block, int n, int real_size) {}
311
312 #endif /* FIRM_STATISTICS */