OSDN Git Service

* config/vax/vax.h (target_flags, MASK_UNIX_ASM, MASK_VAXC_ALIGNMENT)
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-dom.c
index 88ca529..ebb0aa3 100644 (file)
@@ -1,5 +1,5 @@
 /* SSA Dominator optimizations for trees
-   Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
    Contributed by Diego Novillo <dnovillo@redhat.com>
 
 This file is part of GCC.
@@ -29,6 +29,7 @@ Boston, MA 02111-1307, USA.  */
 #include "tm_p.h"
 #include "ggc.h"
 #include "basic-block.h"
+#include "cfgloop.h"
 #include "output.h"
 #include "errors.h"
 #include "expr.h"
@@ -181,7 +182,7 @@ static struct opt_stats_d opt_stats;
    of the form SSA_NAME COND CONST we create a new vrp_element to record
    how the condition affects the possible values SSA_NAME may have.
 
-   Each record contains the condition tested (COND), and the the range of
+   Each record contains the condition tested (COND), and the range of
    values the variable may legitimately have if COND is true.  Note the
    range of values may be a smaller range than COND specifies if we have
    recorded other ranges for this variable.  Each record also contains the
@@ -246,7 +247,7 @@ struct vrp_hash_elt
    in this basic block.  We use this during finalization to know
    which variables need their VRP data updated.  */
 
-/* Stack of SSA_NAMEs which had their values constrainted by operations
+/* Stack of SSA_NAMEs which had their values constrained by operations
    in this basic block.  During finalization of this block we use this
    list to determine which variables need their VRP data updated.
 
@@ -368,17 +369,13 @@ tree_ssa_dominator_optimize (void)
 {
   struct dom_walk_data walk_data;
   unsigned int i;
+  struct loops loops_info;
 
   memset (&opt_stats, 0, sizeof (opt_stats));
 
   for (i = 0; i < num_referenced_vars; i++)
     var_ann (referenced_var (i))->current_def = NULL;
 
-  /* Mark loop edges so we avoid threading across loop boundaries.
-     This may result in transforming natural loop into irreducible
-     region.  */
-  mark_dfs_back_edges ();
-
   /* Create our hash tables.  */
   avail_exprs = htab_create (1024, real_avail_expr_hash, avail_expr_eq, free);
   vrp_data = htab_create (ceil_log2 (num_ssa_names), vrp_hash, vrp_eq, free);
@@ -388,8 +385,8 @@ tree_ssa_dominator_optimize (void)
   nonzero_vars_stack = VEC_alloc (tree_on_heap, 20);
   vrp_variables_stack = VEC_alloc (tree_on_heap, 20);
   stmts_to_rescan = VEC_alloc (tree_on_heap, 20);
-  nonzero_vars = BITMAP_XMALLOC ();
-  need_eh_cleanup = BITMAP_XMALLOC ();
+  nonzero_vars = BITMAP_ALLOC (NULL);
+  need_eh_cleanup = BITMAP_ALLOC (NULL);
 
   /* Setup callbacks for the generic dominator tree walker.  */
   walk_data.walk_stmts_backward = false;
@@ -412,6 +409,17 @@ tree_ssa_dominator_optimize (void)
 
   calculate_dominance_info (CDI_DOMINATORS);
 
+  /* We need to know which edges exit loops so that we can
+     aggressively thread through loop headers to an exit
+     edge.  */
+  flow_loops_find (&loops_info);
+  mark_loop_exit_edges (&loops_info);
+  flow_loops_free (&loops_info);
+
+  /* Clean up the CFG so that any forwarder blocks created by loop
+     canonicalization are removed.  */
+  cleanup_tree_cfg ();
+
   /* If we prove certain blocks are unreachable, then we want to
      repeat the dominator optimization process as PHI nodes may
      have turned into copies which allows better propagation of
@@ -422,6 +430,10 @@ tree_ssa_dominator_optimize (void)
       /* Optimize the dominator tree.  */
       cfg_altered = false;
 
+      /* We need accurate information regarding back edges in the CFG
+        for jump threading.  */
+      mark_dfs_back_edges ();
+
       /* Recursively walk the dominator tree optimizing statements.  */
       walk_dominator_tree (&walk_data, ENTRY_BLOCK_PTR);
 
