bessadestr.c 11.9 KB
Newer Older
1
2
3
4
5
6
7
8
/**
 * Author:      Daniel Grund
 * Date:		25.05.2005
 * Copyright:   (c) Universitaet Karlsruhe
 * Licence:     This file protected by GPL -  GNU GENERAL PUBLIC LICENSE.
 *
 * Performs SSA-Destruction.
 */
Michael Beck's avatar
Michael Beck committed
9
10
11
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
12
13
14
15

#include "debug.h"
#include "set.h"
#include "pmap.h"
Sebastian Hack's avatar
Sebastian Hack committed
16
17
#include "irnode_t.h"
#include "ircons_t.h"
18
#include "iredges_t.h"
Michael Beck's avatar
Michael Beck committed
19
#include "irgwalk.h"
Sebastian Hack's avatar
Sebastian Hack committed
20
#include "irgmod.h"
Sebastian Hack's avatar
Sebastian Hack committed
21
#include "irdump.h"
Sebastian Hack's avatar
Sebastian Hack committed
22
23
#include "irprintf.h"

24
#include "be_t.h"
Sebastian Hack's avatar
Sebastian Hack committed
25
#include "beutil.h"
26
27
#include "bechordal_t.h"
#include "bearch.h"
Daniel Grund's avatar
Bugfix    
Daniel Grund committed
28
#include "belive_t.h"
29
30
#include "benode_t.h"
#include "besched_t.h"
31

32
DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
33

Sebastian Hack's avatar
Sebastian Hack committed
34
#define get_chordal_arch(ce) ((ce)->birg->main_env->arch_env)
Sebastian Hack's avatar
Sebastian Hack committed
35
36
#define get_reg(irn) arch_get_irn_register(get_chordal_arch(chordal_env), irn)
#define set_reg(irn, reg) arch_set_irn_register(get_chordal_arch(chordal_env), irn, reg)
37

38
#define is_Perm(irn)            (arch_irn_classify(arch_env, irn) == arch_irn_class_perm)
Sebastian Hack's avatar
Sebastian Hack committed
39
#define get_reg_cls(irn)        (arch_get_irn_reg_class(arch_env, irn, -1))
40
41
#define is_curr_reg_class(irn)  (get_reg_cls(p) == chordal_env->cls)

42
43
static void clear_link(ir_node *irn, void *data) {
	set_irn_link(irn, NULL);
Sebastian Hack's avatar
Sebastian Hack committed
44
}
45

Sebastian Hack's avatar
Sebastian Hack committed
46
/**
47
48
49
50
 * For each block build a linked list of phis that
 *  - are in that block
 *  - have the current register class
 * The list is rooted at get_irn_link(BB).
Sebastian Hack's avatar
Sebastian Hack committed
51
 */
52
53
54
55
56
57
58
static void collect_phis_walker(ir_node *irn, void *data) {
	be_chordal_env_t *env = data;
	if(is_Phi(irn) && chordal_has_class(env, irn)) {
		ir_node *bl = get_nodes_block(irn);
		set_irn_link(irn, get_irn_link(bl));
		set_irn_link(bl, irn);
	}
Sebastian Hack's avatar
Sebastian Hack committed
59
}
60

61
62
63
64
65
66
67
68
69
70
71
72
73
/**
 * This struct represents a Proj for a Perm.
 * It records the argument in the Perm and the corresponding Proj of the
 * Perm.
 */
typedef struct {
	ir_node *arg;  /**< The phi argument to make the Proj for. */
	int pos;       /**< The proj number the Proj will get.
									 This also denotes the position of @p arg
									 in the in array of the Perm. */
	ir_node *proj; /**< The proj created for @p arg. */
} perm_proj_t;

74
static int cmp_perm_proj(const void *a, const void *b, size_t n) {
75
76
77
78
79
	const perm_proj_t *p = a;
	const perm_proj_t *q = b;
	return !(p->arg == q->arg);
}

