bessaconstr.c 11.4 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.
 */

20
21
/**
 * @file
Christian Würdig's avatar
Christian Würdig committed
22
 * @brief       SSA construction for a set of nodes
23
24
25
26
27
28
29
30
31
 * @author      Sebastian Hack, Daniel Grund, Matthias Braun, Christian Wuerdig
 * @date        04.05.2005
 * @version     $Id$
 *
 * The problem: Given a value and a set of "copies" that are known to
 * represent the same abstract value, rewire all usages of the original value
 * to their closest copy while introducing phis as necessary.
 *
 * Algorithm: Mark all blocks in the iterated dominance frontiers of the value
Michael Beck's avatar
Michael Beck committed
32
33
 * and it's copies. Link the copies ordered by dominance to the blocks.  Then
 * we search for each use all definitions in the current block, if none is
34
 * found, then we search one in the immediate dominator. If we are in a block
Michael Beck's avatar
Michael Beck committed
35
36
 * of the dominance frontier, create a phi and do the same search for all
 * phi arguments.
Christian Würdig's avatar
Christian Würdig committed
37
38
39
40
41
42
43
44
45
46
47
 *
 * A copy in this context means, that you want to introduce several new
 * abstract values (in Firm: nodes) for which you know, that they
 * represent the same concrete value. This is the case if you
 * - copy
 * - spill and reload
 * - re-materialize
 * a value.
 *
 * This function reroutes all uses of the original value to the copies in the
 * corresponding dominance subtrees and creates Phi functions where necessary.
48
49
50
 */
#include "config.h"

51
52
53
/* statev in this file is extensive, so only enable if needed */
#define DISABLE_STATEV

54
55
#include "bessaconstr.h"
#include "bemodule.h"
56
#include "besched.h"
57
#include "beintlive_t.h"
58
#include "beirg.h"
Matthias Braun's avatar
Matthias Braun committed
59
#include "be_t.h"
60
#include "benode.h"
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77

#include "debug.h"
#include "error.h"
#include "pdeq.h"
#include "array.h"
#include "irdom.h"

#include "ircons.h"
#include "iredges_t.h"

DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)

/**
 * Calculates the iterated dominance frontier of a set of blocks. Marks the
 * blocks as visited. Sets the link fields of the blocks in the dominance
 * frontier to the block itself.
 */
78
79
static void mark_iterated_dominance_frontiers(
		const be_ssa_construction_env_t *env)
80
{
81
	stat_ev_cnt_decl(blocks);
82
	DBG((dbg, LEVEL_3, "Dominance Frontier:"));
83
	stat_ev_tim_push();
Michael Beck's avatar
Michael Beck committed
84
	while (!waitq_empty(env->worklist)) {
85
		int i;
86
87
		ir_node *block = waitq_get(env->worklist);
		ir_node **domfront = be_get_dominance_frontier(env->domfronts, block);
88
89
90
91
		int domfront_len = ARR_LEN(domfront);

		for (i = 0; i < domfront_len; ++i) {
			ir_node *y = domfront[i];
92
93
94
95
			if (Block_block_visited(y))
				continue;

			if (!irn_visited(y)) {
96
				set_irn_link(y, NULL);
97
				waitq_put(env->worklist, y);
98
			}
99

100
101
			DBG((dbg, LEVEL_3, " %+F", y));
			mark_Block_block_visited(y);
102
			stat_ev_cnt_inc(blocks);
103
104
		}
	}
105
106
	stat_ev_tim_pop("bessaconstr_idf_time");
	stat_ev_cnt_done(blocks, "bessaconstr_idf_blocks");
107
108
109
	DBG((dbg, LEVEL_3, "\n"));
}

110
111
static ir_node *search_def_end_of_block(be_ssa_construction_env_t *env,
                                        ir_node *block);
112

113
114
static ir_node *create_phi(be_ssa_construction_env_t *env, ir_node *block,
                           ir_node *link_with)
