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