beblocksched.c 19.6 KB
Newer Older
Christian Würdig's avatar
Christian Würdig committed
1
2
/*
 * This file is part of libFirm.
3
 * Copyright (C) 2012 University of Karlsruhe.
Christian Würdig's avatar
Christian Würdig committed
4
5
 */

Christian Würdig's avatar
Christian Würdig committed
6
7
8
9
10
/**
 * @file
 * @brief       Block-scheduling strategies.
 * @author      Matthias Braun, Christoph Mallon
 * @date        27.09.2006
11
12
13
14
15
16
17
18
19
20
 *
 * The goals of the greedy (and ILP) algorithm here works by assuming that
 * we want to change as many jumps to fallthroughs as possible (executed jumps
 * actually, we have to look at the execution frequencies). The algorithms
 * do this by collecting execution frequencies of all branches (which is easily
 * possible when all critical edges are split) then removes critical edges where
 * possible as we don't need and want them anymore now. The algorithms then try
 * to change as many edges to fallthroughs as possible, this is done by setting
 * a next and prev pointers on blocks. The greedy algorithm sorts the edges by
 * execution frequencies and tries to transform them to fallthroughs in this order
21
22
23
24
25
 */
#include "beblocksched.h"

#include <stdlib.h>

26
#include "../../adt/util.h"
27
28
#include "array.h"
#include "pdeq.h"
29
#include "beirg.h"
30
31
#include "iredges.h"
#include "irgwalk.h"
Michael Beck's avatar
Michael Beck committed
32
#include "irnode_t.h"
33
34
#include "irgraph_t.h"
#include "irloop.h"
Michael Beck's avatar
Michael Beck committed
35
#include "execfreq.h"
36
#include "irdump_t.h"
37
38
#include "irtools.h"
#include "debug.h"
39
#include "beirgmod.h"
40
41
#include "bemodule.h"
#include "be.h"
42
#include "error.h"
43

Matthias Braun's avatar
Matthias Braun committed
44
45
#include "lc_opts.h"
#include "lc_opts_enum.h"
46

47
48
#include "lpp.h"
#include "lpp_net.h"
49

Matthias Braun's avatar
Matthias Braun committed
50
51
DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)

52
typedef enum blocksched_algos_t {
53
	BLOCKSCHED_NAIV, BLOCKSCHED_GREEDY, BLOCKSCHED_ILP
54
55
56
57
58
} blocksched_algos_t;

static int algo = BLOCKSCHED_GREEDY;

static const lc_opt_enum_int_items_t blockschedalgo_items[] = {
59
	{ "naiv",   BLOCKSCHED_NAIV },
60
61
62
63
64
65
66
67
68
69
	{ "greedy", BLOCKSCHED_GREEDY },
	{ "ilp",    BLOCKSCHED_ILP },
	{ NULL,     0 }
};

static lc_opt_enum_int_var_t algo_var = {
	&algo, blockschedalgo_items
};

static const lc_opt_table_entry_t be_blocksched_options[] = {
70
	LC_OPT_ENT_ENUM_INT ("blockscheduler", "the block scheduling algorithm", &algo_var),
71
	LC_OPT_LAST
72
73
74
75
76
77
78
79
80
81
82
};

/*
 *   ____                   _
 *  / ___|_ __ ___  ___  __| |_   _
 * | |  _| '__/ _ \/ _ \/ _` | | | |
 * | |_| | | |  __/  __/ (_| | |_| |
 *  \____|_|  \___|\___|\__,_|\__, |
 *                            |___/
 */

83
84
85
86
87
88
typedef struct blocksched_entry_t blocksched_entry_t;
struct blocksched_entry_t {
	ir_node            *block;
	blocksched_entry_t *next;
	blocksched_entry_t *prev;
};
89

90
91
typedef struct edge_t edge_t;
struct edge_t {
92
93
94
	ir_node *block;             /**< source block */
	int     pos;                /**< number of cfg predecessor (target) */
	double  execfreq;           /**< the frequency */
95
96
97
98
99
100
101
	double  outedge_penalty_freq; /**< for edges leaving the loop this is the
	                                   penality when we make them a
	                                   fallthrough. */
	int     highest_execfreq;   /**< flag that indicates whether this edge is
	                                 the edge with the highest execfreq pointing
	                                 away from this block */
};
102