115
116
{
	int i, n_preds = get_Block_n_cfgpreds(block);
117
	ir_graph *irg = get_Block_irg(block);
118
	ir_node **ins = ALLOCAN(ir_node*, n_preds);
119
	ir_node  *dummy;
120
	ir_node  *phi;
121
122
123

	assert(n_preds > 1);

124
	dummy = new_r_Dummy(irg, env->mode);
125
	for (i = 0; i < n_preds; ++i) {
126
		ins[i] = dummy;
127
	}
128
	phi = be_new_Phi(block, n_preds, ins, env->mode, env->phi_cls);
129
	if (env->new_phis != NULL) {
130
131
132
		ARR_APP1(ir_node*, env->new_phis, phi);
	}

133
	if (env->mode != mode_M) {
134
135
136
137
138
139
140
		sched_add_after(block, phi);
	}

	DBG((dbg, LEVEL_2, "\tcreating phi %+F in %+F\n", phi, block));
	set_irn_link(link_with, phi);
	mark_irn_visited(block);

141
	for (i = 0; i < n_preds; ++i) {
142
143
144
145
146
147
148
149
150
		ir_node *pred_block = get_Block_cfgpred_block(block, i);
		ir_node *pred_def   = search_def_end_of_block(env, pred_block);

		set_irn_n(phi, i, pred_def);
	}

	return phi;
}

151
static ir_node *get_def_at_idom(be_ssa_construction_env_t *env, ir_node *block)
152
153
{
	ir_node *dom = get_Block_idom(block);
Matthias Braun's avatar
Matthias Braun committed
154
	assert(dom != NULL);
Michael Beck's avatar
Michael Beck committed
155
	return search_def_end_of_block(env, dom);
156
157
}

158
159
static ir_node *search_def_end_of_block(be_ssa_construction_env_t *env,
                                        ir_node *block)
160
{
161
	if (irn_visited(block)) {
162
163
		assert(get_irn_link(block) != NULL);
		return get_irn_link(block);
164
	} else if (Block_block_visited(block)) {
165
166
167
168
169
170
171
172
173
		return create_phi(env, block, block);
	} else {
		ir_node *def = get_def_at_idom(env, block);
		mark_irn_visited(block);
		set_irn_link(block, def);
		return def;
	}
}

174
static ir_node *search_def(be_ssa_construction_env_t *env, ir_node *at)
175
176
177
178
179
180
181
182
{
	ir_node *block = get_nodes_block(at);
	ir_node *node;
	ir_node *def;

	DBG((dbg, LEVEL_3, "\t...searching def at %+F\n", at));

	/* no defs in the current block we can do the normal searching */
183
	if (!irn_visited(block) && !Block_block_visited(block)) {
184
185
186
187
188
189
190
191
192
		DBG((dbg, LEVEL_3, "\t...continue at idom\n"));
		return get_def_at_idom(env, block);
	}

	/* there are defs in the current block, walk the linked list to find
	   the one immediately dominating us
	 */
	node = block;
	def  = get_irn_link(node);
193
194
	while (def != NULL) {
		if (!value_dominates(at, def)) {
195
196
197
198
199
200
201
202
203
			DBG((dbg, LEVEL_3, "\t...found dominating def %+F\n", def));
			return def;
		}

		node = def;
		def  = get_irn_link(node);
	}

	/* block in dominance frontier? create a phi then */
204
	if (Block_block_visited(block)) {
205
206
207
208
209
210
211
212
213
214
215
216
217
218
		DBG((dbg, LEVEL_3, "\t...create phi at block %+F\n", block));
		assert(!is_Phi(node));
		return create_phi(env, block, node);
	}

	DBG((dbg, LEVEL_3, "\t...continue at idom (after checking block)\n"));
	return get_def_at_idom(env, block);
}

/**
 * Adds a definition into the link field of the block. The definitions are
 * sorted by dominance. A non-visited block means no definition has been
 * inserted yet.
 */
