Fixed hook_strength_red()
[libfirm] / ir / ir / iropt.c
index d105777..443d248 100644 (file)
@@ -106,6 +106,51 @@ static tarval *computed_value_Sub(ir_node *n)
   return tarval_bad;
 }
 
+/**
+ * return the value of a Carry
+ * Special : a op 0, 0 op b
+ */
+static tarval *computed_value_Carry(ir_node *n)
+{
+  ir_node *a = get_binop_left(n);
+  ir_node *b = get_binop_right(n);
+  ir_mode *m = get_irn_mode(n);
+
+  tarval *ta = value_of(a);
+  tarval *tb = value_of(b);
+
+  if ((ta != tarval_bad) && (tb != tarval_bad)) {
+    tarval_add(ta, tb);
+    return tarval_carry() ? get_mode_one(m) : get_mode_null(m);
+  } else {
+    if (   (classify_tarval(ta) == TV_CLASSIFY_NULL)
+        || (classify_tarval(tb) == TV_CLASSIFY_NULL))
+      return get_mode_null(m);
+  }
+  return tarval_bad;
+}
+
+/**
+ * return the value of a Borrow
+ * Special : a op 0
+ */
+static tarval *computed_value_Borrow(ir_node *n)
+{
+  ir_node *a = get_binop_left(n);
+  ir_node *b = get_binop_right(n);
+  ir_mode *m = get_irn_mode(n);
+
+  tarval *ta = value_of(a);
+  tarval *tb = value_of(b);
+
+  if ((ta != tarval_bad) && (tb != tarval_bad)) {
+    return tarval_cmp(ta, tb) == pn_Cmp_Lt ? get_mode_one(m) : get_mode_null(m);
+  } else if (classify_tarval(ta) == TV_CLASSIFY_NULL) {
+      return get_mode_null(m);
+  }
+  return tarval_bad;
+}
+
 /**
  * return the value of an unary Minus
  */
@@ -512,7 +557,6 @@ static tarval *computed_value_Proj_Cmp(ir_node *n)
         return new_tarval_from_long(proj_nr & pn_Cmp_Ne, mode_b);
     }
   }
-
   return computed_value_Cmp_Confirm(a, aa, ab, proj_nr);
 }
 
@@ -573,6 +617,18 @@ static tarval *computed_value_Mux(ir_node *n)
   return tarval_bad;
 }
 
+/**
+ * Calculate the value of a Psi: can be evaluated, if a condition is true
+ * and all previous conditions are false. If all conditions are false
+ * we evaluate to the default one.
+ */
+static tarval *computed_value_Psi(ir_node *n)
+{
+  if (is_Mux(n))
+    return computed_value_Mux(n);
+  return tarval_bad;
+}
+
 /**
  * calculate the value of a Confirm: can be evaluated,
  * if it has the form Confirm(x, '=', Const).
@@ -631,9 +687,12 @@ static ir_op_ops *firm_set_default_computed_value(opcode code, ir_op_ops *ops)
   CASE(Shr);
   CASE(Shrs);
   CASE(Rot);
+  CASE(Carry);
+  CASE(Borrow);
   CASE(Conv);
   CASE(Proj);
   CASE(Mux);
+  CASE(Psi);
   CASE(Confirm);
   default:
     /* leave NULL */;
@@ -643,25 +702,6 @@ static ir_op_ops *firm_set_default_computed_value(opcode code, ir_op_ops *ops)
 #undef CASE
 }
 
