bespillslots.c 21.1 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       Spillslot coalescer.
 * @author      Matthias Braun
 * @date        26.07.2006
 * @version     $Id$
Matthias Braun's avatar
Matthias Braun committed
26
 */
27
#include "config.h"
Matthias Braun's avatar
Matthias Braun committed
28
29
30
31

#include <stdlib.h>

#include "set.h"
Christian Würdig's avatar
Christian Würdig committed
32
#include "array.h"
Matthias Braun's avatar
Matthias Braun committed
33
34
35
36
37
38
39
#include "irgwalk.h"
#include "ircons.h"
#include "irprintf.h"
#include "execfreq.h"
#include "unionfind.h"
#include "irdump_t.h"

40
#include "benode.h"
Matthias Braun's avatar
Matthias Braun committed
41
#include "besched.h"
42
#include "bespill.h"
Matthias Braun's avatar
Matthias Braun committed
43
44
#include "bespillslots.h"
#include "bechordal_t.h"
Sebastian Hack's avatar
Sebastian Hack committed
45
#include "bestatevent.h"
Matthias Braun's avatar
Matthias Braun committed
46
#include "bemodule.h"
47
#include "beintlive_t.h"
48
49
#include "beirg.h"
#include "bearch.h"
Matthias Braun's avatar
Matthias Braun committed
50

51
52
#define DBG_COALESCING      1
#define DBG_INTERFERENCES   2
Matthias Braun's avatar
Matthias Braun committed
53

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

56
typedef struct spill_t {
57
58
59
60
	ir_node       *spill;
	const ir_mode *mode;      /**< mode of the spilled value */
	int            alignment; /**< alignment for the spilled value */
	int            spillslot; /**< index into spillslot_unionfind structure */
Matthias Braun's avatar
Matthias Braun committed
61
62
} spill_t;

63
typedef struct affinity_edge_t {
Matthias Braun's avatar
Matthias Braun committed
64
	double affinity;
65
66
	int    slot1;
	int    slot2;
Matthias Braun's avatar
Matthias Braun committed
67
68
} affinity_edge_t;

69
70
71
72
73
74
75
76
struct be_fec_env_t {
	struct obstack         obst;
	ir_graph              *irg;
	set                   *spills;
	ir_node              **reloads;
	affinity_edge_t      **affinity_edges;
	set                   *memperms;
	set_frame_entity_func  set_frame_entity;
77
};
Matthias Braun's avatar
Matthias Braun committed
78
79

/** Compare 2 affinity edges (used in quicksort) */
80
81
static int cmp_affinity(const void *d1, const void *d2)
{
82
83
	const affinity_edge_t * const *e1 = d1;
	const affinity_edge_t * const *e2 = d2;
Matthias Braun's avatar
Matthias Braun committed
84

85
	/* sort in descending order */
86
	return (*e1)->affinity < (*e2)->affinity ? 1 : -1;
Matthias Braun's avatar
Matthias Braun committed
87
88
}

89
90
static int cmp_spill(const void* d1, const void* d2, size_t size)
{
Matthias Braun's avatar
Matthias Braun committed
91
92
	const spill_t* s1 = d1;
	const spill_t* s2 = d2;
93
94
	(void) size;

Matthias Braun's avatar
Matthias Braun committed
95
96
97
	return s1->spill != s2->spill;
}

98
99
static spill_t *get_spill(be_fec_env_t *env, ir_node *node)
{
Matthias Braun's avatar
Matthias Braun committed
100
	spill_t spill, *res;
101
	int hash = hash_irn(node);
Matthias Braun's avatar
Matthias Braun committed
102
103
104
105
106
107
108
109

	spill.spill = node;
	res = set_find(env->spills, &spill, sizeof(spill), hash);

	return res;
}


110
static inline ir_node *get_memory_edge(const ir_node *node)
111
{
112
113
114
	int i, arity;

	arity = get_irn_arity(node);
115
	for (i = arity - 1; i >= 0; --i) {
116
		ir_node *arg = get_irn_n(node, i);
117
		if (get_irn_mode(arg) == mode_M)
118
119
120
121
122
123
			return arg;
	}

	return NULL;
}