@@ -438,8 +450,19 @@ tree_ssa_dominator_optimize (void)
 
       free_all_edge_infos ();
 
+  {
+    block_stmt_iterator bsi;
+    basic_block bb;
+    FOR_EACH_BB (bb)
+      {
+       for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+         {
+           update_stmt_if_modified (bsi_stmt (bsi));
+         }
+      }
+  }
       /* Thread jumps, creating duplicate blocks as needed.  */
-      cfg_altered = thread_through_all_blocks ();
+      cfg_altered |= thread_through_all_blocks ();
 
       /* Removal of statements may make some EH edges dead.  Purge
         such edges from the CFG as needed.  */
@@ -449,8 +472,25 @@ tree_ssa_dominator_optimize (void)
          bitmap_zero (need_eh_cleanup);
        }
 
-      free_dominance_info (CDI_DOMINATORS);
-      cfg_altered = cleanup_tree_cfg ();
+      if (cfg_altered)
+        free_dominance_info (CDI_DOMINATORS);
+
+      cfg_altered |= cleanup_tree_cfg ();
+
+      if (rediscover_loops_after_threading)
+       {
+         /* Rerun basic loop analysis to discover any newly
+            created loops and update the set of exit edges.  */
+         rediscover_loops_after_threading = false;
+         flow_loops_find (&loops_info);
+         mark_loop_exit_edges (&loops_info);
+         flow_loops_free (&loops_info);
+
+         /* Remove any forwarder blocks inserted by loop
+            header canonicalization.  */
+         cleanup_tree_cfg ();
+       }
+
       calculate_dominance_info (CDI_DOMINATORS);
 
       rewrite_ssa_into_ssa ();
@@ -462,8 +502,29 @@ tree_ssa_dominator_optimize (void)
 
       for (i = 0; i < num_referenced_vars; i++)
        var_ann (referenced_var (i))->current_def = NULL;
+
+      /* Finally, remove everything except invariants in SSA_NAME_VALUE.
+
+        This must be done before we iterate as we might have a
+        reference to an SSA_NAME which was removed by the call to
+        rewrite_ssa_into_ssa.
+
+        Long term we will be able to let everything in SSA_NAME_VALUE
+        persist.  However, for now, we know this is the safe thing to do.  */
+      for (i = 0; i < num_ssa_names; i++)
+       {
+         tree name = ssa_name (i);
+         tree value;
+
+         if (!name)
+           continue;
+
+         value = SSA_NAME_VALUE (name);
+         if (value && !is_gimple_min_invariant (value))
+           SSA_NAME_VALUE (name) = NULL;
+       }
     }
-  while (cfg_altered);
+  while (optimize > 1 && cfg_altered);
 
   /* Debugging dumps.  */
   if (dump_file && (dump_flags & TDF_STATS))
@@ -481,26 +542,8 @@ tree_ssa_dominator_optimize (void)
   fini_walk_dominator_tree (&walk_data);
 
   /* Free nonzero_vars.  */
-  BITMAP_XFREE (nonzero_vars);
-  BITMAP_XFREE (need_eh_cleanup);
-
-  /* Finally, remove everything except invariants in SSA_NAME_VALUE.
-
-     Long term we will be able to let everything in SSA_NAME_VALUE
-     persist.  However, for now, we know this is the safe thing to
-     do.  */
-  for (i = 0; i < num_ssa_names; i++)
-    {
-      tree name = ssa_name (i);
-      tree value;
-
-      if (!name)
-       continue;
-
-      value = SSA_NAME_VALUE (name);
-      if (value && !is_gimple_min_invariant (value))
-       SSA_NAME_VALUE (name) = NULL;
-    }
+  BITMAP_FREE (nonzero_vars);
+  BITMAP_FREE (need_eh_cleanup);
   
   VEC_free (tree_on_heap, block_defs_stack);
   VEC_free (tree_on_heap, avail_exprs_stack);
