Add be_dep_on_frame() to let a node depend on the frame, so it does not get scheduled...
[libfirm] / ir / be / ia32 / ia32_transform.c
index 940f54e..ab8cf69 100644 (file)
@@ -291,16 +291,9 @@ static ir_node *gen_Const(ir_node *node) {
                        }
                }
 end:
-               /* Const Nodes before the initial IncSP are a bad idea, because
-                * they could be spilled and we have no SP ready at that point yet.
-                * So add a dependency to the initial frame pointer calculation to
-                * avoid that situation.
-                */
-               if (get_irg_start_block(irg) == block) {
-                       add_irn_dep(load, get_irg_frame(irg));
-               }
-
                SET_IA32_ORIG_NODE(load, ia32_get_old_node_name(env_cg, node));
+
+               be_dep_on_frame(load);
                return res;
        } else { /* non-float mode */
                ir_node *cnst;
@@ -318,11 +311,7 @@ end:
                cnst = new_rd_ia32_Const(dbgi, irg, block, NULL, 0, val);
                SET_IA32_ORIG_NODE(cnst, ia32_get_old_node_name(env_cg, node));
 
-               /* see above */
-               if (get_irg_start_block(irg) == block) {
-                       add_irn_dep(cnst, get_irg_frame(irg));
-               }
-
+               be_dep_on_frame(cnst);
                return cnst;
        }
 }
@@ -358,15 +347,9 @@ static ir_node *gen_SymConst(ir_node *node) {
                cnst = new_rd_ia32_Const(dbgi, irg, block, entity, 0, 0);
        }
 
-       /* Const Nodes before the initial IncSP are a bad idea, because
-        * they could be spilled and we have no SP ready at that point yet
-        */
-       if (get_irg_start_block(irg) == block) {
-               add_irn_dep(cnst, get_irg_frame(irg));
-       }
-
        SET_IA32_ORIG_NODE(cnst, ia32_get_old_node_name(env_cg, node));
 
+       be_dep_on_frame(cnst);
        return cnst;
 }
 
@@ -763,12 +746,6 @@ static void match_arguments(ia32_address_mode_t *am, ir_node *block,
        am->commutative = commutative;
 }
 
