- fix most of the -Wunreachable-code and -Wlogical-op warnings
[libfirm] / ir / ir / irgmod.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    Support for ir graph modification.
23  * @author   Martin Trapp, Christian Schaefer, Goetz Lindenmaier
24  * @version  $Id$
25  */
26 #include "config.h"
27
28 #include "irvrfy.h"
29 #include "irflag_t.h"
30 #include "irgwalk.h"
31 #include "irnode_t.h"
32 #include "irgraph_t.h"
33 #include "irgmod.h"
34 #include "array.h"
35 #include "ircons.h"
36 #include "irhooks.h"
37 #include "iredges_t.h"
38 #include "irtools.h"
39 #include "error.h"
40
41 /**
42  * Turns a node into a "useless" Tuple.  The Tuple just forms a tuple
43  * from several inputs.
44  * This is useful if a node returning a tuple is removed, but the Projs
45  * extracting values from the tuple are not available.
46  */
47 void turn_into_tuple(ir_node *node, int arity)
48 {
49         assert(node);
50         set_irn_op(node, op_Tuple);
51         if (get_irn_arity(node) == arity) {
52                 /* keep old array */
53         } else {
54                 ir_graph *irg = get_irn_irg(node);
55                 ir_node *block = get_nodes_block(node);
56                 edges_node_deleted(node, irg);
57                 /* Allocate new array, don't free old in_array, it's on the obstack. */
58                 node->in = NEW_ARR_D(ir_node *, irg->obst, arity+1);
59                 /* clear the new in array, else edge_notify tries to delete garbage */
60                 memset(node->in, 0, (arity+1) * sizeof(node->in[0]));
61                 /* set the block back */
62                 set_nodes_block(node, block);
63         }
64 }
65
66 /**
67  * Insert irnode `new' in place of irnode `old'
68  * Since `new' may be bigger than `old' replace `old'
69  * by an op_Id which is smaller than everything.
70  */
71 void exchange(ir_node *old, ir_node *nw)
72 {
73         ir_graph *irg;
74
75         assert(old && nw);
76         assert(old != nw && "Exchanging node with itself is not allowed");
77
78         irg = get_irn_irg(old);
79         assert(irg == get_irn_irg(nw) && "New node must be in same irg as old node");
80
81         hook_replace(old, nw);
82
83         /*
84          * If new outs are on, we can skip the id node creation and reroute
85          * the edges from the old node to the new directly.
86          */
87         if (edges_activated(irg)) {
88                 /* copy all dependencies from old to new */
89                 add_irn_deps(nw, old);
90
91                 edges_reroute(old, nw, irg);
92                 edges_reroute_kind(old, nw, EDGE_KIND_DEP, irg);
93                 edges_node_deleted(old, irg);
94                 old->op = op_Bad;
95         } else {
96                 /* Else, do it the old-fashioned way. */
97                 ir_node *block;
98
99                 hook_turn_into_id(old);
100
101                 block = old->in[0];
102                 if (! block) {
103                         block = is_Block(nw) ? nw : get_nodes_block(nw);
104
105                         if (! block) {
106                                 panic("cannot find legal block for id");
107                         }
108                 }
109
110                 if (get_irn_op(old)->opar == oparity_dynamic) {
111                         DEL_ARR_F(get_irn_in(old));
112                 }
113
114                 old->op    = op_Id;
115                 old->in    = NEW_ARR_D (ir_node *, irg->obst, 2);
116                 old->in[0] = block;
117                 old->in[1] = nw;
118         }
119 }
120
121 /*--------------------------------------------------------------------*/
122 /*  Functionality for collect_phis                                    */
123 /*--------------------------------------------------------------------*/
124
125 /**
126  * Walker: links all Phi nodes to their Blocks lists,
127  *         all Proj nodes to there predecessors and all
128  *         partBlocks to there MacroBlock header.
129  */
130 static void collect_phiprojs_walker(ir_node *n, void *env)
131 {
132         ir_node *pred;
133         (void) env;
134
135         if (is_Phi(n)) {
136                 ir_node *block = get_nodes_block(n);
137                 add_Block_phi(block, n);
138         } else if (is_Proj(n)) {
139                 pred = n;
140                 do {
141                         pred = get_Proj_pred(pred);
142                 } while (is_Proj(pred));
143
144                 set_irn_link(n, get_irn_link(pred));
145                 set_irn_link(pred, n);
146         } else if (is_Block(n)) {
147                 ir_node *mbh = get_Block_MacroBlock(n);
148
149                 if (mbh != n) {
150                         set_irn_link(n, get_irn_link(mbh));
151                         set_irn_link(mbh, n);
152                 }
153         }
154 }
155
156 void collect_phiprojs(ir_graph *irg)
157 {
158         assert((ir_resources_reserved(irg) & (IR_RESOURCE_IRN_LINK|IR_RESOURCE_PHI_LIST)) ==
159                 (IR_RESOURCE_IRN_LINK|IR_RESOURCE_PHI_LIST));
160         irg_walk_graph(irg, firm_clear_node_and_phi_links, collect_phiprojs_walker, NULL);
161 }
162
163 /*--------------------------------------------------------------------*/
164 /*  Functionality for part_block                                      */
165 /*--------------------------------------------------------------------*/
166
167 /**
168  * Moves node and all predecessors of node from from_bl to to_bl.
169  * Does not move predecessors of Phi nodes (or block nodes).
170  */
171 static void move(ir_node *node, ir_node *from_bl, ir_node *to_bl)
172 {
173         int i, arity;
174
175         /* move this node */
176         set_nodes_block(node, to_bl);
177
178         /* move its Projs */
179         if (get_irn_mode(node) == mode_T) {
180                 ir_node *proj = get_irn_link(node);
181                 while (proj) {
182                         if (get_nodes_block(proj) == from_bl)
183                                 set_nodes_block(proj, to_bl);
184                         proj = get_irn_link(proj);
185                 }
186         }
187
188         /* recursion ... */
189         if (is_Phi(node))
190                 return;
191
192         arity = get_irn_arity(node);
193         for (i = 0; i < arity; i++) {
194                 ir_node *pred = get_irn_n(node, i);
195                 if (get_nodes_block(pred) == from_bl)
196                         move(pred, from_bl, to_bl);
197         }
198 }
199
200 void part_block(ir_node *node)
201 {
202         ir_node *new_block, *old_block, *mbh;
203         ir_node *phi, *jmp, *next, *block;
204         ir_graph *rem = current_ir_graph;
205
206         /* Turn off optimizations so that blocks are not merged again. */
207         int rem_opt = get_opt_optimize();
208         set_optimize(0);
209
210         current_ir_graph = get_irn_irg(node);
211
212         /* Transform the control flow */
213         old_block = get_nodes_block(node);
214         mbh       = get_Block_MacroBlock(old_block);
215         new_block = new_Block(get_Block_n_cfgpreds(old_block),
216                               get_Block_cfgpred_arr(old_block));
217
218         if (mbh != old_block) {
219                 /* we splitting a partBlock */
220                 set_Block_MacroBlock(new_block, mbh);
221         } else {
222                 /* we are splitting a header: this creates a new header */
223                 set_Block_MacroBlock(new_block, new_block);
224         }
225
226         /* create a jump from new_block to old_block, which is now the lower one */
227         jmp = new_r_Jmp(new_block);
228         set_irn_in(old_block, 1, &jmp);
229
230         /* move node and its predecessors to new_block */
231         move(node, old_block, new_block);
232
233         /* move Phi nodes to new_block */
234         phi = get_Block_phis(old_block);
235         set_Block_phis(new_block, phi);
236         set_Block_phis(old_block, NULL);
237         while (phi) {
238                 set_nodes_block(phi, new_block);
239                 phi = get_Phi_next(phi);
240         }
241
242         /* rewire partBlocks: This is necessary, because old_block is a new MacroBlock
243            header now */
244         if (mbh != old_block) {
245                 ir_node *list = NULL;
246
247                 /* move blocks from mbh to old_block if old_block dominates them */
248                 block = get_irn_link(mbh);
249
250                 /* mbh's list will be rebuild */
251                 set_irn_link(mbh, NULL);
252                 /* old_block is a new mbh */
253                 set_Block_MacroBlock(old_block, old_block);
254
255                 /* note that we must splice the list of partBlock here */
256                 for (; block != NULL; block = next) {
257                         ir_node *curr = block;
258                         assert(is_Block(curr));
259
260                         next = get_irn_link(block);
261
262                         if (block == old_block) {
263                                 /* this effectively removed old_block from mbh's list */
264                                 continue;
265                         }
266
267                         assert(get_Block_MacroBlock(curr) == mbh);
268
269                         for (;;) {
270                                 if (curr == old_block) {
271                                         /* old_block dominates the block, so old_block will be
272                                            the new macro block header */
273                                         set_Block_MacroBlock(block, old_block);
274                                         set_irn_link(block, list);
275                                         list = block;
276                                         break;
277                                 }
278                                 if (curr == mbh) {
279                                         /* leave it in the mbh */
280                                         set_irn_link(block, get_irn_link(mbh));
281                                         set_irn_link(mbh, block);
282                                         break;
283                                 }
284
285                                 assert(get_Block_n_cfgpreds(curr) == 1);
286                                 curr = get_Block_cfgpred_block(curr, 0);
287                         }
288                 }
289                 /* beware: do NOT directly manipulate old_block's list, as old_block is
290                    in mbh's list and this would destroy the list! */
291                 set_irn_link(old_block, list);
292
293                 /* finally add new_block to mbh's list */
294                 set_irn_link(new_block, get_irn_link(mbh));
295                 set_irn_link(mbh, new_block);
296         } else {
297                 /* old_block is the mbh, as well as new_block */
298                 set_Block_MacroBlock(new_block, new_block);
299         }
300
301         set_optimize(rem_opt);
302         current_ir_graph = rem;
303 }
304
305 /* kill a node by setting its predecessors to Bad and finally exchange the node by Bad itself. */
306 void kill_node(ir_node *node)
307 {
308         ir_graph *irg = get_irn_irg(node);
309         ir_node *bad = get_irg_bad(irg);
310         int i;
311
312         for (i = get_irn_arity(node) - 1; i >= -1; --i) {
313                 set_irn_n(node, i, bad);
314         }
315         exchange(node, bad);
316 }