Use foreach_set() instead of reimplementing it.
[libfirm] / ir / be / bepeephole.c
index 484a5ac..ae296f4 100644 (file)
@@ -21,7 +21,6 @@
  * @file
  * @brief       Peephole optimisation framework keeps track of which registers contain which values
  * @author      Matthias Braun
- * @version     $Id$
  */
 #include "config.h"
 
 #include "irprintf.h"
 #include "ircons.h"
 #include "irgmod.h"
+#include "heights.h"
 #include "error.h"
 
 #include "beirg.h"
 #include "belive_t.h"
 #include "bearch.h"
+#include "beintlive_t.h"
 #include "benode.h"
 #include "besched.h"
 #include "bemodule.h"
@@ -47,39 +48,32 @@ DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
 static const arch_env_t *arch_env;
 static be_lv_t          *lv;
 static ir_node          *current_node;
-ir_node               ***register_values;
+ir_node                **register_values;
 
 static void clear_reg_value(ir_node *node)
 {
-       const arch_register_t       *reg;
-       const arch_register_class_t *cls;
-       unsigned                     reg_idx;
-       unsigned                     cls_idx;
+       const arch_register_t *reg;
+       unsigned               reg_idx;
 
        if (!mode_is_data(get_irn_mode(node)))
                return;
 
-       reg     = arch_get_irn_register(node);
+       reg = arch_get_irn_register(node);
        if (reg == NULL) {
                panic("No register assigned at %+F", node);
        }
        if (reg->type & arch_register_type_virtual)
                return;
-       cls     = arch_register_get_class(reg);
-       reg_idx = arch_register_get_index(reg);
-       cls_idx = arch_register_class_index(cls);
+       reg_idx = reg->global_index;
 
-       //assert(register_values[cls_idx][reg_idx] != NULL);
        DB((dbg, LEVEL_1, "Clear Register %s\n", reg->name));
-       register_values[cls_idx][reg_idx] = NULL;
+       register_values[reg_idx] = NULL;
 }
 
 static void set_reg_value(ir_node *node)
 {
-       const arch_register_t       *reg;
-       const arch_register_class_t *cls;
-       unsigned                     reg_idx;
-       unsigned                     cls_idx;
+       const arch_register_t *reg;
+       unsigned               reg_idx;
 
        if (!mode_is_data(get_irn_mode(node)))
                return;
@@ -90,12 +84,10 @@ static void set_reg_value(ir_node *node)
        }
        if (reg->type & arch_register_type_virtual)
                return;
-       cls     = arch_register_get_class(reg);
-       reg_idx = arch_register_get_index(reg);
-       cls_idx = arch_register_class_index(cls);
+       reg_idx = reg->global_index;
 
        DB((dbg, LEVEL_1, "Set Register %s: %+F\n", reg->name, node));
-       register_values[cls_idx][reg_idx] = node;
+       register_values[reg_idx] = node;
 }
 
 static void clear_defs(ir_node *node)
