Fix typos in comments: s/wether/whether/ and related corrections.
[libfirm] / ir / be / beabi.c
index e5eb80f..e01d364 100644 (file)
@@ -55,6 +55,7 @@
 #include "beirg.h"
 #include "bessaconstr.h"
 #include "bemodule.h"
+#include "betranshlp.h"
 
 DEBUG_ONLY(static firm_dbg_module_t *dbg;)
 
@@ -86,8 +87,6 @@ struct be_abi_call_t {
  * The ABI information for the current graph.
  */
 struct be_abi_irg_t {
-       survive_dce_t        *dce_survivor;
-
        be_abi_call_t        *call;         /**< The ABI call information. */
 
        ir_node              *init_sp;      /**< The node representing the stack pointer
@@ -979,6 +978,7 @@ static int cmp_call_dependency(const void *c1, const void *c2)
 {
        ir_node *n1 = *(ir_node **) c1;
        ir_node *n2 = *(ir_node **) c2;
+       unsigned h1, h2;
 
        /*
                Classical qsort() comparison function behavior:
@@ -993,7 +993,16 @@ static int cmp_call_dependency(const void *c1, const void *c2)
                return 1;
 
        /* The nodes have no depth order, but we need a total order because qsort()
-        * is not stable. */
+        * is not stable.
+        *
+        * Additionally, we need to respect transitive dependencies. Consider a
+        * Call a depending on Call b and an independent Call c.
+        * We MUST NOT order c > a and b > c. */
+       h1 = get_irn_height(ir_heights, n1);
+       h2 = get_irn_height(ir_heights, n2);
+       if (h1 < h2) return -1;
+       if (h1 > h2) return  1;
+       /* Same height, so use a random (but stable) order */
        return get_irn_idx(n1) - get_irn_idx(n2);
 }
 
@@ -1214,76 +1223,14 @@ static void reg_map_to_arr(reg_node_map_t *res, pmap *reg_map)
        qsort(res, n, sizeof(res[0]), cmp_regs);
 }
 
-/**
- * Creates a barrier.
- */
-static ir_node *create_barrier(ir_node *bl, ir_node **mem, pmap *regs,
-                               int in_req)
-{
-       int             n_regs = pmap_count(regs);
-       int             n;
-       ir_node        *irn;
-       ir_node       **in;
-       reg_node_map_t *rm;
-
-       in = ALLOCAN(ir_node*, n_regs+1);
-       rm = ALLOCAN(reg_node_map_t, n_regs);
-       reg_map_to_arr(rm, regs);
-       for (n = 0; n < n_regs; ++n) {
-               in[n] = rm[n].irn;
-       }
-
-       if (mem) {
-               in[n++] = *mem;
-       }
-
-       irn = be_new_Barrier(bl, n, in);
-
-       for (n = 0; n < n_regs; ++n) {
-               ir_node                  *pred     = rm[n].irn;
-               const arch_register_t    *reg      = rm[n].reg;
-               arch_register_req_type_t  add_type = arch_register_req_type_none;
-               ir_node                  *proj;
-               const backend_info_t     *info;
-
-               /* stupid workaround for now... as not all nodes report register
-                * requirements. */
-               info = be_get_info(skip_Proj(pred));
-               if (info != NULL && info->out_infos != NULL) {
-                       const arch_register_req_t *ireq = arch_get_register_req_out(pred);
-                       if (ireq->type & arch_register_req_type_ignore)
-                               add_type |= arch_register_req_type_ignore;
-                       if (ireq->type & arch_register_req_type_produces_sp)
-                               add_type |= arch_register_req_type_produces_sp;
-               }
-
-               proj = new_r_Proj(irn, get_irn_mode(pred), n);
-               be_node_set_reg_class_in(irn, n, reg->reg_class);
-               if (in_req) {
-                       be_set_constr_single_reg_in(irn, n, reg,
-                                                   arch_register_req_type_none);
-               }
-               be_set_constr_single_reg_out(irn, n, reg, add_type);
-               arch_set_irn_register(proj, reg);
-
-               pmap_insert(regs, (void *) reg, proj);
-       }
-
-       if (mem) {
-               *mem = new_r_Proj(irn, mode_M, n);
-       }
-
-       return irn;
-}
-
 /**
  * Creates a be_Return for a Return node.
  *
- * @param @env    the abi environment
- * @param irn     the Return node or NULL if there was none
- * @param bl      the block where the be_Retun should be placed
- * @param mem     the current memory
- * @param n_res   number of return results
+ * @param @env  the abi environment
+ * @param irn   the Return node or NULL if there was none
+ * @param bl    the block where the be_Retun should be placed
+ * @param mem   the current memory
+ * @param n_res number of return results
  */
 static ir_node *create_be_return(be_abi_irg_t *env, ir_node *irn, ir_node *bl,
                ir_node *mem, int n_res)