80
81
82
83
84
85
86
87
/**
 * Insert Perms in all predecessors of a block containing a phi
 */
static void insert_all_perms_walker(ir_node *bl, void *data) {
	be_chordal_env_t *chordal_env = data;
	pmap *perm_map = chordal_env->data;
	ir_graph *irg = chordal_env->irg;
	int i, n;
88

89
	assert(is_Block(bl));
90

91
92
93
	/* If the link flag is NULL, this block has no phis. */
	if(!get_irn_link(bl))
		return;
94

95
96
97
98
99
100
101
	/* Look at all predecessors of the phi block */
	for(i = 0, n = get_irn_arity(bl); i < n; ++i) {
		ir_node *phi, *perm, *insert_after, **in;
		perm_proj_t *pp;
		set *arg_set     = new_set(cmp_perm_proj, chordal_env->cls->n_regs);
		ir_node *pred_bl = get_Block_cfgpred_block(bl, i);
		int n_projs      = 0;
102

103
		assert(!pmap_contains(perm_map, pred_bl) && "Already permed that block");
104

105
106
107
108
109
110
111
112
		/*
		 * Note that all phis in the list are in the same
		 * register class by construction.
		 */
		for(phi = get_irn_link(bl); phi; phi = get_irn_link(phi)) {
			perm_proj_t templ;
			ir_node *arg     = get_irn_n(phi, i);
			unsigned hash    = HASH_PTR(arg);
113

114
115
			templ.arg  = arg;
			pp         = set_find(arg_set, &templ, sizeof(templ), hash);
116
117

			/*
118
119
120
121
122
			 * If a proj_perm_t entry has not been made in the argument set,
			 * create one. The only restriction is, that the phi argument
			 * may not be live in at the current block, since this argument
			 * interferes with the phi and must thus not be member of a
			 * Perm. A copy will be inserted for this argument alter on.
123
			 */
Sebastian Hack's avatar
Sebastian Hack committed
124
			if(!pp && !be_is_live_in(chordal_env->lv, bl, arg)) {
125
126
				templ.pos = n_projs++;
				set_insert(arg_set, &templ, sizeof(templ), hash);
127
			}
128
129
		}

130

131
		if (n_projs) {
132
			/*
133
134
			 * Create a new Perm with the arguments just collected
			 * above in the arg_set and insert it into the schedule.
135
			 */
Michael Beck's avatar
Michael Beck committed
136
			in = xmalloc(n_projs * sizeof(in[0]));
137
138
139
			for(pp = set_first(arg_set); pp; pp = set_next(arg_set))
				in[pp->pos] = pp->arg;

Sebastian Hack's avatar
Sebastian Hack committed
140
			perm = be_new_Perm(chordal_env->cls, irg, pred_bl, n_projs, in);
141
			free(in);
Sebastian Hack's avatar
Sebastian Hack committed
142
			insert_after = sched_skip(sched_last(pred_bl), 0, sched_skip_cf_predicator, chordal_env->birg->main_env->arch_env);
143
144
145
			sched_add_after(insert_after, perm);

			/*
146
147
148
			 * Make the Projs for the Perm and insert into schedule.
			 * Register allocation is copied from the former phi
			 * arguments to the projs (new phi arguments).
149
			 */
150
			insert_after = perm;
151
			for(pp = set_first(arg_set); pp; pp = set_next(arg_set)) {
152
153
154
155
156
157
158
				ir_node *proj = new_r_Proj(irg, pred_bl, perm, get_irn_mode(pp->arg), pp->pos);
				pp->proj = proj;
				assert(get_reg(pp->arg));
				set_reg(proj, get_reg(pp->arg));
				sched_add_after(insert_after, proj);
				insert_after = proj;
				DBG((dbg, LEVEL_2, "Copy register assignment %s from %+F to %+F\n", get_reg(pp->arg)->name, pp->arg, pp->proj));
159
160
161
162
163
164
165
166
167
168
169
			}

			/*
			 * Set the phi nodes to their new arguments: The Projs of the Perm
			 */
			for(phi = get_irn_link(bl); phi; phi = get_irn_link(phi)) {
				perm_proj_t templ;

				templ.arg = get_irn_n(phi, i);
				pp        = set_find(arg_set, &templ, sizeof(templ), HASH_PTR(templ.arg));

170
171
172
				/* If not found, it was an interfering argument */
				if (pp)
					set_irn_n(phi, i, pp->proj);
173
174
175
176
			}

			/* register in perm map */
			pmap_insert(perm_map, pred_bl, perm);
177
		}
178

179
180
		del_set(arg_set);
	}
181
182
}