@@ -550,6 +593,16 @@ thread_across_edge (struct dom_walk_data *walk_data, edge e)
     {
       tree src = PHI_ARG_DEF_FROM_EDGE (phi, e);
       tree dst = PHI_RESULT (phi);
+
+      /* If the desired argument is not the same as this PHI's result 
+        and it is set by a PHI in this block, then we can not thread
+        through this block.  */
+      if (src != dst
+         && TREE_CODE (src) == SSA_NAME
+         && TREE_CODE (SSA_NAME_DEF_STMT (src)) == PHI_NODE
+         && bb_for_stmt (SSA_NAME_DEF_STMT (src)) == e->dest)
+       return;
+
       record_const_or_copy (dst, src);
       register_new_def (dst, &block_defs_stack);
     }
@@ -595,8 +648,8 @@ thread_across_edge (struct dom_walk_data *walk_data, edge e)
          stmt_ann_t ann = stmt_ann (stmt);
          use_optype uses = USE_OPS (ann);
          vuse_optype vuses = VUSE_OPS (ann);
-         tree *uses_copy = xcalloc (NUM_USES (uses),  sizeof (tree));
-         tree *vuses_copy = xcalloc (NUM_VUSES (vuses), sizeof (tree));
+         tree *uses_copy = xmalloc (NUM_USES (uses) * sizeof (tree));
+         tree *vuses_copy = xmalloc (NUM_VUSES (vuses) * sizeof (tree));
          unsigned int i;
 
          /* Make a copy of the uses into USES_COPY, then cprop into
@@ -673,30 +726,17 @@ thread_across_edge (struct dom_walk_data *walk_data, edge e)
      arm will be taken.  */
   if (stmt
       && (TREE_CODE (stmt) == COND_EXPR
-         || TREE_CODE (stmt) == SWITCH_EXPR))
+         || TREE_CODE (stmt) == SWITCH_EXPR
+         || TREE_CODE (stmt) == GOTO_EXPR))
     {
       tree cond, cached_lhs;
-      edge e1;
-      edge_iterator ei;
-
-      /* Do not forward entry edges into the loop.  In the case loop
-        has multiple entry edges we may end up in constructing irreducible
-        region.  
-        ??? We may consider forwarding the edges in the case all incoming
-        edges forward to the same destination block.  */
-      if (!e->flags & EDGE_DFS_BACK)
-       {
-         FOR_EACH_EDGE (e1, ei, e->dest->preds)
-           if (e1->flags & EDGE_DFS_BACK)
-             break;
-         if (e1)
-           return;
-       }
 
       /* Now temporarily cprop the operands and try to find the resulting
         expression in the hash tables.  */
       if (TREE_CODE (stmt) == COND_EXPR)
        cond = COND_EXPR_COND (stmt);
+      else if (TREE_CODE (stmt) == GOTO_EXPR)
+       cond = GOTO_DESTINATION (stmt);
       else
        cond = SWITCH_COND (stmt);
 
@@ -962,17 +1002,29 @@ dom_opt_finalize_block (struct dom_walk_data *walk_data, basic_block bb)
 {
   tree last;
 
-  /* If we are at a leaf node in the dominator graph, see if we can thread
+  /* If we are at a leaf node in the dominator tree, see if we can thread
      the edge from BB through its successor.
 
      Do this before we remove entries from our equivalence tables.  */
-  if (EDGE_COUNT (bb->succs) == 1
-      && (EDGE_SUCC (bb, 0)->flags & EDGE_ABNORMAL) == 0
-      && (get_immediate_dominator (CDI_DOMINATORS, EDGE_SUCC (bb, 0)->dest) != bb
-         || phi_nodes (EDGE_SUCC (bb, 0)->dest)))
+  if (single_succ_p (bb)
+      && (single_succ_edge (bb)->flags & EDGE_ABNORMAL) == 0
+      && (get_immediate_dominator (CDI_DOMINATORS, single_succ (bb)) != bb
+         || phi_nodes (single_succ (bb))))
        
     {
-      thread_across_edge (walk_data, EDGE_SUCC (bb, 0));
+      thread_across_edge (walk_data, single_succ_edge (bb));
+    }
+  else if ((last = last_stmt (bb))
+          && TREE_CODE (last) == GOTO_EXPR
+          && TREE_CODE (TREE_OPERAND (last, 0)) == SSA_NAME)
+    {
+      edge_iterator ei;
+      edge e;
+
+      FOR_EACH_EDGE (e, ei, bb->succs)
+       {
+         thread_across_edge (walk_data, e);
+       }
     }
   else if ((last = last_stmt (bb))
           && TREE_CODE (last) == COND_EXPR
@@ -1177,8 +1229,10 @@ record_equivalences_from_phis (basic_block bb)
        {
          tree t = PHI_ARG_DEF (phi, i);
 
-         /* Ignore alternatives which are the same as our LHS.  */
-         if (operand_equal_for_phi_arg_p (lhs, t))
+         /* Ignore alternatives which are the same as our LHS.  Since
+            LHS is a PHI_RESULT, it is known to be a SSA_NAME, so we
+            can simply compare pointers.  */
+         if (lhs == t)
            continue;
 
          /* If we have not processed an alternative yet, then set
@@ -1261,7 +1315,7 @@ record_equivalences_from_incoming_edge (basic_block bb)
   basic_block parent;
   struct edge_info *edge_info;
 
-  /* If our parent block ended with a control statment, then we may be
+  /* If our parent block ended with a control statement, then we may be
      able to record some equivalences based on which outgoing edge from
      the parent was followed.  */
   parent = get_immediate_dominator (CDI_DOMINATORS, bb);
@@ -1392,7 +1446,7 @@ record_cond (tree cond, tree value)
   initialize_hash_element (cond, value, element);
 
   slot = htab_find_slot_with_hash (avail_exprs, (void *)element,
-                                  element->hash, true);
+                                  element->hash, INSERT);
   if (*slot == NULL)
     {
       *slot = (void *) element;
@@ -1404,7 +1458,7 @@ record_cond (tree cond, tree value)
 
 /* Build a new conditional using NEW_CODE, OP0 and OP1 and store
    the new conditional into *p, then store a boolean_true_node
-   into the the *(p + 1).  */
+   into *(p + 1).  */
    
 static void
 build_and_record_new_cond (enum tree_code new_code, tree op0, tree op1, tree *p)
@@ -1641,6 +1695,46 @@ unsafe_associative_fp_binop (tree exp)
            && FLOAT_TYPE_P (TREE_TYPE (exp)));
 }
 
+/* Returns true when STMT is a simple iv increment.  It detects the
+   following situation:
+   
+   i_1 = phi (..., i_2)
+   i_2 = i_1 +/- ...  */
+
+static bool
+simple_iv_increment_p (tree stmt)
+{
+  tree lhs, rhs, preinc, phi;
+  unsigned i;
+
+  if (TREE_CODE (stmt) != MODIFY_EXPR)
+    return false;
+
+  lhs = TREE_OPERAND (stmt, 0);
+  if (TREE_CODE (lhs) != SSA_NAME)
+    return false;
+
+  rhs = TREE_OPERAND (stmt, 1);
+
+  if (TREE_CODE (rhs) != PLUS_EXPR
+      && TREE_CODE (rhs) != MINUS_EXPR)
+    return false;
+
+  preinc = TREE_OPERAND (rhs, 0);
+  if (TREE_CODE (preinc) != SSA_NAME)
+    return false;
+
+  phi = SSA_NAME_DEF_STMT (preinc);
+  if (TREE_CODE (phi) != PHI_NODE)
+    return false;
+
+  for (i = 0; i < (unsigned) PHI_NUM_ARGS (phi); i++)
+    if (PHI_ARG_DEF (phi, i) == lhs)
+      return true;
+
+  return false;
+}
+
 /* STMT is a MODIFY_EXPR for which we were unable to find RHS in the
    hash tables.  Try to simplify the RHS using whatever equivalences
    we may have recorded.
@@ -1694,6 +1788,11 @@ simplify_rhs_and_lookup_avail_expr (struct dom_walk_data *walk_data,
     {
       tree rhs_def_stmt = SSA_NAME_DEF_STMT (TREE_OPERAND (rhs, 0));
 
+      /* If the statement defines an induction variable, do not propagate
+        its value, so that we do not create overlapping life ranges.  */
+      if (simple_iv_increment_p (rhs_def_stmt))
+       goto dont_fold_assoc;
+
       /* See if the RHS_DEF_STMT has the same form as our statement.  */
       if (TREE_CODE (rhs_def_stmt) == MODIFY_EXPR)
        {
@@ -2009,7 +2108,7 @@ simplify_cond_and_lookup_avail_expr (tree stmt,
                  /* If this is not a real stmt, ann will be NULL and we
                     avoid processing the operands.  */
                  if (ann)
-                   modify_stmt (stmt);
+                   mark_stmt_modified (stmt);
 
                  /* Lookup the condition and return its known value if it
                     exists.  */
@@ -2092,10 +2191,18 @@ simplify_cond_and_lookup_avail_expr (tree stmt,
              tree tmp_high, tmp_low;
              int dummy;
 
-             /* The last element has not been processed.  Process it now.  */
-             extract_range_from_cond (element->cond, &tmp_high,
-                                      &tmp_low, &dummy);
-         
+             /* The last element has not been processed.  Process it now.
+                record_range should ensure for cond inverted is not set.
+                This call can only fail if cond is x < min or x > max,
+                which fold should have optimized into false.
+                If that doesn't happen, just pretend all values are
+                in the range.  */
+             if (! extract_range_from_cond (element->cond, &tmp_high,
+                                            &tmp_low, &dummy))
+               gcc_unreachable ();
+             else
+               gcc_assert (dummy == 0);
+
              /* If this is the only element, then no merging is necessary, 
                 the high/low values from extract_range_from_cond are all
                 we need.  */
@@ -2253,7 +2360,7 @@ simplify_switch_and_lookup_avail_expr (tree stmt, int insert)
              if (!fail)
                {
                  SWITCH_COND (stmt) = def;
-                 modify_stmt (stmt);
+                 mark_stmt_modified (stmt);
 
                  return lookup_avail_expr (stmt, insert);
                }
@@ -2280,8 +2387,6 @@ cprop_into_successor_phis (basic_block bb, bitmap nonzero_vars)
   edge e;
   edge_iterator ei;
 
-  /* This can get rather expensive if the implementation is naive in
-     how it finds the phi alternative associated with a particular edge.  */
   FOR_EACH_EDGE (e, ei, bb->succs)
     {
       tree phi;
@@ -2451,9 +2556,9 @@ record_edge_info (basic_block bb)
                    }
                }
 
-             if (is_gimple_min_invariant (op0)
-                 && (TREE_CODE (op1) == SSA_NAME
-                      || is_gimple_min_invariant (op1)))
+             else if (is_gimple_min_invariant (op0)
+                      && (TREE_CODE (op1) == SSA_NAME
+                          || is_gimple_min_invariant (op1)))
                {
                  tree inverted = invert_truthvalue (cond);
                  struct edge_info *edge_info;
@@ -2477,9 +2582,9 @@ record_edge_info (basic_block bb)
                    }
                }
 
-             if (TREE_CODE (op0) == SSA_NAME
-                 && (is_gimple_min_invariant (op1)
-                     || TREE_CODE (op1) == SSA_NAME))
+             else if (TREE_CODE (op0) == SSA_NAME
+                      && (is_gimple_min_invariant (op1)
+                          || TREE_CODE (op1) == SSA_NAME))
                {
                  tree inverted = invert_truthvalue (cond);
                  struct edge_info *edge_info;
@@ -2549,7 +2654,10 @@ eliminate_redundant_computations (struct dom_walk_data *walk_data,
       || ! def
       || TREE_CODE (def) != SSA_NAME
       || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (def)
-      || NUM_V_MAY_DEFS (v_may_defs) != 0)
+      || NUM_V_MAY_DEFS (v_may_defs) != 0
+      /* Do not record equivalences for increments of ivs.  This would create
+        overlapping live ranges for a very questionable gain.  */
+      || simple_iv_increment_p (stmt))
     insert = false;
 
   /* Check if the expression has been computed before.  */
@@ -2612,7 +2720,7 @@ eliminate_redundant_computations (struct dom_walk_data *walk_data,
        retval = true;
 
       propagate_tree_value (expr_p, cached_lhs);
-      modify_stmt (stmt);
+      mark_stmt_modified (stmt);
     }
   return retval;
 }
@@ -2817,6 +2925,14 @@ cprop_operand (tree stmt, use_operand_p op_p)
         extensions.  */
       else if (!may_propagate_copy (op, val))
        return false;
+      
+      /* Do not propagate copies if the propagated value is at a deeper loop
+        depth than the propagatee.  Otherwise, this may move loop variant
+        variables outside of their loops and prevent coalescing
+        opportunities.  If the value was loop invariant, it will be hoisted
+        by LICM and exposed for copy propagation.  */
+      if (loop_depth_of_name (val) > loop_depth_of_name (op))
+       return false;
 
       /* Dump details.  */
       if (dump_file && (dump_flags & TDF_DETAILS))
@@ -2841,7 +2957,7 @@ cprop_operand (tree stmt, use_operand_p op_p)
       /* And note that we modified this statement.  This is now
         safe, even if we changed virtual operands since we will
         rescan the statement and rewrite its operands again.  */
-      modify_stmt (stmt);
+      mark_stmt_modified (stmt);
     }
   return may_have_exposed_new_symbols;
 }
