48336b8f8786c721fe430ab86a55d2cbdfcb8d1e
[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 /**
92  * Collect reg pressure statistics per block and per class.
93  */
94 static void stat_reg_pressure_block(ir_node *block, void *env) {
95         be_irg_t         *birg = env;
96         const arch_env_t *aenv = birg->main_env->arch_env;
97         int i, n = arch_isa_get_n_reg_class(aenv->isa);
98
99         for (i = 0; i < n; i++) {
100                 const arch_register_class_t *cls = arch_isa_get_reg_class(aenv->isa, i);
101                 ir_node  *irn;
102                 pset     *live_nodes = pset_new_ptr(64);
103                 int       max_live;
104
105                 live_nodes = be_liveness_end_of_block(aenv, cls, block, live_nodes);
106                 max_live   = pset_count(live_nodes);
107
108                 sched_foreach_reverse(block, irn) {
109                         int cnt;
110
111                         live_nodes = be_liveness_transfer(aenv, cls, irn, live_nodes);
112                         cnt        = pset_count(live_nodes);
113
114                         max_live = cnt < max_live ? max_live : cnt;
115                 }
116
117                 stat_be_block_regpressure(birg->irg, block, MIN(max_live, 5), cls->name);
118         }
119 }
120
121 void be_do_stat_reg_pressure(be_irg_t *birg) {
122         if (stat_is_active()) {
123                 be_liveness(birg->irg);
124                 /* Collect register pressure information for each block */
125                 irg_block_walk_graph(birg->irg, stat_reg_pressure_block, NULL, birg);
126         }
127 }
128
129 /**
130  * Notify statistic module about amount of ready nodes.
131  */
132 void be_do_stat_sched_ready(ir_node *block, nodeset *ready_set) {
133         if (stat_is_active()) {
134                 stat_be_block_sched_ready(get_irn_irg(block), block, nodeset_count(ready_set));
135         }
136 }
137
138 /**
139  * Pass information about a perm to the statistic module.
140  */
141 void be_do_stat_perm(const char *class_name, int n_regs, ir_node *perm, ir_node *block, int n, int real_size) {
142         if (stat_is_active()) {
143                 stat_be_block_stat_perm(class_name, n_regs, perm, block, n, real_size);
144         }
145 }
146
147 /**
148  * Pass information about a cycle or chain in a perm to the statistic module.
149  */
150 void be_do_stat_permcycle(const char *class_name, ir_node *perm, ir_node *block, int is_chain, int n_elems, int n_ops) {
151         if (stat_is_active()) {
152                 stat_be_block_stat_permcycle(class_name, perm, block, is_chain, n_elems, n_ops);
153         }
154 }
155
156 /**
157  * Updates nodes statistics.
158  */
159 static void do_nodes_stat(ir_node *irn, void *env) {
160         be_stat_phase_t *phase = env;
161         ir_mode         *mode;
162         opcode          opc;
163
164         if (is_Block(irn))
165                 return;
166
167         mode = get_irn_mode(irn);
168         opc  = get_irn_opcode(irn);
169
170         phase->num_nodes++;
171
172         /* check for nodes we want to ignore */
173         if (be_is_Keep(irn)     ||
174                 be_is_CopyKeep(irn) ||
175                 opc == iro_Start    ||
176                 opc == iro_End)
177                 return;
178
179         if (is_Proj(irn)) {
180                 phase->num_proj++;
181                 return;
182         }
183         else if (is_Phi(irn)) {
184                 phase->num_phi++;
185                 return;
186         }
187         else if (mode_is_datab(mode) || (mode == mode_T && ! is_be_node(irn)))
188                 phase->num_data++;
189
190         if (opc == iro_Load)
191                 phase->num_load++;
192         else if (opc == iro_Store)
193                 phase->num_store++;
194
195         switch (arch_irn_classify(phase->arch_env, irn)) {
196                 case arch_irn_class_spill:
197                         phase->num_spill++;
198                         break;
199                 case arch_irn_class_reload:
200                         phase->num_reload++;
201                         break;
202                 case arch_irn_class_stackparam:
203                 case arch_irn_class_load:
204                         phase->num_load++;
205                         break;
206                 case arch_irn_class_store:
207                         phase->num_store++;
208                         break;
209                 default:
210                         break;
211         }
212 }
213
214 /**
215  * Collects node statistics.
216  *
217  * @param irg      the to do statistics for
218  * @param phase    the phase to collect the statistic for
219  */
220 void be_do_stat_nodes(ir_graph *irg, const char *phase) {
221         be_stat_irg_t   *irg_entry;
222         be_stat_phase_t *phase_entry, phase_key;
223
224         irg_entry = find_stat_irg_entry(irg);
225
226         if (! irg_entry)
227                 return;
228
229         phase_key.phase = phase;
230         phase_entry     = pset_find_ptr(irg_entry->phases, &phase_key);
231
232         if (! phase_entry) {
233                 phase_entry = obstack_alloc(&irg_entry->obst, sizeof(*phase_entry));
234                 phase_entry = pset_insert(irg_entry->phases, phase_entry, HASH_PTR(phase));
235         }
236         memset(phase_entry, 0, sizeof(*phase_entry));
237
238         phase_entry->phase    = phase;
239         phase_entry->arch_env = irg_entry->arch_env;
240
241         irg_walk_blkwise_graph(irg_entry->irg, NULL, do_nodes_stat, phase_entry);
242 }
243
244 /**
245  * Dumps statistics about nodes (called from dump_snapshot)
246  */
247 static void be_dump_node_stat(dumper_t *dmp, graph_entry_t *entry) {
248         be_stat_irg_t   *stat_irg = find_stat_irg_entry(entry->irg);
249         be_stat_phase_t *phase;
250
251         if (! stat_irg || ! stat_irg->phases)
252                 return;
253
254         fprintf(dmp->f, "===> BE NODE STATISTIC BEGIN <===\n");
255
256         foreach_pset(stat_irg->phases, phase) {
257                 fprintf(dmp->f, "--> Phase: %s\n", phase->phase);
258                 fprintf(dmp->f, "# nodes:      %ld\n", phase->num_nodes);
259                 fprintf(dmp->f, "# data nodes: %ld\n", phase->num_data);
260                 fprintf(dmp->f, "# Proj:       %ld\n", phase->num_proj);
261                 fprintf(dmp->f, "# Phi:        %ld\n", phase->num_phi);
262                 fprintf(dmp->f, "# Load:       %ld\n", phase->num_load);
263                 fprintf(dmp->f, "# Store:      %ld\n", phase->num_store);
264                 fprintf(dmp->f, "# Spill:      %ld\n", phase->num_spill);
265                 fprintf(dmp->f, "# Reload:     %ld\n", phase->num_reload);
266         }
267
268         fprintf(dmp->f, "===> BE NODE STATISTIC END <===\n");
269 }
270
271 /**
272  * Returns a be statistic object for the given irg.
273  */
274 void be_stat_init_irg(const arch_env_t *arch_env, ir_graph *irg) {
275         static int reg_func  = 1;
276
277         if (stat_is_active()) {
278                 be_stat_irg_t *stat_irg;
279
280                 if (! be_stat_data)
281                         be_stat_data = new_set(cmp_stat_data, 8);
282
283                 stat_irg           = get_stat_irg_entry(irg);
284                 stat_irg->irg      = irg;
285                 stat_irg->phases   = new_pset(cmp_stat_phase, 8);
286                 stat_irg->arch_env = arch_env;
287                 obstack_init(&stat_irg->obst);
288
289                 if (reg_func) {
290                         /* first init: register dumper */
291                         stat_register_dumper_func(be_dump_node_stat);
292                         reg_func = 0;
293                 }
294         }
295 }
296
297 #else
298
299 void (be_stat_init_irg)(const arch_env_t *arch_env, ir_graph *irg) {}
300 void (be_do_stat_nodes)(ir_graph *irg, const char *phase) {}
301 void (be_do_stat_reg_pressure)(be_irg_t *birg) {}
302 void (be_do_stat_sched_ready)(ir_node *block, nodeset *ready_set) {}
303 void (be_do_stat_perm)(const char *class_name, int n_regs, ir_node *perm, ir_node *block, int n, int real_size) {}
304
305 #endif /* FIRM_STATISTICS */