no unnecessary and cryptic abreviations: rename vrfy to verify
[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.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.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.h"
59 #include "bestat.h"
60 #include "beirg.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_Start(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 {
287         int idx = get_irn_idx(n);
288
289         assert(idx < ARR_LEN(env->sched_info));
290         return env->sched_info[idx].num_not_sched_user;
291 }
292
293 /**
294  * Sets the number of not yet schedules users.
295  */
296 static inline void set_irn_not_sched_user(block_sched_env_t *env, ir_node *n, int num)
297 {
298         int idx = get_irn_idx(n);
299
300         assert(idx < ARR_LEN(env->sched_info));
301         env->sched_info[idx].num_not_sched_user = num;
302 }
303
304 /**
305  * Add @p num to the number of not yet schedules users and returns the result.
306  */
307 static inline int add_irn_not_sched_user(block_sched_env_t *env, ir_node *n, int num)
308 {
309         int idx = get_irn_idx(n);
310
311         assert(idx < ARR_LEN(env->sched_info));
312         env->sched_info[idx].num_not_sched_user += num;
313         return env->sched_info[idx].num_not_sched_user;
314 }
315
316 /**
317  * Returns the number of users of a node having mode datab.
318  */
319 static int get_num_successors(ir_node *irn)
320 {
321         int             sum = 0;
322         const ir_edge_t *edge;
323
324         if (get_irn_mode(irn) == mode_T) {
325                 /* for mode_T nodes: count the users of all Projs */
326                 foreach_out_edge(irn, edge) {
327                         ir_node *proj = get_edge_src_irn(edge);
328                         ir_mode *mode = get_irn_mode(proj);
329
330                         if (mode == mode_T) {
331                                 sum += get_num_successors(proj);
332                         } else if (mode_is_datab(mode)) {
333                                 sum += get_irn_n_edges(proj);
334                         }
335                 }
336         }
337         else {
338                 /* do not count keep-alive edges */
339                 foreach_out_edge(irn, edge) {
340                         if (get_irn_opcode(get_edge_src_irn(edge)) != iro_End)
341                                 sum++;
342                 }
343         }
344
345         return sum;
346 }
347
348 /**
349  * Adds irn to @p live, updates all inputs that this user is scheduled
350  * and counts all of its non scheduled users.
351  */
352 static void update_sched_liveness(block_sched_env_t *env, ir_node *irn)
353 {
354         int i;
355
356         /* ignore Projs */
357         if (is_Proj(irn))
358                 return;
359
360         for (i = get_irn_ins_or_deps(irn) - 1; i >= 0; --i) {
361                 ir_node *in = get_irn_in_or_dep(irn, i);
362
363                 /* if in is a proj: update predecessor */
364                 in = skip_Proj(in);
365
366                 /* if in is still in the live set: reduce number of users by one */
367                 if (ir_nodeset_contains(&env->live, in)) {
368                         if (add_irn_not_sched_user(env, in, -1) <= 0)
369                                 ir_nodeset_remove(&env->live, in);
370                 }
371         }
372
373         /*
374                 get_num_successors returns the number of all users. This includes
375                 users in different blocks as well. As the each block is scheduled separately
376                 the liveness info of those users will not be updated and so these
377                 users will keep up the register pressure as it is desired.
378         */
379         i = get_num_successors(irn);
380         if (i > 0) {
381                 set_irn_not_sched_user(env, irn, i);
382                 ir_nodeset_insert(&env->live, irn);
383         }
384 }
385
386 /**
387  * Append an instruction to a schedule.
388  * @param env The block scheduling environment.
389  * @param irn The node to add to the schedule.
390  * @return    The given node.
391  */
392 static void add_to_sched(block_sched_env_t *env, ir_node *irn)
393 {
394     /* If the node consumes/produces data, it is appended to the schedule
395      * list, otherwise, it is not put into the list */
396     if (must_appear_in_schedule(env->selector, env->selector_block_env, irn)) {
397                 update_sched_liveness(env, irn);
398                 sched_add_before(env->block, irn);
399
400                 DBG((dbg, LEVEL_2, "\tadding %+F\n", irn));
401
402                 /* Remove the node from the ready set */
403                 ir_nodeset_remove(&env->cands, irn);
404     }
405
406         /* notify the selector about the finally selected node. */
407         if (env->selector->node_selected)
408                 env->selector->node_selected(env->selector_block_env, irn);
409
410     /* Insert the node in the set of all available scheduled nodes. */
411     set_already_scheduled(env, irn);
412
413         make_users_ready(env, irn);
414 }
415
416 /**
417  * Perform list scheduling on a block.
418  *
419  * Note, that the caller must compute a linked list of nodes in the block
420  * using the link field before calling this function.
421  *
422  * Also the outs must have been computed.
423  *
424  * @param block The block node.
425  * @param env Scheduling environment.
426  */
427 static void list_sched_block(ir_node *block, void *env_ptr)
428 {
429         sched_env_t *env                      = env_ptr;
430         const list_sched_selector_t *selector = env->selector;
431
432         block_sched_env_t be;
433         const ir_edge_t *edge;
434         ir_node *irn;
435         int j, m;
436
437         /* Initialize the block's list head that will hold the schedule. */
438         sched_init_block(block);
439
440         /* Initialize the block scheduling environment */
441         be.sched_info = env->sched_info;
442         be.block      = block;
443         ir_nodeset_init_size(&be.cands, get_irn_n_edges(block));
444         ir_nodeset_init_size(&be.live, get_irn_n_edges(block));
445         be.selector   = selector;
446         be.sched_env  = env;
447
448         DBG((dbg, LEVEL_1, "scheduling %+F\n", block));
449
450         if (selector->init_block)
451                 be.selector_block_env = selector->init_block(env->selector_env, block);
452
453         /* Then one can add all nodes are ready to the set. */
454         foreach_out_edge(block, edge) {
455                 ir_node   *irn = get_edge_src_irn(edge);
456                 ir_opcode code = get_irn_opcode(irn);
457                 int users;
458
459                 if (code == iro_End) {
460                         /* Skip the end node because of keep-alive edges. */
461                         continue;
462                 } else if (code == iro_Block) {
463                         /* A Block-Block edge. This should be the MacroBlock
464                          * edge, ignore it. */
465                         assert(get_Block_MacroBlock(irn) == block && "Block-Block edge found");
466                         continue;
467                 }
468
469                 users = get_irn_n_edges(irn);
470                 if (users == 0)
471                         continue;
472                 else if (users == 1) { /* ignore nodes that are only hold by the anchor */
473                         const ir_edge_t *edge = get_irn_out_edge_first_kind(irn, EDGE_KIND_NORMAL);
474                         ir_node *user = get_edge_src_irn(edge);
475                         if (is_Anchor(user))
476                                 continue;
477                 }
478
479                 if (is_Phi(irn)) {
480                         /*
481                                 Phi functions are scheduled immediately, since they     only
482                                 transfer data flow from the predecessors to this block.
483                         */
484                         add_to_sched(&be, irn);
485                 } else if (be_is_Start(irn)) {
486                         /* The start block will be scheduled as the first node */
487                         add_to_sched(&be, irn);
488                 } else {
489                         /* Other nodes must have all operands in other blocks to be made
490                          * ready */
491                         int ready = 1;
492
493                         /* Check, if the operands of a node are not local to this block */
494                         for (j = 0, m = get_irn_ins_or_deps(irn); j < m; ++j) {
495                                 ir_node *operand = get_irn_in_or_dep(irn, j);
496
497                                 if (get_nodes_block(operand) == block) {
498                                         ready = 0;
499                                         break;
500                                 } else {
501                                         /* live in values increase register pressure */
502                                         ir_nodeset_insert(&be.live, operand);
503                                 }
504                         }
505
506                         /* Make the node ready, if all operands live in a foreign block */
507                         if (ready) {
508                                 DBG((dbg, LEVEL_2, "\timmediately ready: %+F\n", irn));
509                                 make_ready(&be, NULL, irn);
510                         }
511                 }
512         }
513
514         /* Iterate over all remaining nodes */
515         while (ir_nodeset_size(&be.cands) > 0) {
516                 ir_nodeset_iterator_t iter;
517
518                 /* Keeps must be scheduled immediately */
519                 foreach_ir_nodeset(&be.cands, irn, iter) {
520                         if (be_is_Keep(irn) || be_is_CopyKeep(irn) || is_Sync(irn)) {
521                                 break;
522                         }
523                 }
524
525                 if (! irn) {
526                         /* Keeps must be immediately scheduled */
527                         irn = be.selector->select(be.selector_block_env, &be.cands, &be.live);
528                 }
529
530                 DB((dbg, LEVEL_2, "\tpicked node %+F\n", irn));
531
532                 /* Add the node to the schedule. */
533                 add_to_sched(&be, irn);
534
535                 /* remove the scheduled node from the ready list. */
536                 ir_nodeset_remove(&be.cands, irn);
537         }
538
539         if (selector->finish_block)
540                 selector->finish_block(be.selector_block_env);
541
542         ir_nodeset_destroy(&be.cands);
543         ir_nodeset_destroy(&be.live);
544 }
545
546 /* List schedule a graph. */
547 void list_sched(ir_graph *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         /* Select a scheduler based on backend options */
555         switch (list_sched_options.select) {
556                 case BE_SCHED_SELECT_TRIVIAL:  sel = trivial_selector;      break;
557                 case BE_SCHED_SELECT_RANDOM:   sel = random_selector;       break;
558                 case BE_SCHED_SELECT_REGPRESS: sel = reg_pressure_selector; break;
559                 case BE_SCHED_SELECT_MUCHNIK:  sel = muchnik_selector;      break;
560                 case BE_SCHED_SELECT_HEUR:     sel = heuristic_selector;    break;
561                 case BE_SCHED_SELECT_NORMAL:   sel = normal_selector;       break;
562                 default:
563                 case BE_SCHED_SELECT_HMUCHNIK: sel = heuristic_selector;    break;
564         }
565
566 #if 1
567         /* Matze: This is very slow, we should avoid it to improve backend speed,
568          * we just have to make sure that we have no dangling out-edges at this
569          * point...
570          */
571
572         /* Assure, that we have no dangling out-edges to deleted stuff */
573         edges_deactivate(irg);
574         edges_activate(irg);
575 #endif
576
577         switch (list_sched_options.prep) {
578                 case BE_SCHED_PREP_MRIS:
579                         mris = be_sched_mris_preprocess(irg);
580                         break;
581                 case BE_SCHED_PREP_RSS:
582                         rss_schedule_preparation(irg);
583                         break;
584                 default:
585                         break;
586         }
587
588         num_nodes = get_irg_last_idx(irg);
589
590         /* initialize environment for list scheduler */
591         memset(&env, 0, sizeof(env));
592         env.selector   = arch_env_get_list_sched_selector(be_get_irg_arch_env(irg), &sel);
593         env.sched_info = NEW_ARR_F(sched_irn_t, num_nodes);
594
595         memset(env.sched_info, 0, num_nodes * sizeof(env.sched_info[0]));
596
597         if (env.selector->init_graph)
598                 env.selector_env = env.selector->init_graph(env.selector, irg);
599
600         /* Schedule each single block. */
601         irg_block_walk_graph(irg, list_sched_block, NULL, &env);
602
603         if (env.selector->finish_graph)
604                 env.selector->finish_graph(env.selector_env);
605
606         if (list_sched_options.prep == BE_SCHED_PREP_MRIS)
607                 be_sched_mris_free(mris);
608
609         DEL_ARR_F(env.sched_info);
610 }
611
612 /* List schedule a block. */
613 void list_sched_single_block(ir_graph *irg, ir_node *block)
614 {
615         int num_nodes;
616         sched_env_t env;
617         list_sched_selector_t sel;
618
619         /* Select a scheduler based on backend options */
620         switch (list_sched_options.select) {
621                 case BE_SCHED_SELECT_TRIVIAL:  sel = trivial_selector;      break;
622                 case BE_SCHED_SELECT_RANDOM:   sel = random_selector;       break;
623                 case BE_SCHED_SELECT_REGPRESS: sel = reg_pressure_selector; break;
624                 case BE_SCHED_SELECT_MUCHNIK:  sel = muchnik_selector;      break;
625                 case BE_SCHED_SELECT_HEUR:     sel = heuristic_selector;    break;
626                 case BE_SCHED_SELECT_NORMAL:   sel = normal_selector;       break;
627                 default:
628                 case BE_SCHED_SELECT_HMUCHNIK: sel = trivial_selector;      break;
629         }
630
631         /* Assure, that the out edges are computed */
632         edges_deactivate(irg);
633         edges_activate(irg);
634
635         num_nodes = get_irg_last_idx(irg);
636
637         /* initialize environment for list scheduler */
638         memset(&env, 0, sizeof(env));
639         env.selector   = arch_env_get_list_sched_selector(be_get_irg_arch_env(irg), &sel);
640         env.sched_info = NEW_ARR_F(sched_irn_t, num_nodes);
641
642         memset(env.sched_info, 0, num_nodes * sizeof(env.sched_info[0]));
643
644         if (env.selector->init_graph)
645                 env.selector_env = env.selector->init_graph(env.selector, irg);
646
647         /* Schedule block. */
648         list_sched_block(block, &env);
649
650         if (env.selector->finish_graph)
651                 env.selector->finish_graph(env.selector_env);
652
653         DEL_ARR_F(env.sched_info);
654 }
655
656 BE_REGISTER_MODULE_CONSTRUCTOR(be_init_listsched);
657 void be_init_listsched(void)
658 {
659         lc_opt_entry_t *be_grp    = lc_opt_get_grp(firm_opt_get_root(), "be");
660         lc_opt_entry_t *sched_grp = lc_opt_get_grp(be_grp, "listsched");
661
662         lc_opt_add_table(sched_grp, list_sched_option_table);
663
664         FIRM_DBG_REGISTER(dbg, "firm.be.sched");
665 }