added is_Add(), is_Sub()
[libfirm] / ir / arch / modeconv.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    integer mode conversion
23  * @author   Michael Beck
24  * @version  $Id$
25  * @summary
26  *  Contains the mode conversion for architectures that did not support lesser
27  *  integer modes. Converts all Op(mode_l) into Op(mode) operations by adding
28  *  conversions were needed. These Conv operations must be implemented in the
29  *  backend as bit-reducing ops.
30  */
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34
35 # include "irnode_t.h"
36 # include "irgraph_t.h"
37 # include "irmode_t.h"
38 # include "iropt_t.h"
39 # include "ircons_t.h"
40 # include "irgmod.h"
41 # include "dbginfo.h"
42 # include "iropt_dbg.h"
43 # include "irflag_t.h"
44 # include "irgwalk.h"
45 # include "modeconv.h"
46 # include "firmstat.h"
47
48 typedef struct _walker_t {
49   int bits;                     /**< number of bits in the destination mode */
50   ir_mode *s_mode;              /**< signed destination mode */
51   ir_mode *u_mode;              /**< unsigned destination mode */
52   int changes;                  /**< non-zero if the graph was changed */
53 } walker_t;
54
55 /**
56  * Add a Conv node where needed on output
57  */
58 static ir_node *fix_irn_output(ir_node *node, ir_mode *mode)
59 {
60   switch (get_irn_opcode(node)) {
61     case iro_Proj:
62       /* Args, Load, Div, Mod */
63     case iro_Conv:
64       /* Hmm, maybe the Conv should be replaced */
65     case iro_Rot: {
66       ir_node *block = get_nodes_block(node);
67
68       if (get_irn_mode(node) != mode)
69         return new_r_Conv(current_ir_graph, block, node, mode);
70       else
71         return node;
72     }
73     default:
74       return node;
75   }
76 }
77
78 /**
79  * Add a Conv node where needed on input
80  */
81 static ir_node *fix_irn_input(ir_opcode code, ir_node *block, ir_node *pred, ir_mode *mode)
82 {
83   switch (code) {
84     case iro_DivMod:
85     case iro_Div:
86     case iro_Mod:
87     case iro_Shr:
88     case iro_Shrs:
89     case iro_Rot:
90     case iro_Call:
91     case iro_Return: {
92       ir_mode *p_mode = get_irn_mode(pred);
93
94       if (p_mode != mode && mode_is_int(p_mode))
95         return new_r_Conv(current_ir_graph, block, pred, mode);
96       return pred;
97     }
98     default:
99       return pred;
100   }
101 }
102
103 /**
104  * fix the mode of the operations if possible
105  */
106 static void fix_mode(ir_node *n, ir_mode *mode)
107 {
108   ir_opcode code = get_irn_opcode(n);
109
110   if (code == iro_Proj) {
111     code = get_irn_opcode(get_Proj_pred(n));
112   }
113
114   switch (code) {
115   case iro_Return:
116   case iro_Load:
117   case iro_Proj:
118   case iro_Call:
119   case iro_Conv:
120     return;
121   default:
122     set_irn_mode(n, mode);
123   }
124 }
125
126 /**
127  * walker for the mode conversion
128  */
129 static void do_mode_conv(ir_node *n, void *env)
130 {
131   walker_t *wenv = env;
132   ir_mode *mode  = get_irn_mode(n);
133   ir_node *block;
134   ir_opcode code;
135
136   /* save the old mode, we need this info later */
137   set_irn_link(n, mode);
138
139   /* special case: fix the Return */
140   if (is_Return(n)) {
141     ir_entity *ent = get_irg_entity(current_ir_graph);
142     ir_type *mt    = get_entity_type(ent);
143     int i, n_ress  = get_method_n_ress(mt);
144
145     mode  = mode_is_signed(mode) ? wenv->s_mode : wenv->u_mode;
146     block = get_nodes_block(n);
147     for (i = 0; i < n_ress; ++i) {
148       ir_node *pred = get_irn_n(n, i + 1);
149       ir_type *rt = get_method_res_type(mt, i);
150
151       if (is_atomic_type(rt)) {
152         mode = get_type_mode(rt);
153
154         if (mode != get_irn_mode(pred)) {
155           pred = fix_irn_input(iro_Return, block, pred, mode);
156
157           set_irn_n(n, i + 1, pred);
158         }
159       }
160     }
161
162     return;
163   }
164
165   /* convert only integer modes with less than 'bits' bits */
166   if (mode_is_int(mode) && get_mode_size_bits(mode) < wenv->bits && get_irn_op(n) != op_Conv) {
167     mode  = mode_is_signed(mode) ? wenv->s_mode : wenv->u_mode;
168
169     code = get_irn_opcode(n);
170
171     if (code == iro_Conv) {
172       /* formally, the was a convert from modeA to modeB here.
173        * So, the expression before the conv must have modeA. */
174       ir_node *pred = get_Conv_op(n);
175       ir_mode *modeA = get_irn_link(pred);
176
177       if (modeA != get_irn_mode(pred)) {
178         pred = new_r_Conv(current_ir_graph, get_nodes_block(pred), pred, modeA);
179         set_Conv_op(n, pred);
180       }
181     }
182     else if (code == iro_Proj) {
183       /* special case for Proj: we must fix it's pred */
184       ir_node *oper = get_Proj_pred(n);
185       int i, arity = get_irn_arity(oper);
186
187       code = get_irn_opcode(oper);
188       block = get_nodes_block(oper);
189
190       for (i = 0; i < arity; ++i) {
191         ir_node *pred = get_irn_n(oper, i);
192
193         pred = fix_irn_input(code, block, pred, mode);
194
195         set_irn_n(oper, i, pred);
196       }
197
198     }
199     else {
200       int i, arity = get_irn_arity(n);
201
202       block = get_nodes_block(n);
203       for (i = 0; i < arity; ++i) {
204         ir_node *pred = get_irn_n(n, i);
205
206         pred = fix_irn_output(pred, mode);
207         pred = fix_irn_input(code, block, pred, mode);
208
209         set_irn_n(n, i, pred);
210       }
211     }
212
213     fix_mode(n, mode);
214     wenv->changes = 1;
215   }
216
217   if (get_irn_op(n) == op_Conv) {
218     /* formally, the was a convert from modeA to modeB here.
219      * So, the expression before the conv must have modeA. */
220     ir_node *pred = get_Conv_op(n);
221     ir_mode *modeA = get_irn_link(pred);
222
223     if (modeA != get_irn_mode(pred)) {
224       pred = new_r_Conv(current_ir_graph, get_nodes_block(pred), pred, modeA);
225       set_Conv_op(n, pred);
226     }
227
228     /* old conv may now get useless */
229     if (get_irn_mode(n) == get_irn_mode(pred)) {
230       exchange(n, get_Conv_op(n));
231       wenv->changes = 1;
232     }
233   }
234 }
235
236 /*
237  * do the integer mode conversion
238  */
239 void arch_mode_conversion(ir_graph *irg, ir_mode *mode)
240 {
241   walker_t env;
242
243   assert(get_irg_phase_state(irg) != phase_building);
244
245   assert(mode_is_int(mode));
246
247   env.s_mode  = mode_is_signed(mode) ? mode: find_signed_mode(mode) ;
248   env.u_mode  = mode_is_signed(mode) ? find_unsigned_mode(mode) : mode;
249   env.bits    = get_mode_size_bits(mode);
250   env.changes = 0;
251
252   assert(env.s_mode && env.u_mode && "Could not find modes");
253
254   irg_walk_graph(irg, NULL, do_mode_conv, &env);
255
256   /* Handle graph state. We never change control flow. */
257   if (env.changes) {
258     set_irg_outs_inconsistent(current_ir_graph);
259   }
260 }