Daniel Grund's avatar
Daniel Grund committed
183
184
185
#define is_pinned(irn) (get_irn_link(irn))
#define get_pinning_block(irn) ((ir_node *)get_irn_link(irn))
#define pin_irn(irn, lock) (set_irn_link(irn, lock))
186

187
/**
188
189
 * Adjusts the register allocation for the (new) phi-operands
 * and insert duplicates iff necessary.
190
 */
191
192
193
194
195
static void	set_regs_or_place_dupls_walker(ir_node *bl, void *data) {
	be_chordal_env_t *chordal_env = data;
	ir_node *phi;

	/* Consider all phis of this block */
196
	for (phi = get_irn_link(bl); phi; phi = get_irn_link(phi)) {
197
198
199
200
201
202
		int i, max;
		ir_node *arg, *phi_block, *arg_block;
		const arch_register_t *phi_reg, *arg_reg;
		const arch_register_class_t *cls;

		assert(is_Phi(phi) && "Can only handle phi-destruction :)");
203

204
		phi_block = get_nodes_block(phi);
205
206
		phi_reg   = get_reg(phi);
		cls       = arch_get_irn_reg_class(get_chordal_arch(chordal_env), phi, -1);
207
208

		/* process all arguments of the phi */
209
210
		for (i = 0, max = get_irn_arity(phi); i < max; ++i) {
			arg       = get_irn_n(phi, i);
211
			arg_block = get_Block_cfgpred_block(phi_block, i);
212
213
			arg_reg   = get_reg(arg);

214
215
216
217
			assert(arg_reg && "Register must be set while placing perms");

			DBG((dbg, LEVEL_1, "  for %+F(%s) -- %+F(%s)\n", phi, phi_reg->name, arg, arg_reg->name));

Sebastian Hack's avatar
Sebastian Hack committed
218
			if(values_interfere(chordal_env->lv, phi, arg)) {
219
220
221
222
223
224
225
				/*
					Insert a duplicate in arguments block,
					make it the new phi arg,
					set its register,
					insert it into schedule,
					pin it
				*/
Christian Würdig's avatar
Christian Würdig committed
226
				ir_node *dupl  = be_new_Copy(cls, chordal_env->irg, arg_block, arg);
Christian Würdig's avatar
Christian Würdig committed
227
228
229

				/* this is commented out because it will fail in case of unknown float */
#if 0
Christian Würdig's avatar
Christian Würdig committed
230
231
				ir_mode *m_phi = get_irn_mode(phi), *m_dupl = get_irn_mode(dupl);

232
233
234
235
				/*
					Conv signed <-> unsigned is killed on ia32
					check for: (both int OR both float) AND equal mode sizes
				*/
Christian Würdig's avatar
Christian Würdig committed
236
237
238
				assert(((mode_is_int(m_phi) && mode_is_int(m_dupl)) ||
					(mode_is_float(m_phi) && mode_is_float(m_dupl))) &&
					(get_mode_size_bits(m_phi) == get_mode_size_bits(m_dupl)));
Christian Würdig's avatar
Christian Würdig committed
239
#endif /* if 0 */
Christian Würdig's avatar
Christian Würdig committed
240

241
242
				set_irn_n(phi, i, dupl);
				set_reg(dupl, phi_reg);
Sebastian Hack's avatar
Sebastian Hack committed
243
				sched_add_after(sched_skip(sched_last(arg_block), 0, sched_skip_cf_predicator, chordal_env->birg->main_env->arch_env), dupl);
244
				pin_irn(dupl, phi_block);
245
				DBG((dbg, LEVEL_1, "    they do interfere: insert %+F(%s)\n", dupl, get_reg(dupl)->name));
Daniel Grund's avatar
Daniel Grund committed
246
247
248
249
				continue; /* with next argument */
			}

			if (phi_reg == arg_reg) {
250
				/* Phi and arg have the same register, so pin and continue */
Daniel Grund's avatar
Daniel Grund committed
251
252
253
254
				pin_irn(arg, phi_block);
				DBG((dbg, LEVEL_1, "      arg has same reg: pin %+F(%s)\n", arg, get_reg(arg)->name));
				continue;
			}
255

Daniel Grund's avatar
Daniel Grund committed
256
257
258
			DBG((dbg, LEVEL_1, "    they do not interfere\n"));
			assert(is_Proj(arg));
			/*
259
260
261
262
263
264
265
266
				First check if there is an other phi
				- in the same block
				- having arg at the current pos in its arg-list
				- having the same color as arg

				If found, then pin the arg (for that phi)
			*/
			if (! is_pinned(arg)) {
Daniel Grund's avatar
Daniel Grund committed
267
				ir_node *other_phi;
268

Daniel Grund's avatar
Daniel Grund committed
269
				DBG((dbg, LEVEL_1, "      searching for phi with same arg having args register\n"));
270

Daniel Grund's avatar
Daniel Grund committed
271
				for(other_phi = get_irn_link(phi_block); other_phi; other_phi = get_irn_link(other_phi)) {
272
273
274
275
276

					assert(is_Phi(other_phi)                               &&
						get_nodes_block(phi) == get_nodes_block(other_phi) &&
						"link fields are screwed up");

Daniel Grund's avatar
Daniel Grund committed
277
278
					if (get_irn_n(other_phi, i) == arg && get_reg(other_phi) == arg_reg) {
						DBG((dbg, LEVEL_1, "        found %+F(%s)\n", other_phi, get_reg(other_phi)->name));
Christian Würdig's avatar
Christian Würdig committed
279
						pin_irn(arg, phi_block);
Daniel Grund's avatar
Daniel Grund committed
280
						break;
Christian Würdig's avatar
Christian Würdig committed
281
					}
282
				}
283
			}
Daniel Grund's avatar
Daniel Grund committed
284
285

			if (is_pinned(arg)) {
286
287
288
289
290
291
292
293
				/*
					Insert a duplicate of the original value in arguments block,
					make it the new phi arg,
					set its register,
					insert it into schedule,
					pin it
				*/
				ir_node *perm     = get_Proj_pred(arg);
Matthias Braun's avatar
Matthias Braun committed
294
295
				ir_node *dupl     = be_new_Copy(cls, chordal_env->irg, arg_block, arg);
				ir_node *ins;
Christian Würdig's avatar
Christian Würdig committed
296
297
298

				/* this is commented out because it will fail in case of unknown float */
#if 0
299
300
301
302
303
304
305
306
307
308
				ir_mode *m_phi    = get_irn_mode(phi);
				ir_mode *m_dupl   = get_irn_mode(dupl);

				/*
					Conv signed <-> unsigned is killed on ia32
					check for: (both int OR both float) AND equal mode sizes
				*/
				assert(((mode_is_int(m_phi) && mode_is_int(m_dupl)) ||
					(mode_is_float(m_phi) && mode_is_float(m_dupl))) &&
					(get_mode_size_bits(m_phi) == get_mode_size_bits(m_dupl)));
Christian Würdig's avatar
Christian Würdig committed
309
#endif /* if 0 */
310

Daniel Grund's avatar
Daniel Grund committed
311
312
				set_irn_n(phi, i, dupl);
				set_reg(dupl, phi_reg);
Matthias Braun's avatar
Matthias Braun committed
313
314
315
				/* skip the Perm's Projs and insert the copies behind. */
				for(ins = sched_next(perm); is_Proj(ins); ins = sched_next(ins));
				sched_add_before(ins, dupl);
Daniel Grund's avatar
Daniel Grund committed
316
317
318
				pin_irn(dupl, phi_block);
				DBG((dbg, LEVEL_1, "      arg is pinned: insert %+F(%s)\n", dupl, get_reg(dupl)->name));
			} else {
319
320
321
322
				/*
					No other phi has the same color (else arg would have been pinned),
					so just set the register and pin
				*/
Daniel Grund's avatar
Daniel Grund committed
323
324
325
326
				set_reg(arg, phi_reg);
				pin_irn(arg, phi_block);
				DBG((dbg, LEVEL_1, "      arg is not pinned: so pin %+F(%s)\n", arg, get_reg(arg)->name));
			}
327
328
329
330
		}
	}
}

