Remove handling for 32bit as smaller mode in emit_ia32_Conv_I2I(), because it is...
[libfirm] / ir / be / bessaconstr.c
1 /*
2  * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
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.
10  *
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.
14  *
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
17  * PURPOSE.
18  */
19
20 /**
21  * @file
22  * @brief       SSA construction for a set of nodes
23  * @author      Sebastian Hack, Daniel Grund, Matthias Braun, Christian Wuerdig
24  * @date        04.05.2005
25  * @version     $Id$
26  *
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.
30  *
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.  Then
33  * 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
35  * of the dominance frontier, create a phi and do the same search for all
36  * phi arguments.
37  *
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
41  * - copy
42  * - spill and reload
43  * - re-materialize
44  * a value.
45  *
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.
48  */
49 #ifdef HAVE_CONFIG_H
50 #include "config.h"
51 #endif
52
53 #include "bessaconstr.h"
54 #include "bemodule.h"
55 #include "besched_t.h"
56 #include "beintlive_t.h"
57 #include "beirg_t.h"
58 #include "be_t.h"
59
60 #include "debug.h"
61 #include "error.h"
62 #include "pdeq.h"
63 #include "array.h"
64 #include "irdom.h"
65
66 #include "ircons.h"
67 #include "iredges_t.h"
68
69 DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
70
71 /**
72  * Checks that low <= what < hi.
73  */
74 static INLINE int is_inside(unsigned what, unsigned low, unsigned hi)
75 {
76         return what - low < hi;
77 }
78
79 /**
80  * Calculates the iterated dominance frontier of a set of blocks. Marks the
81  * blocks as visited. Sets the link fields of the blocks in the dominance
82  * frontier to the block itself.
83  */
84 static
85 void mark_iterated_dominance_frontiers(const be_ssa_construction_env_t *env)
86 {
87         stat_ev_cnt_decl(blocks);
88         DBG((dbg, LEVEL_3, "Dominance Frontier:"));
89         stat_ev_tim_push();
90         while (!waitq_empty(env->worklist)) {
91                 int i;
92                 ir_node *block = waitq_get(env->worklist);
93                 ir_node **domfront = be_get_dominance_frontier(env->domfronts, block);
94                 int domfront_len = ARR_LEN(domfront);
95
96                 for (i = 0; i < domfront_len; ++i) {
97                         ir_node *y = domfront[i];
98                         if (Block_block_visited(y))
99                                 continue;
100
101                         /*
102                          * It makes no sense to add phi-functions to blocks
103                          * that are not dominated by any definition;
104                          * all uses are dominated, hence the paths reaching the uses
105                          * have to stay in the dominance subtrees of the given definitions.
106                          */
107
108                         if (!is_inside(get_Block_dom_tree_pre_num(y), env->min_dom, env->max_dom))
109                                 continue;
110
111                         if (!irn_visited(y)) {
112                                 set_irn_link(y, NULL);
113                                 waitq_put(env->worklist, y);
114                         }
115
116                         DBG((dbg, LEVEL_3, " %+F", y));
117                         mark_Block_block_visited(y);
118                         stat_ev_cnt_inc(blocks);
119                 }
120         }
121         stat_ev_tim_pop("bessaconstr_idf_time");
122         stat_ev_cnt_done(blocks, "bessaconstr_idf_blocks");
123         DBG((dbg, LEVEL_3, "\n"));
124 }
125
126 static
127 ir_node *search_def_end_of_block(be_ssa_construction_env_t *env,
128                                  ir_node *block);
129
130 static
131 ir_node *create_phi(be_ssa_construction_env_t *env, ir_node *block,
132                     ir_node *link_with)
133 {
134         int i, n_preds = get_Block_n_cfgpreds(block);
135         ir_graph *irg = get_irn_irg(block);
136         ir_node *phi;
137         ir_node **ins = alloca(n_preds * sizeof(ins[0]));
138
139         assert(n_preds > 1);
140
141         for(i = 0; i < n_preds; ++i) {
142                 ins[i] = new_r_Unknown(irg, env->mode);
143         }
144         phi = new_r_Phi(irg, block, n_preds, ins, env->mode);
145         if(env->new_phis != NULL) {
146                 ARR_APP1(ir_node*, env->new_phis, phi);
147         }
148
149         if(env->mode != mode_M) {
150                 sched_add_after(block, phi);
151         }
152
153         DBG((dbg, LEVEL_2, "\tcreating phi %+F in %+F\n", phi, block));
154         set_irn_link(link_with, phi);
155         mark_irn_visited(block);
156
157         for(i = 0; i < n_preds; ++i) {
158                 ir_node *pred_block = get_Block_cfgpred_block(block, i);
159                 ir_node *pred_def   = search_def_end_of_block(env, pred_block);
160
161                 set_irn_n(phi, i, pred_def);
162         }
163
164         return phi;
165 }
166
167 static
168 ir_node *get_def_at_idom(be_ssa_construction_env_t *env, ir_node *block)
169 {
170         ir_node *dom = get_Block_idom(block);
171         assert(dom != NULL);
172         return search_def_end_of_block(env, dom);
173 }
174
175 static
176 ir_node *search_def_end_of_block(be_ssa_construction_env_t *env, ir_node *block)
177 {
178         if(irn_visited(block)) {
179                 assert(get_irn_link(block) != NULL);
180                 return get_irn_link(block);
181         } else if(Block_block_visited(block)) {
182                 return create_phi(env, block, block);
183         } else {
184                 ir_node *def = get_def_at_idom(env, block);
185                 mark_irn_visited(block);
186                 set_irn_link(block, def);
187                 return def;
188         }
189 }
190
191 static
192 ir_node *search_def(be_ssa_construction_env_t *env, ir_node *at)
193 {
194         ir_node *block = get_nodes_block(at);
195         ir_node *node;
196         ir_node *def;
197
198         DBG((dbg, LEVEL_3, "\t...searching def at %+F\n", at));
199
200         /* no defs in the current block we can do the normal searching */
201         if(!irn_visited(block) && !Block_block_visited(block)) {
202                 DBG((dbg, LEVEL_3, "\t...continue at idom\n"));
203                 return get_def_at_idom(env, block);
204         }
205
206         /* there are defs in the current block, walk the linked list to find
207            the one immediately dominating us
208          */
209         node = block;
210         def  = get_irn_link(node);
211         while(def != NULL) {
212                 if(!value_dominates(at, def)) {
213                         DBG((dbg, LEVEL_3, "\t...found dominating def %+F\n", def));
214                         return def;
215                 }
216
217                 node = def;
218                 def  = get_irn_link(node);
219         }
220
221         /* block in dominance frontier? create a phi then */
222         if(Block_block_visited(block)) {
223                 DBG((dbg, LEVEL_3, "\t...create phi at block %+F\n", block));
224                 assert(!is_Phi(node));
225                 return create_phi(env, block, node);
226         }
227
228         DBG((dbg, LEVEL_3, "\t...continue at idom (after checking block)\n"));
229         return get_def_at_idom(env, block);
230 }
231
232 static
233 void update_domzone(be_ssa_construction_env_t *env, const ir_node *bl)
234 {
235         int start = get_Block_dom_tree_pre_num(bl);
236         int end   = get_Block_dom_max_subtree_pre_num(bl) + 1;
237
238         env->min_dom = MIN(env->min_dom, start);
239         env->max_dom = MAX(env->max_dom, end);
240 }
241
242 /**
243  * Adds a definition into the link field of the block. The definitions are
244  * sorted by dominance. A non-visited block means no definition has been
245  * inserted yet.
246  */
247 static
248 void introduce_def_at_block(ir_node *block, ir_node *def)
249 {
250         if(irn_visited(block)) {
251                 ir_node *node = block;
252                 ir_node *current_def;
253
254                 while(1) {
255                         current_def = get_irn_link(node);
256                         if(current_def == def) {
257                                 /* already in block */
258                                 return;
259                         }
260                         if(current_def == NULL)
261                                 break;
262                         if(value_dominates(current_def, def))
263                                 break;
264                         node = current_def;
265                 }
266
267                 set_irn_link(node, def);
268                 set_irn_link(def, current_def);
269         } else {
270                 set_irn_link(block, def);
271                 set_irn_link(def, NULL);
272                 mark_irn_visited(block);
273         }
274 }
275
276 void be_ssa_construction_init(be_ssa_construction_env_t *env, be_irg_t *birg)
277 {
278         ir_graph *irg = be_get_birg_irg(birg);
279         ir_node *sb   = get_irg_start_block(irg);
280         int n_blocks  = get_Block_dom_max_subtree_pre_num(sb);
281
282         stat_ev_ctx_push_fobj("bessaconstr", irg);
283         stat_ev_tim_push();
284
285         (void) n_blocks;
286         stat_ev_dbl("bessaconstr_n_blocks", n_blocks);
287
288         memset(env, 0, sizeof(env[0]));
289         be_assure_dom_front(birg);
290
291         env->irg       = irg;
292         env->domfronts = be_get_birg_dom_front(birg);
293         env->new_phis  = NEW_ARR_F(ir_node*, 0);
294         env->worklist  = new_waitq();
295         env->min_dom   = INT_MAX;
296         env->max_dom   = 0;
297
298         set_using_irn_visited(irg);
299         set_using_block_visited(irg);
300         set_using_irn_link(irg);
301
302         /* we use the visited flag to indicate blocks in the dominance frontier
303          * and blocks that already have the relevant value at the end calculated */
304         inc_irg_visited(irg);
305         /* We use the block visited flag to indicate blocks in the dominance
306          * frontier of some values (and this potentially needing phis) */
307         inc_irg_block_visited(irg);
308 }
309
310 void be_ssa_construction_destroy(be_ssa_construction_env_t *env)
311 {
312         stat_ev_int("bessaconstr_phis", ARR_LEN(env->new_phis));
313         del_waitq(env->worklist);
314         DEL_ARR_F(env->new_phis);
315
316         clear_using_irn_visited(env->irg);
317         clear_using_block_visited(env->irg);
318         clear_using_irn_link(env->irg);
319
320         stat_ev_tim_pop("bessaconstr_total_time");
321         stat_ev_ctx_pop("bessaconstr");
322 }
323
324 void be_ssa_construction_add_copy(be_ssa_construction_env_t *env,
325                                   ir_node *copy)
326 {
327         ir_node *block;
328
329         assert(env->iterated_domfront_calculated == 0);
330
331         if(env->mode == NULL) {
332                 env->mode = get_irn_mode(copy);
333         } else {
334                 assert(env->mode == get_irn_mode(copy));
335         }
336
337         block = get_nodes_block(copy);
338
339         if(!irn_visited(block)) {
340                 waitq_put(env->worklist, block);
341         }
342         introduce_def_at_block(block, copy);
343         update_domzone(env, block);
344 }
345
346 void be_ssa_construction_add_copies(be_ssa_construction_env_t *env,
347                                     ir_node **copies, size_t copies_len)
348 {
349         size_t i;
350
351         assert(env->iterated_domfront_calculated == 0);
352
353         if(env->mode == NULL) {
354                 env->mode = get_irn_mode(copies[0]);
355         }
356
357         for(i = 0; i < copies_len; ++i) {
358                 ir_node *copy = copies[i];
359                 ir_node *block = get_nodes_block(copy);
360
361                 assert(env->mode == get_irn_mode(copy));
362                 if(!irn_visited(block)) {
363                         waitq_put(env->worklist, block);
364                 }
365                 introduce_def_at_block(block, copy);
366                 update_domzone(env, block);
367         }
368 }
369
370 void be_ssa_construction_set_ignore_uses(be_ssa_construction_env_t *env,
371                                          const ir_nodeset_t *ignore_uses)
372 {
373         env->ignore_uses = ignore_uses;
374 }
375
376 ir_node **be_ssa_construction_get_new_phis(be_ssa_construction_env_t *env)
377 {
378         return env->new_phis;
379 }
380
381 void be_ssa_construction_fix_users_array(be_ssa_construction_env_t *env,
382                                          ir_node **nodes, size_t nodes_len)
383 {
384         stat_ev_cnt_decl(uses);
385         const ir_edge_t *edge, *next;
386         size_t i;
387
388         BE_TIMER_PUSH(t_ssa_constr);
389
390         if(!env->iterated_domfront_calculated) {
391                 mark_iterated_dominance_frontiers(env);
392                 env->iterated_domfront_calculated = 1;
393         }
394
395         stat_ev_int("bessaconstr_domzone", env->max_dom - env->min_dom);
396         stat_ev_tim_push();
397         for(i = 0; i < nodes_len; ++i) {
398                 ir_node *value = nodes[i];
399
400                 /*
401                  * Search the valid def for each use and set it.
402                  */
403                 foreach_out_edge_safe(value, edge, next) {
404                         ir_node *use = get_edge_src_irn(edge);
405                         ir_node *at  = use;
406                         int pos      = get_edge_src_pos(edge);
407                         ir_node *def;
408
409                         if(env->ignore_uses != NULL     &&
410                            ir_nodeset_contains(env->ignore_uses, use))
411                                 continue;
412                         if(is_Anchor(use))
413                                 continue;
414
415                         if(is_Phi(use)) {
416                                 ir_node *block = get_nodes_block(use);
417                                 ir_node *predblock = get_Block_cfgpred_block(block, pos);
418                                 at = sched_last(predblock);
419                         }
420
421                         def = search_def(env, at);
422
423                         if(def == NULL) {
424                                 panic("no definition found for %+F at position %d\n", use, pos);
425                         }
426
427                         DBG((dbg, LEVEL_2, "\t%+F(%d) -> %+F\n", use, pos, def));
428                         set_irn_n(use, pos, def);
429                         stat_ev_cnt_inc(uses);
430                 }
431         }
432         BE_TIMER_POP(t_ssa_constr);
433
434         stat_ev_tim_pop("bessaconstr_fix_time");
435         stat_ev_cnt_done(uses, "bessaconstr_uses");
436 }
437
438 void be_ssa_construction_fix_users(be_ssa_construction_env_t *env, ir_node *value)
439 {
440         be_ssa_construction_fix_users_array(env, &value, 1);
441 }
442
443
444 void be_ssa_construction_update_liveness_phis(be_ssa_construction_env_t *env,
445                                               be_lv_t *lv)
446 {
447         int i, n;
448
449         BE_TIMER_PUSH(t_ssa_constr);
450
451         n = ARR_LEN(env->new_phis);
452         for(i = 0; i < n; ++i) {
453                 ir_node *phi = env->new_phis[i];
454                 be_liveness_introduce(lv, phi);
455         }
456
457         BE_TIMER_POP(t_ssa_constr);
458 }
459
460 void be_init_ssaconstr(void)
461 {
462         FIRM_DBG_REGISTER(dbg, "firm.be.ssaconstr");
463 }
464
465 BE_REGISTER_MODULE_CONSTRUCTOR(be_init_ssaconstr);