103
104
typedef struct blocksched_env_t blocksched_env_t;
struct blocksched_env_t {
105
	ir_graph       *irg;
106
	struct obstack  obst;
107
108
109
	edge_t         *edges;
	pdeq           *worklist;
	int            blockcount;
110
};
111

112
113
114
115
116
static blocksched_entry_t* get_blocksched_entry(const ir_node *block)
{
	return (blocksched_entry_t*)get_irn_link(block);
}

117
118
119
120
/**
 * Collect cfg frequencies of all edges between blocks.
 * Also determines edge with highest frequency.
 */
121
122
static void collect_egde_frequency(ir_node *block, void *data)
{
123
	blocksched_env_t   *env = (blocksched_env_t*)data;
124
125
	int                arity;
	edge_t             edge;
126
	blocksched_entry_t *entry;
127
	ir_loop            *loop;
128

129
130
	memset(&edge, 0, sizeof(edge));

131
	entry = OALLOCZ(&env->obst, blocksched_entry_t);
132
133
134
	entry->block = block;
	set_irn_link(block, entry);

135
136
	loop = get_irn_loop(block);

137
	arity = get_Block_n_cfgpreds(block);
138

139
	if (arity == 0) {
140
141
		/* must be the start block (or end-block for endless loops),
		 * everything else is dead code and should be removed by now */
142
143
		assert(block == get_irg_start_block(env->irg)
				|| block == get_irg_end_block(env->irg));
144
		/* nothing to do here */
145
146
		return;
	} else if (arity == 1) {
147
148
		ir_node *pred_block = get_Block_cfgpred_block(block, 0);
		ir_loop *pred_loop  = get_irn_loop(pred_block);
149
		float    freq       = (float)get_block_execfreq(block);
150
151
152

		/* is it an edge leaving a loop */
		if (get_loop_depth(pred_loop) > get_loop_depth(loop)) {
153
			float pred_freq = (float)get_block_execfreq(pred_block);
154
155
156
			edge.outedge_penalty_freq = -(pred_freq - freq);
		}

157
158
		edge.block            = block;
		edge.pos              = 0;
159
		edge.execfreq         = freq;
160
161
162
		edge.highest_execfreq = 1;
		ARR_APP1(edge_t, env->edges, edge);
	} else {
163
		int    i;
164
		double highest_execfreq = -1.0;
165
		int    highest_edge_num = -1;
166
167

		edge.block = block;
168
169
		for (i = 0; i < arity; ++i) {
			double  execfreq;
170
			ir_node *pred_block = get_Block_cfgpred_block(block, i);
171

172
			execfreq = get_block_execfreq(pred_block);
173

174
175
			edge.pos              = i;
			edge.execfreq         = execfreq;
176
177
			edge.highest_execfreq = 0;
			ARR_APP1(edge_t, env->edges, edge);
178
179

			if (execfreq > highest_execfreq) {
180
181
182
183
184
				highest_execfreq = execfreq;
				highest_edge_num = ARR_LEN(env->edges) - 1;
			}
		}

185
		if (highest_edge_num >= 0)
186
			env->edges[highest_edge_num].highest_execfreq = 1;
187
188
189
	}
}

190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
static int cmp_edges_base(const edge_t *e1, const edge_t *e2)
{
	long nr1 = get_irn_node_nr(e1->block);
	long nr2 = get_irn_node_nr(e2->block);
	if (nr1 < nr2) {
		return 1;
	} else if (nr1 > nr2) {
		return -1;
	} else {
		if (e1->pos < e2->pos) {
			return 1;
		} else if (e1->pos > e2->pos) {
			return -1;
		} else {
			return 0;
		}
	}
}

209
210
static int cmp_edges(const void *d1, const void *d2)
{
211
212
	const edge_t *e1 = (const edge_t*)d1;
	const edge_t *e2 = (const edge_t*)d2;
213
214
215
216
217
218
219
220
221
	double        freq1 = e1->execfreq;
	double        freq2 = e2->execfreq;
	if (freq1 < freq2) {
		return 1;
	} else if (freq1 > freq2) {
		return -1;
	} else {
		return cmp_edges_base(e1, e2);
	}
222
223
}