Sebastian Hack's avatar
Sebastian Hack committed
331
332
void be_ssa_destruction(be_chordal_env_t *chordal_env) {
	pmap *perm_map = pmap_create();
333
	ir_graph *irg  = chordal_env->irg;
334

335
	FIRM_DBG_REGISTER(dbg, "ir.be.ssadestr");
336
337

	/* create a map for fast lookup of perms: block --> perm */
Sebastian Hack's avatar
Sebastian Hack committed
338
	chordal_env->data = perm_map;
339
	irg_walk_graph(irg, clear_link, collect_phis_walker, chordal_env);
340

341
342
	DBG((dbg, LEVEL_1, "Placing perms...\n"));
	irg_block_walk_graph(irg, insert_all_perms_walker, NULL, chordal_env);
343
344
345

	if (chordal_env->opts->dump_flags & BE_CH_DUMP_SSADESTR)
		be_dump(irg, "-ssa_destr_perms_placed", dump_ir_block_graph_sched);
346

Sebastian Hack's avatar
Sebastian Hack committed
347
	be_liveness_recompute(chordal_env->lv);
348

349
350
	DBG((dbg, LEVEL_1, "Setting regs and placing dupls...\n"));
	irg_block_walk_graph(irg, set_regs_or_place_dupls_walker, NULL, chordal_env);
351
352
353

	if (chordal_env->opts->dump_flags & BE_CH_DUMP_SSADESTR)
		be_dump(irg, "-ssa_destr_regs_set", dump_ir_block_graph_sched);
354

Sebastian Hack's avatar
Sebastian Hack committed
355
	pmap_destroy(perm_map);
356
357
}

