7972a12192a56ed5d4a11a7b9b3403768ffad3f3
[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  */
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11
12 #include <stdio.h>
13 #include <stdarg.h>
14 #include <string.h>
15 #include <limits.h>
16
17 #include "benode_t.h"
18
19 #include "obst.h"
20 #include "list.h"
21 #include "iterator.h"
22
23 #include "iredges_t.h"
24 #include "irgwalk.h"
25 #include "irnode_t.h"
26 #include "irmode_t.h"
27 #include "irdump.h"
28 #include "irprintf_t.h"
29 #include "array.h"
30 #include "debug.h"
31
32 #include "besched_t.h"
33 #include "beutil.h"
34 #include "belive_t.h"
35 #include "belistsched.h"
36 #include "bearch.h"
37 #include "bestat.h"
38
39 #define MAX(x,y) ((x) > (y) ? (x) : (y))
40 #define MIN(x,y) ((x) < (y) ? (x) : (y))
41
42 /**
43  * All scheduling info needed per node.
44  */
45 typedef struct _sched_irn_t {
46         sched_timestep_t delay;     /**< The delay for this node if already calculated, else 0. */
47         sched_timestep_t etime;     /**< The earliest time of this node. */
48         unsigned already_sched : 1; /**< Set if this node is already scheduled */
49         unsigned is_root       : 1; /**< is a root node of a block */
50 } sched_irn_t;
51
52 /**
53  * Scheduling environment for the whole graph.
54  */
55 typedef struct _sched_env_t {
56         sched_irn_t *sched_info;                    /**< scheduling info per node */
57         const list_sched_selector_t *selector;      /**< The node selector. */
58         const arch_env_t *arch_env;                 /**< The architecture environment. */
59         const ir_graph *irg;                        /**< The graph to schedule. */
60         void *selector_env;                         /**< A pointer to give to the selector. */
61 } sched_env_t;
62
63 #if 0
64 /*
65  * Ugly global variable for the compare function
66  * since qsort(3) does not pass an extra pointer.
67  */
68 static ir_node *curr_bl = NULL;
69
70 static int cmp_usage(const void *a, const void *b)
71 {
72         struct trivial_sched_env *env;
73         const ir_node *p = a;
74         const ir_node *q = b;
75         int res = 0;
76
77         res = is_live_end(env->curr_bl, a) - is_live_end(env->curr_bl, b);
78
79         /*
80          * One of them is live at the end of the block.
81          * Then, that one shall be scheduled at after the other
82          */
83         if(res != 0)
84                 return res;
85
86
87         return res;
88 }
89 #endif
90
91 /**
92  * The trivial selector:
93  * Just assure that branches are executed last, otherwise select
94  * the first node ready.
95  */
96 static ir_node *trivial_select(void *block_env, nodeset *ready_set)
97 {
98         const arch_env_t *arch_env = block_env;
99         ir_node *irn = NULL;
100         int const_last = 0;
101
102         /* assure that branches and constants are executed last */
103         for (irn = nodeset_first(ready_set); irn; irn = nodeset_next(ready_set)) {
104                 arch_irn_class_t irn_class = arch_irn_classify(arch_env, irn);
105
106                 if (irn_class != arch_irn_class_branch && (const_last ? (irn_class != arch_irn_class_const) : 1)) {
107                         nodeset_break(ready_set);
108                         return irn;
109                 }
110         }
111
112         /* assure that constants are executed before branches */
113         if (const_last) {
114                 for (irn = nodeset_first(ready_set); irn; irn = nodeset_next(ready_set)) {
115                         if (arch_irn_classify(arch_env, irn) != arch_irn_class_branch) {
116                                 nodeset_break(ready_set);
117                                 return irn;
118                         }
119                 }
120         }
121
122
123         /* at last: schedule branches */
124         irn = nodeset_first(ready_set);
125         nodeset_break(ready_set);
126
127         return irn;
128 }
129
130 static void *trivial_init_graph(const list_sched_selector_t *vtab, const arch_env_t *arch_env, ir_graph *irg)
131 {
132         return (void *) arch_env;
133 }
134
135 static void *trivial_init_block(void *graph_env, ir_node *bl)
136 {
137         return graph_env;
138 }
139
140 static INLINE int must_appear_in_schedule(const list_sched_selector_t *sel, void *block_env, const ir_node *irn)
141 {
142         int res = 0;
143
144         if(sel->to_appear_in_schedule)
145                 res = sel->to_appear_in_schedule(block_env, irn);
146
147         return res || to_appear_in_schedule(irn) || be_is_Keep(irn) || be_is_RegParams(irn);
148 }
149
150 static const list_sched_selector_t trivial_selector_struct = {
151         trivial_init_graph,
152         trivial_init_block,
153         trivial_select,
154         NULL,                /* to_appear_in_schedule */
155         NULL,                /* exectime */
156         NULL,                /* latency */
157         NULL,                /* finish_block */
158         NULL                 /* finish_graph */
159 };
160
161 const list_sched_selector_t *trivial_selector = &trivial_selector_struct;
162
163 typedef struct _usage_stats_t {
164         ir_node *irn;
165         struct _usage_stats_t *next;
166         int max_hops;
167         int uses_in_block;      /**< Number of uses inside the current block. */
168         int already_consumed;   /**< Number of insns using this value already
169                                                           scheduled. */
170 } usage_stats_t;
171
172 typedef struct {
173         const list_sched_selector_t *vtab;
174         const arch_env_t *arch_env;
175 } reg_pressure_main_env_t;
176
177 typedef struct {
178         struct obstack obst;
179         const reg_pressure_main_env_t *main_env;
180         usage_stats_t *root;
181         nodeset *already_scheduled;
182 } reg_pressure_selector_env_t;
183
184 static INLINE usage_stats_t *get_or_set_usage_stats(reg_pressure_selector_env_t *env, ir_node *irn)
185 {
186         usage_stats_t *us = get_irn_link(irn);
187
188         if(!us) {
189                 us                   = obstack_alloc(&env->obst, sizeof(us[0]));
190                 us->irn              = irn;
191                 us->already_consumed = 0;
192                 us->max_hops         = INT_MAX;
193                 us->next             = env->root;
194                 env->root            = us;
195                 set_irn_link(irn, us);
196         }
197
198         return us;
199 }
200
201 static INLINE usage_stats_t *get_usage_stats(ir_node *irn)
202 {
203         usage_stats_t *us = get_irn_link(irn);
204         assert(us && "This node must have usage stats");
205         return us;
206 }
207
208 static int max_hops_walker(reg_pressure_selector_env_t *env, ir_node *irn, ir_node *curr_bl, int depth, unsigned visited_nr)
209 {
210         ir_node *bl = get_nodes_block(irn);
211         /*
212          * If the reached node is not in the block desired,
213          * return the value passed for this situation.
214          */
215         if(get_nodes_block(irn) != bl)
216                 return block_dominates(bl, curr_bl) ? 0 : INT_MAX;
217
218         /*
219          * If the node is in the current block but not
220          * yet scheduled, we keep on searching from that node.
221          */
222         if(!nodeset_find(env->already_scheduled, irn)) {
223                 int i, n;
224                 int res = 0;
225                 for(i = 0, n = get_irn_arity(irn); i < n; ++i) {
226                         ir_node *operand = get_irn_n(irn, i);
227
228                         if(get_irn_visited(operand) < visited_nr) {
229                                 int tmp;
230
231                                 set_irn_visited(operand, visited_nr);
232                                 tmp = max_hops_walker(env, operand, bl, depth + 1, visited_nr);
233                                 res = MAX(tmp, res);
234                         }
235                 }
236
237                 return res;
238         }
239
240         /*
241          * If the node is in the current block and scheduled, return
242          * the depth which indicates the number of steps to the
243          * region of scheduled nodes.
244          */
245         return depth;
246 }
247
248 static int compute_max_hops(reg_pressure_selector_env_t *env, ir_node *irn)
249 {
250         ir_node *bl   = get_nodes_block(irn);
251         ir_graph *irg = get_irn_irg(bl);
252         int res       = 0;
253
254         const ir_edge_t *edge;
255
256         foreach_out_edge(irn, edge) {
257                 ir_node *user       = get_edge_src_irn(edge);
258                 unsigned visited_nr = get_irg_visited(irg) + 1;
259                 int max_hops;
260
261                 set_irg_visited(irg, visited_nr);
262                 max_hops = max_hops_walker(env, user, irn, 0, visited_nr);
263                 res      = MAX(res, max_hops);
264         }
265
266         return res;
267 }
268
269 static void *reg_pressure_graph_init(const list_sched_selector_t *vtab, const arch_env_t *arch_env, ir_graph *irg)
270 {
271         reg_pressure_main_env_t *main_env = xmalloc(sizeof(main_env[0]));
272
273         main_env->arch_env = arch_env;
274         main_env->vtab     = vtab;
275         irg_walk_graph(irg, firm_clear_link, NULL, NULL);
276
277         return main_env;
278 }
279
280 static void *reg_pressure_block_init(void *graph_env, ir_node *bl)
281 {
282         ir_node *irn;
283         reg_pressure_selector_env_t *env  = xmalloc(sizeof(env[0]));
284
285         obstack_init(&env->obst);
286         env->already_scheduled = new_nodeset(32);
287         env->root              = NULL;
288         env->main_env          = graph_env;
289
290         /*
291          * Collect usage statistics.
292          */
293         sched_foreach(bl, irn) {
294                 if(must_appear_in_schedule(env->main_env->vtab, env, irn)) {
295                         int i, n;
296
297                         for(i = 0, n = get_irn_arity(irn); i < n; ++i) {
298                                 ir_node *op = get_irn_n(irn, i);
299                                 if(must_appear_in_schedule(env->main_env->vtab, env, irn)) {
300                                         usage_stats_t *us = get_or_set_usage_stats(env, irn);
301                                         if(is_live_end(bl, op))
302                                                 us->uses_in_block = 99999;
303                                         else
304                                                 us->uses_in_block++;
305                                 }
306                         }
307                 }
308         }
309
310         return env;
311 }
312
313 static void reg_pressure_block_free(void *block_env)
314 {
315         reg_pressure_selector_env_t *env = block_env;
316         usage_stats_t *us;
317
318         for(us = env->root; us; us = us->next)
319                 set_irn_link(us->irn, NULL);
320
321         obstack_free(&env->obst, NULL);
322         del_nodeset(env->already_scheduled);
323         free(env);
324 }
325
326 static int get_result_hops_sum(reg_pressure_selector_env_t *env, ir_node *irn)
327 {
328         int res = 0;
329         if(get_irn_mode(irn) == mode_T) {
330                 const ir_edge_t *edge;
331
332                 foreach_out_edge(irn, edge)
333                         res += get_result_hops_sum(env, get_edge_src_irn(edge));
334         }
335
336         else if(mode_is_data(get_irn_mode(irn)))
337                 res = compute_max_hops(env, irn);
338
339
340         return res;
341 }
342
343 static INLINE int reg_pr_costs(reg_pressure_selector_env_t *env, ir_node *irn)
344 {
345         int i, n;
346         int sum = 0;
347
348         for(i = 0, n = get_irn_arity(irn); i < n; ++i) {
349                 ir_node *op = get_irn_n(irn, i);
350
351                 if(must_appear_in_schedule(env->main_env->vtab, env, op))
352                         sum += compute_max_hops(env, op);
353         }
354
355         sum += get_result_hops_sum(env, irn);
356
357         return sum;
358 }
359
360 static ir_node *reg_pressure_select(void *block_env, nodeset *ready_set)
361 {
362         reg_pressure_selector_env_t *env = block_env;
363         ir_node *irn, *res     = NULL;
364         int curr_cost          = INT_MAX;
365
366         assert(nodeset_count(ready_set) > 0);
367
368         for (irn = nodeset_first(ready_set); irn; irn = nodeset_next(ready_set)) {
369                 /*
370                         Ignore branch instructions for the time being.
371                         They should only be scheduled if there is nothing else.
372                 */
373                 if (arch_irn_classify(env->main_env->arch_env, irn) != arch_irn_class_branch) {
374                         int costs = reg_pr_costs(env, irn);
375                         if (costs <= curr_cost) {
376                                 res       = irn;
377                                 curr_cost = costs;
378                         }
379                 }
380         }
381
382         /*
383                 There was no result so we only saw a branch.
384                 Take it and finish.
385         */
386
387         if(!res) {
388                 res = nodeset_first(ready_set);
389                 nodeset_break(ready_set);
390
391                 assert(res && "There must be a node scheduled.");
392         }
393
394         nodeset_insert(env->already_scheduled, res);
395         return res;
396 }
397
398 /**
399  * Environment for a block scheduler.
400  */
401 typedef struct _block_sched_env_t {
402         sched_irn_t *sched_info;                    /**< scheduling info per node, copied from the global scheduler object */
403         sched_timestep_t curr_time;                 /**< current time of the scheduler */
404         nodeset *cands;                             /**< the set of candidates */
405         ir_node *block;                             /**< the current block */
406         sched_env_t *sched_env;                     /**< the scheduler environment */
407         const list_sched_selector_t *selector;
408         void *selector_block_env;
409         DEBUG_ONLY(firm_dbg_module_t *dbg;)
410 } block_sched_env_t;
411
412 /**
413  * Returns non-zero if the node is already scheduled
414  */
415 static INLINE int is_already_scheduled(block_sched_env_t *env, ir_node *n)
416 {
417         int idx = get_irn_idx(n);
418
419         assert(idx < ARR_LEN(env->sched_info));
420         return env->sched_info[idx].already_sched;
421 }
422
423 /**
424  * Mark a node as already scheduled
425  */
426 static INLINE void mark_already_scheduled(block_sched_env_t *env, ir_node *n)
427 {
428         int idx = get_irn_idx(n);
429
430         assert(idx < ARR_LEN(env->sched_info));
431         env->sched_info[idx].already_sched = 1;
432 }
433
434 /**
435  * Returns non-zero if the node is a root node
436  */
437 static INLINE unsigned is_root_node(block_sched_env_t *env, ir_node *n)
438 {
439         int idx = get_irn_idx(n);
440
441         assert(idx < ARR_LEN(env->sched_info));
442         return env->sched_info[idx].is_root;
443 }
444
445 /**
446  * Mark a node as roto node
447  */
448 static INLINE void mark_root_node(block_sched_env_t *env, ir_node *n)
449 {
450         int idx = get_irn_idx(n);
451
452         assert(idx < ARR_LEN(env->sched_info));
453         env->sched_info[idx].is_root = 1;
454 }
455
456 /**
457  * Get the current delay.
458  */
459 static sched_timestep_t get_irn_delay(block_sched_env_t *env, ir_node *n) {
460         int idx = get_irn_idx(n);
461
462         assert(idx < ARR_LEN(env->sched_info));
463         return env->sched_info[idx].delay;
464 }
465
466 /**
467  * Set the current delay.
468  */
469 static void set_irn_delay(block_sched_env_t *env, ir_node *n, sched_timestep_t delay) {
470         int idx = get_irn_idx(n);
471
472         assert(idx < ARR_LEN(env->sched_info));
473         env->sched_info[idx].delay = delay;
474 }
475
476 /**
477  * Get the current etime.
478  */
479 static sched_timestep_t get_irn_etime(block_sched_env_t *env, ir_node *n) {
480         int idx = get_irn_idx(n);
481
482         assert(idx < ARR_LEN(env->sched_info));
483         return env->sched_info[idx].etime;
484 }
485
486 /**
487  * Set the current etime.
488  */
489 static void set_irn_etime(block_sched_env_t *env, ir_node *n, sched_timestep_t etime) {
490         int idx = get_irn_idx(n);
491
492         assert(idx < ARR_LEN(env->sched_info));
493         env->sched_info[idx].etime = etime;
494 }
495
496 /**
497  * returns the exec-time for node n.
498  */
499 static sched_timestep_t exectime(sched_env_t *env, ir_node *n) {
500   if (be_is_Keep(n) || is_Proj(n))
501     return 0;
502         if (env->selector->exectime)
503                 return env->selector->exectime(env->selector_env, n);
504         return 1;
505 }
506
507 /**
508  * Calculates the latency for between two ops
509  */
510 static sched_timestep_t latency(sched_env_t *env, ir_node *pred, int pred_cycle, ir_node *curr, int curr_cycle) {
511         /* a Keep hides a root */
512   if (be_is_Keep(curr))
513                 return exectime(env, pred);
514
515         /* Proj's are executed immediately */
516         if (is_Proj(curr))
517     return 0;
518
519         /* predecessors Proj's must be skipped */
520   if (is_Proj(pred))
521     pred = get_Proj_pred(pred);
522
523         if (env->selector->latency)
524                 return env->selector->latency(env->selector_env, pred, pred_cycle, curr, curr_cycle);
525         return 1;
526 }
527
528 /**
529  * Try to put a node in the ready set.
530  * @param env   The block scheduler environment.
531  * @param pred  The previous scheduled node.
532  * @param irn   The node to make ready.
533  * @return 1, if the node could be made ready, 0 else.
534  */
535 static INLINE int make_ready(block_sched_env_t *env, ir_node *pred, ir_node *irn)
536 {
537     int i, n;
538                 sched_timestep_t etime_p, etime;
539
540     /* Blocks cannot be scheduled. */
541     if (is_Block(irn))
542         return 0;
543
544     /*
545      * Check, if the given ir node is in a different block as the
546      * currently scheduled one. If that is so, don't make the node ready.
547      */
548     if (env->block != get_nodes_block(irn))
549         return 0;
550
551     for (i = 0, n = get_irn_arity(irn); i < n; ++i) {
552         ir_node *op = get_irn_n(irn, i);
553
554         /* if irn is an End we have keep-alives and op might be a block, skip that */
555         if (is_Block(op)) {
556           assert(get_irn_op(irn) == op_End);
557           continue;
558         }
559
560         /* If the operand is local to the scheduled block and not yet
561          * scheduled, this nodes cannot be made ready, so exit. */
562         if (!is_already_scheduled(env, op) && get_nodes_block(op) == env->block)
563             return 0;
564     }
565
566     nodeset_insert(env->cands, irn);
567
568                 /* calculate the etime of this node */
569                 etime = env->curr_time;
570                 if (pred) {
571                         etime_p  = get_irn_etime(env, pred);
572                         etime   += latency(env->sched_env, pred, 1, irn, 0);
573
574                         etime = etime_p > etime ? etime_p : etime;
575                 }
576
577                 set_irn_etime(env, irn, etime);
578
579     DB((env->dbg, LEVEL_2, "\tmaking ready: %+F etime %u\n", irn, etime));
580
581     return 1;
582 }
583
584 /**
585  * Try, to make all users of a node ready.
586  * In fact, a usage node can only be made ready, if all its operands
587  * have already been scheduled yet. This is checked my make_ready().
588  * @param env The block schedule environment.
589  * @param irn The node, which usages (successors) are to be made ready.
590  */
591 static INLINE void make_users_ready(block_sched_env_t *env, ir_node *irn)
592 {
593         const ir_edge_t *edge;
594
595         foreach_out_edge(irn, edge) {
596                 ir_node *user = edge->src;
597                 if(!is_Phi(user))
598                         make_ready(env, irn, user);
599         }
600 }
601
602 /**
603  * Compare to nodes using pointer equality.
604  * @param p1 Node one.
605  * @param p2 Node two.
606  * @return 0 if they are identical.
607  */
608 static int node_cmp_func(const void *p1, const void *p2)
609 {
610     return p1 != p2;
611 }
612
613 /**
614  * Append an instruction to a schedule.
615  * @param env The block scheduling environment.
616  * @param irn The node to add to the schedule.
617  * @return    The given node.
618  */
619 static ir_node *add_to_sched(block_sched_env_t *env, ir_node *irn)
620 {
621     /* If the node consumes/produces data, it is appended to the schedule
622      * list, otherwise, it is not put into the list */
623     if(must_appear_in_schedule(env->selector, env->selector_block_env, irn)) {
624         sched_info_t *info = get_irn_sched_info(irn);
625         INIT_LIST_HEAD(&info->list);
626         info->scheduled = 1;
627         sched_add_before(env->block, irn);
628
629         DBG((env->dbg, LEVEL_2, "\tadding %+F\n", irn));
630     }
631
632     /* Insert the node in the set of all already scheduled nodes. */
633     mark_already_scheduled(env, irn);
634
635     /* Remove the node from the ready set */
636     if(nodeset_find(env->cands, irn))
637         nodeset_remove(env->cands, irn);
638
639     return irn;
640 }
641
642 /**
643  * Add the proj nodes of a tuple-mode irn to the schedule immediately
644  * after the tuple-moded irn. By pinning the projs after the irn, no
645  * other nodes can create a new lifetime between the tuple-moded irn and
646  * one of its projs. This should render a realistic image of a
647  * tuple-moded irn, which in fact models a node which defines multiple
648  * values.
649  *
650  * @param irn The tuple-moded irn.
651  */
652 static void add_tuple_projs(block_sched_env_t *env, ir_node *irn)
653 {
654         const ir_edge_t *edge;
655
656         assert(get_irn_mode(irn) == mode_T && "Mode of node must be tuple");
657
658         foreach_out_edge(irn, edge) {
659                 ir_node *out = edge->src;
660
661                 assert(is_Proj(out) && "successor of a modeT node must be a proj");
662
663                 if (get_irn_mode(out) == mode_T)
664                         add_tuple_projs(env, out);
665                 else {
666                         add_to_sched(env, out);
667                         make_users_ready(env, out);
668                 }
669         }
670 }
671
672 /**
673  * Execute the heuristic function,
674  */
675 static ir_node *select_node_heuristic(block_sched_env_t *be, nodeset *ns)
676 {
677         ir_node *irn;
678
679         for (irn = nodeset_first(ns); irn; irn = nodeset_next(ns)) {
680                 if (be_is_Keep(irn)) {
681                         nodeset_break(ns);
682                         return irn;
683                 }
684         }
685
686         return be->selector->select(be->selector_block_env, ns);
687 }
688
689 /**
690  * Returns non-zero if root is a root in the block block.
691  */
692 static int is_root(ir_node *root, ir_node *block) {
693         const ir_edge_t *edge;
694
695         foreach_out_edge(root, edge) {
696                 ir_node *succ = get_edge_src_irn(edge);
697
698                 if (is_Block(succ))
699                         continue;
700                 if (get_nodes_block(succ) == block)
701                         return 0;
702         }
703         return 1;
704 }
705
706 /* we need a special mark */
707 static char _mark;
708 #define MARK    &_mark
709
710 /**
711  * descent into a dag and create a pre-order list.
712  */
713 static void descent(ir_node *root, ir_node *block, ir_node **list) {
714         int i;
715
716         if (! is_Phi(root)) {
717                 /* Phi nodes always leave the block */
718                 for (i = get_irn_arity(root) - 1; i >= 0; --i) {
719                         ir_node *pred = get_irn_n(root, i);
720
721                         /* Blocks may happen as predecessors of End nodes */
722                         if (is_Block(pred))
723                                 continue;
724
725                         /* already seen nodes are not marked */
726                         if (get_irn_link(pred) != MARK)
727                                 continue;
728
729                         /* don't leave our block */
730                         if (get_nodes_block(pred) != block)
731                                 continue;
732
733                         descent(pred, block, list);
734                 }
735         }
736         set_irn_link(root, *list);
737         *list = root;
738 }
739
740 /**
741  * Perform list scheduling on a block.
742  *
743  * Note, that the caller must compute a linked list of nodes in the block
744  * using the link field before calling this function.
745  *
746  * Also the outs must have been computed.
747  *
748  * @param block The block node.
749  * @param env Scheduling environment.
750  */
751 static void list_sched_block(ir_node *block, void *env_ptr)
752 {
753         sched_env_t *env                      = env_ptr;
754         const list_sched_selector_t *selector = env->selector;
755         ir_node *start_node                   = get_irg_start(get_irn_irg(block));
756         sched_info_t *info                    = get_irn_sched_info(block);
757
758         block_sched_env_t be;
759         const ir_edge_t *edge;
760         ir_node *irn;
761         int j, m;
762
763         ir_node *root = NULL, *preord = NULL;
764         ir_node *curr;
765
766         /* Initialize the block's list head that will hold the schedule. */
767         INIT_LIST_HEAD(&info->list);
768
769         /* Initialize the block scheduling environment */
770         be.sched_info        = env->sched_info;
771         be.block             = block;
772         be.curr_time         = 0;
773         be.cands             = new_nodeset(get_irn_n_edges(block));
774         be.selector          = selector;
775         be.sched_env         = env;
776         FIRM_DBG_REGISTER(be.dbg, "firm.be.sched");
777
778 //      firm_dbg_set_mask(be.dbg, SET_LEVEL_3);
779
780         if (selector->init_block)
781                 be.selector_block_env = selector->init_block(env->selector_env, block);
782
783         DBG((be.dbg, LEVEL_1, "scheduling %+F\n", block));
784
785         /* First step: Find the root set. */
786         foreach_out_edge(block, edge) {
787                 ir_node *succ = get_edge_src_irn(edge);
788
789                 if (is_root(succ, block)) {
790                         mark_root_node(&be, succ);
791                         set_irn_link(succ, root);
792                         root = succ;
793                 }
794                 else
795                         set_irn_link(succ, MARK);
796         }
797
798         /* Second step: calculate the pre-order list. */
799         preord = NULL;
800         for (curr = root; curr; curr = irn) {
801                 irn = get_irn_link(curr);
802                 descent(curr, block, &preord);
803         }
804         root = preord;
805
806         /* Third step: calculate the Delay. Note that our
807          * list is now in pre-order, starting at root
808          */
809         for (curr = root; curr; curr = get_irn_link(curr)) {
810                 sched_timestep_t d;
811
812                 if (arch_irn_classify(env->arch_env, curr) == arch_irn_class_branch) {
813                         /* assure, that branches can be executed last */
814                         d = 0;
815                 }
816                 else {
817                         if (is_root_node(&be, curr))
818                                 d = exectime(env, curr);
819                         else {
820                                 d = 0;
821                                 foreach_out_edge(curr, edge) {
822                                         ir_node *n = get_edge_src_irn(edge);
823
824                                         if (get_nodes_block(n) == block) {
825                                                 sched_timestep_t ld;
826
827                                                 ld = latency(env, curr, 1, n, 0) + get_irn_delay(&be, n);
828                                                 d = ld > d ? ld : d;
829                                         }
830                                 }
831                         }
832                 }
833                 set_irn_delay(&be, curr, d);
834                 DB((be.dbg, LEVEL_2, "\t%+F delay %u\n", curr, d));
835
836                 /* set the etime of all nodes to 0 */
837                 set_irn_etime(&be, curr, 0);
838         }
839
840
841         /* Then one can add all nodes are ready to the set. */
842         foreach_out_edge(block, edge) {
843                 ir_node *irn = get_edge_src_irn(edge);
844
845                 /* Skip the end node because of keepalive edges. */
846                 if (get_irn_opcode(irn) == iro_End)
847                         continue;
848
849                 if (is_Phi(irn)) {
850                         /* Phi functions are scheduled immediately, since they only transfer
851                          * data flow from the predecessors to this block. */
852
853                         /* Increase the time step. */
854                         be.curr_time += get_irn_etime(&be, irn);
855                         add_to_sched(&be, irn);
856                         make_users_ready(&be, irn);
857                 }
858                 else if (irn == start_node) {
859                         /* The start block will be scheduled as the first node */
860                         be.curr_time += get_irn_etime(&be, irn);
861
862                         add_to_sched(&be, irn);
863                         add_tuple_projs(&be, irn);
864                 }
865                 else {
866                         /* Other nodes must have all operands in other blocks to be made
867                          * ready */
868                         int ready = 1;
869
870                         /* Check, if the operands of a node are not local to this block */
871                         for (j = 0, m = get_irn_arity(irn); j < m; ++j) {
872                                 ir_node *operand = get_irn_n(irn, j);
873
874                                 if (get_nodes_block(operand) == block) {
875                                         ready = 0;
876                                         break;
877                                 }
878                         }
879
880                         /* Make the node ready, if all operands live in a foreign block */
881                         if (ready) {
882                                 DBG((be.dbg, LEVEL_2, "\timmediately ready: %+F\n", irn));
883                                 make_ready(&be, NULL, irn);
884                         }
885                 }
886         }
887
888         while (nodeset_count(be.cands) > 0) {
889                 nodeset *mcands;                            /**< the set of candidates with maximum delay time */
890                 nodeset *ecands;                            /**< the set of nodes in mcands whose etime <= curr_time  */
891                 sched_timestep_t max_delay = 0;
892
893                 /* collect statistics about amount of ready nodes */
894                 be_do_stat_sched_ready(block, be.cands);
895
896                 /* calculate the max delay of all candidates */
897                 foreach_nodeset(be.cands, irn) {
898                         sched_timestep_t d = get_irn_delay(&be, irn);
899
900                         max_delay = d > max_delay ? d : max_delay;
901                 }
902                 mcands = new_nodeset(8);
903                 ecands = new_nodeset(8);
904
905                 /* calculate mcands and ecands */
906                 foreach_nodeset(be.cands, irn) {
907       if (be_is_Keep(irn)) {
908         nodeset_break(be.cands);
909         break;
910       }
911                         if (get_irn_delay(&be, irn) == max_delay) {
912                                 nodeset_insert(mcands, irn);
913                                 if (get_irn_etime(&be, irn) <= be.curr_time)
914                                         nodeset_insert(ecands, irn);
915                         }
916                 }
917
918     if (irn) {
919       /* Keeps must be immediately scheduled */
920     }
921     else {
922                   DB((be.dbg, LEVEL_2, "\tbe.curr_time = %u\n", be.curr_time));
923
924                   /* select a node to be scheduled and check if it was ready */
925                   if (nodeset_count(mcands) == 1) {
926                           DB((be.dbg, LEVEL_3, "\tmcand = 1, max_delay = %u\n", max_delay));
927                           irn = nodeset_first(mcands);
928                   }
929                   else {
930                           int cnt = nodeset_count(ecands);
931                           if (cnt == 1) {
932                                         arch_irn_class_t irn_class;
933
934                                   irn = nodeset_first(ecands);
935                                         irn_class = arch_irn_classify(env->arch_env, irn);
936
937                                         if (irn_class == arch_irn_class_branch) {
938                                                 /* BEWARE: don't select a JUMP if others are still possible */
939                                                 goto force_mcands;
940                                         }
941                                   DB((be.dbg, LEVEL_3, "\tecand = 1, max_delay = %u\n", max_delay));
942                           }
943                           else if (cnt > 1) {
944                                   DB((be.dbg, LEVEL_3, "\tecand = %d, max_delay = %u\n", cnt, max_delay));
945                                   irn = select_node_heuristic(&be, ecands);
946                           }
947                           else {
948 force_mcands:
949                                   DB((be.dbg, LEVEL_3, "\tmcand = %d\n", nodeset_count(mcands)));
950                                   irn = select_node_heuristic(&be, mcands);
951                           }
952                   }
953     }
954                 del_nodeset(mcands);
955                 del_nodeset(ecands);
956
957                 DB((be.dbg, LEVEL_2, "\tpicked node %+F\n", irn));
958
959                 /* Increase the time step. */
960                 be.curr_time += exectime(env, irn);
961
962                 /* Add the node to the schedule. */
963                 add_to_sched(&be, irn);
964
965                 if (get_irn_mode(irn) == mode_T)
966                         add_tuple_projs(&be, irn);
967                 else
968                         make_users_ready(&be, irn);
969
970                 /* remove the scheduled node from the ready list. */
971                 if (nodeset_find(be.cands, irn))
972                         nodeset_remove(be.cands, irn);
973         }
974
975         if (selector->finish_block)
976                 selector->finish_block(be.selector_block_env);
977
978         del_nodeset(be.cands);
979 }
980
981 static const list_sched_selector_t reg_pressure_selector_struct = {
982         reg_pressure_graph_init,
983         reg_pressure_block_init,
984         reg_pressure_select,
985         NULL,                    /* to_appear_in_schedule */
986         NULL,                    /* exectime */
987         NULL,                    /* latency */
988         reg_pressure_block_free,
989         free
990 };
991
992 const list_sched_selector_t *reg_pressure_selector = &reg_pressure_selector_struct;
993
994 /* List schedule a graph. */
995 void list_sched(const arch_env_t *arch_env, ir_graph *irg)
996 {
997         sched_env_t env;
998         int num_nodes = get_irg_last_idx(irg);
999
1000         memset(&env, 0, sizeof(env));
1001         env.selector   = arch_env->isa->impl->get_list_sched_selector(arch_env->isa);
1002         env.arch_env   = arch_env;
1003         env.irg        = irg;
1004         env.sched_info = NEW_ARR_F(sched_irn_t, num_nodes);
1005
1006         memset(env.sched_info, 0, num_nodes * sizeof(*env.sched_info));
1007
1008         if (env.selector->init_graph)
1009                 env.selector_env = env.selector->init_graph(env.selector, arch_env, irg);
1010
1011         /* Assure, that the out edges are computed */
1012         edges_assure(irg);
1013
1014         /* Schedule each single block. */
1015         irg_block_walk_graph(irg, list_sched_block, NULL, &env);
1016
1017         if (env.selector->finish_graph)
1018                 env.selector->finish_graph(env.selector_env);
1019
1020         DEL_ARR_F(env.sched_info);
1021 }