-static void set_transformed_and_mark(ir_node *const old_node, ir_node *const new_node)
-{
-       mark_irn_visited(old_node);
-       be_set_transformed_node(old_node, new_node);
-}
-
 static ir_node *fix_mem_proj(ir_node *node, ia32_address_mode_t *am)
 {
        ir_mode  *mode;
@@ -781,7 +758,7 @@ static ir_node *fix_mem_proj(ir_node *node, ia32_address_mode_t *am)
        mode = get_irn_mode(node);
        load = get_Proj_pred(am->mem_proj);
 
-       set_transformed_and_mark(load, node);
+       be_set_transformed_node(load, node);
 
        if (mode != mode_T) {
                set_irn_mode(node, mode_T);
@@ -1099,7 +1076,7 @@ static ir_node *gen_Add(ir_node *node) {
                ir_graph *irg = current_ir_graph;
                new_node = new_rd_ia32_Const(dbgi, irg, new_block, addr.symconst_ent,
                                             addr.symconst_sign, addr.offset);
-               add_irn_dep(new_node, get_irg_frame(irg));
+               be_dep_on_frame(new_node);
                SET_IA32_ORIG_NODE(new_node, ia32_get_old_node_name(env_cg, node));
                return new_node;
        }
@@ -1394,7 +1371,7 @@ static ir_node *create_Div(ir_node *node)
 
        if (mode_is_signed(mode)) {
                ir_node *produceval = new_rd_ia32_ProduceVal(dbgi, irg, new_block);
-               add_irn_dep(produceval, get_irg_frame(irg));
+               be_dep_on_frame(produceval);
                sign_extension = new_rd_ia32_Cltd(dbgi, irg, new_block, am.new_op1,
                                                  produceval);
 
@@ -1403,7 +1380,7 @@ static ir_node *create_Div(ir_node *node)
                                            am.new_op1, sign_extension);
        } else {
                sign_extension = new_rd_ia32_Const(dbgi, irg, new_block, NULL, 0, 0);
-               add_irn_dep(sign_extension, get_irg_frame(irg));
+               be_dep_on_frame(sign_extension);
 
                new_node = new_rd_ia32_Div(dbgi, irg, new_block, addr->base,
                                           addr->index, new_mem, am.new_op2,
@@ -1501,8 +1478,8 @@ static ir_node *gen_Shrs(ir_node *node) {
                        ir_node  *op     = left;
                        ir_node  *new_op = be_transform_node(op);
                        ir_node  *pval   = new_rd_ia32_ProduceVal(dbgi, irg, block);
-                       add_irn_dep(pval, get_irg_frame(irg));
 
+                       be_dep_on_frame(pval);
                        return new_rd_ia32_Cltd(dbgi, irg, block, new_op, pval);
                }
        }
@@ -1730,7 +1707,7 @@ static ir_node *gen_Abs(ir_node *node)
                sign_extension = new_rd_ia32_Cltd(dbgi, irg, new_block,
                                                           new_op, pval);
 
-               add_irn_dep(pval, get_irg_frame(irg));
+               be_dep_on_frame(pval);
                SET_IA32_ORIG_NODE(sign_extension,ia32_get_old_node_name(env_cg, node));
 
                xor = new_rd_ia32_Xor(dbgi, irg, new_block, noreg_gp, noreg_gp,
@@ -1903,15 +1880,9 @@ static ir_node *gen_Load(ir_node *node) {
                add_ia32_flags(new_node, arch_irn_flags_rematerializable);
        }
 
-       /* make sure we are scheduled behind the initial IncSP/Barrier
-        * to avoid spills being placed before it
-        */
-       if (block == get_irg_start_block(irg)) {
-               add_irn_dep(new_node, get_irg_frame(irg));
-       }
-
        SET_IA32_ORIG_NODE(new_node, ia32_get_old_node_name(env_cg, node));
 
+       be_dep_on_frame(new_node);
        return new_node;
 }
 
@@ -2024,9 +1995,9 @@ static ir_node *dest_am_binop(ir_node *node, ir_node *op1, ir_node *op2,
        set_ia32_ls_mode(new_node, mode);
        SET_IA32_ORIG_NODE(new_node, ia32_get_old_node_name(env_cg, node));
 
-       set_transformed_and_mark(get_Proj_pred(am.mem_proj), new_node);
+       be_set_transformed_node(get_Proj_pred(am.mem_proj), new_node);
        mem_proj = be_transform_node(am.mem_proj);
-       set_transformed_and_mark(mem_proj ? mem_proj : am.mem_proj, new_node);
+       be_set_transformed_node(mem_proj ? mem_proj : am.mem_proj, new_node);
 
        return new_node;
 }
@@ -2060,9 +2031,9 @@ static ir_node *dest_am_unop(ir_node *node, ir_node *op, ir_node *mem,
        set_ia32_ls_mode(new_node, mode);
        SET_IA32_ORIG_NODE(new_node, ia32_get_old_node_name(env_cg, node));
 
-       set_transformed_and_mark(get_Proj_pred(am.mem_proj), new_node);
+       be_set_transformed_node(get_Proj_pred(am.mem_proj), new_node);
        mem_proj = be_transform_node(am.mem_proj);
-       set_transformed_and_mark(mem_proj ? mem_proj : am.mem_proj, new_node);
+       be_set_transformed_node(mem_proj ? mem_proj : am.mem_proj, new_node);
 
        return new_node;
 }
@@ -2258,17 +2229,13 @@ static ir_node *try_create_dest_am(ir_node *node) {
        return new_node;
 }
 
-static int is_float_to_int32_conv(const ir_node *node)
+static int is_float_to_int_conv(const ir_node *node)
 {
        ir_mode  *mode = get_irn_mode(node);
        ir_node  *conv_op;
        ir_mode  *conv_mode;
 
-       if(get_mode_size_bits(mode) != 32 || !ia32_mode_needs_gp_reg(mode))
-               return 0;
-       /* don't report unsigned as conv to 32bit, because we really need to do
-        * a vfist with 64bit signed in this case */
-       if(!mode_is_signed(mode))
+       if (mode != mode_Is && mode != mode_Hs)
                return 0;
 
        if(!is_Conv(node))
@@ -2421,7 +2388,7 @@ static ir_node *gen_normal_Store(ir_node *node)
                                                    addr.index, addr.mem, new_val, mode);
                }
                store = new_node;
-       } else if (!ia32_cg_config.use_sse2 && is_float_to_int32_conv(val)) {
+       } else if (!ia32_cg_config.use_sse2 && is_float_to_int_conv(val)) {
                val = get_Conv_op(val);
 
                /* TODO: is this optimisation still necessary at all (middleend)? */
@@ -3129,12 +3096,12 @@ static ir_node *gen_x87_gp_to_fp(ir_node *node, ir_mode *src_mode) {
        ir_node  *new_node;
        int       src_bits;
 
-       /* fild can use source AM if the operand is a signed 32bit integer */
-       if (src_mode == mode_Is) {
+       /* fild can use source AM if the operand is a signed 16bit or 32bit integer */
+       if (src_mode == mode_Is || src_mode == mode_Hs) {
                ia32_address_mode_t am;
 
                match_arguments(&am, src_block, NULL, op, NULL,
-                               match_am | match_try_am);
+                               match_am | match_try_am | match_16bit | match_16bit_am);
                if (am.op_type == ia32_AddrModeS) {
                        ia32_address_t *addr = &am.addr;
 
@@ -3539,7 +3506,7 @@ static ir_node *gen_be_Return(ir_node *node) {
                                  arity, in);
        copy_node_attr(barrier, new_barrier);
        be_duplicate_deps(barrier, new_barrier);
-       set_transformed_and_mark(barrier, new_barrier);
+       be_set_transformed_node(barrier, new_barrier);
 
        /* transform normally */
        return be_duplicate_node(node);
@@ -3599,7 +3566,6 @@ static ir_node *gen_Phi(ir_node *node) {
        copy_node_attr(node, phi);
        be_duplicate_deps(node, phi);
 
-       be_set_transformed_node(node, phi);
        be_enqueue_preds(node);
 
        return phi;
@@ -4214,14 +4180,30 @@ static ir_node *gen_Proj_Quot(ir_node *node) {
        panic("No idea how to transform proj->Quot");
 }
 
-static ir_node *gen_be_Call(ir_node *node) {
-       ir_node *res = be_duplicate_node(node);
-       ir_type *call_tp;
-
-       be_node_add_flags(res, -1, arch_irn_flags_modify_flags);
+static ir_node *gen_be_Call(ir_node *node)
+{
+       dbg_info       *const dbgi      = get_irn_dbg_info(node);
+       ir_graph       *const irg       = current_ir_graph;
+       ir_node        *const src_block = get_nodes_block(node);
+       ir_node        *const block     = be_transform_node(src_block);
+       ir_node        *const src_mem   = get_irn_n(node, be_pos_Call_mem);
+       ir_node        *const src_sp    = get_irn_n(node, be_pos_Call_sp);
+       ir_node        *const sp        = be_transform_node(src_sp);
+       ir_node        *const src_ptr   = get_irn_n(node, be_pos_Call_ptr);
+       ir_node        *const noreg     = ia32_new_NoReg_gp(env_cg);
+       ia32_address_mode_t   am;
+       ia32_address_t *const addr      = &am.addr;
+       ir_node        *      mem;
+       ir_node        *      call;
+       int                   i;
+       ir_node        *      fpcw;
+       ir_node        *      eax       = noreg;
+       ir_node        *      ecx       = noreg;
+       ir_node        *      edx       = noreg;
+       unsigned        const pop       = be_Call_get_pop(node);
+       ir_type        *const call_tp   = be_Call_get_type(node);
 
        /* Run the x87 simulator if the call returns a float value */
-       call_tp = be_Call_get_type(node);
        if (get_method_n_ress(call_tp) > 0) {
                ir_type *const res_type = get_method_res_type(call_tp, 0);
                ir_mode *const res_mode = get_type_mode(res_type);
@@ -4231,7 +4213,41 @@ static ir_node *gen_be_Call(ir_node *node) {
                }
        }
 
-       return res;
+       /* We do not want be_Call direct calls */
+       assert(be_Call_get_entity(node) == NULL);
+
+       match_arguments(&am, src_block, NULL, src_ptr, src_mem,
+                       match_am | match_immediate);
+
+       i    = get_irn_arity(node) - 1;
+       fpcw = be_transform_node(get_irn_n(node, i--));
+       for (; i >= be_pos_Call_first_arg; --i) {
+               arch_register_req_t const *const req =
+                       arch_get_register_req(env_cg->arch_env, node, i);
+               ir_node *const reg_parm = be_transform_node(get_irn_n(node, i));
+
+               assert(req->type == arch_register_req_type_limited);
+               assert(req->cls == &ia32_reg_classes[CLASS_ia32_gp]);
+
+               switch (*req->limited) {
+                       case 1 << REG_EAX: assert(eax == noreg); eax = reg_parm; break;
+                       case 1 << REG_ECX: assert(ecx == noreg); ecx = reg_parm; break;
+                       case 1 << REG_EDX: assert(edx == noreg); edx = reg_parm; break;
+                       default: panic("Invalid GP register for register parameter");
+               }
+       }
+
+       mem  = transform_AM_mem(irg, block, src_ptr, src_mem, addr->mem);
+       call = new_rd_ia32_Call(dbgi, irg, block, addr->base, addr->index, mem,
+                               am.new_op2, sp, fpcw, eax, ecx, edx, pop, call_tp);
+       set_am_attributes(call, &am);
+       call = fix_mem_proj(call, &am);
+
+       if (get_irn_pinned(node) == op_pin_state_pinned)
+               set_irn_pinned(call, op_pin_state_pinned);
+
+       SET_IA32_ORIG_NODE(call, ia32_get_old_node_name(env_cg, node));
+       return call;
 }
 
 static ir_node *gen_be_IncSP(ir_node *node) {
@@ -4244,7 +4260,8 @@ static ir_node *gen_be_IncSP(ir_node *node) {
 /**
  * Transform the Projs from a be_Call.
  */
-static ir_node *gen_Proj_be_Call(ir_node *node) {
+static ir_node *gen_Proj_be_Call(ir_node *node)
+{
        ir_node  *block       = be_transform_node(get_nodes_block(node));
        ir_node  *call        = get_Proj_pred(node);
        ir_node  *new_call    = be_transform_node(call);
@@ -4256,6 +4273,7 @@ static ir_node *gen_Proj_be_Call(ir_node *node) {
        ir_mode  *mode        = get_irn_mode(node);
        ir_node  *sse_load;
        const arch_register_class_t *cls;
+       ir_node                     *res;
 
        /* The following is kinda tricky: If we're using SSE, then we have to
         * move the result value of the call in floating point registers to an
@@ -4274,9 +4292,9 @@ static ir_node *gen_Proj_be_Call(ir_node *node) {
                        call_res_pred = get_Proj_pred(call_res_new);
                }
 
-               if (call_res_pred == NULL || be_is_Call(call_res_pred)) {
+               if (call_res_pred == NULL || is_ia32_Call(call_res_pred)) {
                        return new_rd_Proj(dbgi, irg, block, new_call, mode_M,
-                                          pn_be_Call_M_regular);
+                                          n_ia32_Call_mem);
                } else {
                        assert(is_ia32_xLoad(call_res_pred));
                        return new_rd_Proj(dbgi, irg, block, call_res_pred, mode_M,
@@ -4323,7 +4341,47 @@ static ir_node *gen_Proj_be_Call(ir_node *node) {
                mode = cls->mode;
        }
 
-       return new_rd_Proj(dbgi, irg, block, new_call, mode, proj);
+       /* Map from be_Call to ia32_Call proj number */
+       if (proj == pn_be_Call_sp) {
+               proj = pn_ia32_Call_stack;
+       } else if (proj == pn_be_Call_M_regular) {
+               proj = pn_ia32_Call_M;
+       } else {
+               arch_register_req_t const *const req    = arch_get_register_req(env_cg->arch_env, node, BE_OUT_POS(proj));
+               int                        const n_outs = get_ia32_n_res(new_call);
+               int                              i;
+
+               assert(proj      >= pn_be_Call_first_res);
+               assert(req->type == arch_register_req_type_limited);
+
+               for (i = 0; i < n_outs; ++i) {
+                       arch_register_req_t const *const new_req = get_ia32_out_req(new_call, i);
+
+                       if (new_req->type     != arch_register_req_type_limited ||
+                           new_req->cls      != req->cls                       ||
+                           *new_req->limited != *req->limited)
+                               continue;
+
+                       proj = i;
+                       break;
+               }
+               assert(i < n_outs);
+       }
+
+       res = new_rd_Proj(dbgi, irg, block, new_call, mode, proj);
+
+       /* TODO arch_set_irn_register() only operates on Projs, need variant with index */
+       switch (proj) {
+               case pn_ia32_Call_stack:
+                       arch_set_irn_register(env_cg->arch_env, res, &ia32_gp_regs[REG_ESP]);
+                       break;
+
+               case pn_ia32_Call_fpcw:
+                       arch_set_irn_register(env_cg->arch_env, res, &ia32_fp_cw_regs[REG_FPCW]);
+                       break;
+       }
+
+       return res;
 }
 
 /**
@@ -4417,18 +4475,19 @@ static ir_node *gen_Proj(ir_node *node) {
                return gen_Proj_Bound(node);
        case iro_Start:
                proj = get_Proj_proj(node);
-               if (proj == pn_Start_X_initial_exec) {
-                       ir_node *block = get_nodes_block(pred);
-                       dbg_info *dbgi = get_irn_dbg_info(node);
-                       ir_node *jump;
-
-                       /* we exchange the ProjX with a jump */
-                       block = be_transform_node(block);
-                       jump  = new_rd_Jmp(dbgi, current_ir_graph, block);
-                       return jump;
-               }
-               if (node == be_get_old_anchor(anchor_tls)) {
-                       return gen_Proj_tls(node);
+               switch (proj) {
+                       case pn_Start_X_initial_exec: {
+                               ir_node  *block     = get_nodes_block(pred);
+                               ir_node  *new_block = be_transform_node(block);
+                               dbg_info *dbgi      = get_irn_dbg_info(node);
+                               /* we exchange the ProjX with a jump */
+                               ir_node  *jump      = new_rd_Jmp(dbgi, current_ir_graph, new_block);
+
+                               return jump;
+                       }
+
+                       case pn_Start_P_tls:
+                               return gen_Proj_tls(node);
                }
                break;
 
@@ -4559,8 +4618,9 @@ static void register_transformers(void)
 /**
  * Pre-transform all unknown and noreg nodes.
  */
-static void ia32_pretransform_node(void *arch_cg) {
-       ia32_code_gen_t *cg = arch_cg;
+static void ia32_pretransform_node(void)
+{
+       ia32_code_gen_t *cg = env_cg;
 
        cg->unknown_gp  = be_pre_transform_node(cg->unknown_gp);
        cg->unknown_vfp = be_pre_transform_node(cg->unknown_vfp);
@@ -4597,11 +4657,16 @@ static void add_missing_keep_walker(ir_node *node, void *data)
        assert(n_outs < (int) sizeof(unsigned) * 8);
        foreach_out_edge(node, edge) {
                ir_node *proj = get_edge_src_irn(edge);
-               int      pn   = get_Proj_proj(proj);
+               int      pn;
+
+               /* The node could be kept */
+               if (is_End(proj))
+                       continue;
 
                if (get_irn_mode(proj) == mode_M)
                        continue;
 
+               pn = get_Proj_proj(proj);
                assert(pn < n_outs);
                found_projs |= 1 << pn;
        }
@@ -4653,16 +4718,16 @@ void ia32_add_missing_keeps(ia32_code_gen_t *cg)
 }
 
 /* do the transformation */
-void ia32_transform_graph(ia32_code_gen_t *cg) {
+void ia32_transform_graph(ia32_code_gen_t *cg)
+{
        int cse_last;
-       ir_graph *irg = cg->irg;
 
        register_transformers();
        env_cg       = cg;
        initial_fpcw = NULL;
 
        BE_TIMER_PUSH(t_heights);
-       heights      = heights_new(irg);
+       heights      = heights_new(cg->irg);
        BE_TIMER_POP(t_heights);
        ia32_calculate_non_address_mode_nodes(cg->birg);
 
@@ -4671,7 +4736,7 @@ void ia32_transform_graph(ia32_code_gen_t *cg) {
        cse_last = get_opt_cse();
        set_opt_cse(0);
 
-       be_transform_graph(cg->birg, ia32_pretransform_node, cg);
+       be_transform_graph(cg->birg, ia32_pretransform_node);
 
        set_opt_cse(cse_last);