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