fixed remat flag for load nodes
[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
176         if (is_Block(irn))
177                 return;
178
179         mode = get_irn_mode(irn);
180         opc  = get_irn_opcode(irn);
181
182         phase->num_nodes++;
183
184         /* check for nodes we want to ignore */
185         if (be_is_Keep(irn)     ||
186                 be_is_CopyKeep(irn) ||
187                 opc == iro_Start    ||
188                 opc == iro_End)
189                 return;
190
191         if (is_Proj(irn) && (mode != mode_X)) {
192                 phase->num_proj++;
193                 return;
194         }
195         else if (is_Phi(irn)) {
196                 phase->num_phi++;
197                 return;
198         }
199         else if (mode_is_datab(mode) || ((mode == mode_T) && ! is_be_node(irn)) || (is_Proj(irn) && (mode == mode_X)))
200                 phase->num_data++;
201
202         if (opc == iro_Load)
203                 phase->num_load++;
204         else if (opc == iro_Store)
205                 phase->num_store++;
206
207         switch (arch_irn_classify(phase->arch_env, irn)) {
208                 case arch_irn_class_spill:
209                         phase->num_spill++;
210                         break;
211                 case arch_irn_class_reload:
212                         phase->num_reload++;
213                         break;
214                 case arch_irn_class_stackparam:
215                 case arch_irn_class_load:
216                         phase->num_load++;
217                         break;
218                 case arch_irn_class_store:
219                         phase->num_store++;
220                         break;
221                 default:
222                         break;
223         }
224 }
225
226 /**
227  * Collects node statistics.
228  *
229  * @param irg      the to do statistics for
230  * @param phase    the phase to collect the statistic for
231  */
232 void be_do_stat_nodes(ir_graph *irg, const char *phase) {
233         be_stat_irg_t   *irg_entry;
234         be_stat_phase_t *phase_entry, phase_key;
235
236         irg_entry = find_stat_irg_entry(irg);
237
238         if (! irg_entry)
239                 return;
240
241         phase_key.phase = phase;
242         phase_entry     = pset_find_ptr(irg_entry->phases, &phase_key);
243
244         if (! phase_entry) {
245                 phase_entry = obstack_alloc(&irg_entry->obst, sizeof(*phase_entry));
246                 phase_entry = pset_insert(irg_entry->phases, phase_entry, HASH_PTR(phase));
247         }
248         memset(phase_entry, 0, sizeof(*phase_entry));
249
250         phase_entry->phase    = phase;
251         phase_entry->arch_env = irg_entry->arch_env;
252
253         irg_walk_blkwise_graph(irg_entry->irg, NULL, do_nodes_stat, phase_entry);
254 }
255
256 /**
257  * Dumps statistics about nodes (called from dump_snapshot)
258  */
259 static void be_dump_node_stat(dumper_t *dmp, graph_entry_t *entry) {
260         be_stat_irg_t   *stat_irg = find_stat_irg_entry(entry->irg);
261         be_stat_phase_t *phase;
262
263         if (! stat_irg || ! stat_irg->phases)
264                 return;
265
266         fprintf(dmp->f, "===> BE NODE STATISTIC BEGIN <===\n");
267
268         foreach_pset(stat_irg->phases, phase) {
269                 fprintf(dmp->f, "--> Phase: %s\n", phase->phase);
270                 fprintf(dmp->f, "# nodes:      %ld\n", phase->num_nodes);
271                 fprintf(dmp->f, "# data nodes: %ld\n", phase->num_data);
272                 fprintf(dmp->f, "# Proj:       %ld\n", phase->num_proj);
273                 fprintf(dmp->f, "# Phi:        %ld\n", phase->num_phi);
274                 fprintf(dmp->f, "# Load:       %ld\n", phase->num_load);
275                 fprintf(dmp->f, "# Store:      %ld\n", phase->num_store);
276                 fprintf(dmp->f, "# Spill:      %ld\n", phase->num_spill);
277                 fprintf(dmp->f, "# Reload:     %ld\n", phase->num_reload);
278         }
279
280         fprintf(dmp->f, "===> BE NODE STATISTIC END <===\n");
281 }
282
283 /**
284  * Returns a be statistic object for the given irg.
285  */
286 void be_stat_init_irg(const arch_env_t *arch_env, ir_graph *irg) {
287         static int reg_func  = 1;
288
289         if (stat_is_active()) {
290                 be_stat_irg_t *stat_irg;
291
292                 if (! be_stat_data)
293                         be_stat_data = new_set(cmp_stat_data, 8);
294
295                 stat_irg           = get_stat_irg_entry(irg);
296                 stat_irg->irg      = irg;
297                 stat_irg->phases   = new_pset(cmp_stat_phase, 8);
298                 stat_irg->arch_env = arch_env;
299                 obstack_init(&stat_irg->obst);
300
301                 if (reg_func) {
302                         /* first init: register dumper */
303                         stat_register_dumper_func(be_dump_node_stat);
304                         reg_func = 0;
305                 }
306         }
307 }
308
309 #else
310
311 void (be_stat_init_irg)(const arch_env_t *arch_env, ir_graph *irg) {}
312 void (be_do_stat_nodes)(ir_graph *irg, const char *phase) {}
313 void (be_do_stat_reg_pressure)(be_irg_t *birg) {}
314 void (be_do_stat_sched_ready)(ir_node *block, nodeset *ready_set) {}
315 void (be_do_stat_perm)(const char *class_name, int n_regs, ir_node *perm, ir_node *block, int n, int real_size) {}
316
317 #endif /* FIRM_STATISTICS */