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