beifg.c 7.14 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
 */

6
/**
Christian Würdig's avatar
Christian Würdig committed
7
8
9
10
 * @file
 * @brief       Interface for interference graphs.
 * @author      Sebastian Hack
 * @date        18.11.2005
11
 */
12
13
#include <stdlib.h>

Matthias Braun's avatar
Matthias Braun committed
14
15
#include "lc_opts.h"
#include "lc_opts_enum.h"
16

Matthias Braun's avatar
Matthias Braun committed
17
#include "timing.h"
18
#include "bitset.h"
19
#include "irgwalk.h"
Sebastian Hack's avatar
Sebastian Hack committed
20
#include "irnode_t.h"
21
#include "beifg.h"
Matthias Braun's avatar
Matthias Braun committed
22
#include "panic.h"
23
#include "xmalloc.h"
24
25
26

#include "becopystat.h"
#include "becopyopt.h"
27
#include "beirg.h"
Christian Würdig's avatar
Christian Würdig committed
28
#include "bemodule.h"
Matthias Braun's avatar
Matthias Braun committed
29
#include "belive_t.h"
30

31
void be_ifg_free(be_ifg_t *self)
Sebastian Hack's avatar
Sebastian Hack committed
32
{
33
	free(self);
Sebastian Hack's avatar
Sebastian Hack committed
34
35
}

36
static void nodes_walker(ir_node *bl, void *data)
Daniel Grund's avatar
Daniel Grund committed
37
{
38
	nodes_iter_t     *it   = (nodes_iter_t*)data;
39
40
41
42
43
44
45
46
	struct list_head *head = get_block_border_head(it->env, bl);

	foreach_border_head(head, b) {
		if (b->is_def && b->is_real) {
			obstack_ptr_grow(&it->obst, b->irn);
			it->n++;
		}
	}
Daniel Grund's avatar
Daniel Grund committed
47
48
}

49
nodes_iter_t be_ifg_nodes_begin(be_ifg_t const *const ifg)
50
{
51
52
53
54
55
56
57
58
59
60
	nodes_iter_t iter;
	obstack_init(&iter.obst);
	iter.n    = 0;
	iter.curr = 0;
	iter.env  = ifg->env;

	irg_block_walk_graph(ifg->env->irg, nodes_walker, NULL, &iter);
	obstack_ptr_grow(&iter.obst, NULL);
	iter.nodes = (ir_node**)obstack_finish(&iter.obst);
	return iter;
61
62
}

63
ir_node *be_ifg_nodes_next(nodes_iter_t *const it)
64
{
65
66
67
	if (it->curr < it->n) {
		return it->nodes[it->curr++];
	} else {
68
		obstack_free(&it->obst, NULL);
69
		return NULL;
70
	}
71
72
}

73
static void find_neighbour_walker(ir_node *block, void *data)
Sebastian Hack's avatar
Sebastian Hack committed
74
{
75
	neighbours_iter_t *it    = (neighbours_iter_t*)data;
76
	struct list_head  *head  = get_block_border_head(it->env, block);
77
	be_lv_t           *lv    = be_get_irg_liveness(it->env->irg);
78

79
	int has_started = 0;
Sebastian Hack's avatar
Sebastian Hack committed
80

81
	if (!be_is_live_in(lv, block, it->irn) && block != get_nodes_block(it->irn))
82
		return;
83

84
85
86
87
88
89
90
91
	foreach_border_head(head, b) {
		ir_node *irn = b->irn;

		if (irn == it->irn) {
			if (b->is_def)
				has_started = 1;
			else
				break; /* if we reached the end of the node's lifetime we can safely break */
92
		} else if (b->is_def) {
93
94
			/* if any other node than the one in question starts living, add it to the set */
			ir_nodeset_insert(&it->neighbours, irn);
95
		} else if (!has_started) {
96
97
98
99
100
			/* we only delete, if the live range in question has not yet started */
			ir_nodeset_remove(&it->neighbours, irn);
		}

	}
101
102
}