@@ -1335,7 +1282,6 @@ static ir_node *create_be_return(be_abi_irg_t *env, ir_node *irn, ir_node *bl,
        be_abi_reg_map_set(reg_map, arch_env->sp, stack);
 
        /* Make the Epilogue node and call the arch's epilogue maker. */
-       create_barrier(bl, &mem, reg_map, 1);
        call->cb->epilogue(env->cb, bl, &mem, reg_map);
 
        /*
@@ -1382,13 +1328,14 @@ static ir_node *create_be_return(be_abi_irg_t *env, ir_node *irn, ir_node *bl,
        /* we have to pop the shadow parameter in in case of struct returns */
        pop = call->pop;
        ret = be_new_Return(dbgi, irg, bl, n_res, pop, n, in);
+       arch_irn_add_flags(ret, arch_irn_flags_epilog);
 
        /* Set the register classes of the return's parameter accordingly. */
        for (i = 0; i < n; ++i) {
                if (regs[i] == NULL)
                        continue;
 
-               be_node_set_reg_class_in(ret, i, regs[i]->reg_class);
+               be_set_constr_single_reg_in(ret, i, regs[i], arch_register_req_type_none);
        }
 
        /* Free the space of the Epilog's in array and the register <-> proj map. */
@@ -1611,25 +1558,13 @@ static void fix_address_of_parameter_access(be_abi_irg_t *env, ir_graph *irg,
  */
 static void fix_start_block(ir_graph *irg)
 {
-       ir_node         *initial_X   = get_irg_initial_exec(irg);
-       ir_node         *start_block = get_irg_start_block(irg);
-       const ir_edge_t *edge;
+       ir_node *initial_X   = get_irg_initial_exec(irg);
+       ir_node *start_block = get_irg_start_block(irg);
+       ir_node *jmp         = new_r_Jmp(start_block);
 
        assert(is_Proj(initial_X));
-
-       foreach_out_edge(initial_X, edge) {
-               ir_node *block = get_edge_src_irn(edge);
-
-               if (is_Anchor(block))
-                       continue;
-               if (block != start_block) {
-                       ir_node *jmp = new_r_Jmp(start_block);
-                       set_Block_cfgpred(block, get_edge_src_pos(edge), jmp);
-                       set_irg_initial_exec(irg, jmp);
-                       return;
-               }
-       }
-       panic("Initial exec has no follow block in %+F", irg);
+       exchange(initial_X, jmp);
+       set_irg_initial_exec(irg, new_r_Bad(irg));
 }
 
 /**
@@ -1737,8 +1672,6 @@ static void modify_irg(ir_graph *irg)
 
        DBG((dbg, LEVEL_1, "introducing abi on %+F\n", irg));
 
-       /* Must fetch memory here, otherwise the start Barrier gets the wrong
-        * memory, which leads to loops in the DAG. */
        old_mem = get_irg_initial_mem(irg);
 
        irp_reserve_resources(irp, IR_RESOURCE_ENTITY_LINK);
@@ -1856,6 +1789,8 @@ static void modify_irg(ir_graph *irg)
        pmap_insert(env->regs, (void *) arch_env->bp, NULL);
        start_bl   = get_irg_start_block(irg);
        env->start = be_new_Start(NULL, start_bl, pmap_count(env->regs) + 1);
+       arch_irn_add_flags(env->start, arch_irn_flags_prolog);
+       set_irg_start(irg, env->start);
 
        /*
         * make proj nodes for the callee save registers.
@@ -1896,14 +1831,11 @@ static void modify_irg(ir_graph *irg)
        /* Generate the Prologue */
        fp_reg = call->cb->prologue(env->cb, &mem, env->regs, &stack_layout->initial_bias);
 
-       /* 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_new_IncSP(sp, start_bl, env->init_sp, BE_STACK_FRAME_SIZE_EXPAND, 0);
+       arch_irn_add_flags(env->init_sp, arch_irn_flags_prolog);
        be_abi_reg_map_set(env->regs, sp, env->init_sp);
 
-       create_barrier(start_bl, &mem, env->regs, 0);
-
        env->init_sp = be_abi_reg_map_get(env->regs, sp);
        arch_set_irn_register(env->init_sp, sp);
 
@@ -2197,7 +2129,6 @@ be_abi_irg_t *be_abi_introduce(ir_graph *irg)
        struct obstack   *obst        = &birg->obst;
        unsigned          r;
 
-       pmap_entry *ent;
        ir_node *dummy;
 
        /* determine allocatable registers */
@@ -2218,7 +2149,6 @@ be_abi_irg_t *be_abi_introduce(ir_graph *irg)
 
        be_omit_fp      = options->omit_fp;
 
-       env->dce_survivor = new_survive_dce();
        env->keep_map     = pmap_create();
        env->call         = be_abi_call_new(arch_env->sp->reg_class);
        arch_env_get_call_abi(arch_env, method_type, env->call);
@@ -2257,12 +2187,6 @@ be_abi_irg_t *be_abi_introduce(ir_graph *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);
-       foreach_pmap(env->regs, ent) {
-               survive_dce_register_irn(env->dce_survivor, (ir_node **) &ent->value);
-       }
-
        env->call->cb->done(env->cb);
        env->cb = NULL;
        return env;
@@ -2274,8 +2198,6 @@ void be_abi_free(ir_graph *irg)
 
        if (env->call != NULL)
                be_abi_call_free(env->call);
-       if (env->dce_survivor != NULL)
-               free_survive_dce(env->dce_survivor);
        if (env->regs != NULL)
                pmap_destroy(env->regs);
        free(env);
@@ -2283,6 +2205,28 @@ void be_abi_free(ir_graph *irg)
        be_set_irg_abi(irg, NULL);
 }
 
+/**
+ * called after nodes have been transformed so some node references can be
+ * replaced with new nodes
+ */
+void be_abi_transform_fixup(ir_graph *irg)
+{
+       be_abi_irg_t *abi = be_get_irg_abi(irg);
+       pmap         *new_regs;
+       pmap_entry   *entry;
+       if (abi == NULL || abi->regs == NULL)
+               return;
+
+       new_regs = pmap_create();
+       foreach_pmap(abi->regs, entry) {
+               ir_node *value       = (ir_node*)entry->value;
+               ir_node *transformed = be_transform_node(value);
+               pmap_insert(new_regs, entry->key, transformed);
+       }
+       pmap_destroy(abi->regs);
+       abi->regs = new_regs;
+}
+
 void be_put_allocatable_regs(const ir_graph *irg,
                              const arch_register_class_t *cls, bitset_t *bs)
 {