disable experimental code for now
[libfirm] / ir / be / beabi.c
index f41a7ae..bb0af7b 100644 (file)
@@ -5,9 +5,8 @@
  * @date   7.3.2005
  * @cvsid  $Id$
  */
-
 #ifdef HAVE_CONFIG_H
-# include "config.h"
+# include <config.h>
 #endif
 
 #include "obst.h"
@@ -28,6 +27,7 @@
 #include "height.h"
 #include "pdeq.h"
 #include "irtools.h"
+#include "raw_bitset.h"
 
 #include "be.h"
 #include "beabi.h"
@@ -87,6 +87,9 @@ struct _be_abi_irg_t {
        pmap                 *keep_map;     /**< mapping blocks to keep nodes. */
        pset                 *ignore_regs;  /**< Additional registers which shall be ignored. */
 
+       arch_register_req_t sp_req;
+       arch_register_req_t sp_cls_req;
+
        arch_irn_handler_t irn_handler;
        arch_irn_ops_t     irn_ops;
        DEBUG_ONLY(firm_dbg_module_t    *dbg;)          /**< The debugging module. */
@@ -209,14 +212,14 @@ be_abi_call_flags_t be_abi_call_get_flags(const be_abi_call_t *call)
  *
  * @return the new ABI call object
  */
-static be_abi_call_t *be_abi_call_new(void)
+static be_abi_call_t *be_abi_call_new(const arch_register_class_t *cls_addr)
 {
        be_abi_call_t *call = xmalloc(sizeof(call[0]));
 
        call->flags.val  = 0;
        call->params     = new_set(cmp_call_arg, 16);
        call->cb         = NULL;
-       call->cls_addr   = NULL;
+       call->cls_addr   = cls_addr;
 
        call->flags.bits.try_omit_fp = be_omit_fp;
 
@@ -387,7 +390,6 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp, i
 {
        ir_graph *irg             = env->birg->irg;
        const arch_isa_t *isa     = env->birg->main_env->arch_env->isa;
-       be_abi_call_t *call       = be_abi_call_new();
        ir_type *mt               = get_Call_type(irn);
        ir_node *call_ptr         = get_Call_ptr(irn);
        int n_params              = get_method_n_params(mt);
@@ -398,6 +400,7 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp, i
        int stack_size            = 0;
        int stack_dir             = arch_isa_stack_dir(isa);
        const arch_register_t *sp = arch_isa_sp(isa);
+       be_abi_call_t *call       = be_abi_call_new(sp->reg_class);
        ir_mode *mach_mode        = sp->reg_class->mode;
        struct obstack *obst      = &env->obst;
        int no_alloc              = call->flags.bits.frame_is_setup_on_call;
@@ -485,7 +488,6 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp, i
                        curr_mem = get_Call_mem(irn);
                }
 
-               assert(mode_is_reference(mach_mode) && "machine mode must be pointer");
                for(i = 0; i < n_pos; ++i) {
                        int p                  = pos[i];
                        be_abi_call_arg_t *arg = get_call_arg(call, 0, p);
@@ -515,7 +517,11 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp, i
 
                                /* Make the expression to compute the argument's offset. */
                                if(curr_ofs > 0) {
-                                       addr = new_r_Const_long(irg, bl, mode_Is, curr_ofs);
+                                       ir_mode *constmode = mach_mode;
+                                       if(mode_is_reference(mach_mode)) {
+                                               constmode = mode_Is;
+                                       }
+                                       addr = new_r_Const_long(irg, bl, constmode, curr_ofs);
                                        addr = new_r_Add(irg, bl, curr_sp, addr, mach_mode);
                                }
                        }
@@ -636,13 +642,10 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp, i
                                       get_Call_type(irn));
 
        /*
-               Set the register class of the call address to the same as the stack pointer's
-               if it's not set by the backend in the abi callback.
+               Set the register class of the call address to
+               the backend provided class (default: stack pointer class)
        */
-       be_node_set_reg_class(low_call, be_pos_Call_ptr, call->cls_addr ? call->cls_addr : sp->reg_class);
-
-       /* Set input requirement for stack pointer. */
-       be_node_set_reg_class(low_call, be_pos_Call_sp, arch_get_irn_reg_class(isa->main_env->arch_env, curr_sp, -1));
+       be_node_set_reg_class(low_call, be_pos_Call_ptr, call->cls_addr);
 
        DBG((env->dbg, LEVEL_3, "\tcreated backend call %+F\n", low_call));
 
@@ -657,14 +660,23 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp, i
 
        /* Set the register constraints of the results. */
        for (i = 0; res_projs[i]; ++i) {
-               ir_node *irn = res_projs[i];
-               int     proj = get_Proj_proj(irn);
+               int pn = get_Proj_proj(res_projs[i]);
 
                /* Correct Proj number since it has been adjusted! (see above) */
-               const be_abi_call_arg_t *arg = get_call_arg(call, 1, proj - pn_Call_max);
+               const be_abi_call_arg_t *arg = get_call_arg(call, 1, pn - pn_Call_max);
+
+               /* Matze: we need the information about the real mode for later
+                * transforms (signed/unsigend compares, stores...), so leave the fixup
+                * for the backend transform phase... */
+#if 0
+               /* correct mode */
+               const arch_register_class_t *cls = arch_register_get_class(arg->reg);
+               ir_mode *mode = arch_register_class_mode(cls);
+               set_irn_mode(irn, mode);
+#endif
 
                assert(arg->in_reg);
-               be_set_constr_single_reg(low_call, BE_OUT_POS(proj), arg->reg);
+               be_set_constr_single_reg(low_call, BE_OUT_POS(pn), arg->reg);
        }
        obstack_free(obst, in);
        exchange(irn, low_call);
@@ -673,6 +685,11 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp, i
        for (i = 0; res_projs[i]; ++i)
                set_Proj_pred(res_projs[i], low_call);
 
+       /* set the now unnecessary projT to bad */
+       if(res_proj != NULL) {
+               be_kill_node(res_proj);
+       }
+
        /* Make additional projs for the caller save registers
           and the Keep node which keeps them alive. */
        if (pset_count(caller_save) > 0) {
@@ -749,81 +766,104 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp, i
  */
 static ir_node *adjust_alloc(be_abi_irg_t *env, ir_node *alloc, ir_node *curr_sp, ir_node **result_copy)
 {
-       if (get_Alloc_where(alloc) == stack_alloc) {
-               ir_node *bl        = get_nodes_block(alloc);
-               ir_graph *irg      = get_irn_irg(bl);
-               ir_node *alloc_mem = NULL;
-               ir_node *alloc_res = NULL;
+       ir_node *block;
+       ir_graph *irg;
+       ir_node *alloc_mem;
+       ir_node *alloc_res;
+       ir_type *type;
 
-               const ir_edge_t *edge;
-               ir_node *new_alloc;
-               ir_node *addr;
-               ir_node *copy;
-               ir_node *ins[2];
+       const ir_edge_t *edge;
+       ir_node *new_alloc;
+       ir_node *size;
+       ir_node *addr;
+       ir_node *copy;
+       ir_node *ins[2];
+
+       if (get_Alloc_where(alloc) != stack_alloc) {
+               assert(0);
+               return alloc;
+       }
 
-               foreach_out_edge(alloc, edge) {
-                       ir_node *irn = get_edge_src_irn(edge);
+       block = get_nodes_block(alloc);
+       irg = get_irn_irg(block);
+       alloc_mem = NULL;
+       alloc_res = NULL;
+       type = get_Alloc_type(alloc);
 
-                       assert(is_Proj(irn));
-                       switch(get_Proj_proj(irn)) {
-                       case pn_Alloc_M:
-                               alloc_mem = irn;
-                               break;
-                       case pn_Alloc_res:
-                               alloc_res = irn;
-                               break;
-                       default:
-                               break;
-                       }
-               }
+       foreach_out_edge(alloc, edge) {
+               ir_node *irn = get_edge_src_irn(edge);
 
-               /* Beware: currently Alloc nodes without a result might happen,
-                  only escape analysis kills them and this phase runs only for object
-                  oriented source. We kill the Alloc here. */
-               if (alloc_res == NULL && alloc_mem) {
-                       exchange(alloc_mem, get_Alloc_mem(alloc));
-                       return curr_sp;
+               assert(is_Proj(irn));
+               switch(get_Proj_proj(irn)) {
+               case pn_Alloc_M:
+                       alloc_mem = irn;
+                       break;
+               case pn_Alloc_res:
+                       alloc_res = irn;
+                       break;
+               default:
+                       break;
                }
+       }
 
-               /* The stack pointer will be modified in an unknown manner.
-                  We cannot omit it. */
-               env->call->flags.bits.try_omit_fp = 0;
-               new_alloc = be_new_AddSP(env->isa->sp, irg, bl, curr_sp, get_Alloc_size(alloc));
+       /* Beware: currently Alloc nodes without a result might happen,
+          only escape analysis kills them and this phase runs only for object
+          oriented source. We kill the Alloc here. */
+       if (alloc_res == NULL && alloc_mem) {
+               exchange(alloc_mem, get_Alloc_mem(alloc));
+               return curr_sp;
+       }
 
-               if(alloc_mem != NULL) {
-                       ir_node *addsp_mem;
-                       ir_node *sync;
+       /* we might need to multiply the size with the element size */
+       if(type != get_unknown_type() && get_type_size_bytes(type) != 1) {
+               tarval *tv = new_tarval_from_long(get_type_size_bytes(type), mode_Iu);
+               ir_node *cnst = new_rd_Const(NULL, irg, block, mode_Iu, tv);
+               ir_node *mul = new_rd_Mul(NULL, irg, block, get_Alloc_size(alloc),
+                                         cnst, mode_Iu);
+               size = mul;
+       } else {
+               size = get_Alloc_size(alloc);
+       }
 
-                       addsp_mem = new_r_Proj(irg, bl, new_alloc, mode_M, pn_be_AddSP_M);
+       /* The stack pointer will be modified in an unknown manner.
+          We cannot omit it. */
+       env->call->flags.bits.try_omit_fp = 0;
+       new_alloc = be_new_AddSP(env->isa->sp, irg, block, curr_sp, size);
 
-                       // We need to sync the output mem of the AddSP with the input mem
-                       // edge into the alloc node
-                       ins[0] = get_Alloc_mem(alloc);
-                       ins[1] = addsp_mem;
-                       sync = new_r_Sync(irg, bl, 2, ins);
+       if(alloc_mem != NULL) {
+               ir_node *addsp_mem;
+               ir_node *sync;
 
-                       exchange(alloc_mem, sync);
-               }
+               addsp_mem = new_r_Proj(irg, block, new_alloc, mode_M, pn_be_AddSP_M);
+
+               // We need to sync the output mem of the AddSP with the input mem
+               // edge into the alloc node
+               ins[0] = get_Alloc_mem(alloc);
+               ins[1] = addsp_mem;
+               sync = new_r_Sync(irg, block, 2, ins);
 
-               exchange(alloc, new_alloc);
+               exchange(alloc_mem, sync);
+       }
 
-               /* fix projnum of alloca res */
-               set_Proj_proj(alloc_res, pn_be_AddSP_res);
+       exchange(alloc, new_alloc);
 
-               addr = env->isa->stack_dir < 0 ? alloc_res : curr_sp;
+       /* fix projnum of alloca res */
+       set_Proj_proj(alloc_res, pn_be_AddSP_res);
 
-               /* copy the address away, since it could be used after further stack pointer modifications. */
-               /* Let it point curr_sp just for the moment, I'll reroute it in a second. */
-               *result_copy = copy = be_new_Copy(env->isa->sp->reg_class, irg, bl, curr_sp);
+       addr = env->isa->stack_dir < 0 ? alloc_res : curr_sp;
 
-               /* Let all users of the Alloc() result now point to the copy. */
-               edges_reroute(alloc_res, copy, irg);
+       /* copy the address away, since it could be used after further stack pointer modifications. */
+       /* Let it point curr_sp just for the moment, I'll reroute it in a second. */
+       *result_copy = copy = be_new_Copy(env->isa->sp->reg_class, irg, block, curr_sp);
 
-               /* Rewire the copy appropriately. */
-               set_irn_n(copy, be_pos_Copy_op, addr);
+       /* Let all users of the Alloc() result now point to the copy. */
+       edges_reroute(alloc_res, copy, irg);
+
+       /* Rewire the copy appropriately. */
+       set_irn_n(copy, be_pos_Copy_op, addr);
+
+       curr_sp = alloc_res;
 
-               curr_sp = alloc_res;
-       }
        return curr_sp;
 }  /* adjust_alloc */
 
@@ -833,22 +873,52 @@ static ir_node *adjust_alloc(be_abi_irg_t *env, ir_node *alloc, ir_node *curr_sp
  */
 static ir_node *adjust_free(be_abi_irg_t *env, ir_node *free, ir_node *curr_sp)
 {
-       if (get_Free_where(free) == stack_alloc) {
-               ir_node *bl        = get_nodes_block(free);
-               ir_graph *irg      = get_irn_irg(bl);
-               ir_node *addsp, *mem, *res;
-
-               /* The stack pointer will be modified in an unknown manner.
-                  We cannot omit it. */
-               env->call->flags.bits.try_omit_fp = 0;
-               addsp = be_new_SubSP(env->isa->sp, irg, bl, curr_sp, get_Free_size(free));
+       ir_node *block;
+       ir_graph *irg;
+       ir_node *subsp, *mem, *res, *size, *sync;
+       ir_type *type;
+       ir_node *in[2];
 
-               mem = new_r_Proj(irg, bl, addsp, mode_M, pn_be_SubSP_M);
-               res = new_r_Proj(irg, bl, addsp, mode_P_data, pn_be_SubSP_res);
+       if (get_Free_where(free) != stack_alloc) {
+               assert(0);
+               return free;
+       }
 
-               exchange(free, mem);
-               curr_sp = res;
+       block = get_nodes_block(free);
+       irg = get_irn_irg(block);
+       type = get_Free_type(free);
+
+       /* we might need to multiply the size with the element size */
+       if(type != get_unknown_type() && get_type_size_bytes(type) != 1) {
+               tarval *tv = new_tarval_from_long(get_type_size_bytes(type), mode_Iu);
+               ir_node *cnst = new_rd_Const(NULL, irg, block, mode_Iu, tv);
+               ir_node *mul = new_rd_Mul(NULL, irg, block, get_Free_size(free),
+                                         cnst, mode_Iu);
+               size = mul;
+       } else {
+               size = get_Free_size(free);
        }
+
+       /* The stack pointer will be modified in an unknown manner.
+          We cannot omit it. */
+       env->call->flags.bits.try_omit_fp = 0;
+       subsp = be_new_SubSP(env->isa->sp, irg, block, curr_sp, size);
+
+       mem = new_r_Proj(irg, block, subsp, mode_M, pn_be_SubSP_M);
+       res = new_r_Proj(irg, block, subsp, mode_P_data, pn_be_SubSP_res);
+
+       /* we need to sync the memory */
+       in[0] = get_Free_mem(free);
+       in[1] = mem;
+       sync = new_r_Sync(irg, block, 2, in);
+
+       /* and make the AddSP dependent on the former memory */
+       add_irn_dep(subsp, get_Free_mem(free));
+
+       /* kill the free */
+       exchange(free, sync);
+       curr_sp = res;
+
        return curr_sp;
 }  /* adjust_free */
 
@@ -891,12 +961,9 @@ static int check_dependence(ir_node *curr, ir_node *tgt, ir_node *bl)
  */
 static int dependent_on(ir_node *n1, ir_node *n2)
 {
-       ir_node *bl   = get_nodes_block(n1);
-
-       assert(bl == get_nodes_block(n2));
+       assert(get_nodes_block(n1) == get_nodes_block(n2));
 
        return heights_reachable_in_block(ir_heights, n1, n2);
-       //return check_dependence(n1, n2, bl);
 }
 
 static int cmp_call_dependecy(const void *c1, const void *c2)
@@ -1603,6 +1670,7 @@ static void modify_irg(be_abi_irg_t *env)
        ir_node *reg_params_bl;
        ir_node **args;
        ir_node *arg_tuple;
+       ir_node *value_param_base;
        const ir_edge_t *edge;
        ir_type *arg_type, *bet_type;
        lower_frame_sels_env_t ctx;
@@ -1618,6 +1686,11 @@ static void modify_irg(be_abi_irg_t *env)
        ctx.value_param_list = NULL;
        irg_walk_graph(irg, lower_frame_sels_walker, NULL, &ctx);
 
+       /* value_param_base anchor is not needed anymore now */
+       value_param_base = get_irg_value_param_base(irg);
+       be_kill_node(value_param_base);
+       set_irg_value_param_base(irg, new_r_Bad(irg));
+
        env->frame = obstack_alloc(&env->obst, sizeof(env->frame[0]));
        env->regs  = pmap_create();
 
@@ -1670,7 +1743,7 @@ static void modify_irg(be_abi_irg_t *env)
                const arch_register_class_t *cls = arch_isa_get_reg_class(isa, i);
                for(j = 0; j < cls->n_regs; ++j) {
                        const arch_register_t *reg = &cls->regs[j];
-                       if(arch_register_type_is(reg, callee_save) || arch_register_type_is(reg, ignore))
+                       if(arch_register_type_is(reg, callee_save))
                                pmap_insert(env->regs, (void *) reg, NULL);
                }
        }
@@ -1692,8 +1765,7 @@ static void modify_irg(be_abi_irg_t *env)
        rm = reg_map_to_arr(&env->obst, env->regs);
        for(i = 0, n = pmap_count(env->regs); i < n; ++i) {
                arch_register_t *reg = (void *) rm[i].reg;
-               ir_node *arg_proj    = rm[i].irn;
-               ir_mode *mode        = arg_proj ? get_irn_mode(arg_proj) : reg->reg_class->mode;
+               ir_mode *mode        = reg->reg_class->mode;
                long nr              = i;
                int pos              = BE_OUT_POS((int) nr);
                int flags            = 0;
@@ -1728,19 +1800,21 @@ static void modify_irg(be_abi_irg_t *env)
 
        /* do the stack allocation BEFORE the barrier, or spill code
           might be added before it */
-       env->init_sp  = be_abi_reg_map_get(env->regs, sp);
+       env->init_sp = be_abi_reg_map_get(env->regs, sp);
        env->init_sp = be_new_IncSP(sp, irg, bl, env->init_sp, BE_STACK_FRAME_SIZE_EXPAND);
        be_abi_reg_map_set(env->regs, sp, env->init_sp);
 
        env->start_barrier = barrier = create_barrier(env, bl, &mem, env->regs, 0);
 
-       env->init_sp  = be_abi_reg_map_get(env->regs, sp);
+       env->init_sp = be_abi_reg_map_get(env->regs, sp);
        arch_set_irn_register(env->birg->main_env->arch_env, env->init_sp, sp);
 
        frame_pointer = be_abi_reg_map_get(env->regs, fp_reg);
        set_irg_frame(irg, frame_pointer);
        pset_insert_ptr(env->ignore_regs, fp_reg);
 
+       set_irg_initial_mem(irg, mem);
+
        /* Now, introduce stack param nodes for all parameters passed on the stack */
        for(i = 0; i < n_params; ++i) {
                ir_node *arg_proj = args[i];
@@ -1776,10 +1850,15 @@ static void modify_irg(be_abi_irg_t *env)
                        }
 
                        assert(repl != NULL);
-                       edges_reroute(args[i], repl, irg);
+                       exchange(args[i], repl);
                }
        }
 
+       /* the arg proj is not needed anymore now */
+       assert(get_irn_n_edges(arg_tuple) == 0);
+       be_kill_node(arg_tuple);
+       set_irg_args(irg, new_rd_Bad(irg));
+
        /* All Return nodes hang on the End node, so look for them there. */
        for (i = 0, n = get_Block_n_cfgpreds(end); i < n; ++i) {
                ir_node *irn = get_Block_cfgpred(end, i);
@@ -1809,6 +1888,7 @@ be_abi_irg_t *be_abi_introduce(be_irg_t *birg)
        pmap_entry *ent;
        ir_node *dummy;
        optimization_state_t state;
+       unsigned *limited_bitset;
 
        be_omit_fp = birg->main_env->options->omit_fp;
 
@@ -1816,7 +1896,7 @@ be_abi_irg_t *be_abi_introduce(be_irg_t *birg)
 
        env->isa           = birg->main_env->arch_env->isa;
        env->method_type   = get_entity_type(get_irg_entity(irg));
-       env->call          = be_abi_call_new();
+       env->call          = be_abi_call_new(env->isa->sp->reg_class);
        arch_isa_get_call_abi(env->isa, env->method_type, env->call);
 
        env->ignore_regs      = pset_new_ptr_default();
@@ -1824,6 +1904,16 @@ be_abi_irg_t *be_abi_introduce(be_irg_t *birg)
        env->dce_survivor     = new_survive_dce();
        env->birg             = birg;
        env->stack_phis       = pset_new_ptr(16);
+
+       env->sp_req.type      = arch_register_req_type_limited;
+       env->sp_req.cls       = arch_register_get_class(env->isa->sp);
+       limited_bitset        = rbitset_obstack_alloc(&env->obst, env->sp_req.cls->n_regs);
+       rbitset_set(limited_bitset, arch_register_get_index(env->isa->sp));
+       env->sp_req.limited   = limited_bitset;
+
+       env->sp_cls_req.type  = arch_register_req_type_normal;
+       env->sp_cls_req.cls   = arch_register_get_class(env->isa->sp);
+
        /* Beware: later we replace this node by the real one, ensure it is not CSE'd
           to another Unknown or the stack pointer gets used */
        save_optimization_state(&state);
@@ -1851,13 +1941,14 @@ be_abi_irg_t *be_abi_introduce(be_irg_t *birg)
        pmap_destroy(env->keep_map);
 
        /* reroute the stack origin of the calls to the true stack origin. */
-       edges_reroute(dummy, env->init_sp, irg);
-       edges_reroute(old_frame, get_irg_frame(irg), irg);
+       exchange(dummy, env->init_sp);
+       exchange(old_frame, get_irg_frame(irg));
 
        /* Make some important node pointers survive the dead node elimination. */
        survive_dce_register_irn(env->dce_survivor, &env->init_sp);
-       pmap_foreach(env->regs, ent)
+       pmap_foreach(env->regs, ent) {
                survive_dce_register_irn(env->dce_survivor, (ir_node **) &ent->value);
+       }
 
        arch_env_push_irn_handler(env->birg->main_env->arch_env, &env->irn_handler);
 
@@ -2070,33 +2161,19 @@ static const void *abi_get_irn_ops(const arch_irn_handler_t *handler, const ir_n
        return res;
 }
 
-static void be_abi_limited(void *data, bitset_t *bs)
-{
-       be_abi_irg_t *abi = data;
-       bitset_clear_all(bs);
-       bitset_set(bs, abi->isa->sp->index);
-}
-
-static const arch_register_req_t *abi_get_irn_reg_req(const void *self, arch_register_req_t *req, const ir_node *irn, int pos)
+static
+const arch_register_req_t *abi_get_irn_reg_req(const void *self,
+                                               const ir_node *irn, int pos)
 {
-       be_abi_irg_t *abi          = get_abi_from_ops(self);
-       const arch_register_t *reg = abi->isa->sp;
-
-       memset(req, 0, sizeof(req[0]));
+       be_abi_irg_t *abi = get_abi_from_ops(self);
 
        if(pos == BE_OUT_POS(0)) {
-               req->cls         = reg->reg_class;
-               req->type        = arch_register_req_type_limited;
-               req->limited     = be_abi_limited;
-               req->limited_env = abi;
-       }
-
-       else if(pos >= 0 && pos < get_irn_arity(irn)) {
-               req->cls  = reg->reg_class;
-               req->type = arch_register_req_type_normal;
+               return &abi->sp_req;
+       } else if(pos >= 0 && pos < get_irn_arity(irn)) {
+               return &abi->sp_cls_req;
        }
 
-       return req;
+       return arch_no_register_req;
 }
 
 static void abi_set_irn_reg(const void *self, ir_node *irn, const arch_register_t *reg)