103
static void find_neighbours(const be_ifg_t *ifg, neighbours_iter_t *it, const ir_node *irn)
Sebastian Hack's avatar
Sebastian Hack committed
104
{
105
106
107
108
109
110
111
112
	it->env         = ifg->env;
	it->irn         = irn;
	it->valid       = 1;
	ir_nodeset_init(&it->neighbours);

	dom_tree_walk(get_nodes_block(irn), find_neighbour_walker, NULL, it);

	ir_nodeset_iterator_init(&it->iter, &it->neighbours);
Sebastian Hack's avatar
Sebastian Hack committed
113
114
}

115
static inline void neighbours_break(neighbours_iter_t *it, int force)
Daniel Grund's avatar
Daniel Grund committed
116
{
117
118
119
120
	(void) force;
	assert(it->valid == 1);
	ir_nodeset_destroy(&it->neighbours);
	it->valid = 0;
Daniel Grund's avatar
Daniel Grund committed
121
122
}

123
static ir_node *get_next_neighbour(neighbours_iter_t *it)
Daniel Grund's avatar
Daniel Grund committed
124
{
125
126
127
128
129
130
	ir_node *res = ir_nodeset_iterator_next(&it->iter);

	if (res == NULL) {
		ir_nodeset_destroy(&it->neighbours);
	}
	return res;
Daniel Grund's avatar
Daniel Grund committed
131
132
}

133
134
ir_node *be_ifg_neighbours_begin(const be_ifg_t *ifg, neighbours_iter_t *iter,
                                 const ir_node *irn)
Daniel Grund's avatar
Daniel Grund committed
135
{
136
	find_neighbours(ifg, iter, irn);
Matthias Braun's avatar
Matthias Braun committed
137
	return get_next_neighbour(iter);
Daniel Grund's avatar
Daniel Grund committed
138
139
}

140
ir_node *be_ifg_neighbours_next(neighbours_iter_t *iter)
Sebastian Hack's avatar
Sebastian Hack committed
141
{
142
	return get_next_neighbour(iter);
143
144
}

145
void be_ifg_neighbours_break(neighbours_iter_t *iter)
Sebastian Hack's avatar
Sebastian Hack committed
146
{
147
	neighbours_break(iter, 1);
148
149
}

150
static inline void free_clique_iter(cliques_iter_t *it)
151
{
152
153
154
	it->n_blocks = -1;
	obstack_free(&it->ob, NULL);
	del_pset(it->living);
155
156
}

157
static void get_blocks_dom_order(ir_node *blk, void *env)
158
{
159
	cliques_iter_t *it = (cliques_iter_t*)env;
160
	obstack_ptr_grow(&it->ob, blk);
161
162
}

163
164
165
166
167
/**
 * NOTE: Be careful when changing this function!
 *       First understand the control flow of consecutive calls.
 */
static inline int get_next_clique(cliques_iter_t *it)
168
169
{

170
171
172
173
	/* continue in the block we left the last time */
	for (; it->blk < it->n_blocks; it->blk++) {
		int output_on_shrink = 0;
		struct list_head *head = get_block_border_head(it->cenv, it->blocks[it->blk]);
174

175
176
177
		/* on entry to a new block set the first border ... */
		if (!it->bor)
			it->bor = head->prev;
178

179
180
181
		/* ... otherwise continue with the border we left the last time */
		for (; it->bor != head; it->bor = it->bor->prev) {
			border_t *b = list_entry(it->bor, border_t, list);
182

183
184
185
186
187
188
			/* if its a definition irn starts living */
			if (b->is_def) {
				pset_insert_ptr(it->living, b->irn);
				if (b->is_real)
					output_on_shrink = 1;
			} else
189

190
191
192
193
194
			/* if its the last usage the irn dies */
			{
				/* before shrinking the set, return the current maximal clique */
				if (output_on_shrink) {
					int count = 0;
195

196
					/* fill the output buffer */
197
					foreach_pset(it->living, ir_node, irn) {
198
199
						it->buf[count++] = irn;
					}
200

201
					assert(count > 0 && "We have a 'last usage', so there must be sth. in it->living");
202

203
204
					return count;
				}
205

206
207
				pset_remove_ptr(it->living, b->irn);
			}
208
209
		}

210
211
		it->bor = NULL;
		assert(0 == pset_count(it->living) && "Something has survived! (At the end of the block it->living must be empty)");
212
213
	}

214
215
	if (it->n_blocks != -1)
		free_clique_iter(it);
216

217
	return -1;
218
219
}

