compiles with WITH_LIBCORE disabled again
[libfirm] / ir / be / belistsched.c
1 /**
2  * Scheduling algorithms.
3  * Just a simple list scheduling algorithm is here.
4  * @date   20.10.2004
5  * @author Sebastian Hack
6  * @cvs-id $Id$
7  */
8
9 #ifdef HAVE_CONFIG_H
10 #include "config.h"
11 #endif
12
13 #include <stdio.h>
14 #include <stdarg.h>
15 #include <string.h>
16 #include <limits.h>
17
18 #include "benode_t.h"
19 #include "be_t.h"
20
21 #include "obst.h"
22 #include "list.h"
23 #include "iterator.h"
24
25 #include "iredges_t.h"
26 #include "irgwalk.h"
27 #include "irnode_t.h"
28 #include "irmode_t.h"
29 #include "irdump.h"
30 #include "irprintf_t.h"
31 #include "array.h"
32 #include "debug.h"
33 #include "irtools.h"
34
35 #include "besched_t.h"
36 #include "beutil.h"
37 #include "belive_t.h"
38 #include "belistsched.h"
39 #include "beschedmris.h"
40 #include "bearch.h"
41 #include "bestat.h"
42
43 /**
44  * All scheduling info needed per node.
45  */
46 typedef struct _sched_irn_t {
47         unsigned num_not_sched_user; /**< The number of not yet scheduled users of this node */
48         unsigned already_sched : 1;  /**< Set if this node is already scheduled */
49 } sched_irn_t;
50
51 /**
52  * Scheduling environment for the whole graph.
53  */
54 typedef struct _sched_env_t {
55         sched_irn_t *sched_info;                    /**< scheduling info per node */
56         const list_sched_selector_t *selector;      /**< The node selector. */
57         const arch_env_t *arch_env;                 /**< The architecture environment. */
58         const ir_graph *irg;                        /**< The graph to schedule. */
59         void *selector_env;                         /**< A pointer to give to the selector. */
60 } sched_env_t;
61
62 /**
63  * Environment for a block scheduler.
64  */
65 typedef struct _block_sched_env_t {
66         sched_irn_t *sched_info;                    /**< scheduling info per node, copied from the global scheduler object */
67         nodeset *cands;                             /**< the set of candidates */
68         ir_node *block;                             /**< the current block */
69         sched_env_t *sched_env;                     /**< the scheduler environment */
70         nodeset *live;                              /**< simple liveness during scheduling */
71         const list_sched_selector_t *selector;
72         void *selector_block_env;
73         DEBUG_ONLY(firm_dbg_module_t *dbg;)
74 } block_sched_env_t;
75
76 /**
77  * Returns non-zero if the node is already scheduled
78  */
79 static INLINE int is_already_scheduled(block_sched_env_t *env, ir_node *n)
80 {
81         int idx = get_irn_idx(n);
82
83         assert(idx < ARR_LEN(env->sched_info));
84         return env->sched_info[idx].already_sched;
85 }
86
87 /**
88  * Mark a node as already scheduled
89  */
90 static INLINE void mark_already_scheduled(block_sched_env_t *env, ir_node *n)
91 {
92         int idx = get_irn_idx(n);
93
94         assert(idx < ARR_LEN(env->sched_info));
95         env->sched_info[idx].already_sched = 1;
96 }
97
98 /**
99  * Try to put a node in the ready set.
100  * @param env   The block scheduler environment.
101  * @param pred  The previous scheduled node.
102  * @param irn   The node to make ready.
103  * @return 1, if the node could be made ready, 0 else.
104  */
105 static INLINE int make_ready(block_sched_env_t *env, ir_node *pred, ir_node *irn)
106 {
107         int i, n;
108
109     /* Blocks cannot be scheduled. */
110     if (is_Block(irn))
111         return 0;
112
113     /*
114      * Check, if the given ir node is in a different block as the
115      * currently scheduled one. If that is so, don't make the node ready.
116      */
117     if (env->block != get_nodes_block(irn))
118         return 0;
119
120         for (i = 0, n = get_irn_ins_or_deps(irn); i < n; ++i) {
121         ir_node *op = get_irn_in_or_dep(irn, i);
122
123         /* if irn is an End we have keep-alives and op might be a block, skip that */
124         if (is_Block(op)) {
125           assert(get_irn_op(irn) == op_End);
126           continue;
127         }
128
129         /* If the operand is local to the scheduled block and not yet
130          * scheduled, this nodes cannot be made ready, so exit. */
131         if (! is_already_scheduled(env, op) && get_nodes_block(op) == env->block)
132             return 0;
133     }
134
135         nodeset_insert(env->cands, irn);
136
137         /* Notify selector about the ready node. */
138         if (env->selector->node_ready)
139                 env->selector->node_ready(env->selector_block_env, irn, pred);
140
141     DB((env->dbg, LEVEL_2, "\tmaking ready: %+F\n", irn));
142
143     return 1;
144 }
145
146 /**
147  * Try, to make all users of a node ready.
148  * In fact, a usage node can only be made ready, if all its operands
149  * have already been scheduled yet. This is checked my make_ready().
150  * @param env The block schedule environment.
151  * @param irn The node, which usages (successors) are to be made ready.
152  */
153 static INLINE void make_users_ready(block_sched_env_t *env, ir_node *irn)
154 {
155         const ir_edge_t *edge;
156
157         foreach_out_edge(irn, edge) {
158                 ir_node *user = get_edge_src_irn(edge);
159                 if (! is_Phi(user))
160                         make_ready(env, irn, user);
161         }
162
163         foreach_out_edge_kind(irn, edge, EDGE_KIND_DEP) {
164                 ir_node *user = get_edge_src_irn(edge);
165                 if (! is_Phi(user))
166                         make_ready(env, irn, user);
167         }
168 }
169
170 /**
171  * Returns the number of not yet schedules users.
172  */
173 static INLINE int get_irn_not_sched_user(block_sched_env_t *env, ir_node *n) {
174         int idx = get_irn_idx(n);
175
176         assert(idx < ARR_LEN(env->sched_info));
177         return env->sched_info[idx].num_not_sched_user;
178 }
179
180 /**
181  * Sets the number of not yet schedules users.
182  */
183 static INLINE void set_irn_not_sched_user(block_sched_env_t *env, ir_node *n, int num) {
184         int idx = get_irn_idx(n);
185
186         assert(idx < ARR_LEN(env->sched_info));
187         env->sched_info[idx].num_not_sched_user = num;
188 }
189
190 /**
191  * Add @p num to the number of not yet schedules users and returns the result.
192  */
193 static INLINE int add_irn_not_sched_user(block_sched_env_t *env, ir_node *n, int num) {
194         int idx = get_irn_idx(n);
195
196         assert(idx < ARR_LEN(env->sched_info));
197         env->sched_info[idx].num_not_sched_user += num;
198         return env->sched_info[idx].num_not_sched_user;
199 }
200
201 /**
202  * Returns the number of users of a node having mode datab.
203  */
204 static int get_num_successors(ir_node *irn) {
205         int             sum = 0;
206         const ir_edge_t *edge;
207
208         if (get_irn_mode(irn) == mode_T) {
209                 /* for mode_T nodes: count the users of all Projs */
210                 foreach_out_edge(irn, edge) {
211                         ir_node *proj = get_edge_src_irn(edge);
212                         ir_mode *mode = get_irn_mode(proj);
213
214                         if (mode == mode_T)
215                                 sum += get_num_successors(proj);
216                         else if (mode_is_datab(mode))
217                                 sum += get_irn_n_edges(proj);
218                 }
219         }
220         else {
221                 /* do not count keep-alive edges */
222                 foreach_out_edge(irn, edge) {
223                         if (get_irn_opcode(get_edge_src_irn(edge)) != iro_End)
224                                 sum++;
225                 }
226         }
227
228         return sum;
229 }
230
231 /**
232  * Adds irn to @p live, updates all inputs that this user is scheduled
233  * and counts all of it's non scheduled users.
234  */
235 static void update_sched_liveness(block_sched_env_t *env, ir_node *irn) {
236         int i;
237
238         /* ignore Projs */
239         if (is_Proj(irn))
240                 return;
241
242         for (i = get_irn_ins_or_deps(irn) - 1; i >= 0; --i) {
243                 ir_node *in = get_irn_in_or_dep(irn, i);
244
245                 /* if in is a proj: update predecessor */
246                 while (is_Proj(in))
247                         in = get_Proj_pred(in);
248
249                 /* if in is still in the live set: reduce number of users by one */
250                 if (nodeset_find(env->live, in)) {
251                         if (add_irn_not_sched_user(env, in, -1) <= 0)
252                                 nodeset_remove(env->live, in);
253                 }
254         }
255
256         /*
257                 get_num_successors returns the number of all users. This includes
258                 users in different blocks as well. As the each block is scheduled separately
259                 the liveness info of those users will not be updated and so these
260                 users will keep up the register pressure as it is desired.
261         */
262         i = get_num_successors(irn);
263         if (i > 0) {
264                 set_irn_not_sched_user(env, irn, i);
265                 nodeset_insert(env->live, irn);
266         }
267 }
268
269 static INLINE int must_appear_in_schedule(const list_sched_selector_t *sel, void *block_env, const ir_node *irn)
270 {
271         int res = -1;
272
273         if(sel->to_appear_in_schedule)
274                 res = sel->to_appear_in_schedule(block_env, irn);
275
276         return res >= 0 ? res : (to_appear_in_schedule(irn) || be_is_Keep(irn) || be_is_CopyKeep(irn) || be_is_RegParams(irn));
277 }
278
279 /**
280  * Append an instruction to a schedule.
281  * @param env The block scheduling environment.
282  * @param irn The node to add to the schedule.
283  * @return    The given node.
284  */
285 static ir_node *add_to_sched(block_sched_env_t *env, ir_node *irn)
286 {
287     /* If the node consumes/produces data, it is appended to the schedule
288      * list, otherwise, it is not put into the list */
289     if (must_appear_in_schedule(env->selector, env->selector_block_env, irn)) {
290         sched_info_t *info = get_irn_sched_info(irn);
291         INIT_LIST_HEAD(&info->list);
292         info->scheduled = 1;
293                 update_sched_liveness(env, irn);
294         sched_add_before(env->block, irn);
295
296         DBG((env->dbg, LEVEL_2, "\tadding %+F\n", irn));
297     }
298
299         /* notify the selector about the finally selected node. */
300         if (env->selector->node_selected)
301                 env->selector->node_selected(env->selector_block_env, irn);
302
303     /* Insert the node in the set of all already scheduled nodes. */
304     mark_already_scheduled(env, irn);
305
306     /* Remove the node from the ready set */
307     if(nodeset_find(env->cands, irn))
308         nodeset_remove(env->cands, irn);
309
310     return irn;
311 }
312
313 /**
314  * Add the proj nodes of a tuple-mode irn to the schedule immediately
315  * after the tuple-moded irn. By pinning the projs after the irn, no
316  * other nodes can create a new lifetime between the tuple-moded irn and
317  * one of its projs. This should render a realistic image of a
318  * tuple-moded irn, which in fact models a node which defines multiple
319  * values.
320  *
321  * @param irn The tuple-moded irn.
322  */
323 static void add_tuple_projs(block_sched_env_t *env, ir_node *irn)
324 {
325         const ir_edge_t *edge;
326
327         assert(get_irn_mode(irn) == mode_T && "Mode of node must be tuple");
328
329         if(is_Bad(irn))
330                 return;
331
332         foreach_out_edge(irn, edge) {
333                 ir_node *out = edge->src;
334
335                 assert(is_Proj(out) && "successor of a modeT node must be a proj");
336
337                 if (get_irn_mode(out) == mode_T)
338                         add_tuple_projs(env, out);
339                 else {
340                         add_to_sched(env, out);
341                         make_users_ready(env, out);
342                 }
343         }
344 }
345
346 /**
347  * Perform list scheduling on a block.
348  *
349  * Note, that the caller must compute a linked list of nodes in the block
350  * using the link field before calling this function.
351  *
352  * Also the outs must have been computed.
353  *
354  * @param block The block node.
355  * @param env Scheduling environment.
356  */
357 static void list_sched_block(ir_node *block, void *env_ptr)
358 {
359         sched_env_t *env                      = env_ptr;
360         const list_sched_selector_t *selector = env->selector;
361         ir_node *start_node                   = get_irg_start(get_irn_irg(block));
362         sched_info_t *info                    = get_irn_sched_info(block);
363
364         block_sched_env_t be;
365         const ir_edge_t *edge;
366         ir_node *irn;
367         int j, m;
368
369         /* Initialize the block's list head that will hold the schedule. */
370         INIT_LIST_HEAD(&info->list);
371
372         /* Initialize the block scheduling environment */
373         be.sched_info        = env->sched_info;
374         be.block             = block;
375         be.cands             = new_nodeset(get_irn_n_edges(block));
376         be.live              = new_nodeset(get_irn_n_edges(block));
377         be.selector          = selector;
378         be.sched_env         = env;
379         FIRM_DBG_REGISTER(be.dbg, "firm.be.sched");
380
381         DBG((be.dbg, LEVEL_1, "scheduling %+F\n", block));
382
383         if (selector->init_block)
384                 be.selector_block_env = selector->init_block(env->selector_env, block);
385
386         /* Then one can add all nodes are ready to the set. */
387         foreach_out_edge(block, edge) {
388                 ir_node *irn = get_edge_src_irn(edge);
389
390                 /* Skip the end node because of keepalive edges. */
391                 if (get_irn_opcode(irn) == iro_End)
392                         continue;
393
394                 if (is_Phi(irn)) {
395                         /*
396                                 Phi functions are scheduled immediately, since they     only
397                                 transfer data flow from the predecessors to this block.
398                         */
399                         add_to_sched(&be, irn);
400                         make_users_ready(&be, irn);
401                 }
402                 else if (irn == start_node) {
403                         /* The start block will be scheduled as the first node */
404                         add_to_sched(&be, irn);
405                         add_tuple_projs(&be, irn);
406                 }
407                 else {
408                         /* Other nodes must have all operands in other blocks to be made
409                         * ready */
410                         int ready = 1;
411
412                         /* Check, if the operands of a node are not local to this block */
413                         for (j = 0, m = get_irn_ins_or_deps(irn); j < m; ++j) {
414                                 ir_node *operand = get_irn_in_or_dep(irn, j);
415
416                                 if (get_nodes_block(operand) == block) {
417                                         ready = 0;
418                                         break;
419                                 }
420                                 else {
421                                         /* live in values increase register pressure */
422                                         update_sched_liveness(&be, operand);
423                                 }
424                         }
425
426                         /* Make the node ready, if all operands live in a foreign block */
427                         if (ready) {
428                                 DBG((be.dbg, LEVEL_2, "\timmediately ready: %+F\n", irn));
429                                 make_ready(&be, NULL, irn);
430                         }
431                 }
432         }
433
434         /* Iterate over all remaining nodes */
435         while (nodeset_count(be.cands) > 0) {
436                 /* collect statistics about amount of ready nodes */
437                 be_do_stat_sched_ready(block, be.cands);
438
439                 /* Keeps must be scheduled immediatly */
440                 foreach_nodeset(be.cands, irn) {
441                         if (be_is_Keep(irn) || be_is_CopyKeep(irn)) {
442                                 nodeset_break(be.cands);
443                                 break;
444                         }
445                 }
446
447                 if (! irn) {
448                         /* Keeps must be immediately scheduled */
449                         irn = be.selector->select(be.selector_block_env, be.cands, be.live);
450                 }
451
452                 DB((be.dbg, LEVEL_2, "\tpicked node %+F\n", irn));
453
454                 /* Add the node to the schedule. */
455                 add_to_sched(&be, irn);
456
457                 if (get_irn_mode(irn) == mode_T)
458                         add_tuple_projs(&be, irn);
459                 else
460                         make_users_ready(&be, irn);
461
462                 /* remove the scheduled node from the ready list. */
463                 if (nodeset_find(be.cands, irn))
464                         nodeset_remove(be.cands, irn);
465         }
466
467         if (selector->finish_block)
468                 selector->finish_block(be.selector_block_env);
469
470         del_nodeset(be.cands);
471         del_nodeset(be.live);
472 }
473
474 /* List schedule a graph. */
475 void list_sched(const be_irg_t *birg, be_options_t *be_opts)
476 {
477         const arch_env_t *arch_env  = birg->main_env->arch_env;
478         ir_graph         *irg       = birg->irg;
479
480         int num_nodes;
481         sched_env_t env;
482         mris_env_t *mris = NULL;
483         list_sched_selector_t sel;
484
485         /* Select a scheduler based on backend options */
486         switch (be_opts->sched_select) {
487                 case BE_SCHED_SELECT_TRIVIAL:
488                         memcpy(&sel, trivial_selector, sizeof(sel));
489                         break;
490                 case BE_SCHED_SELECT_REGPRESS:
491                         memcpy(&sel, reg_pressure_selector, sizeof(sel));
492                         break;
493                 case BE_SCHED_SELECT_MUCHNIK:
494                         memcpy(&sel, muchnik_selector, sizeof(sel));
495                         break;
496                 case BE_SCHED_SELECT_HEUR:
497                         memcpy(&sel, heuristic_selector, sizeof(sel));
498                         break;
499                 case BE_SCHED_SELECT_HMUCHNIK:
500                 default:
501                         memcpy(&sel, trivial_selector, sizeof(sel));
502         }
503
504         /* Assure, that the out edges are computed */
505         edges_assure(irg);
506
507         if (be_opts->mris)
508                 mris = be_sched_mris_preprocess(birg);
509
510         num_nodes = get_irg_last_idx(irg);
511
512         /* initialize environment for list scheduler */
513         memset(&env, 0, sizeof(env));
514         env.selector   = arch_env->isa->impl->get_list_sched_selector(arch_env->isa, &sel);
515         env.arch_env   = arch_env;
516         env.irg        = irg;
517         env.sched_info = NEW_ARR_F(sched_irn_t, num_nodes);
518
519         memset(env.sched_info, 0, num_nodes * sizeof(env.sched_info[0]));
520
521         if (env.selector->init_graph)
522                 env.selector_env = env.selector->init_graph(env.selector, arch_env, irg);
523
524         /* Schedule each single block. */
525         irg_block_walk_graph(irg, list_sched_block, NULL, &env);
526
527         if (env.selector->finish_graph)
528                 env.selector->finish_graph(env.selector_env);
529
530         if (be_opts->mris)
531                 be_sched_mris_free(mris);
532
533         DEL_ARR_F(env.sched_info);
534 }