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