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