219
static void introduce_def_at_block(ir_node *block, ir_node *def)
220
{
221
	if (irn_visited_else_mark(block)) {
222
223
224
		ir_node *node = block;
		ir_node *current_def;

225
		for (;;) {
226
			current_def = get_irn_link(node);
227
			if (current_def == def) {
228
229
230
				/* already in block */
				return;
			}
231
			if (current_def == NULL)
232
				break;
233
			if (value_dominates(current_def, def))
234
235
236
237
238
239
240
241
242
243
244
245
				break;
			node = current_def;
		}

		set_irn_link(node, def);
		set_irn_link(def, current_def);
	} else {
		set_irn_link(block, def);
		set_irn_link(def, NULL);
	}
}

246
void be_ssa_construction_init(be_ssa_construction_env_t *env, ir_graph *irg)
247
{
248
249
250
251
252
	ir_node *sb   = get_irg_start_block(irg);
	int n_blocks  = get_Block_dom_max_subtree_pre_num(sb);

	stat_ev_ctx_push_fobj("bessaconstr", irg);
	stat_ev_tim_push();
253

254
255
256
257
	(void) n_blocks;
	stat_ev_dbl("bessaconstr_n_blocks", n_blocks);

	memset(env, 0, sizeof(env[0]));
258
	be_assure_dom_front(irg);
259
260

	env->irg       = irg;
261
	env->domfronts = be_get_irg_dom_front(irg);
262
263
264
	env->new_phis  = NEW_ARR_F(ir_node*, 0);
	env->worklist  = new_waitq();

265
266
	ir_reserve_resources(irg, IR_RESOURCE_IRN_VISITED
			| IR_RESOURCE_BLOCK_VISITED | IR_RESOURCE_IRN_LINK);
267
268
269
270
271

	/* we use the visited flag to indicate blocks in the dominance frontier
	 * and blocks that already have the relevant value at the end calculated */
	inc_irg_visited(irg);
	/* We use the block visited flag to indicate blocks in the dominance
Michael Beck's avatar
Michael Beck committed
272
	 * frontier of some values (and this potentially needing phis) */
273
274
275
276
277
	inc_irg_block_visited(irg);
}

void be_ssa_construction_destroy(be_ssa_construction_env_t *env)
{
278
	stat_ev_int("bessaconstr_phis", ARR_LEN(env->new_phis));
279
280
281
	del_waitq(env->worklist);
	DEL_ARR_F(env->new_phis);

282
283
	ir_free_resources(env->irg, IR_RESOURCE_IRN_VISITED
			| IR_RESOURCE_BLOCK_VISITED | IR_RESOURCE_IRN_LINK);
284
285
286

	stat_ev_tim_pop("bessaconstr_total_time");
	stat_ev_ctx_pop("bessaconstr");
287
288
289
290
291
292
293
294
295
}

void be_ssa_construction_add_copy(be_ssa_construction_env_t *env,
                                  ir_node *copy)
{
	ir_node *block;

	assert(env->iterated_domfront_calculated == 0);

296
	if (env->mode == NULL) {
297
298
		env->mode    = get_irn_mode(copy);
		env->phi_cls = arch_get_irn_reg_class_out(copy);
299
300
301
302
303
304
	} else {
		assert(env->mode == get_irn_mode(copy));
	}

	block = get_nodes_block(copy);

305
	if (!irn_visited(block)) {
306
307
308
309
310
311
312
313
314
315
316
317
		waitq_put(env->worklist, block);
	}
	introduce_def_at_block(block, copy);
}

void be_ssa_construction_add_copies(be_ssa_construction_env_t *env,
                                    ir_node **copies, size_t copies_len)
{
	size_t i;

	assert(env->iterated_domfront_calculated == 0);

318
	if (env->mode == NULL) {
319
320
		env->mode    = get_irn_mode(copies[0]);
		env->phi_cls = arch_get_irn_reg_class_out(copies[0]);
321
322
	}

323
	for (i = 0; i < copies_len; ++i) {
324
		ir_node *copy  = copies[i];
325
326
327
		ir_node *block = get_nodes_block(copy);

		assert(env->mode == get_irn_mode(copy));
328
		if (!irn_visited(block)) {
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
			waitq_put(env->worklist, block);
		}
		introduce_def_at_block(block, copy);
	}
}

