beblocksched.c 19.9 KB
Newer Older
Christian Würdig's avatar
Christian Würdig committed
1
/*
Michael Beck's avatar
Michael Beck committed
2
 * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
Christian Würdig's avatar
Christian Würdig committed
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 *
 * This file is part of libFirm.
 *
 * This file may be distributed and/or modified under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation and appearing in the file LICENSE.GPL included in the
 * packaging of this file.
 *
 * Licensees holding valid libFirm Professional Edition licenses may use
 * this file in accordance with the libFirm Commercial License.
 * Agreement provided with the Software.
 *
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE.
 */

Christian Würdig's avatar
Christian Würdig committed
20
21
22
23
24
25
/**
 * @file
 * @brief       Block-scheduling strategies.
 * @author      Matthias Braun, Christoph Mallon
 * @date        27.09.2006
 * @version     $Id$
26
27
28
29
30
31
32
33
34
35
 *
 * 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
36
37
 */
#ifdef HAVE_CONFIG_H
38
#include "config.h"
Matthias Braun's avatar
Matthias Braun committed
39
#endif
40
41
42
43
44
45
46
47
48
49

#include "beblocksched.h"

#include <stdlib.h>

#include "array.h"
#include "pdeq.h"

#include "iredges.h"
#include "irgwalk.h"
Michael Beck's avatar
Michael Beck committed
50
#include "irnode_t.h"
51
52
53
#include "irgraph_t.h"
#include "irloop.h"
#include "irprintf.h"
Michael Beck's avatar
Michael Beck committed
54
#include "execfreq.h"
55
#include "irdump_t.h"
56
57
#include "irtools.h"
#include "debug.h"
58
#include "beirgmod.h"
59
60
#include "bemodule.h"
#include "be.h"
61
#include "error.h"
62

Matthias Braun's avatar
Matthias Braun committed
63
64
#include "lc_opts.h"
#include "lc_opts_enum.h"
65

66
67
68
#ifdef WITH_ILP
#include <lpp/lpp.h>
#include <lpp/lpp_net.h>
Christian Würdig's avatar
Christian Würdig committed
69
#endif /* WITH_ILP */
70

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

73
74
75
76
77
78
79
80
81
82
83
84
typedef enum _blocksched_algos_t {
	BLOCKSCHED_NAIV, BLOCKSCHED_EXTBB, BLOCKSCHED_GREEDY, BLOCKSCHED_ILP
} blocksched_algos_t;

static int algo = BLOCKSCHED_GREEDY;

static const lc_opt_enum_int_items_t blockschedalgo_items[] = {
	{ "naiv",	BLOCKSCHED_NAIV },
	{ "extbb",	BLOCKSCHED_EXTBB },
	{ "greedy", BLOCKSCHED_GREEDY },
#ifdef WITH_ILP
	{ "ilp",    BLOCKSCHED_ILP },
Christian Würdig's avatar
Christian Würdig committed
85
#endif /* WITH_ILP */
86
87
88
89
90
91
92
93
	{ NULL,     0 }
};

static lc_opt_enum_int_var_t algo_var = {
	&algo, blockschedalgo_items
};

static const lc_opt_table_entry_t be_blocksched_options[] = {
Christian Würdig's avatar
Christian Würdig committed
94
	LC_OPT_ENT_ENUM_INT ("algo", "the block scheduling algorithm", &algo_var),
95
	LC_OPT_LAST
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
};

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

typedef struct _blocksched_entry_t {
	ir_node *block;
	struct _blocksched_entry_t *next;
	struct _blocksched_entry_t *prev;
} blocksched_entry_t;

typedef struct _edge_t {
114
115
116
	ir_node *block;             /**< source block */
	int     pos;                /**< number of cfg predecessor (target) */
	double  execfreq;           /**< the frequency */
117
	int     highest_execfreq;   /**< flag that indicates whether this edge is the edge with the highest
118
	                                 execfreq pointing away from this block */
119
120
121
} edge_t;

typedef struct _blocksched_env_t {
122
	ir_graph       *irg;
123
	struct obstack *obst;
124
125
126
127
	ir_exec_freq   *execfreqs;
	edge_t         *edges;
	pdeq           *worklist;
	int            blockcount;
128
129
} blocksched_env_t;

130
131
132
133
/**
 * Collect cfg frequencies of all edges between blocks.
 * Also determines edge with highest frequency.
 */
