- fixed r22803
[libfirm] / ir / be / belistsched.c
1 /*
2  * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19
20 /**
21  * @file
22  * @brief       Primitive list scheduling with different node selectors.
23  * @author      Sebastian Hack
24  * @date        20.10.2004
25  * @version     $Id$
26  */
27 #include "config.h"
28
29 #include <stdio.h>
30 #include <stdarg.h>
31 #include <string.h>
32 #include <limits.h>
33
34 #include "benode_t.h"
35 #include "be_t.h"
36
37 #include "obst.h"
38 #include "list.h"
39 #include "iterator.h"
40
41 #include "iredges_t.h"
42 #include "irgwalk.h"
43 #include "irnode_t.h"
44 #include "irmode_t.h"
45 #include "irdump.h"
46 #include "irprintf_t.h"
47 #include "array.h"
48 #include "debug.h"
49 #include "irtools.h"
50
51 #include "bemodule.h"
52 #include "besched_t.h"
53 #include "beutil.h"
54 #include "belive_t.h"
55 #include "belistsched.h"
56 #include "beschedmris.h"
57 #include "beschedrss.h"
58 #include "bearch_t.h"
59 #include "bestat.h"
60 #include "beirg_t.h"
61
62 #include "lc_opts.h"
63 #include "lc_opts_enum.h"
64
65 DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL);
66
67 #define BE_SCHED_NODE(irn) (be_is_Keep(irn) || be_is_CopyKeep(irn) || be_is_RegParams(irn))
68
69 enum {
70         BE_SCHED_SELECT_TRIVIAL,
71         BE_SCHED_SELECT_REGPRESS,
72         BE_SCHED_SELECT_MUCHNIK,
73         BE_SCHED_SELECT_HEUR,
74         BE_SCHED_SELECT_HMUCHNIK,
75         BE_SCHED_SELECT_RANDOM,
76         BE_SCHED_SELECT_NORMAL,
77 };
78
79 enum {
80         BE_SCHED_PREP_NONE = 0,
81         BE_SCHED_PREP_MRIS = 2,
82         BE_SCHED_PREP_RSS  = 3
83 };
84
85 typedef struct _list_sched_options_t {
86         int select;  /**< the node selector */
87         int prep;    /**< schedule preparation */
88 } list_sched_options_t;
89
90 static list_sched_options_t list_sched_options = {
91         BE_SCHED_SELECT_NORMAL,   /* mueller heuristic selector */
92         BE_SCHED_PREP_NONE,       /* no scheduling preparation */
93 };
94
95 /* schedule selector options. */
96 static const lc_opt_enum_int_items_t sched_select_items[] = {
97         { "trivial",  BE_SCHED_SELECT_TRIVIAL  },
98         { "random",   BE_SCHED_SELECT_RANDOM   },
99         { "regpress", BE_SCHED_SELECT_REGPRESS },
100         { "normal",   BE_SCHED_SELECT_NORMAL   },
101         { "muchnik",  BE_SCHED_SELECT_MUCHNIK  },
102         { "heur",     BE_SCHED_SELECT_HEUR     },
103         { "hmuchnik", BE_SCHED_SELECT_HMUCHNIK },
104         { NULL,       0 }
105 };
106
107 /* schedule preparation options. */
108 static const lc_opt_enum_int_items_t sched_prep_items[] = {
109         { "none", BE_SCHED_PREP_NONE },
110         { "mris", BE_SCHED_PREP_MRIS },
111         { "rss",  BE_SCHED_PREP_RSS  },
112         { NULL,   0 }
113 };
114
115 static lc_opt_enum_int_var_t sched_select_var = {
116         &list_sched_options.select, sched_select_items
117 };
118
119 static lc_opt_enum_int_var_t sched_prep_var = {
120         &list_sched_options.prep, sched_prep_items
121 };
122
123 static const lc_opt_table_entry_t list_sched_option_table[] = {
124         LC_OPT_ENT_ENUM_PTR("prep",   "schedule preparation",   &sched_prep_var),
125         LC_OPT_ENT_ENUM_PTR("select", "node selector",          &sched_select_var),
126         LC_OPT_LAST
127 };
128
129 /**
130  * All scheduling info needed per node.
131  */
132 typedef struct _sched_irn_t {
133         unsigned num_not_sched_user; /**< The number of not yet scheduled users of this node */
134         unsigned already_sched : 1;  /**< Set if this node is already scheduled */
135 } sched_irn_t;
136
137 /**
138  * Scheduling environment for the whole graph.
139  */
140 typedef struct _sched_env_t {
141         sched_irn_t *sched_info;                    /**< scheduling info per node */
142         const list_sched_selector_t *selector;      /**< The node selector. */
143         void *selector_env;                         /**< A pointer to give to the selector. */
144 } sched_env_t;
145
146 /**
147  * Environment for a block scheduler.
148  */
149 typedef struct _block_sched_env_t {
150         sched_irn_t *sched_info;                    /**< scheduling info per node, copied from the global scheduler object */
151         ir_nodeset_t cands;                         /**< the set of candidates */
152         ir_node *block;                             /**< the current block */
153         sched_env_t *sched_env;                     /**< the scheduler environment */
154         ir_nodeset_t live;                          /**< simple liveness during scheduling */
155         const list_sched_selector_t *selector;
156         void *selector_block_env;
157 } block_sched_env_t;
158
159 /**
160  * Returns non-zero if a node must be placed in the schedule.
161  */
162 static INLINE int must_appear_in_schedule(const list_sched_selector_t *sel, void *block_env, const ir_node *irn)
163 {
164         int res = -1;
165
166         /* if there are no uses, don't schedule */
167         if (get_irn_n_edges(irn) < 1)
168                 return 0;
169
170         /* else ask the scheduler */
171         if (sel->to_appear_in_schedule)
172                 res = sel->to_appear_in_schedule(block_env, irn);
173
174         return res >= 0 ? res : ((to_appear_in_schedule(irn) || BE_SCHED_NODE(irn)) && ! is_Unknown(irn));
175 }
176
177 /**
178  * Returns non-zero if the node is already scheduled
179  */
180 static INLINE int is_already_scheduled(block_sched_env_t *env, ir_node *n)
181 {
182         int idx = get_irn_idx(n);
183
184         assert(idx < ARR_LEN(env->sched_info));
185         return env->sched_info[idx].already_sched;
186 }
187
188 /**
189  * Mark a node as already scheduled
190  */
191 static INLINE void set_already_scheduled(block_sched_env_t *env, ir_node *n)
192 {
193         int idx = get_irn_idx(n);
194
195         assert(idx < ARR_LEN(env->sched_info));
196         env->sched_info[idx].already_sched = 1;
197 }
198
199 static void add_to_sched(block_sched_env_t *env, ir_node *irn);
200
201 /**
202  * Try to put a node in the ready set.
203  * @param env   The block scheduler environment.
204  * @param pred  The previous scheduled node.
205  * @param irn   The node to make ready.
206  * @return 1, if the node could be made ready, 0 else.
207  */
208 static INLINE int make_ready(block_sched_env_t *env, ir_node *pred, ir_node *irn)
209 {
210         int i, n;
211
212         /* Blocks cannot be scheduled. */
213         if (is_Block(irn) || get_irn_n_edges(irn) == 0)
214                 return 0;
215
216         /*
217          * Check, if the given ir node is in a different block as the
218          * currently scheduled one. If that is so, don't make the node ready.
219          */
220         if (env->block != get_nodes_block(irn))
221                 return 0;
222
223         for (i = 0, n = get_irn_ins_or_deps(irn); i < n; ++i) {
224                 ir_node *op = get_irn_in_or_dep(irn, i);
225
226                 /* if irn is an End we have keep-alives and op might be a block, skip that */
227                 if (is_Block(op)) {
228                         assert(is_End(irn));
229                         continue;
230                 }
231
232                 /* If the operand is local to the scheduled block and not yet
233                  * scheduled, this nodes cannot be made ready, so exit. */
234                 if (! is_already_scheduled(env, op) && get_nodes_block(op) == env->block)
235                         return 0;
236         }
237
238         if (! must_appear_in_schedule(env->selector, env, irn)) {
239                 add_to_sched(env, irn);
240                 DB((dbg, LEVEL_3, "\tmaking immediately available: %+F\n", irn));
241         } else {
242                 ir_nodeset_insert(&env->cands, irn);
243
244                 /* Notify selector about the ready node. */
245                 if (env->selector->node_ready)
246                         env->selector->node_ready(env->selector_block_env, irn, pred);
247
248                 DB((dbg, LEVEL_2, "\tmaking ready: %+F\n", irn));
249         }
250
251     return 1;
252 }
253
254 /**
255  * Try, to make all users of a node ready.
256  * In fact, a usage node can only be made ready, if all its operands
257  * have already been scheduled yet. This is checked by make_ready().
258  * @param env The block schedule environment.
259  * @param irn The node, which usages (successors) are to be made ready.
260  */
261 static void make_users_ready(block_sched_env_t *env, ir_node *irn)
262 {
263         const ir_edge_t *edge;
264
265         /* make all data users ready */
266         foreach_out_edge(irn, edge) {
267                 ir_node *user = get_edge_src_irn(edge);
268
269                 if (! is_Phi(user))
270                         make_ready(env, irn, user);
271         }
272
273         /* and the dependent nodes as well */
274         foreach_out_edge_kind(irn, edge, EDGE_KIND_DEP) {
275                 ir_node *user = get_edge_src_irn(edge);
276
277                 if (! is_Phi(user))
278                         make_ready(env, irn, user);
279         }
280 }
281
282 /**
283  * Returns the number of not yet schedules users.
284  */
285 static INLINE int get_irn_not_sched_user(block_sched_env_t *env, ir_node *n) {
286         int idx = get_irn_idx(n);
287
288         assert(idx < ARR_LEN(env->sched_info));
289         return env->sched_info[idx].num_not_sched_user;
290 }
291
292 /**
293  * Sets the number of not yet schedules users.
294  */
295 static INLINE void set_irn_not_sched_user(block_sched_env_t *env, ir_node *n, int num) {
296         int idx = get_irn_idx(n);
297
298         assert(idx < ARR_LEN(env->sched_info));
299         env->sched_info[idx].num_not_sched_user = num;
300 }
301
302 /**
303  * Add @p num to the number of not yet schedules users and returns the result.
304  */
305 static INLINE int add_irn_not_sched_user(block_sched_env_t *env, ir_node *n, int num) {
306         int idx = get_irn_idx(n);
307
308         assert(idx < ARR_LEN(env->sched_info));
309         env->sched_info[idx].num_not_sched_user += num;
310         return env->sched_info[idx].num_not_sched_user;
311 }
312
313 /**
314  * Returns the number of users of a node having mode datab.
315  */
316 static int get_num_successors(ir_node *irn) {
317         int             sum = 0;
318         const ir_edge_t *edge;
319
320         if (get_irn_mode(irn) == mode_T) {
321                 /* for mode_T nodes: count the users of all Projs */
322                 foreach_out_edge(irn, edge) {
323                         ir_node *proj = get_edge_src_irn(edge);
324                         ir_mode *mode = get_irn_mode(proj);
325
326                         if (mode == mode_T) {
327                                 sum += get_num_successors(proj);
328                         } else if (mode_is_datab(mode)) {
329                                 sum += get_irn_n_edges(proj);
330                         }
331                 }
332         }
333         else {
334                 /* do not count keep-alive edges */
335                 foreach_out_edge(irn, edge) {
336                         if (get_irn_opcode(get_edge_src_irn(edge)) != iro_End)
337                                 sum++;
338                 }
339         }
340
341         return sum;
342 }
343
344 /**
345  * Adds irn to @p live, updates all inputs that this user is scheduled
346  * and counts all of its non scheduled users.
347  */
348 static void update_sched_liveness(block_sched_env_t *env, ir_node *irn) {
349         int i;
350
351         /* ignore Projs */
352         if (is_Proj(irn))
353                 return;
354
355         for (i = get_irn_ins_or_deps(irn) - 1; i >= 0; --i) {
356                 ir_node *in = get_irn_in_or_dep(irn, i);
357
358                 /* if in is a proj: update predecessor */
359                 in = skip_Proj(in);
360
361                 /* if in is still in the live set: reduce number of users by one */
362                 if (ir_nodeset_contains(&env->live, in)) {
363                         if (add_irn_not_sched_user(env, in, -1) <= 0)
364                                 ir_nodeset_remove(&env->live, in);
365                 }
366         }
367
368         /*
369                 get_num_successors returns the number of all users. This includes
370                 users in different blocks as well. As the each block is scheduled separately
371                 the liveness info of those users will not be updated and so these
372                 users will keep up the register pressure as it is desired.
373         */
374         i = get_num_successors(irn);
375         if (i > 0) {
376                 set_irn_not_sched_user(env, irn, i);
377                 ir_nodeset_insert(&env->live, irn);
378         }
379 }
380
381 /**
382  * Append an instruction to a schedule.
383  * @param env The block scheduling environment.
384  * @param irn The node to add to the schedule.
385  * @return    The given node.
386  */
387 static void add_to_sched(block_sched_env_t *env, ir_node *irn)
388 {
389     /* If the node consumes/produces data, it is appended to the schedule
390      * list, otherwise, it is not put into the list */
391     if (must_appear_in_schedule(env->selector, env->selector_block_env, irn)) {
392                 update_sched_liveness(env, irn);
393                 sched_add_before(env->block, irn);
394
395                 DBG((dbg, LEVEL_2, "\tadding %+F\n", irn));
396
397                 /* Remove the node from the ready set */
398                 ir_nodeset_remove(&env->cands, irn);
399     }
400
401         /* notify the selector about the finally selected node. */
402         if (env->selector->node_selected)
403                 env->selector->node_selected(env->selector_block_env, irn);
404
405     /* Insert the node in the set of all available scheduled nodes. */
406     set_already_scheduled(env, irn);
407
408         make_users_ready(env, irn);
409 }
410
411 /**
412  * Perform list scheduling on a block.
413  *
414  * Note, that the caller must compute a linked list of nodes in the block
415  * using the link field before calling this function.
416  *
417  * Also the outs must have been computed.
418  *
419  * @param block The block node.
420  * @param env Scheduling environment.
421  */
422 static void list_sched_block(ir_node *block, void *env_ptr)
423 {
424         sched_env_t *env                      = env_ptr;
425         const list_sched_selector_t *selector = env->selector;
426         ir_node *start_node                   = get_irg_start(get_irn_irg(block));
427
428         block_sched_env_t be;
429         const ir_edge_t *edge;
430         ir_node *irn;
431         int j, m;
432
433         /* Initialize the block's list head that will hold the schedule. */
434         sched_init_block(block);
435
436         /* Initialize the block scheduling environment */
437         be.sched_info = env->sched_info;
438         be.block      = block;
439         ir_nodeset_init_size(&be.cands, get_irn_n_edges(block));
440         ir_nodeset_init_size(&be.live, get_irn_n_edges(block));
441         be.selector   = selector;
442         be.sched_env  = env;
443
444         DBG((dbg, LEVEL_1, "scheduling %+F\n", block));
445
446         if (selector->init_block)
447                 be.selector_block_env = selector->init_block(env->selector_env, block);
448
449         /* Then one can add all nodes are ready to the set. */
450         foreach_out_edge(block, edge) {
451                 ir_node   *irn = get_edge_src_irn(edge);
452                 ir_opcode code = get_irn_opcode(irn);
453                 int users;
454
455                 if (code == iro_End) {
456                         /* Skip the end node because of keep-alive edges. */
457                         continue;
458                 } else if (code == iro_Block) {
459                         /* A Block-Block edge. This should be the MacroBlock
460                          * edge, ignore it. */
461                         assert(get_Block_MacroBlock(irn) == block && "Block-Block edge found");
462                         continue;
463                 }
464
465                 users = get_irn_n_edges(irn);
466                 if (users == 0)
467                         continue;
468                 else if (users == 1) { /* ignore nodes that are only hold by the anchor */
469                         const ir_edge_t *edge = get_irn_out_edge_first_kind(irn, EDGE_KIND_NORMAL);
470                         ir_node *user = get_edge_src_irn(edge);
471                         if (is_Anchor(user))
472                                 continue;
473                 }
474
475                 if (is_Phi(irn)) {
476                         /*
477                                 Phi functions are scheduled immediately, since they     only
478                                 transfer data flow from the predecessors to this block.
479                         */
480                         add_to_sched(&be, irn);
481                 }
482                 else if (irn == start_node) {
483                         /* The start block will be scheduled as the first node */
484                         add_to_sched(&be, irn);
485                 }
486                 else {
487                         /* Other nodes must have all operands in other blocks to be made
488                          * ready */
489                         int ready = 1;
490
491                         /* Check, if the operands of a node are not local to this block */
492                         for (j = 0, m = get_irn_ins_or_deps(irn); j < m; ++j) {
493                                 ir_node *operand = get_irn_in_or_dep(irn, j);
494
495                                 if (get_nodes_block(operand) == block) {
496                                         ready = 0;
497                                         break;
498                                 } else {
499                                         /* live in values increase register pressure */
500                                         ir_nodeset_insert(&be.live, operand);
501                                 }
502                         }
503
504                         /* Make the node ready, if all operands live in a foreign block */
505                         if (ready) {
506                                 DBG((dbg, LEVEL_2, "\timmediately ready: %+F\n", irn));
507                                 make_ready(&be, NULL, irn);
508                         }
509                 }
510         }
511
512         /* Iterate over all remaining nodes */
513         while (ir_nodeset_size(&be.cands) > 0) {
514                 ir_nodeset_iterator_t iter;
515
516                 /* Keeps must be scheduled immediately */
517                 foreach_ir_nodeset(&be.cands, irn, iter) {
518                         if (be_is_Keep(irn) || be_is_CopyKeep(irn) || is_Sync(irn)) {
519                                 break;
520                         }
521                 }
522
523                 if (! irn) {
524                         /* Keeps must be immediately scheduled */
525                         irn = be.selector->select(be.selector_block_env, &be.cands, &be.live);
526                 }
527
528                 DB((dbg, LEVEL_2, "\tpicked node %+F\n", irn));
529
530                 /* Add the node to the schedule. */
531                 add_to_sched(&be, irn);
532
533                 /* remove the scheduled node from the ready list. */
534                 ir_nodeset_remove(&be.cands, irn);
535         }
536
537         if (selector->finish_block)
538                 selector->finish_block(be.selector_block_env);
539
540         ir_nodeset_destroy(&be.cands);
541         ir_nodeset_destroy(&be.live);
542 }
543
544 /* List schedule a graph. */
545 void list_sched(be_irg_t *birg, be_options_t *be_opts)
546 {
547         ir_graph *irg = birg->irg;
548
549         int num_nodes;
550         sched_env_t env;
551         mris_env_t *mris = NULL;
552         list_sched_selector_t sel;
553
554         (void)be_opts;
555
556         /* Select a scheduler based on backend options */
557         switch (list_sched_options.select) {
558                 case BE_SCHED_SELECT_TRIVIAL:  sel = trivial_selector;      break;
559                 case BE_SCHED_SELECT_RANDOM:   sel = random_selector;       break;
560                 case BE_SCHED_SELECT_REGPRESS: sel = reg_pressure_selector; break;
561                 case BE_SCHED_SELECT_MUCHNIK:  sel = muchnik_selector;      break;
562                 case BE_SCHED_SELECT_HEUR:     sel = heuristic_selector;    break;
563                 case BE_SCHED_SELECT_NORMAL:   sel = normal_selector;       break;
564                 default:
565                 case BE_SCHED_SELECT_HMUCHNIK: sel = trivial_selector;      break;
566         }
567
568 #if 1
569         /* Matze: This is very slow, we should avoid it to improve backend speed,
570          * we just have to make sure that we have no dangling out-edges at this
571          * point...
572          */
573
574         /* Assure, that we have no dangling out-edges to deleted stuff */
575         edges_deactivate(irg);
576         edges_activate(irg);
577 #endif
578
579         switch (list_sched_options.prep) {
580                 case BE_SCHED_PREP_MRIS:
581                         mris = be_sched_mris_preprocess(birg);
582                         break;
583                 case BE_SCHED_PREP_RSS:
584                         rss_schedule_preparation(birg);
585                         break;
586                 default:
587                         break;
588         }
589
590         num_nodes = get_irg_last_idx(irg);
591
592         /* initialize environment for list scheduler */
593         memset(&env, 0, sizeof(env));
594         env.selector   = arch_env_get_list_sched_selector(birg->main_env->arch_env, &sel);
595         env.sched_info = NEW_ARR_F(sched_irn_t, num_nodes);
596
597         memset(env.sched_info, 0, num_nodes * sizeof(env.sched_info[0]));
598
599         if (env.selector->init_graph)
600                 env.selector_env = env.selector->init_graph(env.selector, birg);
601
602         /* Schedule each single block. */
603         irg_block_walk_graph(irg, list_sched_block, NULL, &env);
604
605         if (env.selector->finish_graph)
606                 env.selector->finish_graph(env.selector_env);
607
608         if (list_sched_options.prep == BE_SCHED_PREP_MRIS)
609                 be_sched_mris_free(mris);
610
611         DEL_ARR_F(env.sched_info);
612 }
613
614 /* List schedule a block. */
615 void list_sched_single_block(const be_irg_t *birg, ir_node *block,
616                              be_options_t *be_opts)
617 {
618         ir_graph *irg = birg->irg;
619
620         int num_nodes;
621         sched_env_t env;
622         list_sched_selector_t sel;
623
624         (void)be_opts;
625
626         /* Select a scheduler based on backend options */
627         switch (list_sched_options.select) {
628                 case BE_SCHED_SELECT_TRIVIAL:  sel = trivial_selector;      break;
629                 case BE_SCHED_SELECT_RANDOM:   sel = random_selector;       break;
630                 case BE_SCHED_SELECT_REGPRESS: sel = reg_pressure_selector; break;
631                 case BE_SCHED_SELECT_MUCHNIK:  sel = muchnik_selector;      break;
632                 case BE_SCHED_SELECT_HEUR:     sel = heuristic_selector;    break;
633                 case BE_SCHED_SELECT_NORMAL:   sel = normal_selector;       break;
634                 default:
635                 case BE_SCHED_SELECT_HMUCHNIK: sel = trivial_selector;      break;
636         }
637
638         /* Assure, that the out edges are computed */
639         edges_deactivate(irg);
640         edges_activate(irg);
641
642         num_nodes = get_irg_last_idx(irg);
643
644         /* initialize environment for list scheduler */
645         memset(&env, 0, sizeof(env));
646         env.selector   = arch_env_get_list_sched_selector(birg->main_env->arch_env, &sel);
647         env.sched_info = NEW_ARR_F(sched_irn_t, num_nodes);
648
649         memset(env.sched_info, 0, num_nodes * sizeof(env.sched_info[0]));
650
651         if (env.selector->init_graph)
652                 env.selector_env = env.selector->init_graph(env.selector, birg);
653
654         /* Schedule block. */
655         list_sched_block(block, &env);
656
657         if (env.selector->finish_graph)
658                 env.selector->finish_graph(env.selector_env);
659
660         DEL_ARR_F(env.sched_info);
661 }
662
663 /**
664  * Register list scheduler options.
665  */
666 void be_init_listsched(void) {
667         lc_opt_entry_t *be_grp = lc_opt_get_grp(firm_opt_get_root(), "be");
668         lc_opt_entry_t *sched_grp = lc_opt_get_grp(be_grp, "listsched");
669
670         lc_opt_add_table(sched_grp, list_sched_option_table);
671
672         FIRM_DBG_REGISTER(dbg, "firm.be.sched");
673 }
674
675 BE_REGISTER_MODULE_CONSTRUCTOR(be_init_listsched);