Extended semantics of Cond node. There are two flavors now.
[libfirm] / ir / ir / iropt.c
index 54494a6..1dd151f 100644 (file)
@@ -6,11 +6,19 @@
 ** iropt --- optimizations intertwined with IR construction.
 */
 
-# include "iropt.h"
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+# include "irnode_t.h"
+# include "irgraph_t.h"
+# include "iropt_t.h"
 # include "ircons.h"
 # include "irgmod.h"
 # include "irvrfy.h"
 # include "tv.h"
+# include "tune.h"
+# include "debinfo.h"
 
 /* Make types visible to allow most efficient access */
 # include "entity_t.h"
@@ -78,14 +86,15 @@ computed_value (ir_node *n)
     break;
   case iro_Minus:
       if (ta && mode_is_float(get_irn_mode(a)))
-        res = /*tarval_minus (ta);*/ res;
+        res = tarval_neg (ta);
     break;
   case iro_Mul:
     if (ta && tb) /* tarval_mul tests for equivalent modes itself */ {
       res = tarval_mul (ta, tb);
     } else {
-      /* calls computed_value recursive and returns the 0 with proper
-         mode.  Why is this an extra case? */
+      /* a*0 = 0 or 0*b = 0:
+        calls computed_value recursive and returns the 0 with proper
+         mode. */
       tarval *v;
       if (   (tarval_classify ((v = computed_value (a))) == 0)
          || (tarval_classify ((v = computed_value (b))) == 0)) {
@@ -93,10 +102,31 @@ computed_value (ir_node *n)
       }
     }
     break;
+  case iro_Quot:
+    /* This was missing in original implementation. Why? */
+    if (ta && tb  && (get_irn_mode(a) == get_irn_mode(b))) {
+      if (tarval_classify(tb) == 0) {res = NULL; break;}
+      res = tarval_quo(ta, tb);
+    }
+    break;
+  case iro_Div:
+    /* This was missing in original implementation. Why? */
+    if (ta && tb  && (get_irn_mode(a) == get_irn_mode(b))) {
+      if (tarval_classify(tb) == 0) {res = NULL; break;}
+      res = tarval_div(ta, tb);
+    }
+    break;
+  case iro_Mod:
+    /* This was missing in original implementation. Why? */
+    if (ta && tb  && (get_irn_mode(a) == get_irn_mode(b))) {
+      if (tarval_classify(tb) == 0) {res = NULL; break;}
+      res = tarval_mod(ta, tb);
+    }
+    break;
+  /* for iro_DivMod see iro_Proj */
   case iro_Abs:
     if (ta)
-      res = /*tarval_abs (ta);*/ res;
-    /* allowed or problems with max/min ?? */
+      res = tarval_abs (ta);
     break;
   case iro_And:
     if (ta && tb) {
@@ -121,14 +151,15 @@ computed_value (ir_node *n)
     }
     break;
   case iro_Eor: if (ta && tb) { res = tarval_eor (ta, tb); } break;
-  case iro_Not: if (ta)       { /*res = tarval_not (ta)*/; } break;
+  case iro_Not: if (ta)       { res = tarval_neg (ta); } break;
   case iro_Shl: if (ta && tb) { res = tarval_shl (ta, tb); } break;
+    /* tarval_shr is faulty !! */
   case iro_Shr: if (ta && tb) { res = tarval_shr (ta, tb); } break;
-  case iro_Shrs: if(ta && tb) { /*res = tarval_shrs (ta, tb)*/; } break;
+  case iro_Shrs:if (ta && tb) { /*res = tarval_shrs (ta, tb)*/; } break;
   case iro_Rot: if (ta && tb) { /*res = tarval_rot (ta, tb)*/; } break;
-  case iro_Conv: if(ta)    { res = tarval_convert_to (ta, get_irn_mode (n)); }
+  case iro_Conv:if (ta)       { res = tarval_convert_to (ta, get_irn_mode (n)); }
     break;
-  case iro_Proj:
+  case iro_Proj:  /* iro_Cmp */
     {
       ir_node *aa, *ab;
 
@@ -191,6 +222,16 @@ computed_value (ir_node *n)
              res = tarval_from_long (mode_b, get_Proj_proj(n) & irpn_Ne);
          }
        }