134
135
static void collect_egde_frequency(ir_node *block, void *data)
{
136
	blocksched_env_t   *env = data;
137
138
	int                arity;
	edge_t             edge;
139
140
	blocksched_entry_t *entry;

141
	entry        = obstack_alloc(env->obst, sizeof(entry[0]));
142
	entry->block = block;
143
144
	entry->next  = NULL;
	entry->prev  = NULL;
145
146
	set_irn_link(block, entry);

147
	arity = get_Block_n_cfgpreds(block);
148

149
	if (arity == 0) {
150
151
152
153
		assert(block == get_irg_start_block(env->irg)
				|| block == get_irg_end_block(env->irg));
		/* must be the start block (or end-block for endless loops), nothing to
		 * do here */
154
155
		return;
	} else if (arity == 1) {
156
157
158
		edge.block            = block;
		edge.pos              = 0;
		edge.execfreq         = get_block_execfreq(env->execfreqs, block);
159
160
161
		edge.highest_execfreq = 1;
		ARR_APP1(edge_t, env->edges, edge);
	} else {
162
		int    i;
163
		double highest_execfreq = -1.0;
164
		int    highest_edge_num = -1;
165
166

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

171
172
			execfreq = get_block_execfreq(env->execfreqs, pred_block);

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

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

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

static int cmp_edges(const void *d1, const void *d2)
{
	const edge_t *e1 = d1;
	const edge_t *e2 = d2;
193
194

	return QSORT_CMP(e2->execfreq, e1->execfreq);
195
196
197
198
199
200
201
}

static void coalesce_blocks(blocksched_env_t *env)
{
	int i;
	int edge_count = ARR_LEN(env->edges);

202
203
204
205
	/* run1: only look at jumps */
	for (i = 0; i < edge_count; ++i) {
		const edge_t *edge  = &env->edges[i];
		ir_node      *block = edge->block;
206
		int           pos   = edge->pos;
207
		ir_node      *pred_block;
208
209
		blocksched_entry_t *entry, *pred_entry;

210
211
		/* only check edge with highest frequency */
		if (! edge->highest_execfreq)
212
213
			continue;

214
215
216
217
218
		/* the block might have been removed already... */
		if (is_Bad(get_Block_cfgpred(block, 0)))
			continue;

		pred_block = get_Block_cfgpred_block(block, pos);
219
		entry      = get_irn_link(block);
220
221
		pred_entry = get_irn_link(pred_block);

222
		if (pred_entry->next != NULL || entry->prev != NULL)
223
			continue;
224
225
226

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

229
		/* schedule the 2 blocks behind each other */
Matthias Braun's avatar
Matthias Braun committed
230
		DBG((dbg, LEVEL_1, "Coalesce (Jump) %+F -> %+F (%.3g)\n",
231
		           pred_entry->block, entry->block, edge->execfreq));
232
		pred_entry->next = entry;
233
		entry->prev      = pred_entry;
234
235
	}

236
237
238
239
	/* run2: remaining edges */
	for (i = 0; i < edge_count; ++i) {
		const edge_t *edge  = &env->edges[i];
		ir_node      *block = edge->block;
240
		int           pos   = edge->pos;
241
		ir_node      *pred_block;
242
243
		blocksched_entry_t *entry, *pred_entry;

244
245
		/* the block might have been removed already... */
		if (is_Bad(get_Block_cfgpred(block, 0)))
246
247
			continue;

248
249
		/* we can't do fallthroughs in backedges */
		if (is_backedge(block, pos))
250
251
252
			continue;

		pred_block = get_Block_cfgpred_block(block, pos);
253
		entry      = get_irn_link(block);
254
255
		pred_entry = get_irn_link(pred_block);

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

260
		/* schedule the 2 blocks behind each other */
Matthias Braun's avatar
Matthias Braun committed
261
		DBG((dbg, LEVEL_1, "Coalesce (CondJump) %+F -> %+F (%.3g)\n",
262
		           pred_entry->block, entry->block, edge->execfreq));
263
		pred_entry->next = entry;
264
		entry->prev      = pred_entry;
265
266
267
268
269
	}
}

static void pick_block_successor(blocksched_entry_t *entry, blocksched_env_t *env)
{
270
271
	ir_node            *block = entry->block;
	ir_node            *succ  = NULL;
272
	blocksched_entry_t *succ_entry;
273
274
	const ir_edge_t    *edge;
	double             best_succ_execfreq;
275

276
	if (irn_visited(block))
277
		return;
278

279
280
281
	env->blockcount++;
	mark_irn_visited(block);

Matthias Braun's avatar
Matthias Braun committed
282
	DBG((dbg, LEVEL_1, "Pick succ of %+F\n", block));
283

284
	/* put all successors into the worklist */
285
286
287
	foreach_block_succ(block, edge) {
		ir_node *succ_block = get_edge_src_irn(edge);

288
		if (irn_visited(succ_block))
289
290
			continue;

291
292
		/* we only need to put the first of a series of already connected
		 * blocks into the worklist */
293
		succ_entry = get_irn_link(succ_block);
294
295
296
		while (succ_entry->prev != NULL) {
			/* break cycles... */
			if (succ_entry->prev->block == succ_block) {
297
				succ_entry->prev->next = NULL;
298
				succ_entry->prev       = NULL;
299
300
301
302
303
				break;
			}
			succ_entry = succ_entry->prev;
		};

304
		if (irn_visited(succ_entry->block))
305
306
			continue;

Matthias Braun's avatar
Matthias Braun committed
307
		DBG((dbg, LEVEL_1, "Put %+F into worklist\n", succ_entry->block));
308
309
310
		pdeq_putr(env->worklist, succ_entry->block);
	}

311
	if (entry->next != NULL) {
312
313
314
315
		pick_block_successor(entry->next, env);
		return;
	}

Matthias Braun's avatar
Matthias Braun committed
316
	DBG((dbg, LEVEL_1, "deciding...\n"));
317
	best_succ_execfreq = -1;
318

319
	/* no successor yet: pick the successor block with the highest execution
320
321
	 * frequency which has no predecessor yet */

322
323
	foreach_block_succ(block, edge) {
		ir_node *succ_block = get_edge_src_irn(edge);
324
		double  execfreq;
325

326
		if (irn_visited(succ_block))
327
328
329
			continue;

		succ_entry = get_irn_link(succ_block);
330
		if (succ_entry->prev != NULL)
331
332
			continue;

Michael Beck's avatar
Michael Beck committed
333
		execfreq = get_block_execfreq(env->execfreqs, succ_block);
334
		if (execfreq > best_succ_execfreq) {
335
336
337
338
339
			best_succ_execfreq = execfreq;
			succ = succ_block;
		}
	}

340
	if (succ == NULL) {
Matthias Braun's avatar
Matthias Braun committed
341
		DBG((dbg, LEVEL_1, "pick from worklist\n"));
342
343

		do {
344
			if (pdeq_empty(env->worklist)) {
Matthias Braun's avatar
Matthias Braun committed
345
				DBG((dbg, LEVEL_1, "worklist empty\n"));
346
347
348
				return;
			}
			succ = pdeq_getl(env->worklist);
349
		} while (irn_visited(succ));
350
351
	}

352
353
	succ_entry       = get_irn_link(succ);
	entry->next      = succ_entry;
354
355
356
357
358
359
360
	succ_entry->prev = entry;

	pick_block_successor(succ_entry, env);
}

static blocksched_entry_t *finish_block_schedule(blocksched_env_t *env)
{
361
362
363
	ir_graph           *irg        = env->irg;
	ir_node            *startblock = get_irg_start_block(irg);
	blocksched_entry_t *entry      = get_irn_link(startblock);
364

365
	ir_reserve_resources(irg, IR_RESOURCE_IRN_VISITED);
366
367
368
369
370
371
372
	inc_irg_visited(irg);

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

373
	ir_free_resources(irg, IR_RESOURCE_IRN_VISITED);
374

375
376
377
	return entry;
}

378
379
380
381
382
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;
383
	blocksched_entry_t *entry;
384
	(void) env;
385
386

	block_list = NEW_ARR_D(ir_node *, obst, count);
Matthias Braun's avatar
Matthias Braun committed
387
	DBG((dbg, LEVEL_1, "Blockschedule:\n"));
388
389

	for (entry = first; entry != NULL; entry = entry->next) {
390
391
		assert(i < count);
		block_list[i++] = entry->block;
Matthias Braun's avatar
Matthias Braun committed
392
		DBG((dbg, LEVEL_1, "\t%+F\n", entry->block));
393
394
395
396
397
398
399
400
	}
	assert(i == count);

	return block_list;
}

static ir_node **create_block_schedule_greedy(ir_graph *irg, ir_exec_freq *execfreqs)
{
401
402
	blocksched_env_t   env;
	struct obstack     obst;
403
	blocksched_entry_t *start_entry;
404
	ir_node            **block_list;
405
406
407

	obstack_init(&obst);

408
409
410
411
412
	env.irg        = irg;
	env.obst       = &obst;
	env.execfreqs  = execfreqs;
	env.edges      = NEW_ARR_F(edge_t, 0);
	env.worklist   = NULL;
413
414
415
416
417
418
419
420
	env.blockcount = 0;

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

	// sort interblock edges by execution frequency
	qsort(env.edges, ARR_LEN(env.edges), sizeof(env.edges[0]), cmp_edges);

421
	(void)be_remove_empty_blocks(irg);
422

423
	if (algo != BLOCKSCHED_NAIV)
424
425
426
		coalesce_blocks(&env);

	start_entry = finish_block_schedule(&env);
427
	block_list  = create_blocksched_array(&env, start_entry, env.blockcount, get_irg_obstack(irg));
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445

	DEL_ARR_F(env.edges);
	obstack_free(&obst, NULL);

	return block_list;
}

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

#ifdef WITH_ILP
typedef struct _ilp_edge_t {
446
447
448
	ir_node *block;   /**< source block */
	int     pos;      /**< number of cfg predecessor (target) */
	int     ilpvar;
449
450
451
452
} ilp_edge_t;

typedef struct _blocksched_ilp_env_t {
	blocksched_env_t env;
453
454
	ilp_edge_t       *ilpedges;
	lpp_t            *lpp;
455
456
457
458
459
460
461
462
463
464
465
466
} blocksched_ilp_env_t;

typedef struct _blocksched_ilp_entry_t {
	ir_node *block;
	struct _blocksched_entry_t *next;
	struct _blocksched_entry_t *prev;

	int out_cst;
} blocksched_ilp_entry_t;

static int add_ilp_edge(ir_node *block, int pos, double execfreq, blocksched_ilp_env_t *env)
{
467
	char       name[64];
468
	ilp_edge_t edge;
469
	int        edgeidx = ARR_LEN(env->ilpedges);
470
471
472

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

473
474
	edge.block  = block;
	edge.pos    = pos;
475
476
477
478
479
480
481
482
	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)
{
483
484
485
486
487
488
489
	blocksched_ilp_env_t *env        = data;
	ir_graph             *irg        = env->env.irg;
	ir_node              *startblock = get_irg_start_block(irg);
	int                  arity;
	lpp_cst_t            cst;
	char                 name[64];
	int                  out_count;
490
491
492
493
494
	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);

495
496
497
498
	entry          = obstack_alloc(env->env.obst, sizeof(entry[0]));
	entry->block   = block;
	entry->next    = NULL;
	entry->prev    = NULL;
499
500
501
	entry->out_cst = lpp_add_cst_uniq(env->lpp, name, lpp_greater, out_count - 1);
	set_irn_link(block, entry);

502
	if (block == startblock)
503
504
505
		return;

	arity = get_irn_arity(block);
506
	if (arity == 1) {
507
508
		double execfreq = get_block_execfreq(env->env.execfreqs, block);
		add_ilp_edge(block, 0, execfreq, env);
509
510
	}
	else {
511
512
513
514
515
516
		int i;
		int *edgenums = alloca(sizeof(edgenums[0]) * arity);

		snprintf(name, sizeof(name), "block_in_constr_%ld", get_irn_node_nr(block));
		cst = lpp_add_cst_uniq(env->lpp, name, lpp_greater, arity - 1);

517
518
519
		for (i = 0; i < arity; ++i) {
			double     execfreq;
			int        edgenum;
520
			ilp_edge_t *edge;
521
			ir_node    *pred_block = get_Block_cfgpred_block(block, i);
522
523

			execfreq = get_block_execfreq(env->env.execfreqs, pred_block);
524
525
			edgenum  = add_ilp_edge(block, i, execfreq, env);
			edge     = &env->ilpedges[edgenum];
526
527
528
529
530
531
532
533
			lpp_set_factor_fast(env->lpp, cst, edge->ilpvar, 1.0);
		}
	}
}