224
225
static int cmp_edges_outedge_penalty(const void *d1, const void *d2)
{
226
227
228
229
230
231
232
233
234
235
236
	const edge_t *e1   = (const edge_t*)d1;
	const edge_t *e2   = (const edge_t*)d2;
	double        pen1 = e1->outedge_penalty_freq;
	double        pen2 = e2->outedge_penalty_freq;
	if (pen1 > pen2) {
		return 1;
	} else if (pen1 < pen2) {
		return -1;
	} else {
		return cmp_edges_base(e1, e2);
	}
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
}

static void clear_loop_links(ir_loop *loop)
{
	int i, n;

	set_loop_link(loop, NULL);
	n = get_loop_n_elements(loop);
	for (i = 0; i < n; ++i) {
		loop_element elem = get_loop_element(loop, i);
		if (*elem.kind == k_ir_loop) {
			clear_loop_links(elem.son);
		}
	}
}

253
254
255
256
static void coalesce_blocks(blocksched_env_t *env)
{
	int i;
	int edge_count = ARR_LEN(env->edges);
257
258
259
	edge_t *edges = env->edges;

	/* sort interblock edges by execution frequency */
260
	QSORT_ARR(edges, cmp_edges);
261

262
263
	/* run1: only look at jumps */
	for (i = 0; i < edge_count; ++i) {
264
		const edge_t *edge  = &edges[i];
265
		ir_node      *block = edge->block;
266
		int           pos   = edge->pos;
267
		ir_node      *pred_block;
268
269
		blocksched_entry_t *entry, *pred_entry;

270
271
		/* only check edge with highest frequency */
		if (! edge->highest_execfreq)
272
273
			continue;

274
275
276
277
278
		/* the block might have been removed already... */
		if (is_Bad(get_Block_cfgpred(block, 0)))
			continue;

		pred_block = get_Block_cfgpred_block(block, pos);
Christoph Mallon's avatar
Christoph Mallon committed
279
280
		entry      = get_blocksched_entry(block);
		pred_entry = get_blocksched_entry(pred_block);
281

282
		if (pred_entry->next != NULL || entry->prev != NULL)
283
			continue;
284
285
286

		/* only coalesce jumps */
		if (get_block_succ_next(pred_block, get_block_succ_first(pred_block)) != NULL)
287
288
			continue;

289
		/* schedule the 2 blocks behind each other */
290
		DB((dbg, LEVEL_1, "Coalesce (Jump) %+F -> %+F (%.3g)\n",
291
		           pred_entry->block, entry->block, edge->execfreq));
292
		pred_entry->next = entry;
293
		entry->prev      = pred_entry;
294
295
	}

296
297
298
	/* run2: pick loop fallthroughs */
	clear_loop_links(get_irg_loop(env->irg));

299
	QSORT_ARR(edges, cmp_edges_outedge_penalty);
300
	for (i = 0; i < edge_count; ++i) {
301
		const edge_t *edge  = &edges[i];
302
		ir_node      *block = edge->block;
303
		int           pos   = edge->pos;
304
		ir_node      *pred_block;
305
		blocksched_entry_t *entry, *pred_entry;
306
307
308
309
310
311
		ir_loop      *loop;
		ir_loop      *outer_loop;

		/* already seen all loop outedges? */
		if (edge->outedge_penalty_freq == 0)
			break;
312

313
		/* the block might have been removed already... */
314
		if (is_Bad(get_Block_cfgpred(block, pos)))
315
316
			continue;

317
		pred_block = get_Block_cfgpred_block(block, pos);
Christoph Mallon's avatar
Christoph Mallon committed
318
319
		entry      = get_blocksched_entry(block);
		pred_entry = get_blocksched_entry(pred_block);
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344

		if (pred_entry->next != NULL || entry->prev != NULL)
			continue;

		/* we want at most 1 outedge fallthrough per loop */
		loop = get_irn_loop(pred_block);
		if (get_loop_link(loop) != NULL)
			continue;

		/* schedule the 2 blocks behind each other */
		DB((dbg, LEVEL_1, "Coalesce (Loop Outedge) %+F -> %+F (%.3g)\n",
		           pred_entry->block, entry->block, edge->execfreq));
		pred_entry->next = entry;
		entry->prev      = pred_entry;

		/* all loops left have an outedge now */
		outer_loop = get_irn_loop(block);
		do {
			/* we set loop link to loop to mark it */
			set_loop_link(loop, loop);
			loop = get_loop_outer_loop(loop);
		} while (loop != outer_loop);
	}

	/* sort interblock edges by execution frequency */
345
	QSORT_ARR(edges, cmp_edges);
346
347
348
349
350
351
352
353
354
355
356

	/* run3: remaining edges */
	for (i = 0; i < edge_count; ++i) {
		const edge_t *edge  = &edges[i];
		ir_node      *block = edge->block;
		int           pos   = edge->pos;
		ir_node      *pred_block;
		blocksched_entry_t *entry, *pred_entry;

		/* the block might have been removed already... */
		if (is_Bad(get_Block_cfgpred(block, pos)))
357
358
359
			continue;

		pred_block = get_Block_cfgpred_block(block, pos);
Christoph Mallon's avatar
Christoph Mallon committed
360
361
		entry      = get_blocksched_entry(block);
		pred_entry = get_blocksched_entry(pred_block);
362

Matthias Braun's avatar
Matthias Braun committed
363
		/* is 1 of the blocks already attached to another block? */
364
		if (pred_entry->next != NULL || entry->prev != NULL)
365
366
			continue;

367
		/* schedule the 2 blocks behind each other */
368
		DB((dbg, LEVEL_1, "Coalesce (CondJump) %+F -> %+F (%.3g)\n",
369
		           pred_entry->block, entry->block, edge->execfreq));
370
		pred_entry->next = entry;
371
		entry->prev      = pred_entry;
372
373
374
375
376
	}
}

