Fixed initialization of option tables
[libfirm] / ir / be / beblocksched.c
1 /*
2  * Copyright (C) 1995-2007 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       Block-scheduling strategies.
23  * @author      Matthias Braun, Christoph Mallon
24  * @date        27.09.2006
25  * @version     $Id$
26  */
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include "beblocksched.h"
32
33 #include <stdlib.h>
34
35 #include "array.h"
36 #include "pdeq.h"
37
38 #include "iredges.h"
39 #include "irgwalk.h"
40 #include "irnode_t.h"
41 #include "irgraph_t.h"
42 #include "irloop.h"
43 #include "irprintf.h"
44 #include "execfreq.h"
45 #include "irdump_t.h"
46 #include "irtools.h"
47 #include "debug.h"
48 #include "beirgmod.h"
49 #include "bemodule.h"
50 #include "be.h"
51
52 #include <libcore/lc_opts.h>
53 #include <libcore/lc_opts_enum.h>
54 #include <libcore/lc_timing.h>
55
56 #ifdef WITH_ILP
57 #include <lpp/lpp.h>
58 #include <lpp/lpp_net.h>
59 #endif /* WITH_ILP */
60
61 DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
62
63 typedef enum _blocksched_algos_t {
64         BLOCKSCHED_NAIV, BLOCKSCHED_EXTBB, BLOCKSCHED_GREEDY, BLOCKSCHED_ILP
65 } blocksched_algos_t;
66
67 static int algo = BLOCKSCHED_GREEDY;
68
69 static const lc_opt_enum_int_items_t blockschedalgo_items[] = {
70         { "naiv",       BLOCKSCHED_NAIV },
71         { "extbb",      BLOCKSCHED_EXTBB },
72         { "greedy", BLOCKSCHED_GREEDY },
73 #ifdef WITH_ILP
74         { "ilp",    BLOCKSCHED_ILP },
75 #endif /* WITH_ILP */
76         { NULL,     0 }
77 };
78
79 static lc_opt_enum_int_var_t algo_var = {
80         &algo, blockschedalgo_items
81 };
82
83 static const lc_opt_table_entry_t be_blocksched_options[] = {
84         LC_OPT_ENT_ENUM_INT ("algo", "the block scheduling algorithm", &algo_var),
85         LC_OPT_LAST
86 };
87
88 /*
89  *   ____                   _
90  *  / ___|_ __ ___  ___  __| |_   _
91  * | |  _| '__/ _ \/ _ \/ _` | | | |
92  * | |_| | | |  __/  __/ (_| | |_| |
93  *  \____|_|  \___|\___|\__,_|\__, |
94  *                            |___/
95  */
96
97 typedef struct _blocksched_entry_t {
98         ir_node *block;
99         struct _blocksched_entry_t *next;
100         struct _blocksched_entry_t *prev;
101 } blocksched_entry_t;
102
103 typedef struct _edge_t {
104         ir_node *block;             /**< source block */
105         int     pos;                /**< number of cfg predecessor (target) */
106         double  execfreq;           /**< the frequency */
107         int     highest_execfreq;   /**< flag that indicates whether this edge is the edge with the highest
108                                                                      execfreq pointing away from this block */
109 } edge_t;
110
111 typedef struct _blocksched_env_t {
112         ir_graph       *irg;
113         struct obstack *obst;
114         ir_exec_freq   *execfreqs;
115         edge_t         *edges;
116         pdeq           *worklist;
117         int            blockcount;
118 } blocksched_env_t;
119
120 /**
121  * Collect cfg frequencies of all edges between blocks.
122  * Also determines edge with highest frequency.
123  */
124 static void collect_egde_frequency(ir_node *block, void *data)
125 {
126         blocksched_env_t   *env = data;
127         int                arity;
128         edge_t             edge;
129         blocksched_entry_t *entry;
130
131         entry        = obstack_alloc(env->obst, sizeof(entry[0]));
132         entry->block = block;
133         entry->next  = NULL;
134         entry->prev  = NULL;
135         set_irn_link(block, entry);
136
137         if (block == get_irg_start_block(env->irg))
138                 return;
139
140         arity = get_Block_n_cfgpreds(block);
141
142         if (arity == 1) {
143                 edge.block            = block;
144                 edge.pos              = 0;
145                 edge.execfreq         = get_block_execfreq(env->execfreqs, block);
146                 edge.highest_execfreq = 1;
147                 ARR_APP1(edge_t, env->edges, edge);
148         } else {
149                 int    i;
150                 double highest_execfreq = -1.0;
151                 int    highest_edge_num = -1;
152
153                 edge.block = block;
154                 for (i = 0; i < arity; ++i) {
155                         double  execfreq;
156                         ir_node *pred_block = get_Block_cfgpred_block(block, i);
157
158                         execfreq = get_block_execfreq(env->execfreqs, pred_block);
159
160                         edge.pos              = i;
161                         edge.execfreq         = execfreq;
162                         edge.highest_execfreq = 0;
163                         ARR_APP1(edge_t, env->edges, edge);
164
165                         if (execfreq > highest_execfreq) {
166                                 highest_execfreq = execfreq;
167                                 highest_edge_num = ARR_LEN(env->edges) - 1;
168                         }
169                 }
170
171                 if(highest_edge_num >= 0)
172                         env->edges[highest_edge_num].highest_execfreq = 1;
173         }
174 }
175
176 static int cmp_edges(const void *d1, const void *d2)
177 {
178         const edge_t *e1 = d1;
179         const edge_t *e2 = d2;
180
181         return QSORT_CMP(e2->execfreq, e1->execfreq);
182 }
183
184 static void coalesce_blocks(blocksched_env_t *env)
185 {
186         int i;
187         int edge_count = ARR_LEN(env->edges);
188
189         /* run1: only look at jumps */
190         for (i = 0; i < edge_count; ++i) {
191                 const edge_t *edge  = &env->edges[i];
192                 ir_node      *block = edge->block;
193                 ir_node      *pred_block;
194                 blocksched_entry_t *entry, *pred_entry;
195
196                 /* the block might have been removed already... */
197                 if (is_Bad(get_Block_cfgpred(block, 0)))
198                         continue;
199
200                 /* only check edge with highest frequency */
201                 if (! edge->highest_execfreq)
202                         continue;
203
204                 pred_block = get_Block_cfgpred_block(block, edge->pos);
205                 entry      = get_irn_link(block);
206                 pred_entry = get_irn_link(pred_block);
207
208                 if (pred_entry->next != NULL || entry->prev != NULL)
209                         continue;
210
211                 /* only coalesce jumps */
212                 if (get_block_succ_next(pred_block, get_block_succ_first(pred_block)) != NULL)
213                         continue;
214
215                 /* schedule the 2 blocks behind each other */
216                 DBG((dbg, LEVEL_1, "Coalesce (Jump) %+F -> %+F (%.3g)\n",
217                            pred_entry->block, entry->block, edge->execfreq));
218                 pred_entry->next = entry;
219                 entry->prev      = pred_entry;
220         }
221
222         /* run2: remaining edges */
223         for (i = 0; i < edge_count; ++i) {
224                 const edge_t *edge  = &env->edges[i];
225                 ir_node      *block = edge->block;
226                 ir_node      *pred_block;
227                 blocksched_entry_t *entry, *pred_entry;
228
229                 /* the block might have been removed already... */
230                 if (is_Bad(get_Block_cfgpred(block, 0)))
231                         continue;
232
233                 pred_block = get_Block_cfgpred_block(block, edge->pos);
234                 entry      = get_irn_link(block);
235                 pred_entry = get_irn_link(pred_block);
236
237                 /* is 1 of the blocks already attached to another block? */
238                 if (pred_entry->next != NULL || entry->prev != NULL)
239                         continue;
240
241                 /* schedule the 2 blocks behind each other */
242                 DBG((dbg, LEVEL_1, "Coalesce (CondJump) %+F -> %+F (%.3g)\n",
243                            pred_entry->block, entry->block, edge->execfreq));
244                 pred_entry->next = entry;
245                 entry->prev      = pred_entry;
246         }
247 }
248
249 static void pick_block_successor(blocksched_entry_t *entry, blocksched_env_t *env)
250 {
251         ir_node            *block = entry->block;
252         ir_node            *succ  = NULL;
253         blocksched_entry_t *succ_entry;
254         const ir_edge_t    *edge;
255         double             best_succ_execfreq;
256
257         if (irn_visited(block))
258                 return;
259
260         env->blockcount++;
261         mark_irn_visited(block);
262
263         DBG((dbg, LEVEL_1, "Pick succ of %+F\n", block));
264
265         /* put all successors into the worklist */
266         foreach_block_succ(block, edge) {
267                 ir_node *succ_block = get_edge_src_irn(edge);
268
269                 if (irn_visited(succ_block))
270                         continue;
271
272                 /* we only need to put the first of a series of already connected
273                  * blocks into the worklist */
274                 succ_entry = get_irn_link(succ_block);
275                 while (succ_entry->prev != NULL) {
276                         /* break cycles... */
277                         if (succ_entry->prev->block == succ_block) {
278                                 succ_entry->prev->next = NULL;
279                                 succ_entry->prev       = NULL;
280                                 break;
281                         }
282                         succ_entry = succ_entry->prev;
283                 };
284
285                 if (irn_visited(succ_entry->block))
286                         continue;
287
288                 DBG((dbg, LEVEL_1, "Put %+F into worklist\n", succ_entry->block));
289                 pdeq_putr(env->worklist, succ_entry->block);
290         }
291
292         if (entry->next != NULL) {
293                 pick_block_successor(entry->next, env);
294                 return;
295         }
296
297         DBG((dbg, LEVEL_1, "deciding...\n"));
298         best_succ_execfreq = -1;
299
300         /* no successor yet: pick the successor block with the highest execution
301          * frequency which has no predecessor yet */
302
303         foreach_block_succ(block, edge) {
304                 ir_node *succ_block = get_edge_src_irn(edge);
305                 double  execfreq;
306
307                 if (irn_visited(succ_block))
308                         continue;
309
310                 succ_entry = get_irn_link(succ_block);
311                 if (succ_entry->prev != NULL)
312                         continue;
313
314                 execfreq = get_block_execfreq(env->execfreqs, succ_block);
315                 if (execfreq > best_succ_execfreq) {
316                         best_succ_execfreq = execfreq;
317                         succ = succ_block;
318                 }
319         }
320
321         if (succ == NULL) {
322                 DBG((dbg, LEVEL_1, "pick from worklist\n"));
323
324                 do {
325                         if (pdeq_empty(env->worklist)) {
326                                 DBG((dbg, LEVEL_1, "worklist empty\n"));
327                                 return;
328                         }
329                         succ = pdeq_getl(env->worklist);
330                 } while (irn_visited(succ));
331         }
332
333         succ_entry       = get_irn_link(succ);
334         entry->next      = succ_entry;
335         succ_entry->prev = entry;
336
337         pick_block_successor(succ_entry, env);
338 }
339
340 static blocksched_entry_t *finish_block_schedule(blocksched_env_t *env)
341 {
342         ir_graph           *irg        = env->irg;
343         ir_node            *startblock = get_irg_start_block(irg);
344         blocksched_entry_t *entry      = get_irn_link(startblock);
345
346         set_using_visited(irg);
347         inc_irg_visited(irg);
348
349         env->worklist = new_pdeq();
350         pick_block_successor(entry, env);
351         assert(pdeq_empty(env->worklist));
352         del_pdeq(env->worklist);
353
354         clear_using_visited(irg);
355
356         return entry;
357 }
358
359 static ir_node **create_blocksched_array(blocksched_env_t *env, blocksched_entry_t *first,
360                                                                                 int count, struct obstack* obst)
361 {
362         int                i = 0;
363         ir_node            **block_list;
364         blocksched_entry_t *entry;
365         (void) env;
366
367         block_list = NEW_ARR_D(ir_node *, obst, count);
368         DBG((dbg, LEVEL_1, "Blockschedule:\n"));
369
370         for (entry = first; entry != NULL; entry = entry->next) {
371                 assert(i < count);
372                 block_list[i++] = entry->block;
373                 DBG((dbg, LEVEL_1, "\t%+F\n", entry->block));
374         }
375         assert(i == count);
376
377         return block_list;
378 }
379
380 static ir_node **create_block_schedule_greedy(ir_graph *irg, ir_exec_freq *execfreqs)
381 {
382         blocksched_env_t   env;
383         struct obstack     obst;
384         blocksched_entry_t *start_entry;
385         ir_node            **block_list;
386
387         obstack_init(&obst);
388
389         env.irg        = irg;
390         env.obst       = &obst;
391         env.execfreqs  = execfreqs;
392         env.edges      = NEW_ARR_F(edge_t, 0);
393         env.worklist   = NULL;
394         env.blockcount = 0;
395
396         // collect edge execution frequencies
397         irg_block_walk_graph(irg, collect_egde_frequency, NULL, &env);
398
399         // sort interblock edges by execution frequency
400         qsort(env.edges, ARR_LEN(env.edges), sizeof(env.edges[0]), cmp_edges);
401
402         (void)be_remove_empty_blocks(irg);
403
404         if (algo != BLOCKSCHED_NAIV)
405                 coalesce_blocks(&env);
406
407         start_entry = finish_block_schedule(&env);
408         block_list  = create_blocksched_array(&env, start_entry, env.blockcount, get_irg_obstack(irg));
409
410         DEL_ARR_F(env.edges);
411         obstack_free(&obst, NULL);
412
413         return block_list;
414 }
415
416 /*
417  *  ___ _     ____
418  * |_ _| |   |  _ \
419  *  | || |   | |_) |
420  *  | || |___|  __/
421  * |___|_____|_|
422  *
423  */
424
425 #ifdef WITH_ILP
426 typedef struct _ilp_edge_t {
427         ir_node *block;   /**< source block */
428         int     pos;      /**< number of cfg predecessor (target) */
429         int     ilpvar;
430 } ilp_edge_t;
431
432 typedef struct _blocksched_ilp_env_t {
433         blocksched_env_t env;
434         ilp_edge_t       *ilpedges;
435         lpp_t            *lpp;
436 } blocksched_ilp_env_t;
437
438 typedef struct _blocksched_ilp_entry_t {
439         ir_node *block;
440         struct _blocksched_entry_t *next;
441         struct _blocksched_entry_t *prev;
442
443         int out_cst;
444 } blocksched_ilp_entry_t;
445
446 static int add_ilp_edge(ir_node *block, int pos, double execfreq, blocksched_ilp_env_t *env)
447 {
448         char       name[64];
449         ilp_edge_t edge;
450         int        edgeidx = ARR_LEN(env->ilpedges);
451
452         snprintf(name, sizeof(name), "edge%d", edgeidx);
453
454         edge.block  = block;
455         edge.pos    = pos;
456         edge.ilpvar = lpp_add_var_default(env->lpp, name, lpp_binary, execfreq, 1.0);
457
458         ARR_APP1(ilp_edge_t, env->ilpedges, edge);
459         return edgeidx;
460 }
461
462 static void collect_egde_frequency_ilp(ir_node *block, void *data)
463 {
464         blocksched_ilp_env_t *env        = data;
465         ir_graph             *irg        = env->env.irg;
466         ir_node              *startblock = get_irg_start_block(irg);
467         int                  arity;
468         lpp_cst_t            cst;
469         char                 name[64];
470         int                  out_count;
471         blocksched_ilp_entry_t *entry;
472
473         snprintf(name, sizeof(name), "block_out_constr_%ld", get_irn_node_nr(block));
474         out_count = get_irn_n_edges_kind(block, EDGE_KIND_BLOCK);
475
476         entry          = obstack_alloc(env->env.obst, sizeof(entry[0]));
477         entry->block   = block;
478         entry->next    = NULL;
479         entry->prev    = NULL;
480         entry->out_cst = lpp_add_cst_uniq(env->lpp, name, lpp_greater, out_count - 1);
481         set_irn_link(block, entry);
482
483         if (block == startblock)
484                 return;
485
486         arity = get_irn_arity(block);
487         if (arity == 1) {
488                 double execfreq = get_block_execfreq(env->env.execfreqs, block);
489                 add_ilp_edge(block, 0, execfreq, env);
490         }
491         else {
492                 int i;
493                 int *edgenums = alloca(sizeof(edgenums[0]) * arity);
494
495                 snprintf(name, sizeof(name), "block_in_constr_%ld", get_irn_node_nr(block));
496                 cst = lpp_add_cst_uniq(env->lpp, name, lpp_greater, arity - 1);
497
498                 for (i = 0; i < arity; ++i) {
499                         double     execfreq;
500                         int        edgenum;
501                         ilp_edge_t *edge;
502                         ir_node    *pred_block = get_Block_cfgpred_block(block, i);
503
504                         execfreq = get_block_execfreq(env->env.execfreqs, pred_block);
505                         edgenum  = add_ilp_edge(block, i, execfreq, env);
506                         edge     = &env->ilpedges[edgenum];
507                         lpp_set_factor_fast(env->lpp, cst, edge->ilpvar, 1.0);
508                 }
509         }
510 }
511
512
513 static void coalesce_blocks_ilp(blocksched_ilp_env_t *env)
514 {
515         int  i;
516         int  edge_count = ARR_LEN(env->ilpedges);
517
518         /* complete out constraints */
519         for(i = 0; i < edge_count; ++i) {
520                 const ilp_edge_t *edge  = &env->ilpedges[i];
521                 ir_node          *block = edge->block;
522                 ir_node          *pred;
523                 blocksched_ilp_entry_t *entry;
524
525                 /* the block might have been removed already... */
526                 if (is_Bad(get_Block_cfgpred(block, 0)))
527                         continue;
528
529                 pred  = get_Block_cfgpred_block(block, edge->pos);
530                 entry = get_irn_link(pred);
531
532                 DBG((dbg, LEVEL_1, "Adding out cst to %+F from %+F,%d\n",
533                                   pred, block, edge->pos));
534                 lpp_set_factor_fast(env->lpp, entry->out_cst, edge->ilpvar, 1.0);
535         }
536
537 #if 0
538         {
539                 FILE *f;
540                 char fname[256];
541                 lpp_dump(env->lpp, "lpp.out");
542                 snprintf(fname, sizeof(fname), "lpp_%s.plain", get_irg_dump_name(env->env.irg));
543                 f = fopen(fname, "w");
544                 lpp_dump_plain(env->lpp, f);
545                 fclose(f);
546         }
547 #endif
548
549         //lpp_solve_net(env->lpp, main_env->options->ilp_server, main_env->options->ilp_solver);
550         lpp_solve_net(env->lpp, "i44pc52", "cplex");
551         assert(lpp_is_sol_valid(env->lpp));
552
553         /* Apply results to edges */
554         for (i = 0; i < edge_count; ++i) {
555                 const ilp_edge_t   *edge  = &env->ilpedges[i];
556                 ir_node            *block = edge->block;
557                 ir_node            *pred;
558                 int                is_jump;
559                 blocksched_entry_t *entry;
560                 blocksched_entry_t *pred_entry;
561
562                 /* the block might have been removed already... */
563                 if (is_Bad(get_Block_cfgpred(block, 0)))
564                         continue;
565
566                 is_jump = (int)lpp_get_var_sol(env->lpp, edge->ilpvar);
567                 if (is_jump)
568                         continue;
569
570                 pred       = get_Block_cfgpred_block(block, edge->pos);
571                 entry      = get_irn_link(block);
572                 pred_entry = get_irn_link(pred);
573
574                 assert(entry->prev == NULL && pred_entry->next == NULL);
575                 entry->prev      = pred_entry;
576                 pred_entry->next = entry;
577         }
578 }
579
580 static ir_node **create_block_schedule_ilp(ir_graph *irg, ir_exec_freq *execfreqs)
581 {
582         blocksched_ilp_env_t env;
583         struct obstack       obst;
584         blocksched_entry_t   *start_entry;
585         ir_node              **block_list;
586
587         obstack_init(&obst);
588
589         env.env.irg        = irg;
590         env.env.obst       = &obst;
591         env.env.execfreqs  = execfreqs;
592         env.env.worklist   = NULL;
593         env.env.blockcount = 0;
594         env.ilpedges       = NEW_ARR_F(ilp_edge_t, 0);
595
596         env.lpp = new_lpp("blockschedule", lpp_minimize);
597         lpp_set_time_limit(env.lpp, 20);
598         lpp_set_log(env.lpp, stdout);
599
600         irg_block_walk_graph(irg, collect_egde_frequency_ilp, NULL, &env);
601
602         (void)be_remove_empty_blocks(irg);
603         coalesce_blocks_ilp(&env);
604
605         start_entry = finish_block_schedule(&env.env);
606         block_list  = create_blocksched_array(&env.env, start_entry, env.env.blockcount, get_irg_obstack(irg));
607
608         DEL_ARR_F(env.ilpedges);
609         free_lpp(env.lpp);
610         obstack_free(&obst, NULL);
611
612         return block_list;
613 }
614 #endif /* WITH_ILP */
615
616 /*
617  *  _____      _   ____  ____
618  * | ____|_  _| |_| __ )| __ )
619  * |  _| \ \/ / __|  _ \|  _ \
620  * | |___ >  <| |_| |_) | |_) |
621  * |_____/_/\_\\__|____/|____/
622  *
623  */
624
625 /** A simple forward single linked list. */
626 typedef struct {
627         ir_node  *start;   /**< start of the list */
628         ir_node  *end;     /**< last block in the list */
629         unsigned n_blks;  /**< number of blocks in the list */
630 } anchor;
631
632 static void add_block(anchor *list, ir_node *block) {
633         if (list->start == NULL) {
634                 list->start = block;
635                 list->end   = block;
636         } else {
637                 set_irn_link(list->end, block);
638                 list->end = block;
639         }
640
641         list->n_blks++;
642 }
643
644 static void create_block_list(ir_node *leader_block, anchor *list) {
645         int             i;
646         const ir_edge_t *edge;
647         ir_node         *block = NULL;
648         ir_extblk       *extbb = get_Block_extbb(leader_block);
649
650         if (extbb_visited(extbb))
651                 return;
652         mark_extbb_visited(extbb);
653
654         for (i = 0; i < get_extbb_n_blocks(extbb); ++i) {
655                 block = get_extbb_block(extbb, i);
656                 add_block(list, block);
657         }
658
659         assert(block != NULL);
660
661         /* pick successor extbbs */
662         foreach_block_succ(block, edge) {
663                 ir_node *succ = get_edge_src_irn(edge);
664                 create_block_list(succ, list);
665         }
666
667         for (i = 0; i < get_extbb_n_blocks(extbb) - 1; ++i) {
668                 block = get_extbb_block(extbb, i);
669
670                 foreach_block_succ(block, edge) {
671                         ir_node *succ = get_edge_src_irn(edge);
672                         create_block_list(succ, list);
673                 }
674         }
675 }
676
677 void compute_extbb_execfreqs(ir_graph *irg, ir_exec_freq *execfreqs);
678
679 /*
680  * Calculates a block schedule. The schedule is stored as a linked
681  * list starting at the start_block of the irg.
682  */
683 static ir_node **create_extbb_block_schedule(ir_graph *irg, ir_exec_freq *execfreqs)
684 {
685         anchor list;
686         ir_node **blk_list, *b, *n;
687         unsigned i;
688
689         /* schedule extended basic blocks */
690         compute_extbb_execfreqs(irg, execfreqs);
691         //compute_extbb(irg);
692
693         list.start  = NULL;
694         list.end    = NULL;
695         list.n_blks = 0;
696
697         set_using_irn_link(irg);
698         set_using_visited(irg);
699         inc_irg_block_visited(irg);
700
701         create_block_list(get_irg_start_block(irg), &list);
702
703         /** create an array, so we can go forward and backward */
704         blk_list = NEW_ARR_D(ir_node *, irg->obst,list.n_blks);
705
706         for (i = 0, b = list.start; b; b = n, ++i) {
707                 n = get_irn_link(b);
708                 blk_list[i] = b;
709         }
710
711         clear_using_irn_link(irg);
712         clear_using_visited(irg);
713
714         return blk_list;
715 }
716
717 /*
718  *  __  __       _
719  * |  \/  | __ _(_)_ __
720  * | |\/| |/ _` | | '_ \
721  * | |  | | (_| | | | | |
722  * |_|  |_|\__,_|_|_| |_|
723  *
724  */
725 void be_init_blocksched(void)
726 {
727         lc_opt_entry_t *be_grp = lc_opt_get_grp(firm_opt_get_root(), "be");
728         lc_opt_entry_t *blocksched_grp = lc_opt_get_grp(be_grp, "blocksched");
729
730         lc_opt_add_table(blocksched_grp, be_blocksched_options);
731
732         FIRM_DBG_REGISTER(dbg, "firm.be.blocksched");
733 }
734
735 BE_REGISTER_MODULE_CONSTRUCTOR(be_init_blocksched);
736
737 ir_node **be_create_block_schedule(ir_graph *irg, ir_exec_freq *execfreqs)
738 {
739         switch(algo) {
740         case BLOCKSCHED_GREEDY:
741         case BLOCKSCHED_NAIV:
742                 return create_block_schedule_greedy(irg, execfreqs);
743         case BLOCKSCHED_EXTBB:
744                 return create_extbb_block_schedule(irg, execfreqs);
745 #ifdef WITH_ILP
746         case BLOCKSCHED_ILP:
747                 return create_block_schedule_ilp(irg, execfreqs);
748 #endif /* WITH_ILP */
749         }
750
751         assert(0 && "unknown blocksched algo");
752         return NULL;
753 }