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