220
221
int be_ifg_cliques_begin(const be_ifg_t *ifg, cliques_iter_t *it,
                         ir_node **buf)
222
{
223
	obstack_init(&it->ob);
224
	dom_tree_walk_irg(ifg->env->irg, get_blocks_dom_order, NULL, it);
225

226
227
228
	it->cenv     = ifg->env;
	it->buf      = buf;
	it->n_blocks = obstack_object_size(&it->ob) / sizeof(void *);
229
	it->blocks   = (ir_node**)obstack_finish(&it->ob);
230
231
232
	it->blk      = 0;
	it->bor      = NULL;
	it->living   = pset_new_ptr(2 * arch_register_class_n_regs(it->cenv->cls));
233

234
	return get_next_clique(it);
235
}
236

237
int be_ifg_cliques_next(cliques_iter_t *iter)
238
{
239
240
	return get_next_clique(iter);
}
241

242
243
244
245
void be_ifg_cliques_break(cliques_iter_t *iter)
{
	free_clique_iter(iter);
}
246

247
248
249
250
251
252
253
254
255
int be_ifg_degree(const be_ifg_t *ifg, const ir_node *irn)
{
	neighbours_iter_t it;
	int degree;
	find_neighbours(ifg, &it, irn);
	degree = ir_nodeset_size(&it.neighbours);
	neighbours_break(&it, 1);
	return degree;
}
256

257
258
259
260
be_ifg_t *be_create_ifg(const be_chordal_env_t *env)
{
	be_ifg_t *ifg = XMALLOC(be_ifg_t);
	ifg->env = env;
261

262
	return ifg;
263
264
}

265
266
267
268
269
270
271
272
273
274
275
276
277
static bool consider_component_node(bitset_t *const seen, ir_node *const irn)
{
	if (bitset_is_set(seen, get_irn_idx(irn)))
		return false;
	bitset_set(seen, get_irn_idx(irn));

	arch_register_req_t const *const req = arch_get_irn_register_req(irn);
	if (arch_register_req_is(req, ignore))
		return false;

	return true;
}

278
static void int_comp_rec(be_ifg_t *ifg, ir_node *n, bitset_t *seen)
279
{
280
	neighbours_iter_t neigh_it;
Sebastian Hack's avatar
Sebastian Hack committed
281

282
	be_ifg_foreach_neighbour(ifg, &neigh_it, n, m) {
283
284
		if (consider_component_node(seen, m))
			int_comp_rec(ifg, m, seen);
Sebastian Hack's avatar
Sebastian Hack committed
285
286
287
	}
}

288
void be_ifg_stat(ir_graph *irg, be_ifg_t *ifg, be_ifg_stat_t *stat)
Sebastian Hack's avatar
Sebastian Hack committed
289
{
290
291
292
293
	size_t          n_nodes = 0;
	size_t          n_edges = 0;
	size_t          n_comps = 0;
	bitset_t *const seen    = bitset_malloc(get_irg_last_idx(irg));
294
	be_ifg_foreach_node(ifg, n) {
295
		++n_nodes;
296
297

		neighbours_iter_t neigh_it;
298
		be_ifg_foreach_neighbour(ifg, &neigh_it, n, m) {
299
			++n_edges;
300
		}
301
302
303
304
305

		if (consider_component_node(seen, n)) {
			++n_comps;
			int_comp_rec(ifg, n, seen);
		}
306
	}
307
	free(seen);
308

309
	stat->n_nodes = n_nodes;
310
311
	/* Every interference edge was counted twice, once for each end. */
	stat->n_edges = n_edges / 2;
312
	stat->n_comps = n_comps;
313
}