updated
[libfirm] / ir / ir / iropt.c
index ccc0daf..54012f5 100644 (file)
@@ -1577,34 +1577,27 @@ static ir_node *equivalent_node_CopyB(ir_node *n) {
  * Optimize Bounds(idx, idx, upper) into idx.
  */
 static ir_node *equivalent_node_Bound(ir_node *n) {
-       ir_node *idx   = get_Bound_index(n);
-       ir_node *lower = get_Bound_lower(n);
+       ir_node *idx  = get_Bound_index(n);
+       ir_node *pred = skip_Proj(idx);
        int ret_tuple = 0;
 
-       /* By definition lower < upper, so if idx == lower -->
-       lower <= idx && idx < upper */
-       if (idx == lower) {
-               /* Turn Bound into a tuple (mem, jmp, bad, idx) */
-               ret_tuple = 1;
-       } else {
-               ir_node *pred = skip_Proj(idx);
-
-               if (get_irn_op(pred) == op_Bound) {
+       if (is_Bound(pred)) {
+               /*
+                * idx was Bounds checked in the same MacroBlock previously,
+                * it is still valid if lower <= pred_lower && pred_upper <= upper.
+                */
+               ir_node *lower = get_Bound_lower(n);
+               ir_node *upper = get_Bound_upper(n);
+               if (get_Bound_lower(pred) == lower &&
+                       get_Bound_upper(pred) == upper &&
+                       get_irn_MacroBlock(n) == get_irn_MacroBlock(pred)) {
                        /*
-                        * idx was Bounds_check previously, it is still valid if
-                        * lower <= pred_lower && pred_upper <= upper.
+                        * One could expect that we simply return the previous
+                        * Bound here. However, this would be wrong, as we could
+                        * add an exception Proj to a new location then.
+                        * So, we must turn in into a tuple.
                         */
-                       ir_node *upper = get_Bound_upper(n);
-                       if (get_Bound_lower(pred) == lower &&
-                               get_Bound_upper(pred) == upper) {
-                               /*
-                                * One could expect that we simply return the previous
-                                * Bound here. However, this would be wrong, as we could
-                                * add an exception Proj to a new location then.
-                                * So, we must turn in into a tuple.
-                                */
-                               ret_tuple = 1;
-                       }
+                       ret_tuple = 1;
                }
        }
        if (ret_tuple) {
@@ -1774,7 +1767,7 @@ static ir_node *apply_binop_on_2_phis(ir_node *a, ir_node *b, tarval *(*eval)(ta
        int      i, n;
 
        if (get_nodes_block(a) != get_nodes_block(b))
-      return NULL;
+               return NULL;
 
        n = get_irn_arity(a);
        NEW_ARR_A(void *, res, n);
@@ -1887,12 +1880,12 @@ static ir_node *transform_node_AddSub(ir_node *n) {
                unsigned ref_bits = get_mode_size_bits(mode);
 
                if (is_Conv(left)) {
-                       ir_mode *mode = get_irn_mode(left);
-                       unsigned bits = get_mode_size_bits(mode);
+                       ir_mode *lmode = get_irn_mode(left);
+                       unsigned bits = get_mode_size_bits(lmode);
 
                        if (ref_bits == bits &&
-                           mode_is_int(mode) &&
-                           get_mode_arithmetic(mode) == irma_twos_complement) {
+                           mode_is_int(lmode) &&
+                           get_mode_arithmetic(lmode) == irma_twos_complement) {
                                ir_node *pre      = get_Conv_op(left);
                                ir_mode *pre_mode = get_irn_mode(pre);
 
@@ -1910,12 +1903,12 @@ static ir_node *transform_node_AddSub(ir_node *n) {
                }
 
                if (is_Conv(right)) {
-                       ir_mode *mode = get_irn_mode(right);
-                       unsigned bits = get_mode_size_bits(mode);
+                       ir_mode *rmode = get_irn_mode(right);
+                       unsigned bits = get_mode_size_bits(rmode);
 
                        if (ref_bits == bits &&
-                               mode_is_int(mode) &&
-                               get_mode_arithmetic(mode) == irma_twos_complement) {
+                           mode_is_int(rmode) &&
+                           get_mode_arithmetic(rmode) == irma_twos_complement) {
                                ir_node *pre      = get_Conv_op(right);
                                ir_mode *pre_mode = get_irn_mode(pre);
 
@@ -1931,6 +1924,19 @@ static ir_node *transform_node_AddSub(ir_node *n) {
                                }
                        }
                }
+
+               /* let address arithmetic use unsigned modes */
+               if (is_Const(right)) {
+                       ir_mode *rmode = get_irn_mode(right);
+
+                       if (mode_is_signed(rmode) && get_mode_arithmetic(rmode) == irma_twos_complement) {
+                               /* convert a AddP(P, *s) into AddP(P, *u) */
+                               ir_mode *nm = get_reference_mode_unsigned_eq(mode);
+
+                               ir_node *pre = new_r_Conv(current_ir_graph, get_nodes_block(n), right, nm);
+                               set_binop_right(n, pre);
+                       }
+               }
        }
        return n;
 }  /* transform_node_AddSub */
@@ -2887,7 +2893,8 @@ static ir_node *transform_node_Cond(ir_node *n) {
            (get_opt_unreachable_code())) {
                /* It's a boolean Cond, branching on a boolean constant.
                   Replace it by a tuple (Bad, Jmp) or (Jmp, Bad) */
-               jmp = new_r_Jmp(current_ir_graph, get_nodes_block(n));
+               ir_node *blk = get_nodes_block(n);
+               jmp = new_r_Jmp(current_ir_graph, blk);
                turn_into_tuple(n, pn_Cond_max);
                if (ta == tarval_b_true) {
                        set_Tuple_pred(n, pn_Cond_false, new_Bad());
@@ -2897,12 +2904,16 @@ static ir_node *transform_node_Cond(ir_node *n) {
                        set_Tuple_pred(n, pn_Cond_true, new_Bad());
                }
                /* We might generate an endless loop, so keep it alive. */
-               add_End_keepalive(get_irg_end(current_ir_graph), get_nodes_block(n));
+               add_End_keepalive(get_irg_end(current_ir_graph), blk);
        }
        return n;
 }  /* transform_node_Cond */
 
-typedef ir_node* (*recursive_transform) (ir_node *n);
+/**
+ * Prototype of a recursive transform function
+ * for bitwise distributive transformations.
+ */
+typedef ir_node* (*recursive_transform)(ir_node *n);
 
 /**
  * makes use of distributive laws for and, or, eor
@@ -2995,7 +3006,7 @@ static ir_node *transform_bitwise_distributive(ir_node *n,
                                n = new_rd_And(dbgi, irg, blk, new_n, c, mode);
                        } else {
                                n = exact_copy(a);
-                               set_irn_n(n, -1, blk);
+                               set_nodes_block(n, blk);
                                set_binop_left(n, new_n);
                                set_binop_right(n, c);
                                add_identities(current_ir_graph->value_table, n);
@@ -3338,13 +3349,15 @@ static ir_node *transform_node_Minus(ir_node *n) {
                ir_node *mul_r = get_Mul_right(a);
                if (is_Const(mul_r)) {
                        tarval   *tv    = tarval_neg(get_Const_tarval(mul_r));
-                       ir_node  *cnst  = new_Const(mode, tv);
-                       dbg_info *dbg   = get_irn_dbg_info(a);
-                       ir_graph *irg   = current_ir_graph;
-                       ir_node  *block = get_nodes_block(a);
-                       n = new_rd_Mul(dbg, irg, block, mul_l, cnst, mode);
-                       DBG_OPT_ALGSIM2(oldn, a, n, FS_OPT_MINUS_MUL_C);
-                       return n;
+                       if(tv != tarval_bad) {
+                               ir_node  *cnst  = new_Const(mode, tv);
+                               dbg_info *dbg   = get_irn_dbg_info(a);
+                               ir_graph *irg   = current_ir_graph;
+                               ir_node  *block = get_nodes_block(a);
+                               n = new_rd_Mul(dbg, irg, block, mul_l, cnst, mode);
+                               DBG_OPT_ALGSIM2(oldn, a, n, FS_OPT_MINUS_MUL_C);
+                               return n;
+                       }
                }
        }
 
@@ -5002,7 +5015,7 @@ static int node_cmp_attr_SymConst(ir_node *a, ir_node *b) {
 
 /** Compares the attributes of two Call nodes. */
 static int node_cmp_attr_Call(ir_node *a, ir_node *b) {
-       return (get_irn_call_attr(a) != get_irn_call_attr(b));
+       return get_irn_call_attr(a) != get_irn_call_attr(b);
 }  /* node_cmp_attr_Call */
 
 /** Compares the attributes of two Sel nodes. */
@@ -5022,8 +5035,8 @@ static int node_cmp_attr_Phi(ir_node *a, ir_node *b) {
        /* we can only enter this function if both nodes have the same number of inputs,
           hence it is enough to check if one of them is a Phi0 */
        if (is_Phi0(a)) {
-               /* check the Phi0 attribute */
-               return get_irn_phi0_attr(a) != get_irn_phi0_attr(b);
+               /* check the Phi0 pos attribute */
+               return get_irn_phi_attr(a)->u.pos != get_irn_phi_attr(b)->u.pos;
        }
        return 0;
 }  /* node_cmp_attr_Phi */
@@ -5062,6 +5075,49 @@ static int node_cmp_attr_Store(ir_node *a, ir_node *b) {
                get_Store_volatility(b) == volatility_is_volatile);
 }  /* node_cmp_attr_Store */
 
+/** Compares two exception attributes */
+static int node_cmp_exception(ir_node *a, ir_node *b) {
+       const except_attr *ea = get_irn_except_attr(a);
+       const except_attr *eb = get_irn_except_attr(b);
+
+       return ea->pin_state != eb->pin_state;
+}
+
+#define node_cmp_attr_Bound  node_cmp_exception
+
+/** Compares the attributes of two Div nodes. */
+static int node_cmp_attr_Div(ir_node *a, ir_node *b) {
+       const divmod_attr *ma = get_irn_divmod_attr(a);
+       const divmod_attr *mb = get_irn_divmod_attr(b);
+       return ma->exc.pin_state != mb->exc.pin_state ||
+                  ma->res_mode      != mb->res_mode ||
+                  ma->no_remainder  != mb->no_remainder;
+}  /* node_cmp_attr_Div */
+
+/** Compares the attributes of two DivMod nodes. */
+static int node_cmp_attr_DivMod(ir_node *a, ir_node *b) {
+       const divmod_attr *ma = get_irn_divmod_attr(a);
+       const divmod_attr *mb = get_irn_divmod_attr(b);
+       return ma->exc.pin_state != mb->exc.pin_state ||
+                  ma->res_mode      != mb->res_mode;
+}  /* node_cmp_attr_DivMod */
+
+/** Compares the attributes of two Mod nodes. */
+static int node_cmp_attr_Mod(ir_node *a, ir_node *b) {
+       const divmod_attr *ma = get_irn_divmod_attr(a);
+       const divmod_attr *mb = get_irn_divmod_attr(b);
+       return ma->exc.pin_state != mb->exc.pin_state ||
+                  ma->res_mode      != mb->res_mode;
+}  /* node_cmp_attr_Mod */
+
+/** Compares the attributes of two Quot nodes. */
+static int node_cmp_attr_Quot(ir_node *a, ir_node *b) {
+       const divmod_attr *ma = get_irn_divmod_attr(a);
+       const divmod_attr *mb = get_irn_divmod_attr(b);
+       return ma->exc.pin_state != mb->exc.pin_state ||
+                  ma->res_mode      != mb->res_mode;
+}  /* node_cmp_attr_Quot */
+
 /** Compares the attributes of two Confirm nodes. */
 static int node_cmp_attr_Confirm(ir_node *a, ir_node *b) {
        return (get_Confirm_cmp(a) != get_Confirm_cmp(b));
@@ -5145,6 +5201,12 @@ static ir_op_ops *firm_set_default_node_cmp_attr(ir_opcode code, ir_op_ops *ops)
        CASE(Store);
        CASE(Confirm);
        CASE(ASM);
+       CASE(Div);
+       CASE(DivMod);
+       CASE(Mod);
+       CASE(Quot);
+       CASE(Bound);
+       /* FIXME CopyB */
        default:
          /* leave NULL */;
        }
@@ -5158,8 +5220,8 @@ static ir_op_ops *firm_set_default_node_cmp_attr(ir_opcode code, ir_op_ops *ops)
  * nodes as parameters.  Returns 0 if the nodes are a Common Sub Expression.
  */
 int identities_cmp(const void *elt, const void *key) {
-       const ir_node *a = elt;
-       const ir_node *b = key;
+       ir_node *a = (ir_node *)elt;
+       ir_node *b = (ir_node *)key;
        int i, irn_arity_a;
 
        if (a == b) return 0;
@@ -5414,22 +5476,35 @@ static ir_node *gigo(ir_node *node) {
                ir_node *block = get_nodes_block(skip_Proj(node));
 
                /* Don't optimize nodes in immature blocks. */
-               if (!get_Block_matured(block)) return node;
+               if (!get_Block_matured(block))
+                       return node;
                /* Don't optimize End, may have Bads. */
                if (op == op_End) return node;
 
                if (is_Block(block)) {
-                       irn_arity = get_irn_arity(block);
-                       for (i = 0; i < irn_arity; i++) {
+                       if (is_Block_dead(block)) {
+                               /* control flow from dead block is dead */
+                               return new_Bad();
+                       }
+
+                       for (i = get_irn_arity(block) - 1; i >= 0; --i) {
                                if (!is_Bad(get_irn_n(block, i)))
                                        break;
                        }
-                       if (i == irn_arity) {
+                       if (i < 0) {
                                ir_graph *irg = get_irn_irg(block);
                                /* the start block is never dead */
                                if (block != get_irg_start_block(irg)
-                                       && block != get_irg_end_block(irg))
+                                       && block != get_irg_end_block(irg)) {
+                                       /*
+                                        * Do NOT kill control flow without setting
+                                        * the block to dead of bad things can happen:
+                                        * We get a Block that is not reachable be irg_block_walk()
+                                        * but can be found by irg_walk()!
+                                        */
+                                       set_Block_dead(block);
                                        return new_Bad();
+                               }
                        }
                }
        }
@@ -5443,7 +5518,7 @@ static ir_node *gigo(ir_node *node) {
                 * Beware: we can only read the block of a non-floating node.
                 */
                if (is_irn_pinned_in_irg(node) &&
-                       is_Block_dead(get_nodes_block(node)))
+                       is_Block_dead(get_nodes_block(skip_Proj(node))))
                        return new_Bad();
 
                for (i = 0; i < irn_arity; i++) {