static void coalesce_blocks_ilp(blocksched_ilp_env_t *env)
{
534
535
	int  i;
	int  edge_count = ARR_LEN(env->ilpedges);
536
537
538

	/* complete out constraints */
	for(i = 0; i < edge_count; ++i) {
539
540
541
		const ilp_edge_t *edge  = &env->ilpedges[i];
		ir_node          *block = edge->block;
		ir_node          *pred;
542
543
		blocksched_ilp_entry_t *entry;

544
545
		/* the block might have been removed already... */
		if (is_Bad(get_Block_cfgpred(block, 0)))
546
547
			continue;

548
		pred  = get_Block_cfgpred_block(block, edge->pos);
549
550
		entry = get_irn_link(pred);

Matthias Braun's avatar
Matthias Braun committed
551
		DBG((dbg, LEVEL_1, "Adding out cst to %+F from %+F,%d\n",
552
				  pred, block, edge->pos));
553
554
555
		lpp_set_factor_fast(env->lpp, entry->out_cst, edge->ilpvar, 1.0);
	}

556
557
558
559
560
561
562
563
564
565
566
567
#if 0
	{
		FILE *f;
		char fname[256];
		lpp_dump(env->lpp, "lpp.out");
		snprintf(fname, sizeof(fname), "lpp_%s.plain", get_irg_dump_name(env->env.irg));
		f = fopen(fname, "w");
		lpp_dump_plain(env->lpp, f);
		fclose(f);
	}
#endif

568
569
570
571
572
	//lpp_solve_net(env->lpp, main_env->options->ilp_server, main_env->options->ilp_solver);
	lpp_solve_net(env->lpp, "i44pc52", "cplex");
	assert(lpp_is_sol_valid(env->lpp));

	/* Apply results to edges */
573
574
575
576
577
	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;
578
579
580
		blocksched_entry_t *entry;
		blocksched_entry_t *pred_entry;

581
582
		/* the block might have been removed already... */
		if (is_Bad(get_Block_cfgpred(block, 0)))
583
584
			continue;

585
		is_jump = (int)lpp_get_var_sol(env->lpp, edge->ilpvar);
586
		if (is_jump)
587
588
			continue;

589
590
		pred       = get_Block_cfgpred_block(block, edge->pos);
		entry      = get_irn_link(block);
591
592
593
		pred_entry = get_irn_link(pred);

		assert(entry->prev == NULL && pred_entry->next == NULL);
594
		entry->prev      = pred_entry;
595
596
597
598
599
600
601
		pred_entry->next = entry;
	}
}

