cleanup: Remove unnecessary #include.
[libfirm] / ir / lower / lower_hl.c
1 /*
2  * This file is part of libFirm.
3  * Copyright (C) 2012 University of Karlsruhe.
4  */
5
6 /**
7  * @file
8  * @brief   Lower some High-level constructs, moved from the firmlower.
9  * @author  Boris Boesler, Goetz Lindenmaier, Michael Beck
10  */
11 #include "config.h"
12
13 #include "lowering.h"
14 #include "irmode_t.h"
15 #include "irnode_t.h"
16 #include "entity_t.h"
17 #include "typerep.h"
18 #include "irprog_t.h"
19 #include "ircons.h"
20 #include "irhooks.h"
21 #include "irgmod.h"
22 #include "irgwalk.h"
23 #include "irpass_t.h"
24
25 /**
26  * Lower a Sel node. Do not touch Sels accessing entities on the frame type.
27  */
28 static void lower_sel(ir_node *sel)
29 {
30         ir_graph  *irg   = get_irn_irg(sel);
31         ir_entity *ent   = get_Sel_entity(sel);
32         ir_type   *owner = get_entity_owner(ent);
33         dbg_info  *dbg   = get_irn_dbg_info(sel);
34         ir_mode   *mode  = get_irn_mode(sel);
35         ir_node   *bl    = get_nodes_block(sel);
36         ir_node   *newn;
37
38         /* we can only replace Sels when the layout of the owner type is decided. */
39         if (get_type_state(owner) != layout_fixed)
40                 return;
41
42         if (0 < get_Sel_n_indexs(sel)) {
43                 /* an Array access */
44                 ir_type *basetyp = get_entity_type(ent);
45                 ir_mode *basemode;
46                 ir_node *index;
47                 if (is_Primitive_type(basetyp))
48                         basemode = get_type_mode(basetyp);
49                 else
50                         basemode = mode_P_data;
51
52                 assert(basemode && "no mode for lowering Sel");
53                 assert((get_mode_size_bits(basemode) % 8 == 0) && "can not deal with unorthodox modes");
54                 index = get_Sel_index(sel, 0);
55
56                 if (is_Array_type(owner)) {
57                         ir_type *arr_ty = owner;
58                         size_t   dims   = get_array_n_dimensions(arr_ty);
59                         size_t  *map    = ALLOCAN(size_t, dims);
60                         ir_mode *mode_Int = get_reference_mode_signed_eq(mode);
61                         ir_tarval *tv;
62                         ir_node *last_size;
63                         size_t   i;
64
65                         assert(dims == (size_t)get_Sel_n_indexs(sel)
66                                 && "array dimension must match number of indices of Sel node");
67
68                         for (i = 0; i < dims; i++) {
69                                 size_t order = get_array_order(arr_ty, i);
70
71                                 assert(order < dims &&
72                                         "order of a dimension must be smaller than the arrays dim");
73                                 map[order] = i;
74                         }
75                         newn = get_Sel_ptr(sel);
76
77                         /* Size of the array element */
78                         tv = new_tarval_from_long(get_type_size_bytes(basetyp), mode_Int);
79                         last_size = new_rd_Const(dbg, irg, tv);
80
81                         /*
82                          * We compute the offset part of dimension d_i recursively
83                          * with the the offset part of dimension d_{i-1}
84                          *
85                          *     off_0 = sizeof(array_element_type);
86                          *     off_i = (u_i - l_i) * off_{i-1}  ; i >= 1
87                          *
88                          * whereas u_i is the upper bound of the current dimension
89                          * and l_i the lower bound of the current dimension.
90                          */
91                         for (i = dims; i > 0;) {
92                                 size_t dim = map[--i];
93                                 ir_node *lb, *ub, *elms, *n, *ind;
94
95                                 elms = NULL;
96                                 lb = get_array_lower_bound(arr_ty, dim);
97                                 ub = get_array_upper_bound(arr_ty, dim);
98
99                                 if (! is_Unknown(lb))
100                                         lb = new_rd_Conv(dbg, bl, copy_const_value(get_irn_dbg_info(sel), lb, bl), mode_Int);
101                                 else
102                                         lb = NULL;
103
104                                 if (! is_Unknown(ub))
105                                         ub = new_rd_Conv(dbg, bl, copy_const_value(get_irn_dbg_info(sel), ub, bl), mode_Int);
106                                 else
107                                         ub = NULL;
108
109                                 /*
110                                  * If the array has more than one dimension, lower and upper
111                                  * bounds have to be set in the non-last dimension.
112                                  */
113                                 if (i > 0) {
114                                         assert(lb != NULL && "lower bound has to be set in multi-dim array");
115                                         assert(ub != NULL && "upper bound has to be set in multi-dim array");
116
117                                         /* Elements in one Dimension */
118                                         elms = new_rd_Sub(dbg, bl, ub, lb, mode_Int);
119                                 }
120
121                                 ind = new_rd_Conv(dbg, bl, get_Sel_index(sel, dim), mode_Int);
122
123                                 /*
124                                  * Normalize index, id lower bound is set, also assume
125                                  * lower bound == 0
126                          */
127                                 if (lb != NULL)
128                                         ind = new_rd_Sub(dbg, bl, ind, lb, mode_Int);
129
130                                 n = new_rd_Mul(dbg, bl, ind, last_size, mode_Int);
131
132                                 /*
133                                  * see comment above.
134                                  */
135                                 if (i > 0)
136                                         last_size = new_rd_Mul(dbg, bl, last_size, elms, mode_Int);
137
138                                 newn = new_rd_Add(dbg, bl, newn, n, mode);
139                         }
140                 } else {
141                         /* no array type */
142                         ir_mode   *idx_mode = get_irn_mode(index);
143                         ir_tarval *tv       = new_tarval_from_long(get_mode_size_bytes(basemode), idx_mode);
144
145                         newn = new_rd_Add(dbg, bl, get_Sel_ptr(sel),
146                                 new_rd_Mul(dbg, bl, index,
147                                 new_r_Const(irg, tv),
148                                 idx_mode),
149                                 mode);
150                 }
151         } else if (is_Method_type(get_entity_type(ent)) && is_Class_type(owner)) {
152                 /* We need an additional load when accessing methods from a dispatch
153                  * table.
154                  * Matze TODO: Is this really still used? At least liboo does its own
155                  * lowering of Method-Sels...
156                  */
157                 ir_mode   *ent_mode = get_type_mode(get_entity_type(ent));
158                 int        offset   = get_entity_offset(ent);
159                 ir_mode   *mode_Int = get_reference_mode_signed_eq(mode);
160                 ir_tarval *tv       = new_tarval_from_long(offset, mode_Int);
161                 ir_node   *cnst     = new_rd_Const(dbg, irg, tv);
162                 ir_node   *add      = new_rd_Add(dbg, bl, get_Sel_ptr(sel), cnst, mode);
163                 ir_node   *mem      = get_Sel_mem(sel);
164                 newn = new_rd_Load(dbg, bl, mem, add, ent_mode, cons_none);
165                 newn = new_r_Proj(newn, ent_mode, pn_Load_res);
166         } else {
167                 int offset = get_entity_offset(ent);
168
169                 /* replace Sel by add(obj, const(ent.offset)) */
170                 newn = get_Sel_ptr(sel);
171                 if (offset != 0) {
172                         ir_mode   *mode_UInt = get_reference_mode_unsigned_eq(mode);
173                         ir_tarval *tv        = new_tarval_from_long(offset, mode_UInt);
174                         ir_node   *cnst      = new_r_Const(irg, tv);
175                         newn = new_rd_Add(dbg, bl, newn, cnst, mode);
176                 }
177         }
178
179         /* run the hooks */
180         hook_lower(sel);
181
182         exchange(sel, newn);
183 }
184
185 /**
186  * Lower a all possible SymConst nodes.
187  */
188 static void lower_symconst(ir_node *symc)
189 {
190         ir_node       *newn;
191         ir_type       *tp;
192         ir_entity     *ent;
193         ir_tarval     *tv;
194         ir_enum_const *ec;
195         ir_mode       *mode;
196         ir_graph      *irg;
197
198         switch (get_SymConst_kind(symc)) {
199         case symconst_type_size:
200                 /* rewrite the SymConst node by a Const node */
201                 irg  = get_irn_irg(symc);
202                 tp   = get_SymConst_type(symc);
203                 assert(get_type_state(tp) == layout_fixed);
204                 mode = get_irn_mode(symc);
205                 newn = new_r_Const_long(irg, mode, get_type_size_bytes(tp));
206                 assert(newn);
207                 /* run the hooks */
208                 hook_lower(symc);
209                 exchange(symc, newn);
210                 break;
211         case symconst_type_align:
212                 /* rewrite the SymConst node by a Const node */
213                 irg  = get_irn_irg(symc);
214                 tp   = get_SymConst_type(symc);
215                 assert(get_type_state(tp) == layout_fixed);
216                 mode = get_irn_mode(symc);
217                 newn = new_r_Const_long(irg, mode, get_type_alignment_bytes(tp));
218                 assert(newn);
219                 /* run the hooks */
220                 hook_lower(symc);
221                 exchange(symc, newn);
222                 break;
223         case symconst_addr_ent:
224                 /* leave */
225                 break;
226         case symconst_ofs_ent:
227                 /* rewrite the SymConst node by a Const node */
228                 irg  = get_irn_irg(symc);
229                 ent  = get_SymConst_entity(symc);
230                 assert(get_type_state(get_entity_type(ent)) == layout_fixed);
231                 mode = get_irn_mode(symc);
232                 newn = new_r_Const_long(irg, mode, get_entity_offset(ent));
233                 assert(newn);
234                 /* run the hooks */
235                 hook_lower(symc);
236                 exchange(symc, newn);
237                 break;
238         case symconst_enum_const:
239                 /* rewrite the SymConst node by a Const node */
240                 irg  = get_irn_irg(symc);
241                 ec   = get_SymConst_enum(symc);
242                 assert(get_type_state(get_enumeration_owner(ec)) == layout_fixed);
243                 tv   = get_enumeration_value(ec);
244                 newn = new_r_Const(irg, tv);
245                 assert(newn);
246                 /* run the hooks */
247                 hook_lower(symc);
248                 exchange(symc, newn);
249                 break;
250
251         default:
252                 assert(!"unknown SymConst kind");
253                 break;
254         }
255 }
256
257 /**
258  * lowers IR-nodes, called from walker
259  */
260 static void lower_irnode(ir_node *irn, void *env)
261 {
262         (void) env;
263         switch (get_irn_opcode(irn)) {
264         case iro_Sel:
265                 lower_sel(irn);
266                 break;
267         case iro_SymConst:
268                 lower_symconst(irn);
269                 break;
270         default:
271                 break;
272         }
273 }
274
275 /*
276  * Replaces SymConsts by a real constant if possible.
277  * Replace Sel nodes by address computation.  Also resolves array access.
278  * Handle Bitfields by added And/Or calculations.
279  */
280 void lower_highlevel_graph(ir_graph *irg)
281 {
282         /* Finally: lower SymConst-Size and Sel nodes, unaligned Load/Stores. */
283         irg_walk_graph(irg, NULL, lower_irnode, NULL);
284 }
285
286 typedef struct pass_t {
287         ir_graph_pass_t pass;
288 } pass_t;
289
290 /**
291  * Wrapper for running lower_highlevel_graph() as an ir_graph pass.
292  */
293 static int lower_highlevel_graph_wrapper(ir_graph *irg, void *context)
294 {
295         (void)context;
296
297         lower_highlevel_graph(irg);
298         return 0;
299 }
300
301 ir_graph_pass_t *lower_highlevel_graph_pass(const char *name)
302 {
303         pass_t *pass = XMALLOCZ(pass_t);
304
305         return def_graph_pass_constructor(
306                 &pass->pass, name ? name : "lower_hl", lower_highlevel_graph_wrapper);
307 }
308
309 /*
310  * does the same as lower_highlevel() for all nodes on the const code irg
311  */
312 void lower_const_code(void)
313 {
314         walk_const_code(NULL, lower_irnode, NULL);
315 }
316
317 ir_prog_pass_t *lower_const_code_pass(const char *name)
318 {
319         return def_prog_pass(name ? name : "lower_const_code", lower_const_code);
320 }
321
322 /*
323  * Replaces SymConsts by a real constant if possible.
324  * Replace Sel nodes by address computation.  Also resolves array access.
325  * Handle Bitfields by added And/Or calculations.
326  */
327 void lower_highlevel()
328 {
329         size_t i, n;
330
331         n = get_irp_n_irgs();
332         for (i = 0; i < n; ++i) {
333                 ir_graph *irg = get_irp_irg(i);
334                 lower_highlevel_graph(irg);
335         }
336         lower_const_code();
337 }