Before deconving a node, make sure it is a downconv.
[libfirm] / ir / opt / convopt.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   conv node optimisation
23  * @author  Matthias Braun, Christoph Mallon
24  * @version $Id$
25  *
26  * Try to minimize the number of conv nodes by changing modes of operations.
27  * The typical example is the following structure:
28  *    (some node mode_Hs)
29  *            |                                       (some node_Hs)
30  *         Conv Is                                          |
31  *            |                                          Add Hs
32  *          Add Is            gets transformed to           |
33  *            |
34  *         Conv Hs
35  *
36  * TODO: * try to optimize cmp modes
37  *       * decide when it is useful to move the convs through phis
38  */
39 #include "config.h"
40
41 #include "iroptimize.h"
42
43 #include <assert.h>
44 #include "debug.h"
45 #include "ircons.h"
46 #include "irgmod.h"
47 #include "irgopt.h"
48 #include "irnode_t.h"
49 #include "iredges_t.h"
50 #include "irgwalk.h"
51 #include "irprintf.h"
52
53 DEBUG_ONLY(static firm_dbg_module_t *dbg);
54
55 static inline int imin(int a, int b) { return a < b ? a : b; }
56
57 static
58 int is_optimizable_node(const ir_node *node)
59 {
60         switch (get_irn_opcode(node)) {
61                 case iro_Add:
62                 case iro_And:
63                 case iro_Eor:
64                 case iro_Minus:
65                 case iro_Mul:
66                 case iro_Not:
67                 case iro_Or:
68                 case iro_Phi:
69                 case iro_Shl:
70                 case iro_Sub:
71                         return 1;
72
73                 default: return 0;
74         }
75 }
76
77 static tarval* conv_const_tv(const ir_node* cnst, ir_mode* dest_mode)
78 {
79         return tarval_convert_to(get_Const_tarval(cnst), dest_mode);
80 }
81
82 static
83 int is_downconv(ir_mode *src_mode, ir_mode *dest_mode)
84 {
85         return
86                 mode_is_int(src_mode) &&
87                 mode_is_int(dest_mode) &&
88                 get_mode_size_bits(dest_mode) <= get_mode_size_bits(src_mode);
89 }
90
91 static
92 int get_conv_costs(const ir_node *node, ir_mode *dest_mode)
93 {
94         ir_mode *mode = get_irn_mode(node);
95         size_t arity;
96         size_t i;
97         int costs;
98
99         if (mode == dest_mode)
100                 return 0;
101
102         if (is_Const(node)) {
103                 /* TODO tarval module is incomplete and can't convert floats to ints */
104                 return conv_const_tv(node, dest_mode) == tarval_bad ? 1 : 0;
105         }
106
107         if (is_Conv(node) &&
108                         is_downconv(mode, dest_mode) &&
109                         get_irn_mode(get_Conv_op(node)) == dest_mode) {
110                 return -1;
111         }
112
113         if (get_irn_n_edges(node) > 1) {
114                 DB((dbg, LEVEL_3, "multi outs at %+F\n", node));
115                 return 1;
116         }
117
118 #if 0 // TODO
119         /* Take the minimum of the conversion costs for Phi predecessors as only one
120          * branch is actually executed at a time */
121         if (is_Phi(node)) {
122                 size_t i;
123                 size_t arity = get_Phi_n_preds(node);
124                 int costs;
125
126                 costs = get_conv_costs(get_Phi_pred(node, 0), dest_mode);
127                 for (i = 1; i < arity; ++i) {
128                         ir_node *pred = get_Phi_pred(node, i);
129                         int c = get_conv_costs(pred, dest_mode);
130                         if (c < costs) costs = c;
131                 }
132
133                 return costs;
134         }
135 #endif
136
137         if (!is_downconv(mode, dest_mode)) {
138                 return 1;
139         }
140
141         if (is_Conv(node)) {
142                 return get_conv_costs(get_Conv_op(node), dest_mode) - 1;
143         }
144
145         if (!is_optimizable_node(node)) {
146                 return 1;
147         }
148
149         costs = 0;
150         // The shift count does not participate in the conv optimisation
151         arity = is_Shl(node) ? 1 : get_irn_arity(node);
152         for (i = 0; i < arity; ++i) {
153                 ir_node *pred = get_irn_n(node, i);
154                 costs += imin(get_conv_costs(pred, dest_mode), 1);
155         }
156
157         return costs;
158 }
159
160 static ir_node *place_conv(ir_node *node, ir_mode *dest_mode)
161 {
162         ir_node *block = get_nodes_block(node);
163         ir_node *conv = new_r_Conv(current_ir_graph, block, node, dest_mode);
164         return conv;
165 }
166
167 static
168 ir_node *conv_transform(ir_node *node, ir_mode *dest_mode)
169 {
170         ir_mode *mode = get_irn_mode(node);
171         size_t   arity;
172         size_t   i;
173
174         if (mode == dest_mode)
175                 return node;
176
177         if (is_Const(node)) {
178                 /* TODO tarval module is incomplete and can't convert floats to ints */
179                 tarval *tv = conv_const_tv(node, dest_mode);
180                 if (tv == tarval_bad) {
181                         return place_conv(node, dest_mode);
182                 } else {
183                         return new_Const(tv);
184                 }
185         }
186
187         if (is_Conv(node) &&
188                         is_downconv(mode, dest_mode) &&
189                         get_irn_mode(get_Conv_op(node)) == dest_mode) {
190                 return get_Conv_op(node);
191         }
192
193         if (get_irn_n_edges(node) > 1) {
194                 return place_conv(node, dest_mode);
195         }
196
197         if (!is_downconv(mode, dest_mode)) {
198                 return place_conv(node, dest_mode);
199         }
200
201         if (is_Conv(node)) {
202                 return conv_transform(get_Conv_op(node), dest_mode);
203         }
204
205         if (!is_optimizable_node(node)) {
206                 return place_conv(node, dest_mode);
207         }
208
209         // The shift count does not participate in the conv optimisation
210         arity = is_Shl(node) ? 1 : get_irn_arity(node);
211         for (i = 0; i < arity; i++) {
212                 ir_node *pred = get_irn_n(node, i);
213                 ir_node *transformed;
214                 if (get_conv_costs(pred, dest_mode) > 0) {
215                         transformed = place_conv(pred, dest_mode);
216                 } else {
217                         transformed = conv_transform(pred, dest_mode);
218                 }
219                 set_irn_n(node, i, transformed);
220         }
221         set_irn_mode(node, dest_mode);
222         return node;
223 }
224
225 /* TODO, backends (at least ia32) can't handle it at the moment,
226    and it's probably not more efficient on most archs */
227 #if 0
228 static
229 void try_optimize_cmp(ir_node *node)
230 {
231         ir_node *left  = get_Cmp_left(node);
232         ir_node *right = get_Cmp_right(node);
233         ir_node *conv  = NULL;
234
235         if(is_downconv
236 }
237 #endif
238
239 static char changed;
240
241 static
242 void conv_opt_walker(ir_node *node, void *data)
243 {
244         ir_node *transformed;
245         ir_node *pred;
246         ir_mode *pred_mode;
247         ir_mode *mode;
248         int costs;
249         (void) data;
250
251 #if 0
252         if(is_Cmp(node)) {
253                 try_optimize_cmp(node);
254                 return;
255         }
256 #endif
257
258         if (!is_Conv(node))
259                 return;
260
261         pred      = get_Conv_op(node);
262         mode      = get_irn_mode(node);
263         pred_mode = get_irn_mode(pred);
264
265         if (mode_is_reference(mode) || mode_is_reference(pred_mode))
266                 return;
267
268         if (!is_Phi(pred) && !is_downconv(pred_mode, mode))
269                 return;
270
271         /* - 1 for the initial conv */
272         costs = get_conv_costs(pred, mode) - 1;
273         DB((dbg, LEVEL_2, "Costs for %+F -> %+F: %d\n", node, pred, costs));
274         if (costs > 0) return;
275
276         transformed = conv_transform(pred, mode);
277         if (node != transformed) {
278                 exchange(node, transformed);
279                 changed = 1;
280         }
281 }
282
283 int conv_opt(ir_graph *irg)
284 {
285         char invalidate = 0;
286         FIRM_DBG_REGISTER(dbg, "firm.opt.conv");
287
288         DB((dbg, LEVEL_1, "===> Performing conversion optimization on %+F\n", irg));
289
290         edges_assure(irg);
291         do {
292                 changed = 0;
293                 irg_walk_graph(irg, NULL, conv_opt_walker, NULL);
294                 local_optimize_graph(irg);
295                 invalidate |= changed;
296         } while (changed);
297
298         if (invalidate) {
299                 set_irg_outs_inconsistent(irg);
300         }
301         return invalidate;
302 }