-#if 0
-/* returns 1 if the a and b are pointers to different locations. */
-static bool
-different_identity (ir_node *a, ir_node *b)
-{
-  assert (mode_is_reference(get_irn_mode (a))
-          && mode_is_reference(get_irn_mode (b)));
-
-  if (get_irn_op (a) == op_Proj && get_irn_op(b) == op_Proj) {
-    ir_node *a1 = get_Proj_pred (a);
-    ir_node *b1 = get_Proj_pred (b);
-    if (a1 != b1 && get_irn_op (a1) == op_Alloc
-                && get_irn_op (b1) == op_Alloc)
-      return 1;
-  }
-  return 0;
-}
-#endif
-
 /**
  * Returns a equivalent block for another block.
  * If the block has only one predecessor, this is
@@ -734,8 +774,8 @@ static ir_node *equivalent_node_Block(ir_node *n)
     }
   }
   else if (get_opt_unreachable_code() &&
-           (n != current_ir_graph->start_block) &&
-           (n != current_ir_graph->end_block)     ) {
+           (n != get_irg_start_block(current_ir_graph)) &&
+           (n != get_irg_end_block(current_ir_graph))    ) {
     int i;
 
     /* If all inputs are dead, this block is dead too, except if it is
@@ -766,7 +806,7 @@ static ir_node *equivalent_node_Block(ir_node *n)
 
 /**
  * Returns a equivalent node for a Jmp, a Bad :-)
- * Of course this only happens if the Block of the Jmp is Bad.
+ * Of course this only happens if the Block of the Jmp is dead.
  */
 static ir_node *equivalent_node_Jmp(ir_node *n)
 {
@@ -777,7 +817,7 @@ static ir_node *equivalent_node_Jmp(ir_node *n)
   return n;
 }
 
-/* Same for op_Raise */
+/** Raise is handled in the same way as Jmp. */
 #define equivalent_node_Raise   equivalent_node_Jmp
 
 
@@ -825,6 +865,9 @@ static ir_node *equivalent_node_neutral_zero(ir_node *n)
   return n;
 }
 
+/**
+ * Eor is commutative and has neutral 0.
+ */
 #define equivalent_node_Eor  equivalent_node_neutral_zero
 
 /*
@@ -969,10 +1012,10 @@ static ir_node *equivalent_node_idempotent_unop(ir_node *n)
   return n;
 }
 
-/* Not(Not(x)) == x */
+/** Not(Not(x)) == x */
 #define equivalent_node_Not    equivalent_node_idempotent_unop
 
-/* --x == x */  /* ??? Is this possible or can --x raise an
+/** --x == x       ??? Is this possible or can --x raise an
                        out of bounds exception if min =! max? */
 #define equivalent_node_Minus  equivalent_node_idempotent_unop
 
@@ -1140,12 +1183,13 @@ static ir_node *equivalent_node_Cast(ir_node *n) {
   return n;
 }
 
-/* Several optimizations:
+/**
+  Several optimizations:
    - no Phi in start block.
    - remove Id operators that are inputs to Phi
    - fold Phi-nodes, iff they have only one predecessor except
            themselves.
-*/
+ */
 static ir_node *equivalent_node_Phi(ir_node *n)
 {
   int i, n_preds;
@@ -1153,7 +1197,6 @@ static ir_node *equivalent_node_Phi(ir_node *n)
   ir_node *oldn = n;
   ir_node *block = NULL;     /* to shutup gcc */
   ir_node *first_val = NULL; /* to shutup gcc */
-  ir_node *scnd_val = NULL;  /* to shutup gcc */
 
   if (!get_opt_normalize()) return n;
 
@@ -1163,8 +1206,8 @@ static ir_node *equivalent_node_Phi(ir_node *n)
   /* @@@ fliegt 'raus, sollte aber doch immer wahr sein!!!
      assert(get_irn_arity(block) == n_preds && "phi in wrong block!"); */
   if ((is_Block_dead(block)) ||                  /* Control dead */
-      (block == current_ir_graph->start_block))  /* There should be no Phi nodes */
-    return new_Bad();                            /* in the Start Block. */
+      (block == get_irg_start_block(current_ir_graph)))  /* There should be no Phi nodes */
+    return new_Bad();                                    /* in the Start Block. */
 
   if (n_preds == 0) return n;           /* Phi of dead Region without predecessors. */
 
@@ -1190,12 +1233,10 @@ static ir_node *equivalent_node_Phi(ir_node *n)
     return new_Bad();
   }
 