static void pick_block_successor(blocksched_entry_t *entry, blocksched_env_t *env)
{
377
378
	ir_node            *block = entry->block;
	ir_node            *succ  = NULL;
379
	blocksched_entry_t *succ_entry;
380
	double              best_succ_execfreq;
381

382
	if (irn_visited_else_mark(block))
383
		return;
384

385
386
	env->blockcount++;

387
	DB((dbg, LEVEL_1, "Pick succ of %+F\n", block));
388

389
	/* put all successors into the worklist */
390
391
392
	foreach_block_succ(block, edge) {
		ir_node *succ_block = get_edge_src_irn(edge);

393
		if (irn_visited(succ_block))
394
395
			continue;

396
397
		/* we only need to put the first of a series of already connected
		 * blocks into the worklist */
Christoph Mallon's avatar
Christoph Mallon committed
398
		succ_entry = get_blocksched_entry(succ_block);
399
400
401
		while (succ_entry->prev != NULL) {
			/* break cycles... */
			if (succ_entry->prev->block == succ_block) {
402
				succ_entry->prev->next = NULL;
403
				succ_entry->prev       = NULL;
404
405
406
				break;
			}
			succ_entry = succ_entry->prev;
407
		}
408

409
		if (irn_visited(succ_entry->block))
410
411
			continue;

412
		DB((dbg, LEVEL_1, "Put %+F into worklist\n", succ_entry->block));
413
414
415
		pdeq_putr(env->worklist, succ_entry->block);
	}

416
	if (entry->next != NULL) {
417
418
419
420
		pick_block_successor(entry->next, env);
		return;
	}

421
	DB((dbg, LEVEL_1, "deciding...\n"));
422
	best_succ_execfreq = -1;
423

424
	/* no successor yet: pick the successor block with the highest execution
425
426
	 * frequency which has no predecessor yet */

427
428
429
	foreach_block_succ(block, edge) {
		ir_node *succ_block = get_edge_src_irn(edge);

430
		if (irn_visited(succ_block))
431
432
			continue;

Christoph Mallon's avatar
Christoph Mallon committed
433
		succ_entry = get_blocksched_entry(succ_block);
434
		if (succ_entry->prev != NULL)
435
436
			continue;

437
		double execfreq = get_block_execfreq(succ_block);
438
		if (execfreq > best_succ_execfreq) {
439
440
441
442
443
			best_succ_execfreq = execfreq;
			succ = succ_block;
		}
	}

444
	if (succ == NULL) {
445
		DB((dbg, LEVEL_1, "pick from worklist\n"));
446
447

		do {
448
			if (pdeq_empty(env->worklist)) {
449
				DB((dbg, LEVEL_1, "worklist empty\n"));
450
451
				return;
			}
452
			succ = (ir_node*)pdeq_getl(env->worklist);
453
		} while (irn_visited(succ));
454
455
	}

Christoph Mallon's avatar
Christoph Mallon committed
456
	succ_entry       = get_blocksched_entry(succ);
457
	entry->next      = succ_entry;
458
459
460
461
462
463
464
	succ_entry->prev = entry;

	pick_block_successor(succ_entry, env);
}

