added a few benchmarks/testapps from http://shootout.alioth.debian.org
[libfirm] / ir / be / beabi.c
index 34fa0de..55aab00 100644 (file)
@@ -118,7 +118,7 @@ static const arch_irn_handler_t abi_irn_handler;
 static heights_t *ir_heights;
 
 /* Flag: if set, try to omit the frame pointer if called by the backend */
-int be_omit_fp = 1;
+static int be_omit_fp = 1;
 
 /*
      _    ____ ___    ____      _ _ _                _
@@ -338,6 +338,7 @@ static be_stack_layout_t *stack_frame_init(be_stack_layout_t *frame, ir_type *ar
        return frame;
 }
 
+#if 0
 /** Dumps the stack layout to file. */
 static void stack_layout_dump(FILE *file, be_stack_layout_t *frame)
 {
@@ -354,6 +355,7 @@ static void stack_layout_dump(FILE *file, be_stack_layout_t *frame)
                }
        }
 }
+#endif
 
 /**
  * Returns non-zero if the call argument at given position
@@ -383,7 +385,7 @@ static INLINE int is_on_stack(be_abi_call_t *call, int pos)
  * @param curr_sp The stack pointer node to use.
  * @return The stack pointer after the call.
  */
-static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp)
+static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp, ir_node *alloca_copy)
 {
        ir_graph *irg             = env->birg->irg;
        const arch_isa_t *isa     = env->birg->main_env->arch_env->isa;
@@ -400,7 +402,6 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp)
        const arch_register_t *sp = arch_isa_sp(isa);
        ir_mode *mach_mode        = sp->reg_class->mode;
        struct obstack *obst      = &env->obst;
-       ir_node *no_mem           = get_irg_no_mem(irg);
        int no_alloc              = call->flags.bits.frame_is_setup_on_call;
 
        ir_node *res_proj = NULL;
@@ -471,7 +472,18 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp)
                 * moving the stack pointer along the stack's direction.
                 */
                if(stack_dir < 0 && !do_seq && !no_alloc) {
-                       curr_sp = be_new_IncSP(sp, irg, bl, curr_sp, no_mem, stack_size);
+                       curr_sp = be_new_IncSP(sp, irg, bl, curr_sp, stack_size);
+                       if(alloca_copy) {
+                               add_irn_dep(curr_sp, alloca_copy);
+                               alloca_copy = NULL;
+                       }
+               }
+
+               if(!do_seq) {
+                       obstack_ptr_grow(obst, get_Call_mem(irn));
+                       curr_mem = new_NoMem();
+               } else {
+                       curr_mem = get_Call_mem(irn);
                }
 
                assert(mode_is_reference(mach_mode) && "machine mode must be pointer");
@@ -491,8 +503,12 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp)
                         */
                        if (do_seq) {
                                curr_ofs = 0;
-                               addr = curr_sp = be_new_IncSP(sp, irg, bl, curr_sp, curr_mem,
-                                       param_size + arg->space_before);
+                               addr = curr_sp = be_new_IncSP(sp, irg, bl, curr_sp, param_size + arg->space_before);
+                               if(alloca_copy) {
+                                       add_irn_dep(curr_sp, alloca_copy);
+                                       alloca_copy = NULL;
+                               }
+                               add_irn_dep(curr_sp, curr_mem);
                        }
                        else {
                                curr_ofs += arg->space_before;
@@ -507,15 +523,18 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp)
 
                        /* Insert a store for primitive arguments. */
                        if (is_atomic_type(param_type)) {
-                               mem = new_r_Store(irg, bl, curr_mem, addr, param);
-                               mem = new_r_Proj(irg, bl, mem, mode_M, pn_Store_M);
+                               ir_node *store;
+                               store = new_r_Store(irg, bl, curr_mem, addr, param);
+                               mem = new_r_Proj(irg, bl, store, mode_M, pn_Store_M);
                        }
 
                        /* Make a mem copy for compound arguments. */
                        else {
+                               ir_node *copy;
+
                                assert(mode_is_reference(get_irn_mode(param)));
-                               mem = new_r_CopyB(irg, bl, curr_mem, addr, param, param_type);
-                               mem = new_r_Proj(irg, bl, mem, mode_M, pn_CopyB_M_regular);
+                               copy = new_r_CopyB(irg, bl, curr_mem, addr, param, param_type);
+                               mem = new_r_Proj(irg, bl, copy, mode_M, pn_CopyB_M_regular);
                        }
 
                        curr_ofs += param_size;