void be_ssa_construction_set_ignore_uses(be_ssa_construction_env_t *env,
                                         const ir_nodeset_t *ignore_uses)
{
	env->ignore_uses = ignore_uses;
}

ir_node **be_ssa_construction_get_new_phis(be_ssa_construction_env_t *env)
{
	return env->new_phis;
}

346
347
void be_ssa_construction_fix_users_array(be_ssa_construction_env_t *env,
                                         ir_node **nodes, size_t nodes_len)
348
349
{
	const ir_edge_t *edge, *next;
350
	size_t i;
Michael Beck's avatar
Michael Beck committed
351
	stat_ev_cnt_decl(uses);
352

353
	be_timer_push(T_SSA_CONSTR);
Matthias Braun's avatar
Matthias Braun committed
354

355
	if (!env->iterated_domfront_calculated) {
356
		mark_iterated_dominance_frontiers(env);
357
358
359
		env->iterated_domfront_calculated = 1;
	}

360
	stat_ev_tim_push();
361
	for (i = 0; i < nodes_len; ++i) {
362
363
364
365
366
367
368
369
370
371
372
		ir_node *value = nodes[i];

		/*
		 * Search the valid def for each use and set it.
		 */
		foreach_out_edge_safe(value, edge, next) {
			ir_node *use = get_edge_src_irn(edge);
			ir_node *at  = use;
			int pos      = get_edge_src_pos(edge);
			ir_node *def;

373
			if (env->ignore_uses != NULL &&
374
375
			   ir_nodeset_contains(env->ignore_uses, use))
				continue;
376
			if (is_Anchor(use) || is_End(use))
377
				continue;
378

379
			if (is_Phi(use)) {
380
				ir_node *block     = get_nodes_block(use);
381
382
383
				ir_node *predblock = get_Block_cfgpred_block(block, pos);
				at = sched_last(predblock);
			}
384

385
			def = search_def(env, at);
386

387
			if (def == NULL) {
388
				panic("no definition found for %+F at position %d", use, pos);
389
390
391
392
393
394
			}

			DBG((dbg, LEVEL_2, "\t%+F(%d) -> %+F\n", use, pos, def));
			set_irn_n(use, pos, def);
			stat_ev_cnt_inc(uses);
		}
395
	}
396
	be_timer_pop(T_SSA_CONSTR);
Matthias Braun's avatar
Matthias Braun committed
397

398
399
	stat_ev_tim_pop("bessaconstr_fix_time");
	stat_ev_cnt_done(uses, "bessaconstr_uses");
400
401
}

402
void be_ssa_construction_fix_users(be_ssa_construction_env_t *env, ir_node *value)
403
{
404
	be_ssa_construction_fix_users_array(env, &value, 1);
405
406
}

407

408
409
410
411
412
void be_ssa_construction_update_liveness_phis(be_ssa_construction_env_t *env,
                                              be_lv_t *lv)
{
	int i, n;

413
	be_timer_push(T_SSA_CONSTR);
Matthias Braun's avatar
Matthias Braun committed
414

415
	n = ARR_LEN(env->new_phis);
416
	for (i = 0; i < n; ++i) {
417
418
419
		ir_node *phi = env->new_phis[i];
		be_liveness_introduce(lv, phi);
	}
Matthias Braun's avatar
Matthias Braun committed
420

421
	be_timer_pop(T_SSA_CONSTR);
422
423
}

424
BE_REGISTER_MODULE_CONSTRUCTOR(be_init_ssaconstr);
425
426
427
428
void be_init_ssaconstr(void)
{
	FIRM_DBG_REGISTER(dbg, "firm.be.ssaconstr");
}