static blocksched_entry_t *finish_block_schedule(blocksched_env_t *env)
{
465
466
	ir_graph           *irg        = env->irg;
	ir_node            *startblock = get_irg_start_block(irg);
Christoph Mallon's avatar
Christoph Mallon committed
467
	blocksched_entry_t *entry      = get_blocksched_entry(startblock);
468

469
	ir_reserve_resources(irg, IR_RESOURCE_IRN_VISITED);
470
471
472
473
474
475
476
	inc_irg_visited(irg);

	env->worklist = new_pdeq();
	pick_block_successor(entry, env);
	assert(pdeq_empty(env->worklist));
	del_pdeq(env->worklist);

477
	ir_free_resources(irg, IR_RESOURCE_IRN_VISITED);
478

479
480
481
	return entry;
}

482
483
484
485
486
static ir_node **create_blocksched_array(blocksched_env_t *env, blocksched_entry_t *first,
										int count, struct obstack* obst)
{
	int                i = 0;
	ir_node            **block_list;
487
	blocksched_entry_t *entry;
488
	(void) env;
489
490

	block_list = NEW_ARR_D(ir_node *, obst, count);
491
	DB((dbg, LEVEL_1, "Blockschedule:\n"));
492
493

	for (entry = first; entry != NULL; entry = entry->next) {
494
495
		assert(i < count);
		block_list[i++] = entry->block;
496
		DB((dbg, LEVEL_1, "\t%+F\n", entry->block));
497
498
499
500
501
502
	}
	assert(i == count);

	return block_list;
}

503
static ir_node **create_block_schedule_greedy(ir_graph *irg)
504
{
505
	blocksched_env_t   env;
506
	blocksched_entry_t *start_entry;
507
	ir_node            **block_list;
508

509
510
511
	env.irg        = irg;
	env.edges      = NEW_ARR_F(edge_t, 0);
	env.worklist   = NULL;
512
	env.blockcount = 0;
513
	obstack_init(&env.obst);
514

515
	assure_loopinfo(irg);
516

517
518
519
	// collect edge execution frequencies
	irg_block_walk_graph(irg, collect_egde_frequency, NULL, &env);

520
	(void)be_remove_empty_blocks(irg);
521

522
	if (algo != BLOCKSCHED_NAIV)
523
524
525
		coalesce_blocks(&env);

	start_entry = finish_block_schedule(&env);
526
	block_list  = create_blocksched_array(&env, start_entry, env.blockcount,
527
	                                      be_get_be_obst(irg));
528
529

	DEL_ARR_F(env.edges);
530
	obstack_free(&env.obst, NULL);
531
532
533
534
535
536
537
538
539
540
541
542
543

	return block_list;
}

/*
 *  ___ _     ____
 * |_ _| |   |  _ \
 *  | || |   | |_) |
 *  | || |___|  __/
 * |___|_____|_|
 *
 */

544
typedef struct ilp_edge_t {
545
546
547
	ir_node *block;   /**< source block */
	int     pos;      /**< number of cfg predecessor (target) */
	int     ilpvar;
548
549
} ilp_edge_t;