124
125
126
static spill_t *collect_spill(be_fec_env_t *env, ir_node *node,
		                      const ir_mode *mode, int align)
{
Matthias Braun's avatar
Matthias Braun committed
127
	spill_t spill, *res;
128
	int     hash = hash_irn(node);
Matthias Braun's avatar
Matthias Braun committed
129

130
	/* insert into set of spills if not already there */
Matthias Braun's avatar
Matthias Braun committed
131
	spill.spill = node;
132
	res         = set_find(env->spills, &spill, sizeof(spill), hash);
Matthias Braun's avatar
Matthias Braun committed
133

134
	if (res == NULL) {
Matthias Braun's avatar
Matthias Braun committed
135
		spill.spillslot = set_count(env->spills);
136
		spill.mode      = mode;
137
		spill.alignment = align;
138
		res             = set_insert(env->spills, &spill, sizeof(spill), hash);
Matthias Braun's avatar
Matthias Braun committed
139
		DB((dbg, DBG_COALESCING, "Slot %d: %+F\n", spill.spillslot, node));
140
141
142
	} else {
		assert(res->mode == mode);
		assert(res->alignment == align);
Matthias Braun's avatar
Matthias Braun committed
143
144
145
146
147
	}

	return res;
}

148
149
150
static spill_t *collect_memphi(be_fec_env_t *env, ir_node *node,
                               const ir_mode *mode, int align)
{
Matthias Braun's avatar
Matthias Braun committed
151
152
	int i, arity;
	spill_t spill, *res;
153
	int hash = hash_irn(node);
154
	const ir_exec_freq *exec_freq = be_get_irg_exec_freq(env->irg);
Matthias Braun's avatar
Matthias Braun committed
155
156
157
158
159

	assert(is_Phi(node));

	spill.spill = node;
	res = set_find(env->spills, &spill, sizeof(spill), hash);
160
	if (res != NULL) {
161
162
		assert(res->mode == mode);
		assert(res->alignment == align);
Matthias Braun's avatar
Matthias Braun committed
163
164
165
166
		return res;
	}

	spill.spillslot = set_count(env->spills);
167
	spill.mode      = mode;
168
	spill.alignment = align;
Matthias Braun's avatar
Matthias Braun committed
169
	DB((dbg, DBG_COALESCING, "Slot %d: %+F\n", spill.spillslot, node));
170
	res             = set_insert(env->spills, &spill, sizeof(spill), hash);
Matthias Braun's avatar
Matthias Braun committed
171

172
	/* collect attached spills and mem-phis */
173
	arity = get_irn_arity(node);
174
	for (i = 0; i < arity; ++i) {
Matthias Braun's avatar
Matthias Braun committed
175
		affinity_edge_t *affinty_edge;
176
177
		ir_node *arg = get_irn_n(node, i);
		spill_t *arg_spill;
178

179
		if (is_Phi(arg)) {
180
			arg_spill = collect_memphi(env, arg, mode, align);
181
		} else {
182
			arg_spill = collect_spill(env, arg, mode, align);
Matthias Braun's avatar
Matthias Braun committed
183
184
		}

185
		/* add an affinity edge */
186
		affinty_edge           = OALLOC(&env->obst, affinity_edge_t);
187
		affinty_edge->affinity = get_block_execfreq(exec_freq, get_nodes_block(arg));
188
189
		affinty_edge->slot1    = res->spillslot;
		affinty_edge->slot2    = arg_spill->spillslot;
Matthias Braun's avatar
Matthias Braun committed
190
191
192
193
194
195
		ARR_APP1(affinity_edge_t*, env->affinity_edges, affinty_edge);
	}

	return res;
}

196
197
198
199
200
void be_node_needs_frame_entity(be_fec_env_t *env, ir_node *node,
                                const ir_mode *mode, int align)
{
	ir_node *spillnode = get_memory_edge(node);
	spill_t *spill;
Matthias Braun's avatar
Matthias Braun committed
201

202
	assert(spillnode != NULL);
Matthias Braun's avatar
Matthias Braun committed
203

204
	/* walk upwards and collect all phis and spills on this way */
205
206
207
208
	if (is_Phi(spillnode)) {
		spill = collect_memphi(env, spillnode, mode, align);
	} else {
		spill = collect_spill(env, spillnode, mode, align);
Matthias Braun's avatar
Matthias Braun committed
209
	}
210
211

	ARR_APP1(ir_node *, env->reloads, node);
Matthias Braun's avatar
Matthias Braun committed
212
213
}

214

Matthias Braun's avatar
Matthias Braun committed
215

216
217
static int merge_interferences(be_fec_env_t *env, bitset_t** interferences,
                               int* spillslot_unionfind, int s1, int s2)
