- be_peephole_IncSP_IncSP() must return the new node
[libfirm] / ir / be / bepeephole.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       Peephole optimisation framework keeps track of which registers contain which values
23  * @author      Matthias Braun
24  * @version     $Id$
25  */
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include "bepeephole.h"
31
32 #include "iredges_t.h"
33 #include "irgwalk.h"
34 #include "irprintf.h"
35 #include "irgmod.h"
36 #include "error.h"
37
38 #include "beirg_t.h"
39 #include "belive_t.h"
40 #include "bearch_t.h"
41 #include "benode_t.h"
42 #include "besched_t.h"
43 #include "bemodule.h"
44
45 DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
46
47 static const arch_env_t *arch_env;
48 static be_lv_t          *lv;
49 static ir_node          *current_node;
50 ir_node               ***register_values;
51
52 static void clear_reg_value(ir_node *node)
53 {
54         const arch_register_t       *reg;
55         const arch_register_class_t *cls;
56         unsigned                     reg_idx;
57         unsigned                     cls_idx;
58
59         if(!mode_is_data(get_irn_mode(node)))
60                 return;
61
62         reg     = arch_get_irn_register(arch_env, node);
63         if(reg == NULL) {
64                 panic("No register assigned at %+F\n", node);
65         }
66         if(arch_register_type_is(reg, virtual))
67                 return;
68         cls     = arch_register_get_class(reg);
69         reg_idx = arch_register_get_index(reg);
70         cls_idx = arch_register_class_index(cls);
71
72         //assert(register_values[cls_idx][reg_idx] != NULL);
73         DBG((dbg, LEVEL_1, "Clear Register %s\n", reg->name));
74         register_values[cls_idx][reg_idx] = NULL;
75 }
76
77 static void set_reg_value(ir_node *node)
78 {
79         const arch_register_t       *reg;
80         const arch_register_class_t *cls;
81         unsigned                     reg_idx;
82         unsigned                     cls_idx;
83
84         if(!mode_is_data(get_irn_mode(node)))
85                 return;
86
87         reg = arch_get_irn_register(arch_env, node);
88         if(reg == NULL) {
89                 panic("No register assigned at %+F\n", node);
90         }
91         if(arch_register_type_is(reg, virtual))
92                 return;
93         cls     = arch_register_get_class(reg);
94         reg_idx = arch_register_get_index(reg);
95         cls_idx = arch_register_class_index(cls);
96
97         DBG((dbg, LEVEL_1, "Set Register %s: %+F\n", reg->name, node));
98         register_values[cls_idx][reg_idx] = node;
99 }
100
101 static void clear_defs(ir_node *node)
102 {
103         /* clear values defined */
104         if(get_irn_mode(node) == mode_T) {
105                 const ir_edge_t *edge;
106                 foreach_out_edge(node, edge) {
107                         ir_node *proj = get_edge_src_irn(edge);
108                         clear_reg_value(proj);
109                 }
110         } else {
111                 clear_reg_value(node);
112         }
113 }
114
115 static void set_uses(ir_node *node)
116 {
117         int i, arity;
118
119         /* set values used */
120         arity = get_irn_arity(node);
121         for(i = 0; i < arity; ++i) {
122                 ir_node *in = get_irn_n(node, i);
123                 set_reg_value(in);
124         }
125 }
126
127 void be_peephole_before_exchange(const ir_node *old_node, ir_node *new_node)
128 {
129         const arch_register_t       *reg;
130         const arch_register_class_t *cls;
131         unsigned                     reg_idx;
132         unsigned                     cls_idx;
133
134         DBG((dbg, LEVEL_1, "About to exchange %+F with %+F\n", old_node, new_node));
135
136         if(old_node == current_node) {
137                 if(is_Proj(new_node)) {
138                         current_node = get_Proj_pred(new_node);
139                 } else {
140                         current_node = new_node;
141                 }
142         }
143
144         if(!mode_is_data(get_irn_mode(old_node)))
145                 return;
146
147         reg = arch_get_irn_register(arch_env, old_node);
148         if(reg == NULL) {
149                 panic("No register assigned at %+F\n", old_node);
150         }
151         cls     = arch_register_get_class(reg);
152         reg_idx = arch_register_get_index(reg);
153         cls_idx = arch_register_class_index(cls);
154
155         if(register_values[cls_idx][reg_idx] == old_node) {
156                 register_values[cls_idx][reg_idx] = new_node;
157         }
158
159         be_liveness_remove(lv, old_node);
160 }
161
162 void be_peephole_after_exchange(ir_node *new_node)
163 {
164         be_liveness_introduce(lv, new_node);
165 }
166
167 static void process_block(ir_node *block, void *data)
168 {
169         unsigned n_classes;
170         unsigned i;
171         int l;
172         (void) data;
173
174         /* construct initial register assignment */
175         n_classes = arch_env_get_n_reg_class(arch_env);
176         for(i = 0; i < n_classes; ++i) {
177                 const arch_register_class_t *cls    = arch_env_get_reg_class(arch_env, i);
178                 unsigned                     n_regs = arch_register_class_n_regs(cls);
179                 memset(register_values[i], 0, sizeof(ir_node*) * n_regs);
180         }
181
182         assert(lv->nodes && "live sets must be computed");
183         DBG((dbg, LEVEL_1, "\nProcessing block %+F (from end)\n", block));
184         be_lv_foreach(lv, block, be_lv_state_end, l) {
185                 ir_node *node = be_lv_get_irn(lv, block, l);
186                 set_reg_value(node);
187         }
188         DBG((dbg, LEVEL_1, "\nstart processing\n"));
189
190         /* walk the block from last insn to the first */
191         current_node = sched_last(block);
192         for( ; !sched_is_begin(current_node);
193                         current_node = sched_prev(current_node)) {
194                 ir_op             *op;
195                 ir_node           *last;
196                 peephole_opt_func  func;
197
198                 if(is_Phi(current_node))
199                         break;
200
201                 clear_defs(current_node);
202                 set_uses(current_node);
203
204                 op   = get_irn_op(current_node);
205                 func = (peephole_opt_func) op->ops.generic;
206                 if(func == NULL)
207                         continue;
208
209                 last = current_node;
210                 func(current_node);
211                 /* was the current node replaced? */
212                 if(current_node != last) {
213                         set_uses(current_node);
214                 }
215         }
216 }
217
218 /**
219  * Walk through the block schedule and skip all barrier nodes.
220  */
221 static void skip_barrier(ir_node *ret_blk, ir_graph *irg) {
222         ir_node *irn;
223
224         sched_foreach_reverse(ret_blk, irn) {
225                 if (be_is_Barrier(irn)) {
226                         const ir_edge_t *edge, *next;
227
228                         foreach_out_edge_safe(irn, edge, next) {
229                                 ir_node *proj = get_edge_src_irn(edge);
230                                 int      pn   = (int)get_Proj_proj(proj);
231                                 ir_node *pred = get_irn_n(irn, pn);
232
233                                 edges_reroute_kind(proj, pred, EDGE_KIND_NORMAL, irg);
234                                 edges_reroute_kind(proj, pred, EDGE_KIND_DEP, irg);
235                         }
236                         sched_remove(irn);
237                         kill_node(irn);
238                         break;
239                 }
240         }
241 }
242
243 /**
244  * Kill the Barrier nodes for better peephole optimization.
245  */
246 static void     kill_barriers(ir_graph *irg) {
247         ir_node *end_blk = get_irg_end_block(irg);
248         ir_node *start_blk;
249         int i;
250
251         /* skip the barrier on all return blocks */
252         for (i = get_Block_n_cfgpreds(end_blk) - 1; i >= 0; --i) {
253                 ir_node *be_ret = get_Block_cfgpred(end_blk, i);
254                 ir_node *ret_blk = get_nodes_block(be_ret);
255
256                 skip_barrier(ret_blk, irg);
257         }
258
259         /* skip the barrier on the start block */
260         start_blk = get_irg_start_block(irg);
261         skip_barrier(start_blk, irg);
262 }
263
264 /*
265  * Tries to optimize a beIncSp node with it's previous IncSP node.
266  * Must be run from a be_peephole_opt() context.
267  */
268 ir_node *be_peephole_IncSP_IncSP(ir_node *node)
269 {
270         int      pred_offs;
271         int      curr_offs;
272         int      offs;
273         ir_node *pred = be_get_IncSP_pred(node);
274
275         if (!be_is_IncSP(pred))
276                 return node;
277
278         if (get_irn_n_edges(pred) > 1)
279                 return node;
280
281         pred_offs = be_get_IncSP_offset(pred);
282         curr_offs = be_get_IncSP_offset(node);
283
284         if (pred_offs == BE_STACK_FRAME_SIZE_EXPAND) {
285                 if (curr_offs != BE_STACK_FRAME_SIZE_SHRINK) {
286                         return node;
287                 }
288                 offs = 0;
289         } else if (pred_offs == BE_STACK_FRAME_SIZE_SHRINK) {
290                 if (curr_offs != BE_STACK_FRAME_SIZE_EXPAND) {
291                         return node;
292                 }
293                 offs = 0;
294         } else if (curr_offs == BE_STACK_FRAME_SIZE_EXPAND ||
295                    curr_offs == BE_STACK_FRAME_SIZE_SHRINK) {
296                 return node;
297         } else {
298                 offs = curr_offs + pred_offs;
299         }
300
301         /* add node offset to pred and remove our IncSP */
302         be_set_IncSP_offset(pred, offs);
303
304         be_peephole_before_exchange(node, pred);
305
306         /* rewire dependency/data edges */
307         edges_reroute_kind(node, pred, EDGE_KIND_DEP, current_ir_graph);
308         edges_reroute(node, pred, current_ir_graph);
309         sched_remove(node);
310         be_kill_node(node);
311
312         be_peephole_after_exchange(pred);
313         return pred;
314 }
315
316 void be_peephole_opt(be_irg_t *birg)
317 {
318         ir_graph   *irg = be_get_birg_irg(birg);
319         unsigned n_classes;
320         unsigned i;
321
322         /* barrier nodes are used for register allocations. They hinders
323          * peephole optimizations, so remove them here. */
324         kill_barriers(irg);
325
326         /* we sometimes find BadE nodes in float apps like optest_float.c or
327          * kahansum.c for example... */
328         be_liveness_invalidate(birg->lv);
329         be_liveness_assure_sets(be_assure_liveness(birg));
330
331         arch_env = be_get_birg_arch_env(birg);
332         lv       = be_get_birg_liveness(birg);
333
334         n_classes = arch_env_get_n_reg_class(arch_env);
335         register_values = alloca(sizeof(register_values[0]) * n_classes);
336         for(i = 0; i < n_classes; ++i) {
337                 const arch_register_class_t *cls    = arch_env_get_reg_class(arch_env, i);
338                 unsigned                     n_regs = arch_register_class_n_regs(cls);
339                 register_values[i] = alloca(sizeof(ir_node*) * n_regs);
340         }
341
342         irg_block_walk_graph(irg, process_block, NULL, NULL);
343 }
344
345 void be_peephole_init(void)
346 {
347         clear_irp_opcodes_generic_func();
348 }
349
350 void be_init_peephole(void)
351 {
352         FIRM_DBG_REGISTER(dbg, "firm.be.peephole");
353 }
354
355 BE_REGISTER_MODULE_CONSTRUCTOR(be_init_spillbelady);