db302379857efba32d9970a5137abfbb2dc32c75
[libfirm] / ir / opt / return.c
1 /*
2  * Copyright (C) 1995-2007 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  * Project:     libFIRM
22  * File name:   ir/opt/return.c
23  * Purpose:     normalize returns
24  * Author:
25  * Created:
26  * CVS-ID:      $Id$
27  * Copyright:   (c) 1998-2005 Universität Karlsruhe
28  */
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32
33 #include "irgraph_t.h"
34 #include "ircons_t.h"
35 #include "irnode_t.h"
36 #include "irgmod.h"
37 #include "xmalloc.h"
38
39 #define set_bit(n)      (returns[(n) >> 3] |= 1 << ((n) & 7))
40 #define get_bit(n)      (returns[(n) >> 3] & (1 << ((n) & 7)))
41
42 #undef IMAX
43 #define IMAX(a, b)       ((a) > (b) ? (a) : (b))
44
45 /*
46  * Normalize the Returns of a graph by creating a new End block
47  * with One Return(Phi).
48  * This is the preferred input for the if-conversion.
49  *
50  * In pseudocode, it means:
51  *
52  * if (a)
53  *   return b;
54  * else
55  *   return c;
56  *
57  * is transformed into
58  *
59  * if (a)
60  *   res = b;
61  * else
62  *   res = c;
63  * return res;
64  */
65 void normalize_one_return(ir_graph *irg)
66 {
67   ir_node *endbl = get_irg_end_block(irg);
68   int i, j, k, n, last_idx, n_rets, n_ret_vals = -1;
69   unsigned char *returns;
70   ir_node **in, **retvals, **endbl_in;
71
72   ir_node *block;
73
74   /* look, if we have more than one return */
75   n = get_Block_n_cfgpreds(endbl);
76   if (n <= 0) {
77     /* The end block has no predecessors, we have an endless
78        loop. In that case, no returns exists. */
79     return;
80   }
81
82   returns = alloca((n + 7) >> 3);
83   memset(returns, 0, (n + 7) >> 3);
84
85   for (n_rets = i = 0; i < n; ++i) {
86     ir_node *node = get_Block_cfgpred(endbl, i);
87
88     if (is_Return(node)) {
89       ++n_rets;
90
91       set_bit(i);
92
93       if (n_ret_vals < 0)
94         n_ret_vals = get_irn_arity(node);
95     }
96   }
97
98   /* there should be at least one Return node in Firm */
99   if (n_rets <= 1)
100     return;
101
102   in       = alloca(sizeof(*in)       * IMAX(n_rets, n_ret_vals));
103   retvals  = alloca(sizeof(*retvals)  * n_rets * n_ret_vals);
104   endbl_in = alloca(sizeof(*endbl_in) * n);
105
106   last_idx = 0;
107   for (j = i = 0; i < n; ++i) {
108     ir_node *ret = get_Block_cfgpred(endbl, i);
109
110     if (get_bit(i)) {
111       ir_node *block = get_nodes_block(ret);
112
113       /* create a new Jmp for every Ret and place the in in */
114       in[j] = new_r_Jmp(irg, block);
115
116       /* save the return values and shuffle them */
117       for (k = 0; k < n_ret_vals; ++k)
118         retvals[j + k*n_rets] = get_irn_n(ret, k);
119
120       ++j;
121     }
122     else
123       endbl_in[last_idx++] = ret;
124   }
125
126   /* ok, create a new block with all created in's */
127   block = new_r_Block(irg, n_rets, in);
128
129   /* now create the Phi nodes */
130   for (j = i = 0; i < n_ret_vals; ++i, j += n_rets) {
131     int k;
132     ir_node *first;
133     /* the return values are already shuffled */
134
135     /* Beware: normally the Phi constructor automatically replaces a Phi(a,...a) into a
136        but NOT, if a is Unknown. Here, we known that this case can be optimize also,
137        so do it here */
138     first = retvals[j + 0];
139     for (k = 1; k < n_rets; ++k) {
140       if (retvals[j + k] != first) {
141         first = NULL;
142         break;
143       }
144     }
145     if (first)
146       in[i] = first;
147     else
148       in[i] = new_r_Phi(irg, block, n_rets, &retvals[j], get_irn_mode(retvals[j]));
149   }
150
151   endbl_in[last_idx++] = new_r_Return(irg, block, in[0], n_ret_vals-1, &in[1]);
152
153   set_irn_in(endbl, last_idx, endbl_in);
154
155   /* invalidate analysis information:
156    * a new Block was added, so dominator, outs and loop are inconsistent,
157    * trouts and callee-state should be still valid
158    */
159   set_irg_doms_inconsistent(irg);
160   set_irg_outs_inconsistent(irg);
161   set_irg_extblk_inconsistent(irg);
162   set_irg_loopinfo_state(irg, loopinfo_cf_inconsistent);
163 }
164
165 /**
166  * check, whether a Ret can be moved on block upwards.
167  *
168  * In a block with a Return, all live nodes must be linked
169  * with the Return, otherwise they are dead (because the Return leaves
170  * the graph, so no more users of the other nodes can exists.
171  *
172  * We can move a Return, if it's predecessors are Phi nodes or
173  * comes from another block. In the later case, it is always possible
174  * to move the Return one block up, because the predecessor block must
175  * dominate the Return block (SSA) and then it dominates the predecessor
176  * block of the Return block as well.
177  *
178  * All predecessors of the Return block must be Jmp's of course, or we
179  * cannot move it up, so we check this either.
180  */
181 static int can_move_ret(ir_node *ret)
182 {
183   ir_node *retbl = get_nodes_block(ret);
184   int i, n = get_irn_arity(ret);
185
186   for (i = 0; i < n; ++i) {
187     ir_node *pred = get_irn_n(ret, i);
188
189     if (! is_Phi(pred) && retbl == get_nodes_block(pred)) {
190       /* first condition failed, found a non-Phi predecessor
191        * then is in the Return block */
192       return 0;
193     }
194   }
195
196   /* check, that predecessors are Jmps */
197   n = get_Block_n_cfgpreds(retbl);
198   for (i = 0; i < n; ++i)
199     if (get_irn_op(get_Block_cfgpred(retbl, i)) != op_Jmp)
200       return 0;
201
202   /* if we have 0 control flow predecessors, we cannot move :-) */
203   return n > 0;
204 }
205
206 /*
207  * Normalize the Returns of a graph by moving
208  * the Returns upwards as much as possible.
209  * This might be preferred for code generation.
210  *
211  * In pseudocode, it means:
212  *
213  * if (a)
214  *   res = b;
215  * else
216  *   res = c;
217  * return res;
218  *
219  * is transformed into
220  *
221  * if (a)
222  *   return b;
223  * else
224  *   return c;
225  */
226 void normalize_n_returns(ir_graph *irg)
227 {
228   int i, j, n, n_rets, n_finals, n_ret_vals;
229   ir_node *list  = NULL;
230   ir_node *final = NULL;
231   ir_node **in;
232   ir_node *endbl = get_irg_end_block(irg);
233   ir_node *end;
234
235   /*
236    * First, link all returns:
237    * These must be predecessors of the endblock.
238    * Place Returns that can be moved on list, all others
239    * on final.
240    */
241   n = get_Block_n_cfgpreds(endbl);
242   for (n_finals = n_rets = i = 0; i < n; ++i) {
243     ir_node *ret = get_Block_cfgpred(endbl, i);
244
245     if (is_Return(ret) && can_move_ret(ret)) {
246       /*
247        * Ok, all conditions met, we can move this Return, put it
248        * on our work list.
249        */
250       set_irn_link(ret, list);
251       list = ret;
252       ++n_rets;
253     }
254     else {
255       /* Put all nodes that are not changed on the final list. */
256       set_irn_link(ret, final);
257       final = ret;
258       ++n_finals;
259     }
260   }
261
262   if (n_rets <= 0)
263     return;
264
265   /*
266    * Now move the Returns upwards. We move always one block up (and create n
267    * new Returns), than we check if a newly created Return can be moved even further.
268    * If yes, we simply add it to our work list, else to the final list.
269    */
270   end        = get_irg_end(irg);
271   n_ret_vals = get_irn_arity(list);
272   in         = alloca(sizeof(*in) * n_ret_vals);
273   while (list) {
274     ir_node *ret   = list;
275     ir_node *block = get_nodes_block(ret);
276     ir_node *phiM;
277
278     list = get_irn_link(ret);
279     --n_rets;
280
281     n = get_Block_n_cfgpreds(block);
282     for (i = 0; i < n; ++i) {
283       ir_node *jmp = get_Block_cfgpred(block, i);
284       ir_node *new_bl, *new_ret;
285
286       if (get_irn_op(jmp) != op_Jmp)
287         continue;
288
289       new_bl = get_nodes_block(jmp);
290
291       /* create the in-array for the new Ret */
292       for (j = 0; j < n_ret_vals; ++j) {
293         ir_node *pred = get_irn_n(ret, j);
294
295         in[j] = (is_Phi(pred) && get_nodes_block(pred) == block) ? get_Phi_pred(pred, i) : pred;
296       }
297
298       new_ret = new_r_Return(irg, new_bl, in[0], n_ret_vals - 1, &in[1]);
299
300       if (! is_Bad(new_ret)) {
301         /*
302          * The newly created node might be bad, if we
303          * create it in a block with only Bad predecessors.
304          * In that case ignore this block.
305          *
306          * We could even kill the jmp then ...
307          */
308         if (can_move_ret(new_ret)) {
309           set_irn_link(new_ret, list);
310           list = new_ret;
311           ++n_rets;
312         }
313         else {
314           set_irn_link(new_ret, final);
315           final = new_ret;
316           ++n_finals;
317         }
318       }
319
320       /* remove the Jmp, we have placed a Return here */
321       exchange(jmp, new_r_Bad(irg));
322     }
323
324     /*
325      * if the memory of the old Return is a PhiM, remove it
326      * from the keep-alives, or it will keep the block which
327      * will crash the dominator algorithm.
328      */
329     phiM = get_Return_mem(ret);
330     if (is_Phi(phiM)) {
331       n = get_End_n_keepalives(end);
332       for (i = 0; i < n; ++i) {
333         if (get_End_keepalive(end, i) == phiM) {
334           set_End_keepalive(end, i, new_r_Bad(irg));
335           break;
336         }
337       }
338     }
339   }
340
341   /*
342    * Last step: Create a new endblock, with all nodes on the final
343    * list as predecessors.
344    */
345   in = alloca(sizeof(*in) * n_finals);
346
347   for (i = 0; final; ++i, final = get_irn_link(final))
348     in[i] = final;
349
350   exchange(endbl, new_r_Block(irg, n_finals, in));
351
352   /* the end block is not automatically skipped, so do it here */
353   set_irg_end_block(irg, skip_Id(get_irg_end_block(irg)));
354
355   /* Invalidate analysis information:
356    * Blocks become dead and new Returns were deleted, so dominator, outs and loop are inconsistent,
357    * trouts and callee-state should be still valid
358    */
359   set_irg_doms_inconsistent(irg);
360   set_irg_outs_inconsistent(irg);
361   set_irg_loopinfo_state(current_ir_graph, loopinfo_cf_inconsistent);
362 }