Matthias Braun's avatar
Matthias Braun committed
218
219
220
221
222
{
	int res;
	int i;
	int spillcount;

223
	/* merge spillslots and interferences */
Matthias Braun's avatar
Matthias Braun committed
224
	res = uf_union(spillslot_unionfind, s1, s2);
225
	/* we assume that we always merge s2 to s1 so swap s1, s2 if necessary */
226
	if (res != s1) {
Matthias Braun's avatar
Matthias Braun committed
227
228
229
230
231
232
233
		int t = s1;
		s1 = s2;
		s2 = t;
	}

	bitset_or(interferences[s1], interferences[s2]);

234
	/* update other interferences */
Matthias Braun's avatar
Matthias Braun committed
235
	spillcount = set_count(env->spills);
236
	for (i = 0; i < spillcount; ++i) {
Matthias Braun's avatar
Matthias Braun committed
237
		bitset_t *intfs = interferences[i];
238
		if (bitset_is_set(intfs, s2))
Matthias Braun's avatar
Matthias Braun committed
239
240
241
242
243
244
			bitset_set(intfs, s1);
	}

	return res;
}

245
static int my_values_interfere2(ir_graph *irg, const ir_node *a,
246
247
                                const ir_node *b)
{
248
	be_lv_t *lv = be_get_irg_liveness(irg);
249
250
251
252
253

    int a2b = _value_dominates(a, b);
    int b2a = _value_dominates(b, a);

    /* If there is no dominance relation, they do not interfere. */
254
    if ((a2b | b2a) > 0) {
255
256
257
258
259
260
261
        const ir_edge_t *edge;
        ir_node *bb;

        /*
         * Adjust a and b so, that a dominates b if
         * a dominates b or vice versa.
         */
262
        if (b2a) {
263
264
265
266
267
268
269
270
271
272
273
            const ir_node *t = a;
            a = b;
            b = t;
        }

        bb = get_nodes_block(b);

        /*
         * If a is live end in b's block it is
         * live at b's definition (a dominates b)
         */
274
        if (be_is_live_end(lv, bb, a))
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
            return 1;

        /*
         * Look at all usages of a.
         * If there's one usage of a in the block of b, then
         * we check, if this use is dominated by b, if that's true
         * a and b interfere. Note that b must strictly dominate the user,
         * since if b is the last user of in the block, b and a do not
         * interfere.
         * Uses of a not in b's block can be disobeyed, because the
         * check for a being live at the end of b's block is already
         * performed.
         */
        foreach_out_edge(a, edge) {
            const ir_node *user = get_edge_src_irn(edge);
290
			if (is_Sync(user)) {
291
292
293
294
				const ir_edge_t *edge2;
				foreach_out_edge(user, edge2) {
					const ir_node *user2 = get_edge_src_irn(edge2);
					assert(!is_Sync(user2));
295
					if (get_nodes_block(user2) == bb && !is_Phi(user2) &&
296
297
298
299
					   _value_strictly_dominates(b, user2))
						return 1;
				}
			} else {
300
				if (get_nodes_block(user) == bb && !is_Phi(user) &&
301
302
303
304
305
306
307
308
309
310
311
312
						_value_strictly_dominates(b, user))
                return 1;
			}
        }
    }

	return 0;
}

/**
 * same as values_interfere but with special handling for Syncs
 */
313
static int my_values_interfere(ir_graph *irg, ir_node *a, ir_node *b)
314
{
315
	if (is_Sync(a)) {
316
		int i, arity = get_irn_arity(a);
317
		for (i = 0; i < arity; ++i) {
318
			ir_node *in = get_irn_n(a, i);
319
			if (my_values_interfere(irg, in, b))
320
321
322
				return 1;
		}
		return 0;
323
	} else if (is_Sync(b)) {
324
		int i, arity = get_irn_arity(b);
325
		for (i = 0; i < arity; ++i) {
326
327
			ir_node *in = get_irn_n(b, i);
			/* a is not a sync, so no need for my_values_interfere */
328
			if (my_values_interfere2(irg, a, in))
329
330
331
332
333
				return 1;
		}
		return 0;
	}

334
	return my_values_interfere2(irg, a, b);
335
336
}

Matthias Braun's avatar
Matthias Braun committed
337
338
339
340
341
342
/**
 * A greedy coalescing algorithm for spillslots:
 *  1. Sort the list of affinity edges
 *  2. Try to merge slots with affinity edges (most expensive slots first)
 *  3. Try to merge everything else that is possible
 */
