fix backend nodes not copying flags correctly
[libfirm] / ir / be / beabi.c
index 167d197..8b80946 100644 (file)
@@ -336,7 +336,7 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp)
        const arch_env_t *arch_env = be_get_irg_arch_env(irg);
        ir_type *call_tp           = get_Call_type(irn);
        ir_node *call_ptr          = get_Call_ptr(irn);
-       int n_params               = get_method_n_params(call_tp);
+       size_t   n_params          = get_method_n_params(call_tp);
        ir_node *curr_mem          = get_Call_mem(irn);
        ir_node *bl                = get_nodes_block(irn);
        int stack_size             = 0;
@@ -363,6 +363,8 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp)
        int                    *reg_param_idxs;
        int                    *stack_param_idx;
        int                     i, n, destroy_all_regs;
+       size_t                  s;
+       size_t                  p;
        dbg_info               *dbgi;
 
        /* Let the isa fill out the abi description for that call node. */
@@ -371,26 +373,26 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp)
        /* Insert code to put the stack arguments on the stack. */
        assert(get_Call_n_params(irn) == n_params);
        stack_param_idx = ALLOCAN(int, n_params);
-       for (i = 0; i < n_params; ++i) {
-               be_abi_call_arg_t *arg = get_call_arg(call, 0, i, 0);
+       for (p = 0; p < n_params; ++p) {
+               be_abi_call_arg_t *arg = get_call_arg(call, 0, p, 0);
                assert(arg);
                if (arg->on_stack) {
-                       int arg_size = get_type_size_bytes(get_method_param_type(call_tp, i));
+                       int arg_size = get_type_size_bytes(get_method_param_type(call_tp, p));
 
                        stack_size += round_up2(arg->space_before, arg->alignment);
                        stack_size += round_up2(arg_size, arg->alignment);
                        stack_size += round_up2(arg->space_after, arg->alignment);
 
-                       stack_param_idx[n_stack_params++] = i;
+                       stack_param_idx[n_stack_params++] = p;
                }
        }
 
        /* Collect all arguments which are passed in registers. */
        reg_param_idxs = ALLOCAN(int, n_params);
-       for (i = 0; i < n_params; ++i) {
-               be_abi_call_arg_t *arg = get_call_arg(call, 0, i, 0);
+       for (p = 0; p < n_params; ++p) {
+               be_abi_call_arg_t *arg = get_call_arg(call, 0, p, 0);
                if (arg && arg->in_reg) {
-                       reg_param_idxs[n_reg_params++] = i;
+                       reg_param_idxs[n_reg_params++] = p;
                }
        }
 
@@ -580,8 +582,8 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp)
        }
 
        /* add state registers ins */
-       for (i = 0; i < ARR_LEN(states); ++i) {
-               const arch_register_t       *reg = states[i];
+       for (s = 0; s < ARR_LEN(states); ++s) {
+               const arch_register_t       *reg = states[s];
                const arch_register_class_t *cls = arch_register_get_class(reg);
 #if 0
                ir_node *regnode = be_abi_reg_map_get(env->regs, reg);
@@ -644,8 +646,8 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp)
 
                if (arg->in_reg) {
                        /* remove register from destroyed regs */
-                       int j;
-                       int n = ARR_LEN(destroyed_regs);
+                       size_t j;
+                       size_t n = ARR_LEN(destroyed_regs);
                        for (j = 0; j < n; ++j) {
                                if (destroyed_regs[j] == arg->reg) {
                                        destroyed_regs[j] = destroyed_regs[n-1];
@@ -697,6 +699,7 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp)
        {
                ir_node               **in, *keep;
                int                   i;
+               size_t                d;
                int                   n = 0;
                int                   curr_res_proj = pn_be_Call_first_res + n_reg_results;
                int                   n_ins;
@@ -708,8 +711,8 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp)
                set_irn_link(curr_sp, (void*) sp);
                in[n++] = curr_sp;
 
-               for (i = 0; i < ARR_LEN(destroyed_regs); ++i) {
-                       const arch_register_t *reg = destroyed_regs[i];
+               for (d = 0; d < ARR_LEN(destroyed_regs); ++d) {
+                       const arch_register_t *reg = destroyed_regs[d];
                        ir_node *proj = new_r_Proj(low_call, reg->reg_class->mode, curr_res_proj);
 
                        /* memorize the register in the link field. we need afterwards to set the register class of the keep correctly. */
@@ -976,6 +979,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:
@@ -990,7 +994,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);
 }
 
@@ -1608,25 +1621,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));
 }
 
 /**
@@ -1853,6 +1854,7 @@ 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);
+       set_irg_start(irg, env->start);
 
        /*
         * make proj nodes for the callee save registers.