@@ -529,8 +548,13 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp)
                in = (ir_node **) obstack_finish(obst);
 
                /* We need the sync only, if we didn't build the stores sequentially. */
-               if(!do_seq)
-                       curr_mem = new_r_Sync(irg, bl, n_pos, in);
+               if(!do_seq) {
+                       if(n_pos >= 1) {
+                               curr_mem = new_r_Sync(irg, bl, n_pos + 1, in);
+                       } else {
+                               curr_mem = get_Call_mem(irn);
+                       }
+               }
                obstack_free(obst, in);
        }
 
@@ -686,12 +710,20 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp)
                        }
                }
 
-               if(!mem_proj)
+               if(!mem_proj) {
                        mem_proj = new_r_Proj(irg, bl, low_call, mode_M, pn_Call_M);
+                       keep_alive(mem_proj);
+               }
 
                 /* Clean up the stack frame if we allocated it */
-               if(!no_alloc)
-                       curr_sp = be_new_IncSP(sp, irg, bl, curr_sp, mem_proj, -stack_size);
+               if(!no_alloc) {
+                       curr_sp = be_new_IncSP(sp, irg, bl, curr_sp, -stack_size);
+                       add_irn_dep(curr_sp, mem_proj);
+                       if(alloca_copy) {
+                               add_irn_dep(curr_sp, alloca_copy);
+                               alloca_copy = NULL;
+                       }
+               }
        }
 
        be_abi_call_free(call);
@@ -706,7 +738,7 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp)
  * Adjust an alloca.
  * The alloca is transformed into a back end alloca node and connected to the stack nodes.
  */