+      } else if (get_irn_op(a) == op_DivMod) {
+        ta = value_of(get_DivMod_left(a));
+        tb = value_of(get_DivMod_right(a));
+       if (ta && tb  && (get_irn_mode(a) == get_irn_mode(b))) {
+         if (tarval_classify(tb) == 0) {res = NULL; break;}
+         if (get_Proj_proj(n)== 0) /* Div */
+           res = tarval_div(ta, tb);
+         else /* Mod */
+           res = tarval_mod(ta, tb);
+       }
       } else {
         /* printf(" # comp_val: Proj node, not optimized\n"); */
       }
@@ -253,17 +294,21 @@ equivalent_node (ir_node *n)
         calls the optimization. */
       assert(get_Block_matured(n));
 
-      /* a single entry Block following a single exit Block can be merged */
+      /* A single entry Block following a single exit Block can be merged,
+         if it is not the Start block. */
       /* !!! Beware, all Phi-nodes of n must have been optimized away.
-        This is true, as the block is matured before optimize is called.   */
+        This should be true, as the block is matured before optimize is called.
+         But what about Phi-cycles with the Phi0/Id that could not be resolved? */
       if (get_Block_n_cfgpreds(n) == 1
          && get_irn_op(get_Block_cfgpred(n, 0)) == op_Jmp) {
        n = get_nodes_Block(get_Block_cfgpred(n, 0));
 
-      } else if (n != current_ir_graph->start_block) {
+      } else if ((n != current_ir_graph->start_block) &&
+                (n != current_ir_graph->end_block)     ) {
        int i;
        /* If all inputs are dead, this block is dead too, except if it is
-           the start block.  This is a step of unreachable code elimination */
+           the start or end block.  This is a step of unreachable code
+          elimination */
        for (i = 0; i < get_Block_n_cfgpreds(n); i++) {
          if (!is_Bad(get_Block_cfgpred(n, i))) break;
        }
@@ -370,6 +415,8 @@ equivalent_node (ir_node *n)
            themselves.
       */
       int i, n_preds;
+
+
       ir_node *block = NULL;     /* to shutup gcc */
       ir_node *first_val = NULL; /* to shutup gcc */
       ir_node *scnd_val = NULL;  /* to shutup gcc */
@@ -408,6 +455,7 @@ equivalent_node (ir_node *n)
        }
       }
 #endif
+
       /* Find first non-self-referencing input */
       for (i = 0;  i < n_preds;  ++i) {
         first_val = follow_Id(get_Phi_pred(n, i));
@@ -421,7 +469,7 @@ equivalent_node (ir_node *n)
       }
 
       /* A totally Bad or self-referencing Phi (we didn't break the above loop) */
-      if (i > n_preds) { n = new_Bad();  break; }
+      if (i >= n_preds) { n = new_Bad();  break; }
 
       scnd_val = NULL;
 
@@ -440,8 +488,8 @@ equivalent_node (ir_node *n)
       }
 
       /* Fold, if no multiple distinct non-self-referencing inputs */