550
typedef struct blocksched_ilp_env_t {
551
	blocksched_env_t env;
552
553
	ilp_edge_t       *ilpedges;
	lpp_t            *lpp;
554
555
} blocksched_ilp_env_t;

556
typedef struct blocksched_ilp_entry_t {
557
	ir_node *block;
558
559
	struct blocksched_entry_t *next;
	struct blocksched_entry_t *prev;
560
561
562
563
564
565

	int out_cst;
} blocksched_ilp_entry_t;

static int add_ilp_edge(ir_node *block, int pos, double execfreq, blocksched_ilp_env_t *env)
{
566
	char       name[64];
567
	ilp_edge_t edge;
568
	int        edgeidx = ARR_LEN(env->ilpedges);
569
570
571

	snprintf(name, sizeof(name), "edge%d", edgeidx);

572
573
	edge.block  = block;
	edge.pos    = pos;
574
575
576
577
578
579
580
581
	edge.ilpvar = lpp_add_var_default(env->lpp, name, lpp_binary, execfreq, 1.0);

	ARR_APP1(ilp_edge_t, env->ilpedges, edge);
	return edgeidx;
}

static void collect_egde_frequency_ilp(ir_node *block, void *data)
{
582
	blocksched_ilp_env_t *env        = (blocksched_ilp_env_t*)data;
583
584
585
586
587
	ir_graph             *irg        = env->env.irg;
	ir_node              *startblock = get_irg_start_block(irg);
	int                  arity;
	char                 name[64];
	int                  out_count;
588
589
590
591
592
	blocksched_ilp_entry_t *entry;

	snprintf(name, sizeof(name), "block_out_constr_%ld", get_irn_node_nr(block));
	out_count = get_irn_n_edges_kind(block, EDGE_KIND_BLOCK);

593
	entry          = OALLOC(&env->env.obst, blocksched_ilp_entry_t);
594
595
596
	entry->block   = block;
	entry->next    = NULL;
	entry->prev    = NULL;
597
	entry->out_cst = lpp_add_cst_uniq(env->lpp, name, lpp_greater_equal, out_count - 1);
598
599
	set_irn_link(block, entry);

600
	if (block == startblock)
601
602
603
		return;

	arity = get_irn_arity(block);
604
	if (arity == 1) {
605
		double execfreq = get_block_execfreq(block);
606
		add_ilp_edge(block, 0, execfreq, env);
607
	} else {
608
		int i;
609
		int cst_idx;
610
611

		snprintf(name, sizeof(name), "block_in_constr_%ld", get_irn_node_nr(block));
612
		cst_idx = lpp_add_cst_uniq(env->lpp, name, lpp_greater_equal, arity - 1);
613

614
615
616
		for (i = 0; i < arity; ++i) {
			double     execfreq;
			int        edgenum;
617
			ilp_edge_t *edge;
618
			ir_node    *pred_block = get_Block_cfgpred_block(block, i);
619

620
			execfreq = get_block_execfreq(pred_block);
621
622
			edgenum  = add_ilp_edge(block, i, execfreq, env);
			edge     = &env->ilpedges[edgenum];
623
			lpp_set_factor_fast(env->lpp, cst_idx, edge->ilpvar, 1.0);
624
625
626
627
		}
	}
}

628
629
630
631
static blocksched_ilp_entry_t *get_blocksched_ilp_entry(const ir_node *block)
{
	return (blocksched_ilp_entry_t*)get_irn_link(block);
}
632
633
634

