fix bugs in execfreq rework commit
[libfirm] / ir / be / betranshlp.c
1 /*
2  * Copyright (C) 1995-2010 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       be transform helper extracted from the ia32 backend.
23  * @author      Matthias Braun, Michael Beck
24  * @date        14.06.2007
25  */
26 #include "config.h"
27
28 #include "pdeq.h"
29 #include "irop_t.h"
30 #include "iropt_t.h"
31 #include "irnode_t.h"
32 #include "irgraph_t.h"
33 #include "ircons_t.h"
34 #include "irhooks.h"
35 #include "iredges.h"
36 #include "irouts.h"
37 #include "trouts.h"
38 #include "cgana.h"
39 #include "debug.h"
40 #include "execfreq_t.h"
41
42 #include "beirg.h"
43 #include "beabi.h"
44 #include "betranshlp.h"
45 #include "belive.h"
46 #include "benode.h"
47
48 typedef struct be_transform_env_t {
49         ir_graph *irg;         /**< The irg, the node should be created in */
50         waitq    *worklist;    /**< worklist of nodes that still need to be
51                                     transformed */
52         ir_node  *old_anchor;  /**< the old anchor node in the old irg */
53 } be_transform_env_t;
54
55
56 static be_transform_env_t env;
57
58 void be_set_transformed_node(ir_node *old_node, ir_node *new_node)
59 {
60         ir_graph *irg = get_irn_irg(old_node);
61
62         set_irn_link(old_node, new_node);
63         mark_irn_visited(old_node);
64         hook_dead_node_elim_subst(irg, old_node, new_node);
65 }
66
67 int be_is_transformed(const ir_node *node)
68 {
69         return irn_visited(node);
70 }
71
72 static inline ir_node *be_get_transformed_node(ir_node *old_node)
73 {
74         if (irn_visited(old_node)) {
75                 ir_node *new_node = (ir_node*)get_irn_link(old_node);
76                 assert(new_node != NULL);
77                 return new_node;
78         }
79         return NULL;
80 }
81
82 void be_duplicate_deps(ir_node *old_node, ir_node *new_node)
83 {
84         int i;
85         int deps = get_irn_deps(old_node);
86
87         for (i = 0; i < deps; ++i) {
88                 ir_node *dep     = get_irn_dep(old_node, i);
89                 ir_node *new_dep = be_transform_node(dep);
90
91                 add_irn_dep(new_node, new_dep);
92         }
93 }
94
95 void be_set_transform_function(ir_op *op, be_transform_func func)
96 {
97         /* shouldn't be assigned twice (except for exchanging the default
98          * be_duplicate_node entries) */
99         assert(op->ops.generic == NULL
100                         || op->ops.generic == (op_func) be_duplicate_node);
101         op->ops.generic = (op_func) func;
102 }
103
104 /**
105  * Transform helper for blocks.
106  */
107 static ir_node *transform_block(ir_node *node)
108 {
109         ir_graph *irg  = get_irn_irg(node);
110         dbg_info *dbgi = get_irn_dbg_info(node);
111         ir_node  *block;
112
113         block = new_ir_node(dbgi, irg, NULL, get_irn_op(node), get_irn_mode(node),
114                             get_irn_arity(node), get_irn_in(node) + 1);
115         copy_node_attr(irg, node, block);
116         block->node_nr = node->node_nr;
117
118         /* transfer execfreq value */
119         double execfreq = get_block_execfreq(node);
120         set_block_execfreq(block, execfreq);
121
122         /* put the preds in the worklist */
123         be_enqueue_preds(node);
124
125         return block;
126 }
127
128 static ir_node *transform_end(ir_node *node)
129 {
130         /* end has to be duplicated manually because we need a dynamic in array */
131         ir_graph *irg   = get_irn_irg(node);
132         dbg_info *dbgi  = get_irn_dbg_info(node);
133         ir_node  *block = be_transform_node(get_nodes_block(node));
134         int      i, arity;
135         ir_node  *new_end;
136
137         new_end = new_ir_node(dbgi, irg, block, op_End, mode_X, -1, NULL);
138         copy_node_attr(irg, node, new_end);
139         be_duplicate_deps(node, new_end);
140
141         set_irg_end(irg, new_end);
142
143         /* do not transform predecessors yet to keep the pre-transform
144          * phase from visiting all the graph */
145         arity = get_irn_arity(node);
146         for (i = 0; i < arity; ++i) {
147                 ir_node *in = get_irn_n(node, i);
148                 add_End_keepalive(new_end, in);
149         }
150         be_enqueue_preds(node);
151
152         return new_end;
153 }
154
155 void be_start_transform_setup(void)
156 {
157         ir_clear_opcodes_generic_func();
158
159         be_set_transform_function(op_Bad,         be_duplicate_node);
160         be_set_transform_function(op_be_Copy,     be_duplicate_node);
161         be_set_transform_function(op_be_CopyKeep, be_duplicate_node);
162         be_set_transform_function(op_be_IncSP,    be_duplicate_node);
163         be_set_transform_function(op_be_Keep,     be_duplicate_node);
164         be_set_transform_function(op_be_Return,   be_duplicate_node);
165         be_set_transform_function(op_be_Start,    be_duplicate_node);
166         be_set_transform_function(op_Block,       transform_block);
167         be_set_transform_function(op_End,         transform_end);
168         be_set_transform_function(op_NoMem,       be_duplicate_node);
169         be_set_transform_function(op_Pin,         be_duplicate_node);
170         be_set_transform_function(op_Start,       be_duplicate_node);
171         be_set_transform_function(op_Sync,        be_duplicate_node);
172 }
173
174 ir_node *be_duplicate_node(ir_node *node)
175 {
176         ir_node  *block = be_transform_node(get_nodes_block(node));
177         ir_graph *irg   = env.irg;
178         dbg_info *dbgi  = get_irn_dbg_info(node);
179         ir_mode  *mode  = get_irn_mode(node);
180         ir_op    *op    = get_irn_op(node);
181         ir_node  *new_node;
182         int      i, arity;
183
184         arity = get_irn_arity(node);
185         if (op->opar == oparity_dynamic) {
186                 new_node = new_ir_node(dbgi, irg, block, op, mode, -1, NULL);
187                 for (i = 0; i < arity; ++i) {
188                         ir_node *in = get_irn_n(node, i);
189                         in = be_transform_node(in);
190                         add_irn_n(new_node, in);
191                 }
192         } else {
193                 ir_node **ins = ALLOCAN(ir_node*, arity);
194                 for (i = 0; i < arity; ++i) {
195                         ir_node *in = get_irn_n(node, i);
196                         ins[i] = be_transform_node(in);
197                 }
198
199                 new_node = new_ir_node(dbgi, irg, block, op, mode, arity, ins);
200         }
201
202         copy_node_attr(irg, node, new_node);
203         be_duplicate_deps(node, new_node);
204
205         new_node->node_nr = node->node_nr;
206         return new_node;
207 }
208
209 ir_node *be_transform_node(ir_node *node)
210 {
211         ir_op             *op;
212         ir_node           *new_node = be_get_transformed_node(node);
213         be_transform_func *transform;
214
215         if (new_node != NULL)
216                 return new_node;
217
218         DEBUG_ONLY(be_set_transformed_node(node, NULL);)
219
220         op = get_irn_op(node);
221         if (op->ops.generic == NULL) {
222                 panic("No transform function registered for node %+F.", node);
223         }
224         transform = (be_transform_func *)op->ops.generic;
225
226         new_node = transform(node);
227         assert(new_node != NULL);
228
229         be_set_transformed_node(node, new_node);
230         return new_node;
231 }
232
233 void be_enqueue_preds(ir_node *node)
234 {
235         int i, arity;
236
237         /* put the preds in the worklist */
238         arity = get_irn_arity(node);
239         for (i = 0; i < arity; ++i) {
240                 ir_node *pred = get_irn_n(node, i);
241                 pdeq_putr(env.worklist, pred);
242         }
243 }
244
245 /**
246  * Rewire nodes which are potential loops (like Phis) to avoid endless loops.
247  */
248 static void fix_loops(ir_node *node)
249 {
250         int i, arity;
251         int changed;
252
253         assert(node_is_in_irgs_storage(env.irg, node));
254
255         if (irn_visited_else_mark(node))
256                 return;
257
258         changed = 0;
259         if (! is_Block(node)) {
260                 ir_node *block     = get_nodes_block(node);
261                 ir_node *new_block = (ir_node*)get_irn_link(block);
262
263                 if (new_block != NULL) {
264                         set_nodes_block(node, new_block);
265                         block = new_block;
266                         changed = 1;
267                 }
268
269                 fix_loops(block);
270         }
271
272         arity = get_irn_arity(node);
273         for (i = 0; i < arity; ++i) {
274                 ir_node *in = get_irn_n(node, i);
275                 ir_node *nw = (ir_node*)get_irn_link(in);
276
277                 if (nw != NULL && nw != in) {
278                         set_irn_n(node, i, nw);
279                         in = nw;
280                         changed = 1;
281                 }
282
283                 fix_loops(in);
284         }
285         /* fix proj block */
286         if (is_Proj(node)) {
287                 set_nodes_block(node, get_nodes_block(get_Proj_pred(node)));
288                 changed = 1;
289         }
290
291         arity = get_irn_deps(node);
292         for (i = 0; i < arity; ++i) {
293                 ir_node *in = get_irn_dep(node, i);
294                 ir_node *nw = (ir_node*)get_irn_link(in);
295
296                 if (nw != NULL && nw != in) {
297                         set_irn_dep(node, i, nw);
298                         in = nw;
299                         changed = 1;
300                 }
301
302                 fix_loops(in);
303         }
304
305         if (changed) {
306                 identify_remember(node);
307         }
308 }
309
310 ir_node *be_pre_transform_node(ir_node *place)
311 {
312         if (place == NULL)
313                 return NULL;
314
315         return be_transform_node(place);
316 }
317
318 static void pre_transform_anchor(ir_graph *irg, int anchor)
319 {
320         ir_node *old_anchor_node = get_irn_n(env.old_anchor, anchor);
321         ir_node *transformed     = be_transform_node(old_anchor_node);
322         set_irg_anchor(irg, anchor, transformed);
323 }
324
325 /**
326  * Transforms all nodes. Deletes the old obstack and creates a new one.
327  */
328 static void transform_nodes(ir_graph *irg, arch_pretrans_nodes *pre_transform)
329 {
330         int       i;
331         ir_node  *old_end, *new_anchor;
332
333         hook_dead_node_elim(irg, 1);
334
335         inc_irg_visited(irg);
336
337         env.irg        = irg;
338         env.worklist   = new_waitq();
339         env.old_anchor = irg->anchor;
340
341         old_end = get_irg_end(irg);
342
343         /* put all anchor nodes in the worklist */
344         for (i = get_irg_n_anchors(irg) - 1; i >= 0; --i) {
345                 ir_node *anchor = get_irg_anchor(irg, i);
346
347                 if (anchor == NULL)
348                         continue;
349                 waitq_put(env.worklist, anchor);
350         }
351
352         new_anchor  = new_r_Anchor(irg);
353         irg->anchor = new_anchor;
354
355         /* pre transform some anchors (so they are available in the other transform
356          * functions) */
357         pre_transform_anchor(irg, anchor_no_mem);
358         pre_transform_anchor(irg, anchor_end_block);
359         pre_transform_anchor(irg, anchor_end);
360         pre_transform_anchor(irg, anchor_start_block);
361         pre_transform_anchor(irg, anchor_start);
362         pre_transform_anchor(irg, anchor_frame);
363
364         if (pre_transform)
365                 pre_transform();
366
367         /* process worklist (this should transform all nodes in the graph) */
368         while (! waitq_empty(env.worklist)) {
369                 ir_node *node = (ir_node*)waitq_get(env.worklist);
370                 be_transform_node(node);
371         }
372
373         /* fix loops and set new anchors*/
374         inc_irg_visited(irg);
375         for (i = get_irg_n_anchors(irg) - 1; i >= 0; --i) {
376                 ir_node *anchor = get_irn_n(env.old_anchor, i);
377
378                 if (anchor == NULL)
379                         continue;
380
381                 anchor = (ir_node*)get_irn_link(anchor);
382                 fix_loops(anchor);
383                 set_irn_n(new_anchor, i, anchor);
384         }
385
386         del_waitq(env.worklist);
387         free_End(old_end);
388         hook_dead_node_elim(irg, 0);
389 }
390
391 void be_transform_graph(ir_graph *irg, arch_pretrans_nodes *func)
392 {
393         ir_graph *old_current_ir_graph = current_ir_graph;
394         struct obstack *old_obst = NULL;
395         struct obstack *new_obst = NULL;
396
397         current_ir_graph = irg;
398
399         /* create a new obstack */
400         old_obst = irg->obst;
401         new_obst = XMALLOC(struct obstack);
402         obstack_init(new_obst);
403         irg->obst = new_obst;
404         irg->last_node_idx = 0;
405
406         free_vrp_data(irg);
407
408         /* create new value table for CSE */
409         new_identities(irg);
410
411         /* do the main transformation */
412         transform_nodes(irg, func);
413
414         /* free the old obstack */
415         obstack_free(old_obst, 0);
416         xfree(old_obst);
417
418         /* restore state */
419         current_ir_graph = old_current_ir_graph;
420
421         /* most analysis info is wrong after transformation */
422         be_invalidate_live_chk(irg);
423         confirm_irg_properties(irg, IR_GRAPH_PROPERTIES_NONE);
424
425         /* recalculate edges */
426         edges_activate(irg);
427 }