-  scnd_val = NULL;
-
-  /* follow_Id () for rest of inputs, determine if any of these
+  /* search for rest of inputs, determine if any of these
      are non-self-referencing */
   while (++i < n_preds) {
-    scnd_val = get_Phi_pred(n, i);
+    ir_node *scnd_val = get_Phi_pred(n, i);
     if (   (scnd_val != n)
         && (scnd_val != first_val)
 #if 1
@@ -1210,10 +1251,57 @@ static ir_node *equivalent_node_Phi(ir_node *n)
     /* Fold, if no multiple distinct non-self-referencing inputs */
     n = first_val;
     DBG_OPT_PHI(oldn, n);
-  } else {
-    /* skip the remaining Ids (done in get_Phi_pred). */
-    /* superfluous, since we walk all to propagate Block's Bads.
-       while (++i < n_preds) get_Phi_pred(n, i);     */
+  }
+  return n;
+}
+
+/**
+  Several optimizations:
+   - no Sync in start block.
+   - fold Sync-nodes, iff they have only one predecessor except
+           themselves.
+  @fixme: are there loop's in Sync's
+ */
+static ir_node *equivalent_node_Sync(ir_node *n)
+{
+  int i, n_preds;
+
+  ir_node *oldn = n;
+  ir_node *first_val = NULL; /* to shutup gcc */
+
+  if (!get_opt_normalize()) return n;
+
+  n_preds = get_Sync_n_preds(n);
+
+  /* Find first non-self-referencing input */
+  for (i = 0; i < n_preds; ++i) {
+    first_val = get_Sync_pred(n, i);
+    if ((first_val != n)  /* not self pointer */ &&
+        (! is_Bad(first_val))
+       ) {            /* value not dead */
+      break;          /* then found first value. */
+    }
+  }
+
+  if (i >= n_preds)
+    /* A totally Bad or self-referencing Sync (we didn't break the above loop) */
+    return new_Bad();
+
+  /* search the rest of inputs, determine if any of these
+     are non-self-referencing */
+  while (++i < n_preds) {
+    ir_node *scnd_val = get_Sync_pred(n, i);
+    if ((scnd_val != n) &&
+        (scnd_val != first_val) &&
+        (! is_Bad(scnd_val))
+       )
+      break;
+  }
+
+  if (i >= n_preds) {
+    /* Fold, if no multiple distinct non-self-referencing inputs */
+    n = first_val;
+    DBG_OPT_SYNC(oldn, n);
   }
   return n;
 }
@@ -1250,7 +1338,7 @@ static ir_node *equivalent_node_Proj(ir_node *n)
         /* get the load/store address */
         ir_node *addr = get_irn_n(a, 1);
         if (value_not_null(addr)) {
-          /* this node may float */
+          /* this node may float if it did not depend on a Confirm */
           set_irn_pinned(a, op_pin_state_floats);
           DBG_OPT_EXC_REM(n);
           return new_Bad();
@@ -1349,6 +1437,17 @@ static ir_node *equivalent_node_Mux(ir_node *n)
   return n;
 }
 
+/**
+ * Returns a equivalent node of a Psi: if a condition is true
+ * and all previous conditions are false we know its value.
+ * If all conditions are false its value is the default one.
+ */
+static ir_node *equivalent_node_Psi(ir_node *n) {
+  if (is_Mux(n))
+    return equivalent_node_Mux(n);
+  return n;
+}
+
 /**
  * Optimize -a CMP -b into b CMP a.
  * This works only for for modes where unary Minus
@@ -1416,7 +1515,7 @@ static ir_node *equivalent_node_CopyB(ir_node *n)
     turn_into_tuple(n, pn_CopyB_max);
     set_Tuple_pred(n, pn_CopyB_M,        mem);
     set_Tuple_pred(n, pn_CopyB_X_except, new_Bad());        /* no exception */
-    set_Tuple_pred(n, pn_Call_M_except,  new_Bad());
+    set_Tuple_pred(n, pn_CopyB_M_except, new_Bad());
   }
   return n;
 }
@@ -1445,16 +1544,16 @@ static ir_node *equivalent_node_Bound(ir_node *n)
        * lower <= pred_lower && pred_upper <= upper.
        */
       ir_node *upper = get_Bound_upper(n);