-static ir_node *adjust_alloc(be_abi_irg_t *env, ir_node *alloc, ir_node *curr_sp)
+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);
@@ -718,6 +750,7 @@ static ir_node *adjust_alloc(be_abi_irg_t *env, ir_node *alloc, ir_node *curr_sp
                ir_node *new_alloc;
                ir_node *addr;
                ir_node *copy;
+               ir_node *ins[2];
 
                foreach_out_edge(alloc, edge) {
                        ir_node *irn = get_edge_src_irn(edge);
@@ -748,19 +781,31 @@ static ir_node *adjust_alloc(be_abi_irg_t *env, ir_node *alloc, ir_node *curr_sp
                env->call->flags.bits.try_omit_fp = 0;
                new_alloc = be_new_AddSP(env->isa->sp, irg, bl, curr_sp, get_Alloc_size(alloc));
 
-               exchange(alloc, new_alloc);
+               if(alloc_mem != NULL) {
+                       ir_node *addsp_mem;
+                       ir_node *sync;
+
+                       addsp_mem = new_r_Proj(irg, bl, 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, bl, 2, ins);
+
+                       exchange(alloc_mem, sync);
+               }
 
-               if(alloc_mem != NULL)
-                       set_Proj_proj(alloc_mem, pn_be_AddSP_M);
+               exchange(alloc, new_alloc);
 
                /* fix projnum of alloca res */
                set_Proj_proj(alloc_res, pn_be_AddSP_res);
 
                addr = env->isa->stack_dir < 0 ? alloc_res : curr_sp;
 
-               /* copy the address away, since it could be used after further stack pointer modifictions. */
+               /* 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. */
-               copy = be_new_Copy(env->isa->sp->reg_class, irg, bl, curr_sp);
+               *result_copy = copy = be_new_Copy(env->isa->sp->reg_class, irg, bl, curr_sp);
 
                /* Let all users of the Alloc() result now point to the copy. */
                edges_reroute(alloc_res, copy, irg);
@@ -880,6 +925,7 @@ static void process_calls_in_block(ir_node *bl, void *data)
        if(n > 0) {
                ir_node *keep;
                ir_node **nodes;
+               ir_node *copy = NULL;
                int i;
 
                nodes = obstack_finish(&env->obst);
@@ -893,10 +939,10 @@ static void process_calls_in_block(ir_node *bl, void *data)
                        DBG((env->dbg, LEVEL_3, "\tprocessing call %+F\n", irn));
                        switch(get_irn_opcode(irn)) {
                        case iro_Call:
-                               curr_sp = adjust_call(env, irn, curr_sp);
+                               curr_sp = adjust_call(env, irn, curr_sp, copy);
                                break;
                        case iro_Alloc:
-                               curr_sp = adjust_alloc(env, irn, curr_sp);
+                               curr_sp = adjust_alloc(env, irn, curr_sp, &copy);
                                break;
                        default:
                                break;
@@ -929,14 +975,6 @@ static void process_calls(be_abi_irg_t *env)
        heights_free(ir_heights);
 }
 
-static void collect_return_walker(ir_node *irn, void *data)
-{
-       if(get_irn_opcode(irn) == iro_Return) {
-               struct obstack *obst = data;
-               obstack_ptr_grow(obst, irn);
-       }
-}
-
 #if 0 /*
 static ir_node *setup_frame(be_abi_irg_t *env)
 {
@@ -1073,6 +1111,7 @@ static ir_type *compute_arg_type(be_abi_irg_t *env, be_abi_call_t *call, ir_type
        return res;
 }
 
+#if 0
 static void create_register_perms(const arch_isa_t *isa, ir_graph *irg, ir_node *bl, pmap *regs)
 {
        int i, j, n;
@@ -1114,6 +1153,7 @@ static void create_register_perms(const arch_isa_t *isa, ir_graph *irg, ir_node
 
        obstack_free(&obst, NULL);
 }
+#endif
 
 typedef struct {
        const arch_register_t *reg;
@@ -1472,7 +1512,6 @@ static void modify_irg(be_abi_irg_t *env)
        ir_graph *irg             = env->birg->irg;
        ir_node *bl               = get_irg_start_block(irg);
        ir_node *end              = get_irg_end_block(irg);
-       ir_node *no_mem           = get_irg_no_mem(irg);
        ir_node *mem              = get_irg_initial_mem(irg);
        ir_type *method_type      = get_entity_type(get_irg_entity(irg));
        pset *dont_save           = pset_new_ptr(8);
@@ -1611,7 +1650,7 @@ 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_new_IncSP(sp, irg, bl, env->init_sp, no_mem, BE_STACK_FRAME_SIZE_EXPAND);
+       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);
 
        barrier = create_barrier(env, bl, &mem, env->regs, 0);
@@ -1678,16 +1717,6 @@ static void modify_irg(be_abi_irg_t *env)
        obstack_free(&env->obst, args);
 }
 
-/**
- * Walker: puts all Alloc(stack_alloc) on a obstack
- */
-static void collect_alloca_walker(ir_node *irn, void *data)
-{
-       be_abi_irg_t *env = data;
-       if(get_irn_opcode(irn) == iro_Alloc && get_Alloc_where(irn) == stack_alloc)
-               obstack_ptr_grow(&env->obst, irn);
-}
-
 be_abi_irg_t *be_abi_introduce(be_irg_t *birg)
 {
        be_abi_irg_t *env  = xmalloc(sizeof(env[0]));
@@ -1698,6 +1727,8 @@ be_abi_irg_t *be_abi_introduce(be_irg_t *birg)
        ir_node *dummy;
        optimization_state_t state;
 
+       be_omit_fp = birg->main_env->options->omit_fp;
+
        obstack_init(&env->obst);
 
        env->isa           = birg->main_env->arch_env->isa;