343
static void do_greedy_coalescing(be_fec_env_t *env)
Matthias Braun's avatar
Matthias Braun committed
344
345
346
347
348
349
350
351
{
	int spillcount;
	spill_t **spilllist;
	spill_t *spill;
	int i, i2;
	int affinity_edge_count;
	bitset_t **interferences;
	int* spillslot_unionfind;
352
	struct obstack data;
Matthias Braun's avatar
Matthias Braun committed
353
354

	spillcount = set_count(env->spills);
355
	if (spillcount == 0)
Matthias Braun's avatar
Matthias Braun committed
356
357
		return;

358
359
	obstack_init(&data);

Matthias Braun's avatar
Matthias Braun committed
360
	DB((dbg, DBG_COALESCING, "Coalescing %d spillslots\n", spillcount));
Matthias Braun's avatar
Matthias Braun committed
361

362
363
364
	interferences       = OALLOCN(&data, bitset_t*, spillcount);
	spillslot_unionfind = OALLOCN(&data, int,       spillcount);
	spilllist           = OALLOCN(&data, spill_t*,  spillcount);
Matthias Braun's avatar
Matthias Braun committed
365

366
	uf_init(spillslot_unionfind, spillcount);
Matthias Braun's avatar
Matthias Braun committed
367
368
369
370
371

	DEBUG_ONLY(
		memset(spilllist, 0, spillcount * sizeof(spilllist[0]));
	);

372
	for (spill = set_first(env->spills), i = 0; spill != NULL;
373
	    spill = set_next(env->spills), ++i) {
Matthias Braun's avatar
Matthias Braun committed
374
375
376
377
		assert(spill->spillslot < spillcount);
		spilllist[spill->spillslot] = spill;
	}

378
	for (i = 0; i < spillcount; ++i) {
379
		interferences[i] = bitset_obstack_alloc(&data, spillcount);
Matthias Braun's avatar
Matthias Braun committed
380
381
	}

Christian Würdig's avatar
Christian Würdig committed
382
383
	/* construct interferences */
	for (i = 0; i < spillcount; ++i) {
384
		ir_node *spill1 = spilllist[i]->spill;
Christian Würdig's avatar
Christian Würdig committed
385
386

		if (is_NoMem(spill1))
387
388
			continue;

389
		for (i2 = i+1; i2 < spillcount; ++i2) {
390
			ir_node *spill2 = spilllist[i2]->spill;
Christian Würdig's avatar
Christian Würdig committed
391
392

			if (is_NoMem(spill2))
393
394
				continue;

395
			if (my_values_interfere(env->irg, spill1, spill2)) {
Matthias Braun's avatar
Matthias Braun committed
396
				DB((dbg, DBG_INTERFERENCES,
397
398
				     "Slot %d and %d interfere\n", i, i2));

Matthias Braun's avatar
Matthias Braun committed
399
400
401
402
403
404
				bitset_set(interferences[i], i2);
				bitset_set(interferences[i2], i);
			}
		}
	}

Christian Würdig's avatar
Christian Würdig committed
405
	/* sort affinity edges */
Matthias Braun's avatar
Matthias Braun committed
406
	affinity_edge_count = ARR_LEN(env->affinity_edges);
407
408
	qsort(env->affinity_edges, affinity_edge_count,
	      sizeof(env->affinity_edges[0]), cmp_affinity);
Matthias Braun's avatar
Matthias Braun committed
409

410
	/*dump_interference_graph(env, interferences, "before"); */
Matthias Braun's avatar
Matthias Braun committed
411

Christian Würdig's avatar
Christian Würdig committed
412
	/* try to merge affine nodes */
413
	for (i = 0; i < affinity_edge_count; ++i) {
Matthias Braun's avatar
Matthias Braun committed
414
415
416
417
418
		const affinity_edge_t *edge = env->affinity_edges[i];
		int s1 = uf_find(spillslot_unionfind, edge->slot1);
		int s2 = uf_find(spillslot_unionfind, edge->slot2);

		/* test if values interfere */
Christian Würdig's avatar
Christian Würdig committed
419
		if (bitset_is_set(interferences[s1], s2)) {
Matthias Braun's avatar
Matthias Braun committed
420
421
422
423
			assert(bitset_is_set(interferences[s2], s1));
			continue;
		}

Matthias Braun's avatar
Matthias Braun committed
424
		DB((dbg, DBG_COALESCING,
425
		     "Merging %d and %d because of affinity edge\n", s1, s2));
Matthias Braun's avatar
Matthias Braun committed
426
427
428
429

		merge_interferences(env, interferences, spillslot_unionfind, s1, s2);
	}

430
	/* try to merge as much remaining spillslots as possible */
431
	for (i = 0; i < spillcount; ++i) {
Matthias Braun's avatar
Matthias Braun committed
432
		int s1 = uf_find(spillslot_unionfind, i);
433
		if (s1 != i)
Matthias Braun's avatar
Matthias Braun committed
434
435
			continue;

436
		for (i2 = i+1; i2 < spillcount; ++i2) {
Matthias Braun's avatar
Matthias Braun committed
437
			int s2 = uf_find(spillslot_unionfind, i2);
438
			if (s2 != i2)
Matthias Braun's avatar
Matthias Braun committed
439
440
441
442
443
444
				continue;

			/* test if values interfere
			 * we have to test n1-n2 and n2-n1, because only 1 side gets updated
			 * when node merging occurs
			 */
445
			if (bitset_is_set(interferences[s1], s2)) {
Matthias Braun's avatar
Matthias Braun committed
446
447
448
449
				assert(bitset_is_set(interferences[s2], s1));
				continue;
			}

Matthias Braun's avatar
Matthias Braun committed
450
			DB((dbg, DBG_COALESCING,
451
			     "Merging %d and %d because it is possible\n", s1, s2));
Matthias Braun's avatar
Matthias Braun committed
452

453
			if (merge_interferences(env, interferences, spillslot_unionfind, s1, s2) != 0) {
454
455
				/* we can break the loop here, because s2 is the new supernode
				 * now and we'll test s2 again later anyway */
Matthias Braun's avatar
Matthias Braun committed
456
457
458
459
460
				break;
			}
		}
	}

461
	/* assign spillslots to spills */
462
	for (i = 0; i < spillcount; ++i) {
Matthias Braun's avatar
Matthias Braun committed
463
464
465
466
467
		spill_t *spill = spilllist[i];

		spill->spillslot = uf_find(spillslot_unionfind, i);
	}

468
	/*dump_interference_graph(env, interferences, "after");*/
469
	obstack_free(&data, 0);
Matthias Braun's avatar
Matthias Braun committed
470
471
}