-       if (get_Bound_lower(pred) == lower &&
-           get_Bound_upper(pred) == upper) {
-         /*
-          * One could expect that we simple return the previous
-          * Bound here. However, this would be wrong, as we could
-          * add an exception Proj to a new location than.
-          * So, we must turn in into a tuple
-          */
-         ret_tuple = 1;
-       }
+      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 than.
+         * So, we must turn in into a tuple
+         */
+        ret_tuple = 1;
+      }
     }
   }
   if (ret_tuple) {
@@ -1521,9 +1620,11 @@ static ir_op_ops *firm_set_default_equivalent_node(opcode code, ir_op_ops *ops)
   CASE(Conv);
   CASE(Cast);
   CASE(Phi);
+  CASE(Sync);
   CASE(Proj);
   CASE(Id);
   CASE(Mux);
+  CASE(Psi);
   CASE(Cmp);
   CASE(Confirm);
   CASE(CopyB);
@@ -2129,18 +2230,22 @@ static ir_node *transform_node_Proj_Div(ir_node *proj)
     /* div(x, y) && y != 0 */
     proj_nr = get_Proj_proj(proj);
 
-    /* this node may float */
+    /* this node may float if it did not depend on a Confirm */
     set_irn_pinned(n, op_pin_state_floats);
 
     if (proj_nr == pn_Div_X_except) {
       /* we found an exception handler, remove it */
       DBG_OPT_EXC_REM(proj);
       return new_Bad();
-    } else if (proj_nr == pn_Div_M) {
-      /* the memory Proj can be removed */
+    }
+    else if (proj_nr == pn_Div_M) {
       ir_node *res = get_Div_mem(n);
-      set_Div_mem(n, get_irg_no_mem(current_ir_graph));
-
+      /* the memory Proj can only be removed if we divide by a
+         real constant, but the node never produce a new memory */
+      if (value_of(b) != tarval_bad) {
+        /* this is a Div by a const, we can remove the memory edge */
+        set_Div_mem(n, get_irg_no_mem(current_ir_graph));
+      }
       return res;
     }
   }
@@ -2161,7 +2266,7 @@ static ir_node *transform_node_Proj_Mod(ir_node *proj)
     /* mod(x, y) && y != 0 */
     proj_nr = get_Proj_proj(proj);
 
-    /* this node may float */
+    /* this node may float if it did not depend on a Confirm */
     set_irn_pinned(n, op_pin_state_floats);
 
     if (proj_nr == pn_Mod_X_except) {
@@ -2169,10 +2274,13 @@ static ir_node *transform_node_Proj_Mod(ir_node *proj)
       DBG_OPT_EXC_REM(proj);
       return new_Bad();
     } else if (proj_nr == pn_Mod_M) {
-      /* the memory Proj can be removed */
       ir_node *res = get_Mod_mem(n);
-      set_Mod_mem(n, get_irg_no_mem(current_ir_graph));
-
+      /* the memory Proj can only be removed if we divide by a
+         real constant, but the node never produce a new memory */
+      if (value_of(b) != tarval_bad) {
+        /* this is a Mod by a const, we can remove the memory edge */
+        set_Mod_mem(n, get_irg_no_mem(current_ir_graph));
+      }
       return res;
     }
     else if (proj_nr == pn_Mod_res && get_Mod_left(n) == b) {
@@ -2201,7 +2309,7 @@ static ir_node *transform_node_Proj_DivMod(ir_node *proj)
     /* DivMod(x, y) && y != 0 */
     proj_nr = get_Proj_proj(proj);
 
-    /* this node may float */
+    /* this node may float if it did not depend on a Confirm */
     set_irn_pinned(n, op_pin_state_floats);
 
     if (proj_nr == pn_DivMod_X_except) {
@@ -2210,10 +2318,13 @@ static ir_node *transform_node_Proj_DivMod(ir_node *proj)
       return new_Bad();
     }
     else if (proj_nr == pn_DivMod_M) {
-      /* the memory Proj can be removed */
       ir_node *res = get_DivMod_mem(n);
-      set_DivMod_mem(n, get_irg_no_mem(current_ir_graph));
-
+      /* the memory Proj can only be removed if we divide by a
+         real constant, but the node never produce a new memory */
+      if (value_of(b) != tarval_bad) {
+        /* this is a DivMod by a const, we can remove the memory edge */
+        set_DivMod_mem(n, get_irg_no_mem(current_ir_graph));
+      }
       return res;
     }
     else if (proj_nr == pn_DivMod_res_mod && get_DivMod_left(n) == b) {
@@ -2293,7 +2404,7 @@ static ir_node *transform_node_Proj_Cmp(ir_node *proj)
       proj_nr = get_inversed_pnc(proj_nr);
       changed |= 1;
     }
-    else if (left > right) {
+    else if (get_irn_idx(left) > get_irn_idx(right)) {
       ir_node *t = left;
 
       left  = right;
@@ -2437,7 +2548,32 @@ static ir_node *transform_node_Proj_Cmp(ir_node *proj)
             }
           }
         } /* mode_is_int */