-      if (i > n_preds) {
-       n = a;
+      if (i >= n_preds) {
+       n = first_val;
       } else {
       /* skip the remaining Ids. */
        while (++i < n_preds) {
@@ -606,7 +654,7 @@ transform_node (ir_node *n)
        set_Tuple_pred(n, 0, jmp);
        set_Tuple_pred(n, 1, new_Bad());
       }
-    } else if (ta && (get_irn_mode(a) == mode_I)) {
+    } else if (ta && (get_irn_mode(a) == mode_I) && (get_Cond_kind(n) == dense)) {
       /* I don't want to allow Tuples smaller than the biggest Proj.
          Also this tuple might get really big...
          I generate the Jmp here, and remember it in link.  Link is used
@@ -650,7 +698,8 @@ transform_node (ir_node *n)
         set_Proj_proj(n, 0);
     } else if (   (get_irn_op(a) == op_Cond)
                && (get_irn_mode(get_Cond_selector(a)) == mode_I)
-               && value_of(a)) {
+              && value_of(a)
+              && (get_Cond_kind(a) == dense)) {
       /* The Cond is a Switch on a Constant */
       if (get_Proj_proj(n) == tv_val_CHIL(value_of(a))) {
         /* The always taken branch, reuse the existing Jmp. */
@@ -701,7 +750,7 @@ transform_node (ir_node *n)
   return n;
 }
 
-/***************** Common Subexpression Elimination *****************/
+/* **************** Common Subexpression Elimination **************** */
 
 /* Compare function for two nodes in the hash table.   Gets two     */
 /* nodes as parameters.                                             */
@@ -753,8 +802,7 @@ vt_cmp (const void *elt, const void *key)
     return (get_irn_symconst_attr(a).num != get_irn_symconst_attr(b).num)
       || (get_irn_symconst_attr(a).tori.typ != get_irn_symconst_attr(b).tori.typ);
   case iro_Call:
-    return (get_irn_call_attr(a)->kind != get_irn_call_attr(b)->kind)
-      || (get_irn_call_attr(a)->arity != get_irn_call_attr(b)->arity);
+    return (get_irn_call_attr(a) != get_irn_call_attr(b));
   case iro_Sel:
     return (get_irn_sel_attr(a).ent->kind != get_irn_sel_attr(b).ent->kind)
       || (get_irn_sel_attr(a).ent->name != get_irn_sel_attr(b).ent->name)
@@ -867,11 +915,20 @@ gigo (ir_node *node)
   if ( op != op_Block && op != op_Phi && op != op_Tuple) {
     for (i = -1; i < get_irn_arity(node); i++) {
       if (is_Bad(get_irn_n(node, i))) {
-        node = new_Bad();
-        break;
+        return new_Bad();
       }
     }
   }
+#if 0
+  /* If Block has only Bads as predecessors it's garbage. */
+  /* If Phi has only Bads as predecessors it's garbage. */
+  if (op == op_Block || op == op_Phi)  {
+    for (i = 0; i < get_irn_arity(node); i++) {
+      if (!is_Bad(get_irn_n(node, i))) break;
+    }
+    if (i = get_irn_arity(node)) node = new_Bad();
+  }
+#endif
   return node;
 }
 
@@ -956,10 +1013,11 @@ optimize (ir_node *n)
 ir_node *
 optimize_in_place (ir_node *n)
 {
-
   tarval *tv;
   ir_node *old_n = n;
 
+  if (!get_optimize()) return n;
+
   /* if not optimize return n */
   if (n == NULL) {
     /* Here this is possible.  Why? */
@@ -974,15 +1032,17 @@ optimize_in_place (ir_node *n)
       tv = computed_value (n);
       if (tv != NULL) {
         /* evaluation was succesful -- replace the node. */
-       return new_Const (get_tv_mode (tv), tv);
+       n = new_Const (get_tv_mode (tv), tv);
+       deb_info_copy(n, old_n, id_from_str("const_eval", 10));
+       return n;
         /* xprintf("* optimize: computed node %I\n", n->op->name);*/
       }
     }
   }
 
   /* remove unnecessary nodes */
-  if (get_opt_constant_folding())
-    //  if (get_opt_constant_folding() || get_irn_op(n) == op_Phi)
+  /*if (get_opt_constant_folding()) */
+  if (get_opt_constant_folding() || get_irn_op(n) == op_Phi)
     n = equivalent_node (n);
 
   /** common subexpression elimination **/
@@ -1007,12 +1067,11 @@ optimize_in_place (ir_node *n)
   /* Now we can verify the node, as it has no dead inputs any more. */
   irn_vrfy(n);
 
-  /* Now we have a legal, useful node. Enter it in hash table for cse */
-  if (get_opt_cse()) {
-    /* aborts ??! set/pset can not handle several hash tables??!
-       No, suddenly it works. */
+  /* Now we have a legal, useful node. Enter it in hash table for cse.
+     Blocks should be unique anyways.  (Except the successor of start:
+     is cse with the start block!) */
+  if (get_opt_cse() && (get_irn_opcode(n) != iro_Block))
     n = identify_remember (current_ir_graph->value_table, n);
-  }
 
   return n;
 }