472

Matthias Braun's avatar
Matthias Braun committed
473

474
typedef struct spill_slot_t {
Matthias Braun's avatar
Matthias Braun committed
475
476
	int size;
	int align;
477
	ir_entity *entity;
Matthias Braun's avatar
Matthias Braun committed
478
479
} spill_slot_t;

480
typedef struct memperm_entry_t {
Matthias Braun's avatar
Matthias Braun committed
481
482
	ir_node* node;
	int pos;
483
484
	ir_entity *in;
	ir_entity *out;
485
	struct memperm_entry_t *next;
Matthias Braun's avatar
Matthias Braun committed
486
487
} memperm_entry_t;

488
typedef struct memperm_t {
Matthias Braun's avatar
Matthias Braun committed
489
490
491
492
493
	ir_node *block;
	int entrycount;
	memperm_entry_t *entries;
} memperm_t;

494
495
static int cmp_memperm(const void* d1, const void* d2, size_t size)
{
Matthias Braun's avatar
Matthias Braun committed
496
497
	const memperm_t* e1 = d1;
	const memperm_t* e2 = d2;
498
499
	(void) size;

Matthias Braun's avatar
Matthias Braun committed
500
501
502
	return e1->block != e2->block;
}

503
504
static memperm_t *get_memperm(be_fec_env_t *env, ir_node *block)
{
Matthias Braun's avatar
Matthias Braun committed
505
506
507
508
	memperm_t entry, *res;
	int hash;

	entry.block = block;
509
	hash        = hash_irn(block);
Matthias Braun's avatar
Matthias Braun committed
510
511
512

	res = set_find(env->memperms, &entry, sizeof(entry), hash);

513
	if (res == NULL) {
Matthias Braun's avatar
Matthias Braun committed
514
515
516
517
518
519
520
521
		entry.entrycount = 0;
		entry.entries = NULL;
		res = set_insert(env->memperms, &entry, sizeof(entry), hash);
	}

	return res;
}

522
523
static ir_entity* create_stack_entity(be_fec_env_t *env, spill_slot_t *slot)
{
524
	ir_graph *irg  = env->irg;
525
	ir_type *frame = get_irg_frame_type(irg);
526
527
528
529
	/* TODO: backend should be able to specify wether we want spill slots
	 * at begin or end of frame */
	int        at_start = 1;
	ir_entity *res = frame_alloc_area(frame, slot->size, slot->align, at_start);
Matthias Braun's avatar
Matthias Braun committed
530

Christian Würdig's avatar
Christian Würdig committed
531
	/* adjust size of the entity type... */
532
533
534
	ir_type *enttype = get_entity_type(res);
	set_type_size_bytes(enttype, slot->size);

Matthias Braun's avatar
Matthias Braun committed
535
536
537
538
539
540
541
542
543
	slot->entity = res;

	return res;
}