-      }
+
+        /*
+         * optimization for AND:
+         * Optimize:
+         *   And(x, C) == C  ==>  And(x, C) != 0
+         *   And(x, C) != C  ==>  And(X, C) == 0
+         *
+         * if C is a single Bit constant.
+         */
+        if ((proj_nr == pn_Cmp_Eq || proj_nr == pn_Cmp_Lg) &&
+            (get_irn_op(left) == op_And)) {
+          if (is_single_bit_tarval(tv)) {
+            /* check for Constant's match. We have check hare the tarvals,
+               because our const might be changed */
+            ir_node *la = get_And_left(left);
+            ir_node *ra = get_And_right(left);
+            if ((is_Const(la) && get_Const_tarval(la) == tv) ||
+                (is_Const(ra) && get_Const_tarval(ra) == tv)) {
+              /* fine: do the transformation */
+              tv = get_mode_null(get_tarval_mode(tv));
+              proj_nr ^= pn_Cmp_Leg;
+              changed |= 2;
+            }
+          }
+        }
+      } /* tarval != bad */
     }
 
     if (changed) {
@@ -2935,6 +3071,16 @@ static ir_node *transform_node_Mux(ir_node *n)
   return arch_transform_node_Mux(n);
 }
 
+/**
+ * Optimize a Psi into some simpler cases.
+ */
+static ir_node *transform_node_Psi(ir_node *n) {
+  if (is_Mux(n))
+    return transform_node_Mux(n);
+
+  return n;
+}
+
 /**
  * Tries several [inplace] [optimizing] transformations and returns an
  * equivalent node.  The difference to equivalent_node() is that these
@@ -2984,6 +3130,7 @@ static ir_op_ops *firm_set_default_transform_node(opcode code, ir_op_ops *ops)
   CASE(Shl);
   CASE(End);
   CASE(Mux);
+  CASE(Psi);
   default:
     /* leave NULL */;
   }
