2 * Copyright (C) 1995-2007 University of Karlsruhe. All right reserved.
4 * This file is part of libFirm.
6 * This file may be distributed and/or modified under the terms of the
7 * GNU General Public License version 2 as published by the Free Software
8 * Foundation and appearing in the file LICENSE.GPL included in the
9 * packaging of this file.
11 * Licensees holding valid libFirm Professional Edition licenses may use
12 * this file in accordance with the libFirm Commercial License.
13 * Agreement provided with the Software.
15 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * @brief SSA construction for a set of nodes
23 * @author Sebastian Hack, Daniel Grund, Matthias Braun, Christian Wuerdig
27 * The problem: Given a value and a set of "copies" that are known to
28 * represent the same abstract value, rewire all usages of the original value
29 * to their closest copy while introducing phis as necessary.
31 * Algorithm: Mark all blocks in the iterated dominance frontiers of the value
32 * and it's copies. Link the copies ordered by dominance to the blocks. The
33 * we search for each use all 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
35 * of the dominance frontier, create a phi and search do the same search for
38 * A copy in this context means, that you want to introduce several new
39 * abstract values (in Firm: nodes) for which you know, that they
40 * represent the same concrete value. This is the case if you
46 * This function reroutes all uses of the original value to the copies in the
47 * corresponding dominance subtrees and creates Phi functions where necessary.
53 #include "bessaconstr.h"
55 #include "besched_t.h"
66 #include "iredges_t.h"
68 DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
71 * Calculates the iterated dominance frontier of a set of blocks. Marks the
72 * blocks as visited. Sets the link fields of the blocks in the dominance
73 * frontier to the block itself.
76 void mark_iterated_dominance_frontiers(const be_dom_front_info_t *domfronts,
79 DBG((dbg, LEVEL_3, "Dominance Frontier:"));
80 while(!pdeq_empty(worklist)) {
82 ir_node *block = waitq_get(worklist);
83 ir_node **domfront = be_get_dominance_frontier(domfronts, block);
84 int domfront_len = ARR_LEN(domfront);
86 for (i = 0; i < domfront_len; ++i) {
87 ir_node *y = domfront[i];
88 if(Block_block_visited(y))
92 set_irn_link(y, NULL);
93 waitq_put(worklist, y);
95 DBG((dbg, LEVEL_3, " %+F", y));
96 mark_Block_block_visited(y);
99 DBG((dbg, LEVEL_3, "\n"));
103 ir_node *search_def_end_of_block(be_ssa_construction_env_t *env,
107 ir_node *create_phi(be_ssa_construction_env_t *env, ir_node *block,
110 int i, n_preds = get_Block_n_cfgpreds(block);
111 ir_graph *irg = get_irn_irg(block);
113 ir_node **ins = alloca(n_preds * sizeof(ins[0]));
117 for(i = 0; i < n_preds; ++i) {
118 ins[i] = new_r_Unknown(irg, env->mode);
120 phi = new_r_Phi(irg, block, n_preds, ins, env->mode);
121 if(env->new_phis != NULL) {
122 ARR_APP1(ir_node*, env->new_phis, phi);
125 if(env->mode != mode_M) {
126 sched_add_after(block, phi);
129 DBG((dbg, LEVEL_2, "\tcreating phi %+F in %+F\n", phi, block));
130 set_irn_link(link_with, phi);
131 mark_irn_visited(block);
133 for(i = 0; i < n_preds; ++i) {
134 ir_node *pred_block = get_Block_cfgpred_block(block, i);
135 ir_node *pred_def = search_def_end_of_block(env, pred_block);
137 set_irn_n(phi, i, pred_def);
144 ir_node *get_def_at_idom(be_ssa_construction_env_t *env, ir_node *block)
146 ir_node *dom = get_Block_idom(block);
147 ir_node *def = search_def_end_of_block(env, dom);
153 ir_node *search_def_end_of_block(be_ssa_construction_env_t *env, ir_node *block)
155 if(irn_visited(block)) {
156 assert(get_irn_link(block) != NULL);
157 return get_irn_link(block);
158 } else if(Block_block_visited(block)) {
159 return create_phi(env, block, block);
161 ir_node *def = get_def_at_idom(env, block);
162 mark_irn_visited(block);
163 set_irn_link(block, def);
170 ir_node *search_def(be_ssa_construction_env_t *env, ir_node *at)
172 ir_node *block = get_nodes_block(at);
176 DBG((dbg, LEVEL_3, "\t...searching def at %+F\n", at));
178 /* no defs in the current block we can do the normal searching */
179 if(!irn_visited(block) && !Block_block_visited(block)) {
180 DBG((dbg, LEVEL_3, "\t...continue at idom\n"));
181 return get_def_at_idom(env, block);
184 /* there are defs in the current block, walk the linked list to find
185 the one immediately dominating us
188 def = get_irn_link(node);
190 if(!value_dominates(at, def)) {
191 DBG((dbg, LEVEL_3, "\t...found dominating def %+F\n", def));
196 def = get_irn_link(node);
199 /* block in dominance frontier? create a phi then */
200 if(Block_block_visited(block)) {
201 DBG((dbg, LEVEL_3, "\t...create phi at block %+F\n", block));
202 assert(!is_Phi(node));
203 return create_phi(env, block, node);
207 DBG((dbg, LEVEL_3, "\t...continue at idom (after checking block)\n"));
208 return get_def_at_idom(env, block);
212 * Adds a definition into the link field of the block. The definitions are
213 * sorted by dominance. A non-visited block means no definition has been
217 void introduce_def_at_block(ir_node *block, ir_node *def)
219 if(irn_visited(block)) {
220 ir_node *node = block;
221 ir_node *current_def;
224 current_def = get_irn_link(node);
225 if(current_def == def) {
226 /* already in block */
229 if(current_def == NULL)
231 if(value_dominates(current_def, def))
236 set_irn_link(node, def);
237 set_irn_link(def, current_def);
239 set_irn_link(block, def);
240 set_irn_link(def, NULL);
241 mark_irn_visited(block);
245 void be_ssa_construction_init(be_ssa_construction_env_t *env, be_irg_t *birg)
247 ir_graph *irg = be_get_birg_irg(birg);
248 memset(env, 0, sizeof(env[0]));
250 be_assure_dom_front(birg);
253 env->domfronts = be_get_birg_dom_front(birg);
254 env->new_phis = NEW_ARR_F(ir_node*, 0);
255 env->worklist = new_waitq();
257 set_using_visited(irg);
258 set_using_block_visited(irg);
259 set_using_irn_link(irg);
261 /* we use the visited flag to indicate blocks in the dominance frontier
262 * and blocks that already have the relevant value at the end calculated */
263 inc_irg_visited(irg);
264 /* We use the block visited flag to indicate blocks in the dominance
265 * froniter of some values (and this potentially needing phis) */
266 inc_irg_block_visited(irg);
269 void be_ssa_construction_destroy(be_ssa_construction_env_t *env)
271 del_waitq(env->worklist);
272 DEL_ARR_F(env->new_phis);
274 clear_using_visited(env->irg);
275 clear_using_block_visited(env->irg);
276 clear_using_irn_link(env->irg);
279 void be_ssa_construction_add_copy(be_ssa_construction_env_t *env,
284 assert(env->iterated_domfront_calculated == 0);
286 if(env->mode == NULL) {
287 env->mode = get_irn_mode(copy);
289 assert(env->mode == get_irn_mode(copy));
292 block = get_nodes_block(copy);
294 if(!irn_visited(block)) {
295 waitq_put(env->worklist, block);
297 introduce_def_at_block(block, copy);
300 void be_ssa_construction_add_copies(be_ssa_construction_env_t *env,
301 ir_node **copies, size_t copies_len)
305 assert(env->iterated_domfront_calculated == 0);
307 if(env->mode == NULL) {
308 env->mode = get_irn_mode(copies[0]);
311 for(i = 0; i < copies_len; ++i) {
312 ir_node *copy = copies[i];
313 ir_node *block = get_nodes_block(copy);
315 assert(env->mode == get_irn_mode(copy));
316 if(!irn_visited(block)) {
317 waitq_put(env->worklist, block);
319 introduce_def_at_block(block, copy);
323 void be_ssa_construction_set_ignore_uses(be_ssa_construction_env_t *env,
324 const ir_nodeset_t *ignore_uses)
326 env->ignore_uses = ignore_uses;
329 ir_node **be_ssa_construction_get_new_phis(be_ssa_construction_env_t *env)
331 return env->new_phis;
334 void be_ssa_construction_fix_users(be_ssa_construction_env_t *env,
337 const ir_edge_t *edge, *next;
339 if(!env->iterated_domfront_calculated) {
340 mark_iterated_dominance_frontiers(env->domfronts, env->worklist);
341 env->iterated_domfront_calculated = 1;
345 * Search the valid def for each use and set it.
347 foreach_out_edge_safe(value, edge, next) {
348 ir_node *use = get_edge_src_irn(edge);
350 int pos = get_edge_src_pos(edge);
353 if(env->ignore_uses != NULL &&
354 ir_nodeset_contains(env->ignore_uses, use))
358 ir_node *block = get_nodes_block(use);
359 ir_node *predblock = get_Block_cfgpred_block(block, pos);
360 at = sched_last(predblock);
363 def = search_def(env, at);
366 panic("no definition found for %+F at position %d\n", use, pos);
369 DBG((dbg, LEVEL_2, "\t%+F(%d) -> %+F\n", use, pos, def));
370 set_irn_n(use, pos, def);
374 void be_ssa_construction_fix_users_array(be_ssa_construction_env_t *env,
375 ir_node **nodes, size_t nodes_len)
379 for(i = 0; i < nodes_len; ++i) {
380 ir_node *node = nodes[i];
381 be_ssa_construction_fix_users(env, node);
385 void be_ssa_construction_update_liveness_phis(be_ssa_construction_env_t *env,
390 n = ARR_LEN(env->new_phis);
391 for(i = 0; i < n; ++i) {
392 ir_node *phi = env->new_phis[i];
393 be_liveness_introduce(lv, phi);
398 ir_node **be_ssa_construction(const be_dom_front_info_t *domfronts, be_lv_t *lv,
399 ir_node *value, int copies_len, ir_node **copies,
400 const ir_nodeset_t *ignore_uses, int need_new_phis)
402 ir_graph *irg = get_irn_irg(value);
403 const ir_edge_t *edge, *next;
407 be_ssa_construction_env_t env;
409 /* We need to collect the phi functions to compute their liveness. */
410 if(lv != NULL || need_new_phis) {
411 env.new_phis = NEW_ARR_F(ir_node*, 0);
415 env.mode = get_irn_mode(value);
417 set_using_visited(irg);
418 set_using_block_visited(irg);
419 set_using_irn_link(irg);
421 /* we use the visited flag to indicate blocks in the dominance frontier
422 * and blocks that already have the relevant value at the end calculated */
423 inc_irg_visited(irg);
424 /* We use the block visited flag to indicate blocks in the dominance
425 * froniter of some values (and this potentially needing phis) */
426 inc_irg_block_visited(irg);
428 DBG((dbg, LEVEL_1, "Introducing following copies for: %+F\n", value));
429 /* compute iterated dominance frontiers and create lists in the block link
430 * fields that sort usages by dominance. Blocks in the dominance frontier
431 * are marked by links back to the block. */
432 worklist = new_waitq();
434 block = get_nodes_block(value);
435 /* we sometimes replace virtual values by real ones, in this case we do
436 not want to insert them into the def list (they're not scheduled
437 and can't be used anyway) */
438 if(sched_is_scheduled(value)) {
439 introduce_def_at_block(block, value);
441 waitq_put(worklist, block);
443 for(i = 0; i < copies_len; ++i) {
444 ir_node *copy = copies[i];
445 block = get_nodes_block(copy);
447 if(!irn_visited(block)) {
448 waitq_put(worklist, block);
450 introduce_def_at_block(block, copy);
451 DBG((dbg, LEVEL_1, "\t%+F in %+F\n", copy, block));
454 mark_iterated_dominance_frontiers(domfronts, worklist);
457 DBG((dbg, LEVEL_2, "New Definitions:\n"));
459 * Search the valid def for each use and set it.
461 foreach_out_edge_safe(value, edge, next) {
462 ir_node *use = get_edge_src_irn(edge);
464 int pos = get_edge_src_pos(edge);
466 if(ignore_uses != NULL && ir_nodeset_contains(ignore_uses, use))
470 ir_node *block = get_nodes_block(use);
471 ir_node *predblock = get_Block_cfgpred_block(block, pos);
472 at = sched_last(predblock);
475 ir_node *def = search_def(&env, at);
478 panic("no definition found for %+F at position %d\n", use, pos);
481 DBG((dbg, LEVEL_2, "\t%+F(%d) -> %+F\n", use, pos, def));
482 set_irn_n(use, pos, def);
485 /* Recompute the liveness of the original nodes, the copies and the
490 be_liveness_update(lv, value);
491 for(i = 0; i < copies_len; ++i) {
492 ir_node *copy = copies[i];
493 be_liveness_update(lv, copy);
496 n = ARR_LEN(env.new_phis);
497 for(i = 0; i < n; ++i) {
498 ir_node *phi = env.new_phis[i];
499 be_liveness_introduce(lv, phi);
503 clear_using_visited(irg);
504 clear_using_block_visited(irg);
505 clear_using_irn_link(irg);
507 if(!need_new_phis && env.new_phis != NULL) {
508 DEL_ARR_F(env.new_phis);
515 void be_init_ssaconstr(void)
517 FIRM_DBG_REGISTER(dbg, "firm.be.ssaconstr");
520 BE_REGISTER_MODULE_CONSTRUCTOR(be_init_ssaconstr);