@@ -2903,7 +3019,7 @@ optimize_stmt (struct dom_walk_data *walk_data, basic_block bb,
 
   stmt = bsi_stmt (si);
 
-  get_stmt_operands (stmt);
+  update_stmt_if_modified (stmt);
   ann = stmt_ann (stmt);
   opt_stats.num_stmts++;
   may_have_exposed_new_symbols = false;
@@ -3073,7 +3189,7 @@ update_rhs_and_lookup_avail_expr (tree stmt, tree new_rhs, bool insert)
 
   /* And make sure we record the fact that we modified this
      statement.  */
-  modify_stmt (stmt);
+  mark_stmt_modified (stmt);
 
   return cached_lhs;
 }
@@ -3096,7 +3212,7 @@ lookup_avail_expr (tree stmt, bool insert)
   void **slot;
   tree lhs;
   tree temp;
-  struct expr_hash_elt *element = xcalloc (sizeof (struct expr_hash_elt), 1);
+  struct expr_hash_elt *element = xmalloc (sizeof (struct expr_hash_elt));
 
   lhs = TREE_CODE (stmt) == MODIFY_EXPR ? TREE_OPERAND (stmt, 0) : NULL;
 
@@ -3179,16 +3295,19 @@ extract_range_from_cond (tree cond, tree *hi_p, tree *lo_p, int *inverted_p)
   tree op1 = TREE_OPERAND (cond, 1);
   tree high, low, type;
   int inverted;