@@ -3228,8 +3375,7 @@ del_identities(pset *value_table) {
  * nodes are extremely time critical because of their frequent use in
  * constant string arrays.
  */
-static INLINE ir_node *
-identify (pset *value_table, ir_node *n)
+static INLINE ir_node *identify(pset *value_table, ir_node *n)
 {
   ir_node *o = NULL;
 
@@ -3241,14 +3387,14 @@ identify (pset *value_table, ir_node *n)
       ir_node *r = get_binop_right(n);
 
       /* for commutative operators perform  a OP b == b OP a */
-      if (l > r) {
+      if (get_irn_idx(l) > get_irn_idx(r)) {
         set_binop_left(n, r);
         set_binop_right(n, l);
       }
     }
   }
 
-  o = pset_find (value_table, n, ir_node_hash (n));
+  o = pset_find(value_table, n, ir_node_hash (n));
   if (!o) return n;
 
   DBG_OPT_CSE(n, o);
@@ -3261,8 +3407,7 @@ identify (pset *value_table, ir_node *n)
  * optimization is performed.  The flag turning on procedure global cse could
  * be changed between two allocations.  This way we are safe.
  */
-static INLINE ir_node *
-identify_cons (pset *value_table, ir_node *n) {
+static INLINE ir_node *identify_cons(pset *value_table, ir_node *n) {
   ir_node *old = n;
 
   n = identify(value_table, n);
@@ -3276,8 +3421,7 @@ identify_cons (pset *value_table, ir_node *n) {
  * Looks up the node in a hash table, enters it in the table
  * if it isn't there yet.
  */
-ir_node *
-identify_remember (pset *value_table, ir_node *n)
+ir_node *identify_remember(pset *value_table, ir_node *n)
 {
   ir_node *o = NULL;
 
@@ -3306,18 +3450,28 @@ identify_remember (pset *value_table, ir_node *n)
   return o;
 }
 
-void
-add_identities (pset *value_table, ir_node *node) {
-  if (get_opt_cse() && (get_irn_opcode(node) != iro_Block))
-    identify_remember (value_table, node);
+/* Add a node to the identities value table. */
+void add_identities(pset *value_table, ir_node *node) {
+  if (get_opt_cse() && is_no_Block(node))
+    identify_remember(value_table, node);
+}
+
+/* Visit each node in the value table of a graph. */
+void visit_all_identities(ir_graph *irg, irg_walk_func visit, void *env) {
+  ir_node *node;
+  ir_graph *rem = current_ir_graph;
+
+  current_ir_graph = irg;
+  foreach_pset(irg->value_table, node)
+    visit(node, env);
+  current_ir_graph = rem;
 }
 
 /**
  * garbage in, garbage out. If a node has a dead input, i.e., the
  * Bad node is input to the node, return the Bad node.
  */
-static INLINE ir_node *
-gigo (ir_node *node)
+static INLINE ir_node *gigo(ir_node *node)
 {
   int i, irn_arity;
   ir_op *op = get_irn_op(node);
@@ -3359,8 +3513,15 @@ gigo (ir_node *node)
 
       if (is_Bad(pred))
         return new_Bad();
+#if 0
+      /* Propagating Unknowns here seems to be a bad idea, because
+         sometimes we need a node as a input and did not want that
+         it kills it's user.
+         However, i might be useful to move this into a later phase
+         (it you thing optimizing such code is useful). */
       if (is_Unknown(pred) && mode_is_data(get_irn_mode(node)))
         return new_Unknown(get_irn_mode(node));
+#endif
     }
   }
 #if 0
@@ -3379,7 +3540,6 @@ gigo (ir_node *node)
   return node;
 }
 
-
 /**
  * These optimizations deallocate nodes from the obstack.
  * It can only be called if it is guaranteed that no other nodes
@@ -3387,8 +3547,7 @@ gigo (ir_node *node)
  *
  * current_ir_graph must be set to the graph of the node!
  */
-ir_node *
-optimize_node(ir_node *n)
+ir_node *optimize_node(ir_node *n)
 {
   tarval *tv;
   ir_node *oldn = n;
@@ -3432,7 +3591,7 @@ optimize_node(ir_node *n)
         edges_node_deleted(n, current_ir_graph);
 
         /* evaluation was successful -- replace the node. */
-        obstack_free(current_ir_graph->obst, n);
+        irg_kill_node(current_ir_graph, n);
         nw = new_Const(get_tarval_mode (tv), tv);
 
         if (old_tp && get_type_mode(old_tp) == get_tarval_mode (tv))
@@ -3467,8 +3626,7 @@ optimize_node(ir_node *n)
     edges_node_deleted(oldn, current_ir_graph);
 
     /* We found an existing, better node, so we can deallocate the old node. */
-    obstack_free (current_ir_graph->obst, oldn);
-
+    irg_kill_node(current_ir_graph, oldn);
     return n;
   }
 
@@ -3499,8 +3657,7 @@ optimize_node(ir_node *n)
  * nodes lying on the obstack.  Remove these by a dead node elimination,
  * i.e., a copying garbage collection.
  */
-ir_node *
-optimize_in_place_2 (ir_node *n)
+ir_node *optimize_in_place_2(ir_node *n)
 {
   tarval *tv;
   ir_node *oldn = n;
@@ -3582,8 +3739,7 @@ optimize_in_place_2 (ir_node *n)
 /**
  * Wrapper for external use, set proper status bits after optimization.
  */
-ir_node *
-optimize_in_place (ir_node *n)
+ir_node *optimize_in_place(ir_node *n)
 {
   /* Handle graph state */
   assert(get_irg_phase_state(current_ir_graph) != phase_building);