/**
 * Enlarges a spillslot (if necessary) so that it can carry a value of size
 * @p othersize and alignment @p otheralign.
 */
544
545
static void enlarge_spillslot(spill_slot_t *slot, int otheralign, int othersize)
{
546
	if (othersize > slot->size) {
Matthias Braun's avatar
Matthias Braun committed
547
548
		slot->size = othersize;
	}
549
550
	if (otheralign > slot->align) {
		if (otheralign % slot->align != 0)
Matthias Braun's avatar
Matthias Braun committed
551
552
553
			slot->align *= otheralign;
		else
			slot->align = otheralign;
554
	} else if (slot->align % otheralign != 0) {
Matthias Braun's avatar
Matthias Braun committed
555
556
557
558
		slot->align *= otheralign;
	}
}

559
560
static void assign_spill_entity(be_fec_env_t *env,
                                ir_node *node, ir_entity *entity)
561
{
562
	if (is_NoMem(node))
563
		return;
564
	if (is_Sync(node)) {
565
566
567
		int i, arity;

		arity = get_irn_arity(node);
568
		for (i = 0; i < arity; ++i) {
569
570
571
			ir_node *in = get_irn_n(node, i);
			assert(!is_Phi(in));

572
			assign_spill_entity(env, in, entity);
573
574
575
576
		}
		return;
	}

577
578
	/* beware: we might have Stores with Memory Proj's, ia32 fisttp for
	   instance */
579
	node = skip_Proj(node);
580
	assert(arch_get_frame_entity(node) == NULL);
581
	env->set_frame_entity(node, entity);
582
583
}

Matthias Braun's avatar
Matthias Braun committed
584
585
586
587
/**
 * Create stack entities for the spillslots and assign them to the spill and
 * reload nodes.
 */
588
589
static void assign_spillslots(be_fec_env_t *env)
{
590
591
592
593
	int           spillcount = set_count(env->spills);
	spill_slot_t *spillslots = ALLOCANZ(spill_slot_t, spillcount);
	spill_t      *spill;
	int           i;
Matthias Braun's avatar
Matthias Braun committed
594

595
	/* construct spillslots */
596
	for (spill = set_first(env->spills); spill != NULL;
597
598
		spill = set_next(env->spills)) {

Matthias Braun's avatar
Matthias Braun committed
599
		int slotid = spill->spillslot;
600
		const ir_mode *mode = spill->mode;
Matthias Braun's avatar
Matthias Braun committed
601
		spill_slot_t *slot = & (spillslots[slotid]);
602
603
		int size = get_mode_size_bytes(mode);
		int align = spill->alignment;
Matthias Braun's avatar
Matthias Braun committed
604

605
		if (slot->align == 0 && slot->size == 0) {
Matthias Braun's avatar
Matthias Braun committed
606
607
608
609
610
611
612
			slot->align = align;
			slot->size = size;
		} else {
			enlarge_spillslot(slot, align, size);
		}
	}

613
	for (spill = set_first(env->spills); spill != NULL;
614
615
616
617
	    spill = set_next(env->spills)) {

		ir_node      *node   = spill->spill;
		int           slotid = spill->spillslot;
Matthias Braun's avatar
Matthias Braun committed
618
619
620
		spill_slot_t *slot;

		slot = &spillslots[slotid];
621
		if (slot->entity == NULL) {
Matthias Braun's avatar
Matthias Braun committed
622
623
624
			create_stack_entity(env, slot);
		}

625
		if (is_Phi(node)) {
Matthias Braun's avatar
Matthias Braun committed
626
			int i, arity;
627
			ir_node *block = get_nodes_block(node);
Matthias Braun's avatar
Matthias Braun committed
628

629
			/* should be a PhiM */
Matthias Braun's avatar
Matthias Braun committed
630
631
			assert(is_Phi(node));

632
			for (i = 0, arity = get_irn_arity(node); i < arity; ++i) {
Matthias Braun's avatar
Matthias Braun committed
633
				ir_node *arg = get_irn_n(node, i);
634
				ir_node *predblock = get_Block_cfgpred_block(block, i);
Matthias Braun's avatar
Matthias Braun committed
635
636
637
638
639
640
641
				spill_t *argspill;
				int argslotid;

				argspill = get_spill(env, arg);
				assert(argspill != NULL);

				argslotid = argspill->spillslot;
642
				if (slotid != argslotid) {
Matthias Braun's avatar
Matthias Braun committed
643
644
645
					memperm_t *memperm;
					memperm_entry_t *entry;
					spill_slot_t *argslot = &spillslots[argslotid];
646
					if (argslot->entity == NULL) {
Matthias Braun's avatar
Matthias Braun committed
647
648
649
						create_stack_entity(env, argslot);
					}

650
					memperm = get_memperm(env, predblock);
Matthias Braun's avatar
Matthias Braun committed
651

652
					entry = OALLOC(&env->obst, memperm_entry_t);
Matthias Braun's avatar
Matthias Braun committed
653
654
655
656
657
658
659
660
661
					entry->node = node;
					entry->pos = i;
					entry->in = argslot->entity;
					entry->out = slot->entity;
					entry->next = memperm->entries;
					memperm->entrycount++;
					memperm->entries = entry;
				}
			}
662
		} else {
663
			assign_spill_entity(env, node, slot->entity);
Matthias Braun's avatar
Matthias Braun committed
664
665
666
		}
	}

667
	for (i = 0; i < ARR_LEN(env->reloads); ++i) {
668
		ir_node            *reload    = env->reloads[i];
669
		ir_node            *spillnode = get_memory_edge(reload);
670
671
		spill_t            *spill     = get_spill(env, spillnode);
		const spill_slot_t *slot      = & spillslots[spill->spillslot];
Matthias Braun's avatar
Matthias Braun committed
672
673
674

		assert(slot->entity != NULL);

675
		env->set_frame_entity(reload, slot->entity);
Matthias Braun's avatar
Matthias Braun committed
676
677
678
	}
}