-  
+
+  type = TREE_TYPE (op1);
+
   /* Experiments have shown that it's rarely, if ever useful to
      record ranges for enumerations.  Presumably this is due to
      the fact that they're rarely used directly.  They are typically
      cast into an integer type and used that way.  */
-  if (TREE_CODE (TREE_TYPE (op1)) != INTEGER_TYPE)
+  if (TREE_CODE (type) != INTEGER_TYPE
+      /* We don't know how to deal with types with variable bounds.  */
+      || TREE_CODE (TYPE_MIN_VALUE (type)) != INTEGER_CST
+      || TREE_CODE (TYPE_MAX_VALUE (type)) != INTEGER_CST)
     return 0;
 
-  type = TREE_TYPE (op1);
-
   switch (TREE_CODE (cond))
     {
     case EQ_EXPR:
@@ -3208,8 +3327,10 @@ extract_range_from_cond (tree cond, tree *hi_p, tree *lo_p, int *inverted_p)
       break;
 
     case GT_EXPR:
-      low = int_const_binop (PLUS_EXPR, op1, integer_one_node, 1);
       high = TYPE_MAX_VALUE (type);
+      if (!tree_int_cst_lt (op1, high))
+       return 0;
+      low = int_const_binop (PLUS_EXPR, op1, integer_one_node, 1);
       inverted = 0;
       break;
 
@@ -3220,8 +3341,10 @@ extract_range_from_cond (tree cond, tree *hi_p, tree *lo_p, int *inverted_p)
       break;
 
     case LT_EXPR:
-      high = int_const_binop (MINUS_EXPR, op1, integer_one_node, 1);
       low = TYPE_MIN_VALUE (type);
+      if (!tree_int_cst_lt (low, op1))
+       return 0;
+      high = int_const_binop (MINUS_EXPR, op1, integer_one_node, 1);
       inverted = 0;
       break;