static void coalesce_blocks_ilp(blocksched_ilp_env_t *env)
{
Matthias Braun's avatar
Matthias Braun committed
635
636
	int           edge_count = ARR_LEN(env->ilpedges);
	int           i;
637
638

	/* complete out constraints */
639
	for (i = 0; i < edge_count; ++i) {
640
641
642
		const ilp_edge_t *edge  = &env->ilpedges[i];
		ir_node          *block = edge->block;
		ir_node          *pred;
643
644
		blocksched_ilp_entry_t *entry;

645
646
		/* the block might have been removed already... */
		if (is_Bad(get_Block_cfgpred(block, 0)))
647
648
			continue;

649
		pred  = get_Block_cfgpred_block(block, edge->pos);
650
		entry = get_blocksched_ilp_entry(pred);
651

652
		DB((dbg, LEVEL_1, "Adding out cst to %+F from %+F,%d\n",
653
				  pred, block, edge->pos));
654
655
656
		lpp_set_factor_fast(env->lpp, entry->out_cst, edge->ilpvar, 1.0);
	}

657
	lpp_solve_net(env->lpp, be_options.ilp_server, be_options.ilp_solver);
658
659
660
	assert(lpp_is_sol_valid(env->lpp));

	/* Apply results to edges */
661
662
663
664
665
	for (i = 0; i < edge_count; ++i) {
		const ilp_edge_t   *edge  = &env->ilpedges[i];
		ir_node            *block = edge->block;
		ir_node            *pred;
		int                is_jump;
666
667
668
		blocksched_entry_t *entry;
		blocksched_entry_t *pred_entry;

669
670
		/* the block might have been removed already... */
		if (is_Bad(get_Block_cfgpred(block, 0)))
671
672
			continue;

673
		is_jump = (int)lpp_get_var_sol(env->lpp, edge->ilpvar);
674
		if (is_jump)
675
676
			continue;

677
		pred       = get_Block_cfgpred_block(block, edge->pos);
678
679
		entry      = get_blocksched_entry(block);
		pred_entry = get_blocksched_entry(pred);
680
681

		assert(entry->prev == NULL && pred_entry->next == NULL);
682
		entry->prev      = pred_entry;
683
684
685
686
		pred_entry->next = entry;
	}
}

687
static ir_node **create_block_schedule_ilp(ir_graph *irg)
688
689
{
	blocksched_ilp_env_t env;
690
691
	blocksched_entry_t   *start_entry;
	ir_node              **block_list;
692

693
694
	env.env.irg        = irg;
	env.env.worklist   = NULL;
695
	env.env.blockcount = 0;
696
	env.ilpedges       = NEW_ARR_F(ilp_edge_t, 0);
697
	obstack_init(&env.env.obst);
698

699
	env.lpp = lpp_new("blockschedule", lpp_minimize);
700
701
702
703
704
	lpp_set_time_limit(env.lpp, 20);
	lpp_set_log(env.lpp, stdout);

	irg_block_walk_graph(irg, collect_egde_frequency_ilp, NULL, &env);

705
	(void)be_remove_empty_blocks(irg);
706
707
708
	coalesce_blocks_ilp(&env);

	start_entry = finish_block_schedule(&env.env);
709
710
	block_list  = create_blocksched_array(&env.env, start_entry,
	                                      env.env.blockcount,
711
	                                      be_get_be_obst(irg));
712
713

	DEL_ARR_F(env.ilpedges);
714
	lpp_free(env.lpp);
715
	obstack_free(&env.env.obst, NULL);
716
717
718
719
720
721
722
723
724
725
726
727

	return block_list;
}

/*
 *  __  __       _
 * |  \/  | __ _(_)_ __
 * | |\/| |/ _` | | '_ \
 * | |  | | (_| | | | | |
 * |_|  |_|\__,_|_|_| |_|
 *
 */
Matthias Braun's avatar
Matthias Braun committed
728
BE_REGISTER_MODULE_CONSTRUCTOR(be_init_blocksched)
729
void be_init_blocksched(void)
730
{
731
	lc_opt_entry_t *be_grp = lc_opt_get_grp(firm_opt_get_root(), "be");
732

733
	lc_opt_add_table(be_grp, be_blocksched_options);
734

Matthias Braun's avatar
Matthias Braun committed
735
	FIRM_DBG_REGISTER(dbg, "firm.be.blocksched");
736
}
737

738
ir_node **be_create_block_schedule(ir_graph *irg)
739
{
740
	switch (algo) {
741
742
	case BLOCKSCHED_GREEDY:
	case BLOCKSCHED_NAIV:
743
		return create_block_schedule_greedy(irg);
744
	case BLOCKSCHED_ILP:
745
		return create_block_schedule_ilp(irg);
746
747
	}

748
	panic("unknown blocksched algo");
749
}