358
static void ssa_destruction_check_walker(ir_node *bl, void *data) {
359
360
	be_chordal_env_t *chordal_env = data;
	ir_node *phi;
361
362
	int i, max;

363
	for (phi = get_irn_link(bl); phi; phi = get_irn_link(phi)) {
364
365
366
367
		const arch_register_t *phi_reg, *arg_reg;

		phi_reg = get_reg(phi);
		/* iterate over all args of phi */
368
		for (i = 0, max = get_irn_arity(phi); i < max; ++i) {
369
			ir_node *arg = get_irn_n(phi, i);
370

371
			arg_reg = get_reg(arg);
372
373

			if (phi_reg != arg_reg) {
374
375
376
				DBG((dbg, 0, "Error: Registers of %+F and %+F differ: %s %s\n", phi, arg, phi_reg->name, arg_reg->name));
				assert(0);
			}
377
378

			if (! is_pinned(arg)) {
379
380
381
382
383
				DBG((dbg, 0, "Warning: Phi argument %+F is not pinned.\n", arg));
				assert(0);
			}
		}
	}
Sebastian Hack's avatar
Sebastian Hack committed
384
385
386
}

void be_ssa_destruction_check(be_chordal_env_t *chordal_env) {
Sebastian Hack's avatar
Sebastian Hack committed
387
	irg_block_walk_graph(chordal_env->irg, ssa_destruction_check_walker, NULL, chordal_env);
388
}