change pn_XXX_max enum to really be the maximum pn and not maximum+1, add n_XXX_max...
[libfirm] / ir / be / beabihelper.c
index d511f91..5b5fe69 100644 (file)
@@ -52,11 +52,10 @@ typedef struct reg_flag_t {
  */
 typedef struct register_state_mapping_t {
        ir_node   **value_map;     /**< mapping of state indices to values */
-       int       **reg_index_map; /**< mapping of regclass,regnum to an index
+       size_t    **reg_index_map; /**< mapping of regclass,regnum to an index
                                        into the value_map */
        reg_flag_t *regs;          /**< registers (and memory values) that form a
                                        state */
-       ir_node    *last_barrier;
 } register_state_mapping_t;
 
 /**
@@ -90,15 +89,15 @@ static void prepare_rsm(register_state_mapping_t *rsm,
        ARR_APP1(reg_flag_t, rsm->regs, memory);
 
        rsm->value_map     = NULL;
-       rsm->reg_index_map = XMALLOCN(int*, n_reg_classes);
+       rsm->reg_index_map = XMALLOCN(size_t*, n_reg_classes);
        for (c = 0; c < n_reg_classes; ++c) {
                const arch_register_class_t *cls    = &arch_env->register_classes[c];
                unsigned                     n_regs = arch_register_class_n_regs(cls);
                unsigned                     r;
 
-               rsm->reg_index_map[c] = XMALLOCN(int, n_regs);
+               rsm->reg_index_map[c] = XMALLOCN(size_t, n_regs);
                for (r = 0; r < n_regs; ++r) {
-                       rsm->reg_index_map[c][r] = -1;
+                       rsm->reg_index_map[c][r] = (size_t)-1;
                }
        }
 }
@@ -150,7 +149,7 @@ static void rsm_clear_regs(register_state_mapping_t *rsm,
                unsigned                     r;
 
                for (r = 0; r < n_regs; ++r) {
-                       rsm->reg_index_map[c][r] = -1;
+                       rsm->reg_index_map[c][r] = (size_t)-1;
                }
        }
        ARR_RESIZE(reg_flag_t, rsm->regs, 0);
@@ -166,17 +165,17 @@ static void rsm_clear_regs(register_state_mapping_t *rsm,
  * Add a register and its constraint flags to a register state map
  * and return its index inside the map.
  */
-static int rsm_add_reg(register_state_mapping_t *rsm,
-                       const arch_register_t *reg,
-                       arch_register_req_type_t flags)
+static size_t rsm_add_reg(register_state_mapping_t *rsm,
+                          const arch_register_t *reg,
+                           arch_register_req_type_t flags)
 {
-       int        input_idx = ARR_LEN(rsm->regs);
+       size_t     input_idx = ARR_LEN(rsm->regs);
        int        cls_idx   = reg->reg_class->index;
        int        reg_idx   = reg->index;
        reg_flag_t regflag   = { reg, flags };
 
        /* we must not have used get_value yet */
-       assert(rsm->reg_index_map[cls_idx][reg_idx] == -1);
+       assert(rsm->reg_index_map[cls_idx][reg_idx] == (size_t)-1);
        rsm->reg_index_map[cls_idx][reg_idx] = input_idx;
        ARR_APP1(reg_flag_t, rsm->regs, regflag);
 
@@ -190,9 +189,9 @@ static int rsm_add_reg(register_state_mapping_t *rsm,
 /**
  * Retrieve the ir_node stored at the given index in the register state map.
  */
-static ir_node *rsm_get_value(register_state_mapping_t *rsm, int index)
+static ir_node *rsm_get_value(register_state_mapping_t *rsm, size_t index)
 {
-       assert(0 <= index && index < ARR_LEN(rsm->value_map));
+       assert(index < ARR_LEN(rsm->value_map));
        return rsm->value_map[index];
 }
 
@@ -202,9 +201,9 @@ static ir_node *rsm_get_value(register_state_mapping_t *rsm, int index)
 static ir_node *rsm_get_reg_value(register_state_mapping_t *rsm,
                                   const arch_register_t *reg)
 {
-       int cls_idx   = reg->reg_class->index;
-       int reg_idx   = reg->index;
-       int input_idx = rsm->reg_index_map[cls_idx][reg_idx];
+       int    cls_idx   = reg->reg_class->index;
+       int    reg_idx   = reg->index;
+       size_t input_idx = rsm->reg_index_map[cls_idx][reg_idx];
 
        return rsm_get_value(rsm, input_idx);
 }
@@ -212,10 +211,10 @@ static ir_node *rsm_get_reg_value(register_state_mapping_t *rsm,
 /**
  * Enter a ir_node at the given index in the register state map.
  */
-static void rsm_set_value(register_state_mapping_t *rsm, int index,
+static void rsm_set_value(register_state_mapping_t *rsm, size_t index,
                           ir_node *value)
 {
-       assert(0 <= index && index < ARR_LEN(rsm->value_map));
+       assert(index < ARR_LEN(rsm->value_map));
        rsm->value_map[index] = value;
 }
 
@@ -225,53 +224,12 @@ static void rsm_set_value(register_state_mapping_t *rsm, int index,
 static void rsm_set_reg_value(register_state_mapping_t *rsm,
                               const arch_register_t *reg, ir_node *value)
 {
-       int cls_idx   = reg->reg_class->index;
-       int reg_idx   = reg->index;
-       int input_idx = rsm->reg_index_map[cls_idx][reg_idx];
+       int    cls_idx   = reg->reg_class->index;
+       int    reg_idx   = reg->index;
+       size_t input_idx = rsm->reg_index_map[cls_idx][reg_idx];
        rsm_set_value(rsm, input_idx, value);
 }
 
-/**
- * Create a Barrier from the registers stored at a register state map.
- *
- * @param rsm    the register state map
- * @param block  the block to create the Barrier on
- */
-static ir_node *rsm_create_barrier(register_state_mapping_t *rsm,
-                                   ir_node *block)
-{
-       size_t    n_barrier_outs = ARR_LEN(rsm->regs);
-       ir_node **in             = rsm->value_map;
-       ir_node  *barrier;
-       size_t    o;
-
-       assert(ARR_LEN(rsm->value_map) == n_barrier_outs);
-
-       barrier = be_new_Barrier(block, n_barrier_outs, in);
-
-       for (o = 0; o < n_barrier_outs; ++o) {
-               const reg_flag_t      *regflag = &rsm->regs[o];
-               const arch_register_t *reg     = regflag->reg;
-               ir_node               *proj;
-               if (reg == NULL) {
-                       arch_set_out_register_req(barrier, o, arch_no_register_req);
-                       proj = new_r_Proj(barrier, mode_M, o);
-               } else {
-                       be_set_constr_single_reg_in(barrier, o, reg, arch_register_req_type_none);
-                       be_set_constr_single_reg_out(barrier, o, reg, regflag->flags);
-                       proj = new_r_Proj(barrier, reg->reg_class->mode, o);
-               }
-               rsm->value_map[o] = proj;
-       }
-
-       rsm->last_barrier = barrier;
-
-       return barrier;
-}
-
-
-
-
 
 beabi_helper_env_t *be_abihelper_prepare(ir_graph *irg)
 {
@@ -328,18 +286,9 @@ ir_node *be_prolog_create_start(beabi_helper_env_t *env, dbg_info *dbgi,
                env->prolog.value_map[o] = proj;
        }
 
-       /* start node should really be the first thing constructed */
-       assert(env->prolog.last_barrier == NULL);
-       env->prolog.last_barrier = start;
-
        return start;
 }
 
-ir_node *be_prolog_create_barrier(beabi_helper_env_t *env, ir_node *block)
-{
-       return rsm_create_barrier(&env->prolog, block);
-}
-
 ir_node *be_prolog_get_reg_value(beabi_helper_env_t *env,
                                  const arch_register_t *reg)
 {
@@ -375,7 +324,7 @@ void be_epilog_begin(beabi_helper_env_t *env)
 void be_epilog_add_reg(beabi_helper_env_t *env, const arch_register_t *reg,
                        arch_register_req_type_t flags, ir_node *value)
 {
-       int index = rsm_add_reg(&env->epilog, reg, flags);
+       size_t index = rsm_add_reg(&env->epilog, reg, flags);
        rsm_set_value(&env->epilog, index, value);
 }
 
@@ -401,11 +350,6 @@ ir_node *be_epilog_get_memory(beabi_helper_env_t *env)
        return rsm_get_value(&env->epilog, 0);
 }
 
-ir_node *be_epilog_create_barrier(beabi_helper_env_t *env, ir_node *block)
-{
-       return rsm_create_barrier(&env->epilog, block);
-}
-
 ir_node *be_epilog_create_return(beabi_helper_env_t *env, dbg_info *dbgi,
                                  ir_node *block)
 {
@@ -430,11 +374,44 @@ ir_node *be_epilog_create_return(beabi_helper_env_t *env, dbg_info *dbgi,
        }
 
        rsm_clear_regs(&env->epilog, be_get_irg_arch_env(env->irg));
-       env->epilog.last_barrier = NULL;
 
        return ret;
 }
 
+/**
+ * Tests whether a node has a real user and is not just kept by the End or
+ * Anchor node
+ */
+static bool has_real_user(const ir_node *node)
+{
+       const ir_edge_t *edge;
+       foreach_out_edge(node, edge) {
+               ir_node *user = get_edge_src_irn(edge);
+               if (!is_End(user) && !is_Anchor(user))
+                       return true;
+       }
+       return false;
+}
+
+static ir_node *add_to_keep(ir_node *last_keep,
+                            const arch_register_class_t *cls, ir_node *node)
+{
+       if (last_keep != NULL) {
+               be_Keep_add_node(last_keep, cls, node);
+       } else {
+               ir_node *in[1] = { node };
+               ir_node *block = get_nodes_block(node);
+               ir_node *schedpoint;
+               last_keep = be_new_Keep(block, 1, in);
+
+               schedpoint = skip_Proj(node);
+               if (sched_is_scheduled(schedpoint)) {
+                       sched_add_after(schedpoint, last_keep);
+               }
+       }
+       return last_keep;
+}
+
 static void add_missing_keep_walker(ir_node *node, void *data)
 {
        int              n_outs, i;
@@ -442,15 +419,28 @@ static void add_missing_keep_walker(ir_node *node, void *data)
        const ir_edge_t *edge;
        ir_mode         *mode = get_irn_mode(node);
        ir_node         *last_keep;
+       ir_node        **existing_projs;
        (void) data;
-       if (mode != mode_T)
+       if (mode != mode_T) {
+               if (!has_real_user(node)) {
+                       const arch_register_req_t   *req = arch_get_register_req_out(node);
+                       const arch_register_class_t *cls = req->cls;
+                       if (cls == NULL
+                                       || (cls->flags & arch_register_class_flag_manual_ra)) {
+                               return;
+                       }
+
+                       add_to_keep(NULL, cls, node);
+               }
                return;
+       }
 
        n_outs = arch_irn_get_n_outs(node);
        if (n_outs <= 0)
                return;
 
        rbitset_alloca(found_projs, n_outs);
+       existing_projs = ALLOCANZ(ir_node*, n_outs);
        foreach_out_edge(node, edge) {
                ir_node *succ = get_edge_src_irn(edge);
                ir_mode *mode = get_irn_mode(succ);
@@ -459,21 +449,21 @@ static void add_missing_keep_walker(ir_node *node, void *data)
                /* The node could be kept */
                if (is_End(succ) || is_Anchor(succ))
                        continue;
-
                if (mode == mode_M || mode == mode_X)
                        continue;
+               pn                 = get_Proj_proj(succ);
+               existing_projs[pn] = succ;
+               if (!has_real_user(succ))
+                       continue;
 
-               pn = get_Proj_proj(succ);
                assert(pn < n_outs);
                rbitset_set(found_projs, pn);
        }
 
-
        /* are keeps missing? */
        last_keep = NULL;
        for (i = 0; i < n_outs; ++i) {
-               ir_node                     *block;
-               ir_node                     *in[1];
+               ir_node                     *value;
                const arch_register_req_t   *req;
                const arch_register_class_t *cls;
 
@@ -487,16 +477,10 @@ static void add_missing_keep_walker(ir_node *node, void *data)
                        continue;
                }
 
-               block = get_nodes_block(node);
-               in[0] = new_r_Proj(node, arch_register_class_mode(cls), i);
-               if (last_keep != NULL) {
-                       be_Keep_add_node(last_keep, cls, in[0]);
-               } else {
-                       last_keep = be_new_Keep(block, 1, in);
-                       if (sched_is_scheduled(node)) {
-                               sched_add_after(node, last_keep);
-                       }
-               }
+               value = existing_projs[i];
+               if (value == NULL)
+                       value = new_r_Proj(node, arch_register_class_mode(cls), i);
+               last_keep = add_to_keep(last_keep, cls, value);
        }
 }