still buggy, but some typos fixed
[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;                     /**< number of bits in the destination mode */
40   ir_mode *s_mode;              /**< signed destination mode */
41   ir_mode *u_mode;              /**< unsigned destination mode */
42   int changes;                  /**< non-zero if the graph was changed */
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       /* Args, Load, Div, Mod */
53     case iro_Conv:
54       /* Hmm, maybe the Conv should be replaced */
55     case iro_Rot: {
56       ir_node *block = get_nodes_block(node);
57
58       if (get_irn_mode(node) != mode)
59         return new_r_Conv(current_ir_graph, block, node, mode);
60       else
61         return node;
62     }
63     default:
64       return node;
65   }
66 }
67
68 /**
69  * Add a Conv node where needed on input
70  */
71 static ir_node *fix_irn_input(opcode code, ir_node *block, ir_node *pred, ir_mode *mode)
72 {
73   switch (code) {
74     case iro_DivMod:
75     case iro_Div:
76     case iro_Mod:
77     case iro_Shr:
78     case iro_Shrs:
79     case iro_Rot:
80     case iro_Call:
81     case iro_Return: {
82       ir_mode *p_mode = get_irn_mode(pred);
83
84       if (p_mode != mode && mode_is_int(p_mode))
85         return new_r_Conv(current_ir_graph, block, pred, mode);
86       return pred;
87     }
88     default:
89       return pred;
90   }
91 }
92
93 /**
94  * fix the mode of the operations if possible
95  */
96 static void fix_mode(ir_node *n, ir_mode *mode)
97 {
98   opcode code = get_irn_opcode(n);
99
100   if (code == iro_Proj) {
101     code = get_irn_opcode(get_Proj_pred(n));
102   }
103
104   switch (code) {
105   case iro_Return:
106   case iro_Load:
107   case iro_Proj:
108   case iro_Call:
109   case iro_Conv:
110     return;
111   default:
112     set_irn_mode(n, mode);
113   }
114 }
115
116 /**
117  * walker for the mode conversion
118  */
119 static void do_mode_conv(ir_node *n, void *env)
120 {
121   walker_t *wenv = env;
122   ir_mode *mode  = get_irn_mode(n);
123   ir_node *block;
124   opcode code;
125
126   /* save the old mode, we need this info later */
127   set_irn_link(n, mode);
128
129   /* special case: fix the Return */
130   if (is_Return(n)) {
131     entity *ent = get_irg_entity(current_ir_graph);
132     ir_type *mt = get_entity_type(ent);
133     int i, n_ress = get_method_n_ress(mt);
134
135     mode  = mode_is_signed(mode) ? wenv->s_mode : wenv->u_mode;
136     block = get_nodes_block(n);
137     for (i = 0; i < n_ress; ++i) {
138       ir_node *pred = get_irn_n(n, i + 1);
139       ir_type *rt = get_method_res_type(mt, i);
140
141       if (is_atomic_type(rt)) {
142         mode = get_type_mode(rt);
143
144         if (mode != get_irn_mode(pred)) {
145           pred = fix_irn_input(iro_Return, block, pred, mode);
146
147           set_irn_n(n, i + 1, pred);
148         }
149       }
150     }
151
152     return;
153   }
154
155   /* convert only integer modes with less than 'bits' bits */
156   if (mode_is_int(mode) && get_mode_size_bits(mode) < wenv->bits && get_irn_op(n) != op_Conv) {
157     mode  = mode_is_signed(mode) ? wenv->s_mode : wenv->u_mode;
158
159     code = get_irn_opcode(n);
160
161     if (code == iro_Conv) {
162       /* formally, the was a convert from modeA to modeB here.
163        * So, the expression before the conv must have modeA. */
164       ir_node *pred = get_Conv_op(n);
165       ir_mode *modeA = get_irn_link(pred);
166
167       if (modeA != get_irn_mode(pred)) {
168         pred = new_r_Conv(current_ir_graph, get_nodes_block(pred), pred, modeA);
169         set_Conv_op(n, pred);
170       }
171     }
172     else if (code == iro_Proj) {
173       /* special case for Proj: we must fix it's pred */
174       ir_node *oper = get_Proj_pred(n);
175       int i, arity = get_irn_arity(oper);
176
177       code = get_irn_opcode(oper);
178       block = get_nodes_block(oper);
179
180       for (i = 0; i < arity; ++i) {
181         ir_node *pred = get_irn_n(oper, i);
182
183         pred = fix_irn_input(code, block, pred, mode);
184
185         set_irn_n(oper, i, pred);
186       }
187
188     }
189     else {
190       int i, arity = get_irn_arity(n);
191
192       block = get_nodes_block(n);
193       for (i = 0; i < arity; ++i) {
194         ir_node *pred = get_irn_n(n, i);
195
196         pred = fix_irn_output(pred, mode);
197         pred = fix_irn_input(code, block, pred, mode);
198
199         set_irn_n(n, i, pred);
200       }
201     }
202
203     fix_mode(n, mode);
204     wenv->changes = 1;
205   }
206
207   if (get_irn_op(n) == op_Conv) {
208     /* formally, the was a convert from modeA to modeB here.
209      * So, the expression before the conv must have modeA. */
210     ir_node *pred = get_Conv_op(n);
211     ir_mode *modeA = get_irn_link(pred);
212
213     if (modeA != get_irn_mode(pred)) {
214       pred = new_r_Conv(current_ir_graph, get_nodes_block(pred), pred, modeA);
215       set_Conv_op(n, pred);
216     }
217
218     /* old conv may now get useless */
219     if (get_irn_mode(n) == get_irn_mode(pred)) {
220       exchange(n, get_Conv_op(n));
221       wenv->changes = 1;
222     }
223   }
224 }
225
226 /*
227  * do the integer mode conversion
228  */
229 void arch_mode_conversion(ir_graph *irg, ir_mode *mode)
230 {
231   walker_t env;
232
233   assert(get_irg_phase_state(irg) != phase_building);
234
235   assert(mode_is_int(mode));
236
237   env.s_mode  = mode_is_signed(mode) ? mode: find_signed_mode(mode) ;
238   env.u_mode  = mode_is_signed(mode) ? find_unsigned_mode(mode) : mode;
239   env.bits    = get_mode_size_bits(mode);
240   env.changes = 0;
241
242   assert(env.s_mode && env.u_mode && "Could not find modes");
243
244   irg_walk_graph(irg, NULL, do_mode_conv, &env);
245
246   /* Handle graph state. We never change control flow. */
247   if (env.changes) {
248     set_irg_outs_inconsistent(current_ir_graph);
249   }
250 }