static ir_node **create_block_schedule_ilp(ir_graph *irg, ir_exec_freq *execfreqs)
{
	blocksched_ilp_env_t env;
602
603
604
	struct obstack       obst;
	blocksched_entry_t   *start_entry;
	ir_node              **block_list;
605
606
607

	obstack_init(&obst);

608
609
610
611
	env.env.irg        = irg;
	env.env.obst       = &obst;
	env.env.execfreqs  = execfreqs;
	env.env.worklist   = NULL;
612
	env.env.blockcount = 0;
613
	env.ilpedges       = NEW_ARR_F(ilp_edge_t, 0);
614
615
616
617
618
619
620

	env.lpp = new_lpp("blockschedule", lpp_minimize);
	lpp_set_time_limit(env.lpp, 20);
	lpp_set_log(env.lpp, stdout);

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

621
	(void)be_remove_empty_blocks(irg);
622
623
624
	coalesce_blocks_ilp(&env);

	start_entry = finish_block_schedule(&env.env);
625
	block_list  = create_blocksched_array(&env.env, start_entry, env.env.blockcount, get_irg_obstack(irg));
626
627
628
629
630
631
632

	DEL_ARR_F(env.ilpedges);
	free_lpp(env.lpp);
	obstack_free(&obst, NULL);

	return block_list;
}
Christian Würdig's avatar
Christian Würdig committed
633
#endif /* WITH_ILP */
634
635
636
637
638
639
640
641
642
643
644
645

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