679
680
681
682
683
684
/**
 * Returns the last node in a block which is no control flow changing node
 */
static ir_node *get_end_of_block_insertion_point(ir_node* block)
{
	ir_node* ins = sched_last(block);
685
	while (is_Proj(ins) && get_irn_mode(ins) == mode_X) {
686
687
688
689
		ins = sched_prev(ins);
		assert(ins != NULL);
	}

690
691
	if (is_cfop(ins)) {
		for (;;) {
692
			ir_node *prev = sched_prev(ins);
693
			if (!is_cfop(prev))
694
695
696
697
698
699
700
701
				break;
			ins = prev;
		}
	}

	return ins;
}

702
703
static void create_memperms(be_fec_env_t *env)
{
704
	memperm_t *memperm;
Matthias Braun's avatar
Matthias Braun committed
705

706
	for (memperm = set_first(env->memperms); memperm != NULL; memperm = set_next(env->memperms)) {
707
708
709
710
711
		ir_node         **nodes = ALLOCAN(ir_node*, memperm->entrycount);
		memperm_entry_t  *entry;
		ir_node          *blockend;
		ir_node          *mempermnode;
		int               i;
Matthias Braun's avatar
Matthias Braun committed
712
713
714

		assert(memperm->entrycount > 0);

715
		for (entry = memperm->entries, i = 0; entry != NULL; entry = entry->next, ++i) {
Matthias Braun's avatar
Matthias Braun committed
716
717
718
719
			ir_node* arg = get_irn_n(entry->node, entry->pos);
			nodes[i] = arg;
		}

720
721
		mempermnode = be_new_MemPerm(memperm->block, memperm->entrycount,
		                             nodes);
Matthias Braun's avatar
Matthias Braun committed
722

723
		/* insert node into schedule */
724
		blockend = get_end_of_block_insertion_point(memperm->block);
725
		sched_add_before(blockend, mempermnode);
Sebastian Hack's avatar
Sebastian Hack committed
726
		stat_ev_dbl("mem_perm", memperm->entrycount);
727

728
		i = 0;
729
		for (entry = memperm->entries; entry != NULL; entry = entry->next, ++i) {
Matthias Braun's avatar
Matthias Braun committed
730
731
732
733
734
			ir_node *proj;
			ir_node* arg = get_irn_n(entry->node, entry->pos);

			be_set_MemPerm_in_entity(mempermnode, i, entry->in);
			be_set_MemPerm_out_entity(mempermnode, i, entry->out);
735
			proj = new_r_Proj(mempermnode, get_irn_mode(arg), i);
736

737
			set_irn_n(entry->node, entry->pos, proj);
Matthias Braun's avatar
Matthias Braun committed
738
739
740
741
		}
	}
}

