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