2 * This file is part of libFirm.
3 * Copyright (C) 2012 University of Karlsruhe.
8 * @brief Lower some High-level constructs, moved from the firmlower.
9 * @author Boris Boesler, Goetz Lindenmaier, Michael Beck
27 * Lower a Sel node. Do not touch Sels accessing entities on the frame type.
29 static void lower_sel(ir_node *sel)
31 ir_graph *irg = get_irn_irg(sel);
32 ir_entity *ent = get_Sel_entity(sel);
33 ir_type *owner = get_entity_owner(ent);
34 dbg_info *dbg = get_irn_dbg_info(sel);
35 ir_mode *mode = get_irn_mode(sel);
36 ir_node *bl = get_nodes_block(sel);
39 /* we can only replace Sels when the layout of the owner type is decided. */
40 if (get_type_state(owner) != layout_fixed)
43 if (0 < get_Sel_n_indexs(sel)) {
45 ir_type *basetyp = get_entity_type(ent);
48 if (is_Primitive_type(basetyp))
49 basemode = get_type_mode(basetyp);
51 basemode = mode_P_data;
53 assert(basemode && "no mode for lowering Sel");
54 assert((get_mode_size_bits(basemode) % 8 == 0) && "can not deal with unorthodox modes");
55 index = get_Sel_index(sel, 0);
57 if (is_Array_type(owner)) {
58 ir_type *arr_ty = owner;
59 size_t dims = get_array_n_dimensions(arr_ty);
60 size_t *map = ALLOCAN(size_t, dims);
61 ir_mode *mode_Int = get_reference_mode_signed_eq(mode);
66 assert(dims == (size_t)get_Sel_n_indexs(sel)
67 && "array dimension must match number of indices of Sel node");
69 for (i = 0; i < dims; i++) {
70 size_t order = get_array_order(arr_ty, i);
72 assert(order < dims &&
73 "order of a dimension must be smaller than the arrays dim");
76 newn = get_Sel_ptr(sel);
78 /* Size of the array element */
79 tv = new_tarval_from_long(get_type_size_bytes(basetyp), mode_Int);
80 last_size = new_rd_Const(dbg, irg, tv);
83 * We compute the offset part of dimension d_i recursively
84 * with the the offset part of dimension d_{i-1}
86 * off_0 = sizeof(array_element_type);
87 * off_i = (u_i - l_i) * off_{i-1} ; i >= 1
89 * whereas u_i is the upper bound of the current dimension
90 * and l_i the lower bound of the current dimension.
92 for (i = dims; i > 0;) {
93 size_t dim = map[--i];
94 ir_node *lb, *ub, *elms, *n, *ind;
97 lb = get_array_lower_bound(arr_ty, dim);
98 ub = get_array_upper_bound(arr_ty, dim);
100 if (! is_Unknown(lb))
101 lb = new_rd_Conv(dbg, bl, copy_const_value(get_irn_dbg_info(sel), lb, bl), mode_Int);
105 if (! is_Unknown(ub))
106 ub = new_rd_Conv(dbg, bl, copy_const_value(get_irn_dbg_info(sel), ub, bl), mode_Int);
111 * If the array has more than one dimension, lower and upper
112 * bounds have to be set in the non-last dimension.
115 assert(lb != NULL && "lower bound has to be set in multi-dim array");
116 assert(ub != NULL && "upper bound has to be set in multi-dim array");
118 /* Elements in one Dimension */
119 elms = new_rd_Sub(dbg, bl, ub, lb, mode_Int);
122 ind = new_rd_Conv(dbg, bl, get_Sel_index(sel, dim), mode_Int);
125 * Normalize index, id lower bound is set, also assume
129 ind = new_rd_Sub(dbg, bl, ind, lb, mode_Int);
131 n = new_rd_Mul(dbg, bl, ind, last_size, mode_Int);
137 last_size = new_rd_Mul(dbg, bl, last_size, elms, mode_Int);
139 newn = new_rd_Add(dbg, bl, newn, n, mode);
143 ir_mode *idx_mode = get_irn_mode(index);
144 ir_tarval *tv = new_tarval_from_long(get_mode_size_bytes(basemode), idx_mode);
146 newn = new_rd_Add(dbg, bl, get_Sel_ptr(sel),
147 new_rd_Mul(dbg, bl, index,
148 new_r_Const(irg, tv),
152 } else if (is_Method_type(get_entity_type(ent)) && is_Class_type(owner)) {
153 /* We need an additional load when accessing methods from a dispatch
155 * Matze TODO: Is this really still used? At least liboo does its own
156 * lowering of Method-Sels...
158 ir_mode *ent_mode = get_type_mode(get_entity_type(ent));
159 int offset = get_entity_offset(ent);
160 ir_mode *mode_Int = get_reference_mode_signed_eq(mode);
161 ir_tarval *tv = new_tarval_from_long(offset, mode_Int);
162 ir_node *cnst = new_rd_Const(dbg, irg, tv);
163 ir_node *add = new_rd_Add(dbg, bl, get_Sel_ptr(sel), cnst, mode);
164 ir_node *mem = get_Sel_mem(sel);
165 newn = new_rd_Load(dbg, bl, mem, add, ent_mode, cons_none);
166 newn = new_r_Proj(newn, ent_mode, pn_Load_res);
168 int offset = get_entity_offset(ent);
170 /* replace Sel by add(obj, const(ent.offset)) */
171 newn = get_Sel_ptr(sel);
173 ir_mode *mode_UInt = get_reference_mode_unsigned_eq(mode);
174 ir_tarval *tv = new_tarval_from_long(offset, mode_UInt);
175 ir_node *cnst = new_r_Const(irg, tv);
176 newn = new_rd_Add(dbg, bl, newn, cnst, mode);
187 * Lower a all possible SymConst nodes.
189 static void lower_symconst(ir_node *symc)
199 switch (get_SymConst_kind(symc)) {
200 case symconst_type_size:
201 /* rewrite the SymConst node by a Const node */
202 irg = get_irn_irg(symc);
203 tp = get_SymConst_type(symc);
204 assert(get_type_state(tp) == layout_fixed);
205 mode = get_irn_mode(symc);
206 newn = new_r_Const_long(irg, mode, get_type_size_bytes(tp));
210 exchange(symc, newn);
212 case symconst_type_align:
213 /* rewrite the SymConst node by a Const node */
214 irg = get_irn_irg(symc);
215 tp = get_SymConst_type(symc);
216 assert(get_type_state(tp) == layout_fixed);
217 mode = get_irn_mode(symc);
218 newn = new_r_Const_long(irg, mode, get_type_alignment_bytes(tp));
222 exchange(symc, newn);
224 case symconst_addr_ent:
227 case symconst_ofs_ent:
228 /* rewrite the SymConst node by a Const node */
229 irg = get_irn_irg(symc);
230 ent = get_SymConst_entity(symc);
231 assert(get_type_state(get_entity_type(ent)) == layout_fixed);
232 mode = get_irn_mode(symc);
233 newn = new_r_Const_long(irg, mode, get_entity_offset(ent));
237 exchange(symc, newn);
239 case symconst_enum_const:
240 /* rewrite the SymConst node by a Const node */
241 irg = get_irn_irg(symc);
242 ec = get_SymConst_enum(symc);
243 assert(get_type_state(get_enumeration_owner(ec)) == layout_fixed);
244 tv = get_enumeration_value(ec);
245 newn = new_r_Const(irg, tv);
249 exchange(symc, newn);
253 assert(!"unknown SymConst kind");
259 * lowers IR-nodes, called from walker
261 static void lower_irnode(ir_node *irn, void *env)
264 switch (get_irn_opcode(irn)) {
277 * Replaces SymConsts by a real constant if possible.
278 * Replace Sel nodes by address computation. Also resolves array access.
279 * Handle Bitfields by added And/Or calculations.
281 void lower_highlevel_graph(ir_graph *irg)
283 /* Finally: lower SymConst-Size and Sel nodes, unaligned Load/Stores. */
284 irg_walk_graph(irg, NULL, lower_irnode, NULL);
287 typedef struct pass_t {
288 ir_graph_pass_t pass;
292 * Wrapper for running lower_highlevel_graph() as an ir_graph pass.
294 static int lower_highlevel_graph_wrapper(ir_graph *irg, void *context)
298 lower_highlevel_graph(irg);
302 ir_graph_pass_t *lower_highlevel_graph_pass(const char *name)
304 pass_t *pass = XMALLOCZ(pass_t);
306 return def_graph_pass_constructor(
307 &pass->pass, name ? name : "lower_hl", lower_highlevel_graph_wrapper);
311 * does the same as lower_highlevel() for all nodes on the const code irg
313 void lower_const_code(void)
315 walk_const_code(NULL, lower_irnode, NULL);
318 ir_prog_pass_t *lower_const_code_pass(const char *name)
320 return def_prog_pass(name ? name : "lower_const_code", lower_const_code);
324 * Replaces SymConsts by a real constant if possible.
325 * Replace Sel nodes by address computation. Also resolves array access.
326 * Handle Bitfields by added And/Or calculations.
328 void lower_highlevel()
332 n = get_irp_n_irgs();
333 for (i = 0; i < n; ++i) {
334 ir_graph *irg = get_irp_irg(i);
335 lower_highlevel_graph(irg);