742
743
static int count_spillslots(const be_fec_env_t *env)
{
744
745
746
747
748
749
	const spill_t *spill;
	int spillcount = set_count(env->spills);
	bitset_t *counted = bitset_alloca(spillcount);
	int slotcount;

	slotcount = 0;
750
	for (spill = set_first(env->spills); spill != NULL;
751
752
	    spill = set_next(env->spills)) {
		int spillslot = spill->spillslot;
753
		if (!bitset_is_set(counted, spillslot)) {
754
755
756
757
758
759
760
761
			slotcount++;
			bitset_set(counted, spillslot);
		}
	}

	return slotcount;
}

762
be_fec_env_t *be_new_frame_entity_coalescer(ir_graph *irg)
763
{
764
	be_fec_env_t *env = XMALLOCZ(be_fec_env_t);
Matthias Braun's avatar
Matthias Braun committed
765

766
	be_liveness_assure_chk(be_assure_liveness(irg));
767
768

	obstack_init(&env->obst);
769
	env->irg            = irg;
Christian Würdig's avatar
Christian Würdig committed
770
771
	env->spills         = new_set(cmp_spill, 10);
	env->reloads        = NEW_ARR_F(ir_node*, 0);
772
	env->affinity_edges = NEW_ARR_F(affinity_edge_t*, 0);
Christian Würdig's avatar
Christian Würdig committed
773
	env->memperms       = new_set(cmp_memperm, 10);
Matthias Braun's avatar
Matthias Braun committed
774

775
776
777
778
779
780
781
782
783
784
785
786
787
	return env;
}

void be_free_frame_entity_coalescer(be_fec_env_t *env)
{
	del_set(env->memperms);
	DEL_ARR_F(env->reloads);
	DEL_ARR_F(env->affinity_edges);
	del_set(env->spills);
	obstack_free(&env->obst, NULL);

	free(env);
}
Matthias Braun's avatar
Matthias Braun committed
788

789
790
void be_assign_entities(be_fec_env_t *env,
                        set_frame_entity_func set_frame_entity)
791
{
792
793
	env->set_frame_entity = set_frame_entity;

Sebastian Hack's avatar
Sebastian Hack committed
794
	stat_ev_dbl("spillslots", set_count(env->spills));
795

796
	if (be_coalesce_spill_slots) {
797
798
799
		do_greedy_coalescing(env);
	}

Sebastian Hack's avatar
Sebastian Hack committed
800
	stat_ev_dbl("spillslots_after_coalescing", count_spillslots(env));
Matthias Braun's avatar
Matthias Braun committed
801

802
803
804
805
806
807
808
809
810
811
812
	assign_spillslots(env);

	create_memperms(env);
}

/**
 * This walker function searches for reloads and collects all the spills
 * and memphis attached to them.
 */
static void collect_spills_walker(ir_node *node, void *data)
{
813
814
	be_fec_env_t                *env = data;
	const ir_mode               *mode;
815
	const arch_register_class_t *cls;
816
817
818
	int                          align;
	ir_graph                    *irg;
	const arch_env_t            *arch_env;
819

820
	if (! (arch_irn_classify(node) & arch_irn_class_reload))
821
822
		return;

823
824
825
826
827
	mode     = get_irn_mode(node);
	cls      = arch_get_irn_reg_class_out(node);
	irg      = get_irn_irg(node);
	arch_env = be_get_irg_arch_env(irg);
	align    = arch_env_get_reg_class_alignment(arch_env, cls);
828
829
830
831

	be_node_needs_frame_entity(env, node, mode, align);
}

832
void be_coalesce_spillslots(ir_graph *irg)
833
{
834
	be_fec_env_t *env = be_new_frame_entity_coalescer(irg);
Matthias Braun's avatar
Matthias Braun committed
835

836
	/* collect reloads */
837
	irg_walk_graph(irg, NULL, collect_spills_walker, env);
Matthias Braun's avatar
Matthias Braun committed
838

839
	be_assign_entities(env, be_node_set_frame_entity);
Matthias Braun's avatar
Matthias Braun committed
840

841
	be_free_frame_entity_coalescer(env);
Matthias Braun's avatar
Matthias Braun committed
842
}
Matthias Braun's avatar
Matthias Braun committed
843

844
BE_REGISTER_MODULE_CONSTRUCTOR(be_init_spillslots);
Matthias Braun's avatar
Matthias Braun committed
845
846
847
848
void be_init_spillslots(void)
{
	FIRM_DBG_REGISTER(dbg, "firm.be.spillslots");
}