improve peephole API, do IncSP stuff as peephole opts, add IncSP -4 -> Pop opt
[libfirm] / ir / be / bepeephole.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  * @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 "error.h"
36
37 #include "beirg_t.h"
38 #include "belive_t.h"
39 #include "bearch_t.h"
40 #include "besched_t.h"
41
42 static const arch_env_t *arch_env;
43 static be_lv_t          *lv;
44 static ir_node          *current_node;
45 ir_node               ***register_values;
46
47 static void clear_reg_value(ir_node *node)
48 {
49         const arch_register_t       *reg;
50         const arch_register_class_t *cls;
51         unsigned                     reg_idx;
52         unsigned                     cls_idx;
53
54         if(!mode_is_data(get_irn_mode(node)))
55                 return;
56
57         reg     = arch_get_irn_register(arch_env, node);
58         if(reg == NULL) {
59                 panic("No register assigned at %+F\n", node);
60         }
61         if(arch_register_type_is(reg, virtual))
62                 return;
63         cls     = arch_register_get_class(reg);
64         reg_idx = arch_register_get_index(reg);
65         cls_idx = arch_register_class_index(cls);
66
67         //assert(register_values[cls_idx][reg_idx] != NULL);
68         register_values[cls_idx][reg_idx] = NULL;
69 }
70
71 static void set_reg_value(ir_node *node)
72 {
73         const arch_register_t       *reg;
74         const arch_register_class_t *cls;
75         unsigned                     reg_idx;
76         unsigned                     cls_idx;
77
78         if(!mode_is_data(get_irn_mode(node)))
79                 return;
80
81         reg = arch_get_irn_register(arch_env, node);
82         if(reg == NULL) {
83                 panic("No register assigned at %+F\n", node);
84         }
85         if(arch_register_type_is(reg, virtual))
86                 return;
87         cls     = arch_register_get_class(reg);
88         reg_idx = arch_register_get_index(reg);
89         cls_idx = arch_register_class_index(cls);
90
91 #ifdef DEBUG_libfirm
92         {
93                 ir_node *old_value = register_values[cls_idx][reg_idx];
94                 assert(old_value == NULL || old_value == node);
95         }
96 #endif
97         register_values[cls_idx][reg_idx] = node;
98 }
99
100 static void clear_defs(ir_node *node)
101 {
102         /* clear values defined */
103         if(get_irn_mode(node) == mode_T) {
104                 const ir_edge_t *edge;
105                 foreach_out_edge(node, edge) {
106                         ir_node *proj = get_edge_src_irn(edge);
107                         clear_reg_value(proj);
108                 }
109         } else {
110                 clear_reg_value(node);
111         }
112 }
113
114 static void set_uses(ir_node *node)
115 {
116         int i, arity;
117
118         /* set values used */
119         arity = get_irn_arity(node);
120         for(i = 0; i < arity; ++i) {
121                 ir_node *in = get_irn_n(node, i);
122                 set_reg_value(in);
123         }
124 }
125
126 void be_peephole_node_replaced(const ir_node *old_node, ir_node *new_node)
127 {
128         const arch_register_t       *reg;
129         const arch_register_class_t *cls;
130         unsigned                     reg_idx;
131         unsigned                     cls_idx;
132
133         be_liveness_remove(lv, old_node);
134         be_liveness_introduce(lv, new_node);
135
136         if(old_node == current_node)
137                 current_node = new_node;
138
139         if(!mode_is_data(get_irn_mode(old_node)))
140                 return;
141
142         reg = arch_get_irn_register(arch_env, old_node);
143         if(reg == NULL) {
144                 panic("No register assigned at %+F\n", old_node);
145         }
146         cls     = arch_register_get_class(reg);
147         reg_idx = arch_register_get_index(reg);
148         cls_idx = arch_register_class_index(cls);
149
150         if(register_values[cls_idx][reg_idx] == old_node) {
151                 register_values[cls_idx][reg_idx] = new_node;
152         }
153 }
154
155 static void process_block(ir_node *block, void *data)
156 {
157         arch_isa_t *isa = arch_env->isa;
158         unsigned n_classes;
159         unsigned i;
160         int l;
161         (void) data;
162
163         /* construct initial register assignment */
164         n_classes = arch_isa_get_n_reg_class(isa);
165         for(i = 0; i < n_classes; ++i) {
166                 const arch_register_class_t *cls    = arch_isa_get_reg_class(isa, i);
167                 unsigned                     n_regs = arch_register_class_n_regs(cls);
168                 memset(register_values[i], 0, sizeof(ir_node*) * n_regs);
169         }
170
171         assert(lv->nodes && "live sets must be computed");
172         be_lv_foreach(lv, block, be_lv_state_end, l) {
173                 ir_node *node = be_lv_get_irn(lv, block, l);
174                 set_reg_value(node);
175         }
176
177         /* walk the block from last insn to the first */
178         current_node = sched_last(block);
179         for( ; !sched_is_begin(current_node);
180                         current_node = sched_prev(current_node)) {
181                 ir_op             *op;
182                 ir_node           *last;
183                 peephole_opt_func  func;
184
185                 if(is_Phi(current_node))
186                         break;
187
188                 clear_defs(current_node);
189                 set_uses(current_node);
190
191                 op   = get_irn_op(current_node);
192                 func = (peephole_opt_func) op->ops.generic;
193                 if(func == NULL)
194                         continue;
195
196                 last = current_node;
197                 func(current_node);
198                 /* was the current node replaced? */
199                 if(current_node != last) {
200                         set_uses(current_node);
201                 }
202         }
203 }
204
205 void be_peephole_opt(be_irg_t *birg)
206 {
207         arch_isa_t *isa;
208         ir_graph   *irg = be_get_birg_irg(birg);
209         unsigned n_classes;
210         unsigned i;
211
212         /* we sometimes find BadE nodes in float apps like optest_float.c or
213          * kahansum.c for example... */
214         be_liveness_invalidate(birg->lv);
215         be_liveness_assure_sets(be_assure_liveness(birg));
216
217         arch_env = be_get_birg_arch_env(birg);
218         lv       = be_get_birg_liveness(birg);
219         isa      = arch_env->isa;
220
221         n_classes = arch_isa_get_n_reg_class(isa);
222         register_values = alloca(sizeof(register_values[0]) * n_classes);
223         for(i = 0; i < n_classes; ++i) {
224                 const arch_register_class_t *cls    = arch_isa_get_reg_class(isa, i);
225                 unsigned                     n_regs = arch_register_class_n_regs(cls);
226                 register_values[i] = alloca(sizeof(ir_node*) * n_regs);
227         }
228
229         irg_block_walk_graph(irg, process_block, NULL, NULL);
230 }
231
232 void be_peephole_init(void)
233 {
234         clear_irp_opcodes_generic_func();
235 }