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