2 * Copyright (C) 1995-2007 University of Karlsruhe. All right reserved.
4 * This file is part of libFirm.
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.
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.
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
22 * @brief integer mode conversion
23 * @author Michael Beck
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.
35 # include "irnode_t.h"
36 # include "irgraph_t.h"
37 # include "irmode_t.h"
39 # include "ircons_t.h"
42 # include "iropt_dbg.h"
43 # include "irflag_t.h"
45 # include "modeconv.h"
46 # include "firmstat.h"
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 */
56 * Add a Conv node where needed on output
58 static ir_node *fix_irn_output(ir_node *node, ir_mode *mode)
60 switch (get_irn_opcode(node)) {
62 /* Args, Load, Div, Mod */
64 /* Hmm, maybe the Conv should be replaced */
66 ir_node *block = get_nodes_block(node);
68 if (get_irn_mode(node) != mode)
69 return new_r_Conv(current_ir_graph, block, node, mode);
79 * Add a Conv node where needed on input
81 static ir_node *fix_irn_input(ir_opcode code, ir_node *block, ir_node *pred, ir_mode *mode)
92 ir_mode *p_mode = get_irn_mode(pred);
94 if (p_mode != mode && mode_is_int(p_mode))
95 return new_r_Conv(current_ir_graph, block, pred, mode);
104 * fix the mode of the operations if possible
106 static void fix_mode(ir_node *n, ir_mode *mode)
108 ir_opcode code = get_irn_opcode(n);
110 if (code == iro_Proj) {
111 code = get_irn_opcode(get_Proj_pred(n));
122 set_irn_mode(n, mode);
127 * walker for the mode conversion
129 static void do_mode_conv(ir_node *n, void *env)
131 walker_t *wenv = env;
132 ir_mode *mode = get_irn_mode(n);
136 /* save the old mode, we need this info later */
137 set_irn_link(n, mode);
139 /* special case: fix the Return */
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);
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);
151 if (is_atomic_type(rt)) {
152 mode = get_type_mode(rt);
154 if (mode != get_irn_mode(pred)) {
155 pred = fix_irn_input(iro_Return, block, pred, mode);
157 set_irn_n(n, i + 1, pred);
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;
169 code = get_irn_opcode(n);
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);
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);
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);
187 code = get_irn_opcode(oper);
188 block = get_nodes_block(oper);
190 for (i = 0; i < arity; ++i) {
191 ir_node *pred = get_irn_n(oper, i);
193 pred = fix_irn_input(code, block, pred, mode);
195 set_irn_n(oper, i, pred);
200 int i, arity = get_irn_arity(n);
202 block = get_nodes_block(n);
203 for (i = 0; i < arity; ++i) {
204 ir_node *pred = get_irn_n(n, i);
206 pred = fix_irn_output(pred, mode);
207 pred = fix_irn_input(code, block, pred, mode);
209 set_irn_n(n, i, pred);
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);
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);
228 /* old conv may now get useless */
229 if (get_irn_mode(n) == get_irn_mode(pred)) {
230 exchange(n, get_Conv_op(n));
237 * do the integer mode conversion
239 void arch_mode_conversion(ir_graph *irg, ir_mode *mode)
243 assert(get_irg_phase_state(irg) != phase_building);
245 assert(mode_is_int(mode));
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);
252 assert(env.s_mode && env.u_mode && "Could not find modes");
254 irg_walk_graph(irg, NULL, do_mode_conv, &env);
256 /* Handle graph state. We never change control flow. */
258 set_irg_outs_inconsistent(current_ir_graph);