/** A simple forward single linked list. */
typedef struct {
646
647
	ir_node  *start;   /**< start of the list */
	ir_node  *end;     /**< last block in the list */
648
649
650
651
	unsigned n_blks;  /**< number of blocks in the list */
} anchor;

static void add_block(anchor *list, ir_node *block) {
652
	if (list->start == NULL) {
653
		list->start = block;
654
		list->end   = block;
655
	} else {
656
657
658
659
660
661
662
663
		set_irn_link(list->end, block);
		list->end = block;
	}

	list->n_blks++;
}

static void create_block_list(ir_node *leader_block, anchor *list) {
664
	int             i;
665
	const ir_edge_t *edge;
666
667
	ir_node         *block = NULL;
	ir_extblk       *extbb = get_Block_extbb(leader_block);
668

669
	if (extbb_visited(extbb))
670
671
672
		return;
	mark_extbb_visited(extbb);

673
	for (i = 0; i < get_extbb_n_blocks(extbb); ++i) {
674
675
676
677
678
679
		block = get_extbb_block(extbb, i);
		add_block(list, block);
	}

	assert(block != NULL);

680
	/* pick successor extbbs */
681
682
683
684
685
	foreach_block_succ(block, edge) {
		ir_node *succ = get_edge_src_irn(edge);
		create_block_list(succ, list);
	}

686
	for (i = 0; i < get_extbb_n_blocks(extbb) - 1; ++i) {
687
		block = get_extbb_block(extbb, i);
688

689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
		foreach_block_succ(block, edge) {
			ir_node *succ = get_edge_src_irn(edge);
			create_block_list(succ, list);
		}
	}
}