@@ -140,18 +132,26 @@ void be_peephole_new_node(ir_node * nw)
 static void be_peephole_before_exchange(const ir_node *old_node,
                                         ir_node *new_node)
 {
-       const arch_register_t       *reg;
-       const arch_register_class_t *cls;
-       unsigned                     reg_idx;
-       unsigned                     cls_idx;
+       const arch_register_t *reg;
+       unsigned               reg_idx;
+       bool                   old_is_current = false;
 
        DB((dbg, LEVEL_1, "About to exchange and kill %+F with %+F\n", old_node, new_node));
 
+       assert(sched_is_scheduled(skip_Proj_const(old_node)));
+       assert(sched_is_scheduled(skip_Proj(new_node)));
+
        if (current_node == old_node) {
+               old_is_current = true;
+
                /* next node to be processed will be killed. Its scheduling predecessor
                 * must be processed next. */
                current_node = sched_next(current_node);
                assert (!is_Bad(current_node));
+
+               /* we can't handle liveness updates correctly when exchange current node
+                * with something behind it */
+               assert(value_dominates(skip_Proj(new_node), skip_Proj_const(old_node)));
        }
 
        if (!mode_is_data(get_irn_mode(old_node)))
@@ -164,12 +164,9 @@ static void be_peephole_before_exchange(const ir_node *old_node,
        assert(reg == arch_get_irn_register(new_node) &&
              "KILLING a node and replacing by different register is not allowed");
 
-       cls     = arch_register_get_class(reg);
-       reg_idx = arch_register_get_index(reg);
-       cls_idx = arch_register_class_index(cls);
-
-       if (register_values[cls_idx][reg_idx] == old_node) {
-               register_values[cls_idx][reg_idx] = new_node;
+       reg_idx = reg->global_index;
+       if (register_values[reg_idx] == old_node || old_is_current) {
+               register_values[reg_idx] = new_node;
        }
 
        be_liveness_remove(lv, old_node);
@@ -188,20 +185,13 @@ void be_peephole_exchange(ir_node *old, ir_node *nw)
  */
 static void process_block(ir_node *block, void *data)
 {
-       unsigned n_classes;
-       unsigned i;
        int l;
        (void) data;
 
        /* construct initial register assignment */
-       n_classes = arch_env->n_register_classes;
-       for (i = 0; i < n_classes; ++i) {
-               const arch_register_class_t *cls    = &arch_env->register_classes[i];
-               unsigned                     n_regs = arch_register_class_n_regs(cls);
-               memset(register_values[i], 0, sizeof(ir_node*) * n_regs);
-       }
+       memset(register_values, 0, sizeof(ir_node*) * arch_env->n_registers);
 
-       assert(lv->nodes && "live sets must be computed");
+       assert(lv->sets_valid && "live sets must be computed");
        DB((dbg, LEVEL_1, "\nProcessing block %+F (from end)\n", block));
        be_lv_foreach(lv, block, be_lv_state_end, l) {
                ir_node *node = be_lv_get_irn(lv, block, l);
@@ -258,6 +248,52 @@ bool be_has_only_one_user(ir_node *node)
        return n_users == 1;
 }
 
+bool be_can_move_before(ir_heights_t *heights, const ir_node *node,
+                        const ir_node *before)
+{
+       int      node_arity = get_irn_arity(node);
+       ir_node *schedpoint = sched_next(node);
+
+       while (schedpoint != before) {
+               int      i;
+               unsigned n_outs = arch_get_irn_n_outs(schedpoint);
+
+               /* the node must not use our computed values */
+               if (heights_reachable_in_block(heights, schedpoint, node))
+                       return false;
+
+               /* the node must not overwrite registers of our inputs */
+               for (i = 0; i < node_arity; ++i) {
+                       ir_node                   *in  = get_irn_n(node, i);
+                       const arch_register_t     *reg = arch_get_irn_register(in);
+                       const arch_register_req_t *in_req
+                               = arch_get_irn_register_req_in(node, i);
+                       unsigned                   o;
+                       if (reg == NULL)
+                               continue;
+                       for (o = 0; o < n_outs; ++o) {
+                               const arch_register_t *outreg
+                                       = arch_get_irn_register_out(schedpoint, o);
+                               const arch_register_req_t *outreq
+                                       = arch_get_irn_register_req_out(schedpoint, o);
+                               if (outreg == NULL)
+                                       continue;
+                               if (outreg->global_index >= reg->global_index
+                                       && outreg->global_index
+                                          < (unsigned)reg->global_index + in_req->width)
+                                       return false;
+                               if (reg->global_index >= outreg->global_index
+                                       && reg->global_index
+                                          < (unsigned)outreg->global_index + outreq->width)
+                                       return false;
+                       }
+               }
+
+               schedpoint = sched_next(schedpoint);
+       }
+       return true;
+}
+
 /*
  * Tries to optimize a beIncSP node with its previous IncSP node.
  * Must be run from a be_peephole_opt() context.
@@ -277,23 +313,7 @@ ir_node *be_peephole_IncSP_IncSP(ir_node *node)
 
        pred_offs = be_get_IncSP_offset(pred);
        curr_offs = be_get_IncSP_offset(node);
-
-       if (pred_offs == BE_STACK_FRAME_SIZE_EXPAND) {
-               if (curr_offs != BE_STACK_FRAME_SIZE_SHRINK) {
-                       return node;
-               }
-               offs = 0;
-       } else if (pred_offs == BE_STACK_FRAME_SIZE_SHRINK) {
-               if (curr_offs != BE_STACK_FRAME_SIZE_EXPAND) {
-                       return node;
-               }
-               offs = 0;
-       } else if (curr_offs == BE_STACK_FRAME_SIZE_EXPAND ||
-                  curr_offs == BE_STACK_FRAME_SIZE_SHRINK) {
-               return node;
-       } else {
-               offs = curr_offs + pred_offs;
-       }
+       offs = curr_offs + pred_offs;
 
        /* add node offset to pred and remove our IncSP */
        be_set_IncSP_offset(pred, offs);
@@ -304,34 +324,24 @@ ir_node *be_peephole_IncSP_IncSP(ir_node *node)
 
 void be_peephole_opt(ir_graph *irg)
 {
-       unsigned  n_classes;
-       unsigned  i;
-
+#if 0
        /* we sometimes find BadE nodes in float apps like optest_float.c or
         * kahansum.c for example... */
-       be_liveness_invalidate(be_get_irg_liveness(irg));
-       be_liveness_assure_sets(be_assure_liveness(irg));
+       be_invalidate_live_sets(irg);
+#endif
+       be_assure_live_sets(irg);
 
        arch_env = be_get_irg_arch_env(irg);
        lv       = be_get_irg_liveness(irg);
 
-       n_classes = arch_env->n_register_classes;
-       register_values = XMALLOCN(ir_node**, n_classes);
-       for (i = 0; i < n_classes; ++i) {
-               const arch_register_class_t *cls    = &arch_env->register_classes[i];
-               unsigned                     n_regs = arch_register_class_n_regs(cls);
-               register_values[i] = XMALLOCN(ir_node*, n_regs);
-       }
+       register_values = XMALLOCN(ir_node*, arch_env->n_registers);
 
        irg_block_walk_graph(irg, process_block, NULL, NULL);
 
-       for (i = 0; i < n_classes; ++i) {
-               xfree(register_values[i]);
-       }
        xfree(register_values);
 }
 
-BE_REGISTER_MODULE_CONSTRUCTOR(be_init_peephole);
+BE_REGISTER_MODULE_CONSTRUCTOR(be_init_peephole)
 void be_init_peephole(void)
 {
        FIRM_DBG_REGISTER(dbg, "firm.be.peephole");