X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Flower%2Flower_dw.c;h=8770fbdea8703ee78c606a81f35f466da40a8824;hb=3a1332a3ef152098ab60ec5a30c66e495abd8ba0;hp=aa0172bacfba76a752f55c7367928cfdd40d820e;hpb=1fc3cbdc3509dbaa14dbe275b6996c1b00d87226;p=libfirm diff --git a/ir/lower/lower_dw.c b/ir/lower/lower_dw.c index aa0172bac..8770fbdea 100644 --- a/ir/lower/lower_dw.c +++ b/ir/lower/lower_dw.c @@ -26,13 +26,8 @@ */ #include "config.h" -#ifdef HAVE_STRING_H -# include -#endif -#ifdef HAVE_STDLIB_H -# include -#endif - +#include +#include #include #include "error.h" @@ -115,13 +110,19 @@ enum lower_flags { typedef struct _lower_env_t { node_entry_t **entries; /**< entries per node */ struct obstack obst; /**< an obstack holding the temporary data */ + ir_type *l_mtp; /**< lowered method type of the current method */ tarval *tv_mode_bytes; /**< a tarval containing the number of bytes in the lowered modes */ tarval *tv_mode_bits; /**< a tarval containing the number of bits in the lowered modes */ pdeq *waitq; /**< a wait queue of all nodes that must be handled later */ pmap *proj_2_block; /**< a map from ProjX to its destination blocks */ + ident *first_id; /**< .l for little and .h for big endian */ + ident *next_id; /**< .h for little and .l for big endian */ const lwrdw_param_t *params; /**< transformation parameter */ unsigned flags; /**< some flags */ int n_entries; /**< number of entries */ +#ifndef NDEBUG + ir_type *value_param_tp; /**< the old value param type */ +#endif } lower_env_t; /** @@ -217,7 +218,7 @@ static void add_block_cf_input_nr(ir_node *block, int nr, ir_node *cf) set_irn_in(block, i + 1, in); - for (phi = get_irn_link(block); phi; phi = get_irn_link(phi)) { + for (phi = get_Block_phis(block); phi != NULL; phi = get_Phi_next(phi)) { for (i = 0; i < arity; ++i) in[i] = get_irn_n(phi, i); in[i] = in[nr]; @@ -346,10 +347,10 @@ static void lower_Const(ir_node *node, ir_mode *mode, lower_env_t *env) { tv = get_Const_tarval(node); tv_l = tarval_convert_to(tv, low_mode); - low = new_rd_Const(dbg, irg, low_mode, tv_l); + low = new_rd_Const(dbg, irg, tv_l); tv_h = tarval_convert_to(tarval_shrs(tv, env->tv_mode_bits), mode); - high = new_rd_Const(dbg, irg, mode, tv_h); + high = new_rd_Const(dbg, irg, tv_h); idx = get_irn_idx(node); assert(idx < env->n_entries); @@ -361,35 +362,34 @@ static void lower_Const(ir_node *node, ir_mode *mode, lower_env_t *env) { * Translate a Load: create two. */ static void lower_Load(ir_node *node, ir_mode *mode, lower_env_t *env) { - ir_mode *low_mode = env->params->low_unsigned; - ir_graph *irg = current_ir_graph; - ir_node *adr = get_Load_ptr(node); - ir_node *mem = get_Load_mem(node); - ir_node *low, *high, *proj; - dbg_info *dbg; - ir_node *block = get_nodes_block(node); - int idx; + ir_mode *low_mode = env->params->low_unsigned; + ir_graph *irg = current_ir_graph; + ir_node *adr = get_Load_ptr(node); + ir_node *mem = get_Load_mem(node); + ir_node *low, *high, *proj; + dbg_info *dbg; + ir_node *block = get_nodes_block(node); + int idx; + ir_cons_flags volatility = get_Load_volatility(node) == volatility_is_volatile + ? cons_volatile : 0; if (env->params->little_endian) { low = adr; high = new_r_Add(irg, block, adr, - new_r_Const(irg, get_tarval_mode(env->tv_mode_bytes), env->tv_mode_bytes), + new_r_Const(irg, env->tv_mode_bytes), get_irn_mode(adr)); } else { low = new_r_Add(irg, block, adr, - new_r_Const(irg, get_tarval_mode(env->tv_mode_bytes), env->tv_mode_bytes), + new_r_Const(irg, env->tv_mode_bytes), get_irn_mode(adr)); high = adr; } /* if */ /* create two loads */ dbg = get_irn_dbg_info(node); - low = new_rd_Load(dbg, irg, block, mem, low, low_mode); + low = new_rd_Load(dbg, irg, block, mem, low, low_mode, volatility); proj = new_r_Proj(irg, block, low, mode_M, pn_Load_M); - high = new_rd_Load(dbg, irg, block, proj, high, mode); - - set_Load_volatility(low, get_Load_volatility(node)); - set_Load_volatility(high, get_Load_volatility(node)); + high = new_rd_Load(dbg, irg, block, proj, high, mode, volatility); idx = get_irn_idx(node); assert(idx < env->n_entries); @@ -426,13 +426,14 @@ static void lower_Load(ir_node *node, ir_mode *mode, lower_env_t *env) { * Translate a Store: create two. */ static void lower_Store(ir_node *node, ir_mode *mode, lower_env_t *env) { - ir_graph *irg; - ir_node *block, *adr, *mem; - ir_node *low, *high, *irn, *proj; - dbg_info *dbg; - int idx; + ir_graph *irg; + ir_node *block, *adr, *mem; + ir_node *low, *high, *irn, *proj; + dbg_info *dbg; + int idx; node_entry_t *entry; - (void) node; + ir_cons_flags volatility = get_Store_volatility(node) == volatility_is_volatile + ? cons_volatile : 0; (void) mode; irn = get_Store_value(node); @@ -453,23 +454,20 @@ static void lower_Store(ir_node *node, ir_mode *mode, lower_env_t *env) { if (env->params->little_endian) { low = adr; high = new_r_Add(irg, block, adr, - new_r_Const(irg, get_tarval_mode(env->tv_mode_bytes), env->tv_mode_bytes), + new_r_Const(irg, env->tv_mode_bytes), get_irn_mode(adr)); } else { low = new_r_Add(irg, block, adr, - new_r_Const(irg, get_tarval_mode(env->tv_mode_bytes), env->tv_mode_bytes), + new_r_Const(irg, env->tv_mode_bytes), get_irn_mode(adr)); high = adr; } /* if */ /* create two Stores */ dbg = get_irn_dbg_info(node); - low = new_rd_Store(dbg, irg, block, mem, low, entry->low_word); + low = new_rd_Store(dbg, irg, block, mem, low, entry->low_word, volatility); proj = new_r_Proj(irg, block, low, mode_M, pn_Store_M); - high = new_rd_Store(dbg, irg, block, proj, high, entry->high_word); - - set_Store_volatility(low, get_Store_volatility(node)); - set_Store_volatility(high, get_Store_volatility(node)); + high = new_rd_Store(dbg, irg, block, proj, high, entry->high_word, volatility); idx = get_irn_idx(node); assert(idx < env->n_entries); @@ -937,7 +935,7 @@ static void lower_Shr(ir_node *node, ir_mode *mode, lower_env_t *env) { } else { env->entries[idx]->low_word = left; } /* if */ - env->entries[idx]->high_word = new_r_Const(irg, mode, get_mode_null(mode)); + env->entries[idx]->high_word = new_r_Const(irg, get_mode_null(mode)); return; } /* if */ @@ -974,7 +972,7 @@ static void lower_Shl(ir_node *node, ir_mode *mode, lower_env_t *env) { } else { env->entries[idx]->high_word = left; } /* if */ - env->entries[idx]->low_word = new_r_Const(irg, mode_l, get_mode_null(mode_l)); + env->entries[idx]->low_word = new_r_Const(irg, get_mode_null(mode_l)); return; } /* if */ @@ -1515,7 +1513,7 @@ static void lower_Conv_to_Ls(ir_node *node, lower_env_t *env) { env->entries[idx]->high_word = new_rd_Shrs(dbg, irg, block, op_conv, new_Const_long(dst_mode_l, get_mode_size_bits(dst_mode_h) - 1), dst_mode_h); } else { - env->entries[idx]->high_word = new_Const(dst_mode_h, get_mode_null(dst_mode_h)); + env->entries[idx]->high_word = new_Const(get_mode_null(dst_mode_h)); } /* if */ } /* if */ } else { @@ -1570,7 +1568,7 @@ static void lower_Conv_to_Lu(ir_node *node, lower_env_t *env) { env->entries[idx]->high_word = new_rd_Shrs(dbg, irg, block, op, new_Const_long(dst_mode, get_mode_size_bits(dst_mode) - 1), dst_mode); } else { - env->entries[idx]->high_word = new_Const(dst_mode, get_mode_null(dst_mode)); + env->entries[idx]->high_word = new_Const(get_mode_null(dst_mode)); } /* if */ } /* if */ } else { @@ -1700,11 +1698,16 @@ static void lower_Conv(ir_node *node, ir_mode *mode, lower_env_t *env) { /** * Lower the method type. + * + * @param mtp the method type to lower + * @param ent the lower environment + * + * @return the lowered type */ static ir_type *lower_mtp(ir_type *mtp, lower_env_t *env) { pmap_entry *entry; - ident *id; - ir_type *res; + ident *id, *lid; + ir_type *res, *value_type; if (is_lowered_type(mtp)) return mtp; @@ -1741,7 +1744,7 @@ static ir_type *lower_mtp(ir_type *mtp, lower_env_t *env) { } /* if */ } /* for */ - id = id_mangle_u(new_id_from_chars("L", 1), get_type_ident(mtp)); + id = id_mangle_u(new_id_from_chars("L", 1), get_type_ident(mtp)); res = new_type_method(id, n_param, n_res); /* set param types and result types */ @@ -1785,6 +1788,44 @@ static ir_type *lower_mtp(ir_type *mtp, lower_env_t *env) { } /* for */ set_lowered_type(mtp, res); pmap_insert(lowered_type, mtp, res); + + value_type = get_method_value_param_type(mtp); + if (value_type != NULL) { + /* this creates a new value parameter type */ + (void)get_method_value_param_ent(res, 0); + + /* set new param positions */ + for (i = n_param = 0; i < n; ++i) { + ir_type *tp = get_method_param_type(mtp, i); + ident *id = get_method_param_ident(mtp, i); + ir_entity *ent = get_method_value_param_ent(mtp, i); + + set_entity_link(ent, INT_TO_PTR(n_param)); + if (is_Primitive_type(tp)) { + ir_mode *mode = get_type_mode(tp); + + if (mode == env->params->high_signed || mode == env->params->high_unsigned) { + if (id != NULL) { + lid = id_mangle(id, env->first_id); + set_method_param_ident(res, n_param, lid); + set_entity_ident(get_method_value_param_ent(res, n_param), lid); + lid = id_mangle(id, env->next_id); + set_method_param_ident(res, n_param + 1, lid); + set_entity_ident(get_method_value_param_ent(res, n_param + 1), lid); + } /* if */ + n_param += 2; + continue; + } /* if */ + } /* if */ + if (id != NULL) { + set_method_param_ident(res, n_param, id); + set_entity_ident(get_method_value_param_ent(res, n_param), id); + } /* if */ + ++n_param; + } /* for */ + + set_lowered_type(value_type, get_method_value_param_type(res)); + } /* if */ } else { res = entry->value; } /* if */ @@ -2150,10 +2191,12 @@ static void lower_Phi(ir_node *phi, ir_mode *mode, lower_env_t *env) { env->entries[idx]->low_word = phi_l = new_rd_Phi(dbg, irg, block, arity, inl, mode_l); env->entries[idx]->high_word = phi_h = new_rd_Phi(dbg, irg, block, arity, inh, mode); - /* Don't forget to link the new Phi nodes into the block! */ - set_irn_link(phi_l, get_irn_link(block)); - set_irn_link(phi_h, phi_l); - set_irn_link(block, phi_h); + /* Don't forget to link the new Phi nodes into the block. + * Beware that some Phis might be optimized away. */ + if (is_Phi(phi_l)) + add_Block_phi(block, phi_l); + if (is_Phi(phi_h)) + add_Block_phi(block, phi_h); if (enq) { /* not yet finished */ @@ -2207,8 +2250,10 @@ static void lower_Mux(ir_node *mux, ir_mode *mode, lower_env_t *env) { env->entries[idx]->high_word = new_rd_Mux(dbg, irg, block, sel, false_h, true_h, mode); } /* lower_Mux */ -static void lower_ASM(ir_node *asmn, ir_mode *mode, lower_env_t *env) -{ +/** + * Translate an ASM node. + */ +static void lower_ASM(ir_node *asmn, ir_mode *mode, lower_env_t *env) { ir_mode *his = env->params->high_signed; ir_mode *hiu = env->params->high_unsigned; int i; @@ -2220,8 +2265,8 @@ static void lower_ASM(ir_node *asmn, ir_mode *mode, lower_env_t *env) ir_mode *op_mode = get_irn_mode(get_irn_n(asmn, i)); if (op_mode == his || op_mode == hiu) { panic("lowering ASM unimplemented"); - } - } + } /* if */ + } /* for */ for (n = asmn;;) { ir_mode *proj_mode; @@ -2233,9 +2278,28 @@ static void lower_ASM(ir_node *asmn, ir_mode *mode, lower_env_t *env) proj_mode = get_irn_mode(n); if (proj_mode == his || proj_mode == hiu) { panic("lowering ASM unimplemented"); - } - } -} + } /* if */ + } /* for */ +} /* lower_ASM */ + +/** + * Translate a Sel node. + */ +static void lower_Sel(ir_node *sel, ir_mode *mode, lower_env_t *env) { + (void) mode; + + /* we must only lower value parameter Sels if we change the + value parameter type. */ + if (env->value_param_tp != NULL) { + ir_entity *ent = get_Sel_entity(sel); + if (get_entity_owner(ent) == env->value_param_tp) { + int pos = PTR_TO_INT(get_entity_link(ent)); + + ent = get_method_value_param_ent(env->l_mtp, pos); + set_Sel_entity(sel, ent); + } /* if */ + } /* if */ +} /* lower_Sel */ /** * check for opcodes that must always be lowered. @@ -2249,6 +2313,7 @@ static int always_lower(ir_opcode code) { case iro_Return: case iro_Cond: case iro_Conv: + case iro_Sel: return 1; default: return 0; @@ -2401,14 +2466,41 @@ static int cmp_conv_tp(const void *elt, const void *key, size_t size) { (void) size; return (e1->imode - e2->imode) | (e1->omode - e2->omode); -} /* static int cmp_conv_tp */ +} /* cmp_conv_tp */ /** * Enter a lowering function into an ir_op. */ static void enter_lower_func(ir_op *op, lower_func func) { op->ops.generic = (op_func)func; -} +} /* enter_lower_func */ + +/** + * Returns non-zero if a method type must be lowered. + * + * @param mtp the method type + */ +static int mtp_must_to_lowered(ir_type *mtp, lower_env_t *env) { + int i, n_params; + + n_params = get_method_n_params(mtp); + if (n_params <= 0) + return 0; + + /* first check if we have parameters that must be fixed */ + for (i = 0; i < n_params; ++i) { + ir_type *tp = get_method_param_type(mtp, i); + + if (is_Primitive_type(tp)) { + ir_mode *mode = get_type_mode(tp); + + if (mode == env->params->high_signed || + mode == env->params->high_unsigned) + return 1; + } /* if */ + } /* for */ + return 0; +} /* mtp_must_to_lowered */ /* * Do the lowering. @@ -2416,8 +2508,8 @@ static void enter_lower_func(ir_op *op, lower_func func) { void lower_dw_ops(const lwrdw_param_t *param) { lower_env_t lenv; - int i; - ir_graph *rem; + int i; + ir_graph *rem; if (! param) return; @@ -2478,7 +2570,6 @@ void lower_dw_ops(const lwrdw_param_t *param) shiftop_tp_s = new_type_method(IDENT("shiftop_s_intrinsic"), 3, 2); set_method_param_type(shiftop_tp_s, 0, tp_u); set_method_param_type(shiftop_tp_s, 1, tp_s); - /* beware: shift count is always mode_Iu */ set_method_param_type(shiftop_tp_s, 2, tp_u); set_method_res_type(shiftop_tp_s, 0, tp_u); set_method_res_type(shiftop_tp_s, 1, tp_s); @@ -2498,10 +2589,12 @@ void lower_dw_ops(const lwrdw_param_t *param) set_method_res_type(unop_tp_s, 1, tp_s); } /* if */ - lenv.tv_mode_bytes = new_tarval_from_long(get_mode_size_bytes(param->low_unsigned), mode_Iu); - lenv.tv_mode_bits = new_tarval_from_long(get_mode_size_bits(param->low_unsigned), mode_Iu); + lenv.tv_mode_bytes = new_tarval_from_long(get_mode_size_bytes(param->low_unsigned), param->low_unsigned); + lenv.tv_mode_bits = new_tarval_from_long(get_mode_size_bits(param->low_unsigned), param->low_unsigned); lenv.waitq = new_pdeq(); lenv.params = param; + lenv.first_id = new_id_from_chars(param->little_endian ? ".l" : ".h", 2); + lenv.next_id = new_id_from_chars(param->little_endian ? ".h" : ".l", 2); /* first clear the generic function pointer for all ops */ clear_irp_opcodes_generic_func(); @@ -2538,6 +2631,7 @@ void lower_dw_ops(const lwrdw_param_t *param) LOWER(DivMod); LOWER(Div); LOWER(Mod); + LOWER(Sel); LOWER_UN(Abs); LOWER_UN(Minus); @@ -2551,7 +2645,9 @@ void lower_dw_ops(const lwrdw_param_t *param) /* transform all graphs */ rem = current_ir_graph; for (i = get_irp_n_irgs() - 1; i >= 0; --i) { - ir_graph *irg = get_irp_irg(i); + ir_graph *irg = get_irp_irg(i); + ir_entity *ent; + ir_type *mtp; int n_idx; obstack_init(&lenv.obst); @@ -2562,9 +2658,28 @@ void lower_dw_ops(const lwrdw_param_t *param) lenv.entries = NEW_ARR_F(node_entry_t *, n_idx); memset(lenv.entries, 0, n_idx * sizeof(lenv.entries[0])); - /* first step: link all nodes and allocate data */ - lenv.flags = 0; + lenv.l_mtp = NULL; + lenv.flags = 0; lenv.proj_2_block = pmap_create(); +#ifndef NDEBUG + lenv.value_param_tp = NULL; +#endif + ir_reserve_resources(irg, IR_RESOURCE_PHI_LIST | IR_RESOURCE_IRN_LINK); + + ent = get_irg_entity(irg); + mtp = get_entity_type(ent); + + if (mtp_must_to_lowered(mtp, &lenv)) { + ir_type *ltp = lower_mtp(mtp, &lenv); + lenv.flags |= MUST_BE_LOWERED; + set_entity_type(ent, ltp); + lenv.l_mtp = ltp; +#ifndef NDEBUG + lenv.value_param_tp = get_method_value_param_type(mtp); +#endif + } /* if */ + + /* first step: link all nodes and allocate data */ irg_walk_graph(irg, firm_clear_node_and_phi_links, prepare_links_and_handle_rotl, &lenv); if (lenv.flags & MUST_BE_LOWERED) { @@ -2582,6 +2697,8 @@ void lower_dw_ops(const lwrdw_param_t *param) lower_ops(node, &lenv); } /* while */ + ir_free_resources(irg, IR_RESOURCE_PHI_LIST | IR_RESOURCE_IRN_LINK); + /* outs are invalid, we changed the graph */ set_irg_outs_inconsistent(irg); @@ -2591,6 +2708,8 @@ void lower_dw_ops(const lwrdw_param_t *param) set_irg_extblk_inconsistent(irg); set_irg_loopinfo_inconsistent(irg); } /* if */ + } else { + ir_free_resources(irg, IR_RESOURCE_PHI_LIST | IR_RESOURCE_IRN_LINK); } /* if */ pmap_destroy(lenv.proj_2_block); DEL_ARR_F(lenv.entries);