void compute_extbb_execfreqs(ir_graph *irg, ir_exec_freq *execfreqs);

/*
 * Calculates a block schedule. The schedule is stored as a linked
 * list starting at the start_block of the irg.
 */
static ir_node **create_extbb_block_schedule(ir_graph *irg, ir_exec_freq *execfreqs)
{
	anchor list;
	ir_node **blk_list, *b, *n;
	unsigned i;

	/* schedule extended basic blocks */
	compute_extbb_execfreqs(irg, execfreqs);
	//compute_extbb(irg);

	list.start  = NULL;
	list.end    = NULL;
	list.n_blks = 0;
715

716
	ir_reserve_resources(irg, IR_RESOURCE_IRN_VISITED | IR_RESOURCE_IRN_LINK);
717
	inc_irg_block_visited(irg);
718

719
720
721
722
723
724
725
726
727
728
	create_block_list(get_irg_start_block(irg), &list);

	/** create an array, so we can go forward and backward */
	blk_list = NEW_ARR_D(ir_node *, irg->obst,list.n_blks);

	for (i = 0, b = list.start; b; b = n, ++i) {
		n = get_irn_link(b);
		blk_list[i] = b;
	}

729
	ir_free_resources(irg, IR_RESOURCE_IRN_VISITED | IR_RESOURCE_IRN_LINK);
730

731
732
733
734
735
736
737
738
739
740
741
	return blk_list;
}

/*
 *  __  __       _
 * |  \/  | __ _(_)_ __
 * | |\/| |/ _` | | '_ \
 * | |  | | (_| | | | | |
 * |_|  |_|\__,_|_|_| |_|
 *
 */
742
void be_init_blocksched(void)
743
{
744
745
	lc_opt_entry_t *be_grp = lc_opt_get_grp(firm_opt_get_root(), "be");
	lc_opt_entry_t *blocksched_grp = lc_opt_get_grp(be_grp, "blocksched");
746
747

	lc_opt_add_table(blocksched_grp, be_blocksched_options);
748

Matthias Braun's avatar
Matthias Braun committed
749
	FIRM_DBG_REGISTER(dbg, "firm.be.blocksched");
750
}
751
752

BE_REGISTER_MODULE_CONSTRUCTOR(be_init_blocksched);
753
754
755
756
757
758
759
760
761
762
763
764

ir_node **be_create_block_schedule(ir_graph *irg, ir_exec_freq *execfreqs)
{
	switch(algo) {
	case BLOCKSCHED_GREEDY:
	case BLOCKSCHED_NAIV:
		return create_block_schedule_greedy(irg, execfreqs);
	case BLOCKSCHED_EXTBB:
		return create_extbb_block_schedule(irg, execfreqs);
#ifdef WITH_ILP
	case BLOCKSCHED_ILP:
		return create_block_schedule_ilp(irg, execfreqs);
Christian Würdig's avatar
Christian Würdig committed
765
#endif /* WITH_ILP */
766
767
	}

768
	panic("unknown blocksched algo");
769
770
	return NULL;
}