set_irn_mode(irn, mode);
}
+ /*
+ Annotate mode of stored value to link field of the Store
+ as floating point converts might be optimized and we would
+ loose the mode.
+ */
+ if (get_irn_opcode(irn) == iro_Store) {
+ set_irn_link(irn, get_irn_mode(get_Store_value(irn)));
+ }
+
tenv.block = get_nodes_block(irn);
tenv.cg = cg;
tenv.irg = cg->irg;
ir_node *sp = get_irn_n(irn, 0);
ir_node *val, *next, *push, *bl, *proj_M, *proj_res, *old_proj_M;
const ir_edge_t *edge;
+ heights_t *h;
- if (get_ia32_am_offs(irn) || !be_is_IncSP(sp))
+ /* do not create push if store has already an offset assigned or base is not a IncSP */
+ if (get_ia32_am_offs(irn) || ! be_is_IncSP(sp))
return;
+ /* do not create push if index is not NOREG */
if (arch_get_irn_register(cg->arch_env, get_irn_n(irn, 1)) !=
&ia32_gp_regs[REG_GP_NOREG])
return;
+ /* do not create push for floating point */
val = get_irn_n(irn, 2);
if (mode_is_float(get_irn_mode(val)))
return;
+ /* do not create push if IncSp doesn't expand stack or expand size is different from register size */
if (be_get_IncSP_direction(sp) != be_stack_dir_expand ||
be_get_IncSP_offset(sp) != get_mode_size_bytes(ia32_reg_classes[CLASS_ia32_gp].mode))
return;
+ /* do not create push, if there is a path (inside the block) from the push value to IncSP */
+ h = heights_new(cg->irg);
+ if (get_nodes_block(val) == get_nodes_block(sp) &&
+ heights_reachable_in_block(h, val, sp))
+ {
+ heights_free(h);
+ return;
+ }
+ heights_free(h);
+
/* ok, translate into Push */
- edge = get_irn_out_edge_first(irn);
+ edge = get_irn_out_edge_first(irn);
old_proj_M = get_edge_src_irn(edge);
next = sched_next(irn);
* - the load must not have other users than the irn AND
* - the irn must not have a frame entity set
*
+ * @param cg The ia32 code generator
* @param h The height information of the irg
* @param block The block the Loads must/mustnot be in
* @param irn The irn to check
* return 0 if irn is no candidate, 1 if left load can be used, 2 if right one, 3 for both
*/
-static ia32_am_cand_t is_am_candidate(heights_t *h, const ir_node *block, ir_node *irn) {
+static ia32_am_cand_t is_am_candidate(ia32_code_gen_t *cg, heights_t *h, const ir_node *block, ir_node *irn) {
ir_node *in, *load, *other, *left, *right;
int n, is_cand = 0, cand;
cand = is_cand ? (cand | IA32_AM_CAND_RIGHT) : cand;
+ /* check some special cases */
+ if (USE_SSE2(cg) && is_ia32_Conv_I2FP(irn)) {
+ /* SSE Conv I -> FP cvtsi2s(s|d) can only load 32 bit values */
+ if (get_mode_size_bits(get_ia32_tgt_mode(irn)) != 32)
+ cand = IA32_AM_CAND_NONE;
+ }
+ else if (is_ia32_Conv_I2I(irn)) {
+ /* we cannot load an N bit value and implicitly convert it into an M bit value if N > M */
+ if (get_mode_size_bits(get_ia32_src_mode(irn)) > get_mode_size_bits(get_ia32_tgt_mode(irn)))
+ cand = IA32_AM_CAND_NONE;
+ }
+
/* if the irn has a frame entity: we do not use address mode */
return get_ia32_frame_ent(irn) ? IA32_AM_CAND_NONE : cand;
}
/* - nobody else uses the result of the op */
if ((get_ia32_am_support(irn) != ia32_am_None) && ! is_ia32_Lea(irn)) {
- ia32_am_cand_t cand = is_am_candidate(h, block, irn);
+ ia32_am_cand_t cand = is_am_candidate(cg, h, block, irn);
ia32_am_cand_t orig_cand = cand;
/* cand == 1: load is left; cand == 2: load is right; */