OSDN Git Service

Fix PR debug/49047
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-uncprop.c
index 4400ee7..30aa4c7 100644 (file)
@@ -1,11 +1,12 @@
 /* Routines for discovering and unpropagating edge equivalences.
-   Copyright (C) 2005 Free Software Foundation, Inc.
+   Copyright (C) 2005, 2007, 2008, 2010
+   Free Software Foundation, Inc.
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GCC is distributed in the hope that it will be useful,
@@ -14,9 +15,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
@@ -24,20 +24,14 @@ Boston, MA 02111-1307, USA.  */
 #include "tm.h"
 #include "tree.h"
 #include "flags.h"
-#include "rtl.h"
 #include "tm_p.h"
-#include "ggc.h"
 #include "basic-block.h"
 #include "output.h"
-#include "errors.h"
-#include "expr.h"
 #include "function.h"
-#include "diagnostic.h"
 #include "timevar.h"
 #include "tree-dump.h"
 #include "tree-flow.h"
 #include "domwalk.h"
-#include "real.h"
 #include "tree-pass.h"
 #include "tree-ssa-propagate.h"
 #include "langhooks.h"
@@ -55,7 +49,7 @@ struct edge_equivalency
    in the CFG.
 
    When complete, each edge that creates an equivalency will have an
-   EDGE_EQUIVALENCY structure hanging off the edge's AUX field. 
+   EDGE_EQUIVALENCY structure hanging off the edge's AUX field.
    The caller is responsible for freeing the AUX fields.  */
 
 static void
@@ -67,67 +61,54 @@ associate_equivalences_with_edges (void)
      then it might create a useful equivalence.  */
   FOR_EACH_BB (bb)
     {
-      block_stmt_iterator bsi = bsi_last (bb);
-      tree stmt;
+      gimple_stmt_iterator gsi = gsi_last_bb (bb);
+      gimple stmt;
 
       /* If the block does not end with a COND_EXPR or SWITCH_EXPR
         then there is nothing to do.  */
-      if (bsi_end_p (bsi))
+      if (gsi_end_p (gsi))
        continue;
 
-      stmt = bsi_stmt (bsi);
+      stmt = gsi_stmt (gsi);
 
       if (!stmt)
        continue;
 
       /* A COND_EXPR may create an equivalency in a variety of different
         ways.  */
-      if (TREE_CODE (stmt) == COND_EXPR)
+      if (gimple_code (stmt) == GIMPLE_COND)
        {
-         tree cond = COND_EXPR_COND (stmt);
          edge true_edge;
          edge false_edge;
          struct edge_equivalency *equivalency;
+         enum tree_code code = gimple_cond_code (stmt);
 
          extract_true_false_edges_from_block (bb, &true_edge, &false_edge);
 
-         /* If the conditional is a single variable 'X', record 'X = 1'
-            for the true edge and 'X = 0' on the false edge.  */
-         if (TREE_CODE (cond) == SSA_NAME)
-           {
-             equivalency = xmalloc (sizeof (struct edge_equivalency));
-             equivalency->rhs = constant_boolean_node (1, TREE_TYPE (cond));
-             equivalency->lhs = cond;
-             true_edge->aux = equivalency;
-
-             equivalency = xmalloc (sizeof (struct edge_equivalency));
-             equivalency->rhs = constant_boolean_node (0, TREE_TYPE (cond));
-             equivalency->lhs = cond;
-             false_edge->aux = equivalency;
-           }
          /* Equality tests may create one or two equivalences.  */
-         else if (TREE_CODE (cond) == EQ_EXPR || TREE_CODE (cond) == NE_EXPR)
+         if (code == EQ_EXPR || code == NE_EXPR)
            {
-             tree op0 = TREE_OPERAND (cond, 0);
-             tree op1 = TREE_OPERAND (cond, 1);
+             tree op0 = gimple_cond_lhs (stmt);
+             tree op1 = gimple_cond_rhs (stmt);
 
              /* Special case comparing booleans against a constant as we
                 know the value of OP0 on both arms of the branch.  i.e., we
                 can record an equivalence for OP0 rather than COND.  */
              if (TREE_CODE (op0) == SSA_NAME
+                 && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op0)
                  && TREE_CODE (TREE_TYPE (op0)) == BOOLEAN_TYPE
                  && is_gimple_min_invariant (op1))
                {
-                 if (TREE_CODE (cond) == EQ_EXPR)
+                 if (code == EQ_EXPR)
                    {
-                     equivalency = xmalloc (sizeof (struct edge_equivalency));
+                     equivalency = XNEW (struct edge_equivalency);
                      equivalency->lhs = op0;
                      equivalency->rhs = (integer_zerop (op1)
                                          ? boolean_false_node
                                          : boolean_true_node);
                      true_edge->aux = equivalency;
 
-                     equivalency = xmalloc (sizeof (struct edge_equivalency));
+                     equivalency = XNEW (struct edge_equivalency);
                      equivalency->lhs = op0;
                      equivalency->rhs = (integer_zerop (op1)
                                          ? boolean_true_node
@@ -136,14 +117,14 @@ associate_equivalences_with_edges (void)
                    }
                  else
                    {
-                     equivalency = xmalloc (sizeof (struct edge_equivalency));
+                     equivalency = XNEW (struct edge_equivalency);
                      equivalency->lhs = op0;
                      equivalency->rhs = (integer_zerop (op1)
                                          ? boolean_true_node
                                          : boolean_false_node);
                      true_edge->aux = equivalency;
 
-                     equivalency = xmalloc (sizeof (struct edge_equivalency));
+                     equivalency = XNEW (struct edge_equivalency);
                      equivalency->lhs = op0;
                      equivalency->rhs = (integer_zerop (op1)
                                          ? boolean_false_node
@@ -152,9 +133,11 @@ associate_equivalences_with_edges (void)
                    }
                }
 
-             if (TREE_CODE (op0) == SSA_NAME
-                 && (is_gimple_min_invariant (op1)
-                     || TREE_CODE (op1) == SSA_NAME))
+             else if (TREE_CODE (op0) == SSA_NAME
+                      && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op0)
+                      && (is_gimple_min_invariant (op1)
+                          || (TREE_CODE (op1) == SSA_NAME
+                              && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (op1))))
                {
                  /* For IEEE, -0.0 == 0.0, so we don't necessarily know
                     the sign of a variable compared against zero.  If
@@ -165,12 +148,12 @@ associate_equivalences_with_edges (void)
                          || REAL_VALUES_EQUAL (dconst0, TREE_REAL_CST (op1))))
                    continue;
 
-                 equivalency = xmalloc (sizeof (struct edge_equivalency));
+                 equivalency = XNEW (struct edge_equivalency);
                  equivalency->lhs = op0;
                  equivalency->rhs = op1;
-                 if (TREE_CODE (cond) == EQ_EXPR)
+                 if (code == EQ_EXPR)
                    true_edge->aux = equivalency;
-                 else 
+                 else
                    false_edge->aux = equivalency;
 
                }
@@ -182,25 +165,24 @@ associate_equivalences_with_edges (void)
       /* For a SWITCH_EXPR, a case label which represents a single
         value and which is the only case label which reaches the
         target block creates an equivalence.  */
-      if (TREE_CODE (stmt) == SWITCH_EXPR)
+      else if (gimple_code (stmt) == GIMPLE_SWITCH)
        {
-         tree cond = SWITCH_COND (stmt);
+         tree cond = gimple_switch_index (stmt);
 
-         if (TREE_CODE (cond) == SSA_NAME)
+         if (TREE_CODE (cond) == SSA_NAME
+             && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (cond))
            {
-             tree labels = SWITCH_LABELS (stmt);
-             int i, n_labels = TREE_VEC_LENGTH (labels);
-             tree *info = xcalloc (n_basic_blocks, sizeof (tree));
+             int i, n_labels = gimple_switch_num_labels (stmt);
+             tree *info = XCNEWVEC (tree, last_basic_block);
 
              /* Walk over the case label vector.  Record blocks
                 which are reached by a single case label which represents
                 a single value.  */
              for (i = 0; i < n_labels; i++)
                {
-                 tree label = TREE_VEC_ELT (labels, i);
+                 tree label = gimple_switch_label (stmt, i);
                  basic_block bb = label_to_block (CASE_LABEL (label));
 
-
                  if (CASE_HIGH (label)
                      || !CASE_LOW (label)
                      || info[bb->index])
@@ -223,7 +205,7 @@ associate_equivalences_with_edges (void)
 
                      /* Record an equivalency on the edge from BB to basic
                         block I.  */
-                     equivalency = xmalloc (sizeof (struct edge_equivalency));
+                     equivalency = XNEW (struct edge_equivalency);
                      equivalency->rhs = x;
                      equivalency->lhs = cond;
                      find_edge (bb, BASIC_BLOCK (i))->aux = equivalency;
@@ -258,7 +240,7 @@ associate_equivalences_with_edges (void)
    COND_EXPRs and SWITCH_EXPRs.
 
    We want to do those propagations as they can sometimes allow
-   the SSA optimziers to do a better job.  However, in the cases
+   the SSA optimizers to do a better job.  However, in the cases
    where such propagations do not result in further optimization,
    we would like to "undo" the propagation to avoid the redundant
    copies and constant initializations.
@@ -286,7 +268,7 @@ associate_equivalences_with_edges (void)
    leading to this block.  If no such edge equivalency exists, then we
    record NULL.  These equivalences are live until we leave the dominator
    subtree rooted at the block where we record the equivalency.  */
-static varray_type equiv_stack;
+static VEC(tree,heap) *equiv_stack;
 
 /* Global hash table implementing a mapping from invariant values
    to a list of SSA_NAMEs which have the same value.  We might be
@@ -300,31 +282,41 @@ struct equiv_hash_elt
   tree value;
 
   /* List of SSA_NAMEs which have the same value/key.  */
-  varray_type equivalences;
+  VEC(tree,heap) *equivalences;
 };
 
-static void uncprop_initialize_block (struct dom_walk_data *, basic_block);
-static void uncprop_finalize_block (struct dom_walk_data *, basic_block);
-static void uncprop_into_successor_phis (struct dom_walk_data *, basic_block);
+static void uncprop_enter_block (struct dom_walk_data *, basic_block);
+static void uncprop_leave_block (struct dom_walk_data *, basic_block);
+static void uncprop_into_successor_phis (basic_block);
 
 /* Hashing and equality routines for the hash table.  */
 
 static hashval_t
 equiv_hash (const void *p)
 {
-  tree value = ((struct equiv_hash_elt *)p)->value;
+  tree const value = ((const struct equiv_hash_elt *)p)->value;
   return iterative_hash_expr (value, 0);
 }
 
 static int
 equiv_eq (const void *p1, const void *p2)
 {
-  tree value1 = ((struct equiv_hash_elt *)p1)->value;
-  tree value2 = ((struct equiv_hash_elt *)p2)->value;
+  tree value1 = ((const struct equiv_hash_elt *)p1)->value;
+  tree value2 = ((const struct equiv_hash_elt *)p2)->value;
 
   return operand_equal_p (value1, value2, 0);
 }
 
+/* Free an instance of equiv_hash_elt.  */
+
+static void
+equiv_free (void *p)
+{
+  struct equiv_hash_elt *elt = (struct equiv_hash_elt *) p;
+  VEC_free (tree, heap, elt->equivalences);
+  free (elt);
+}
+
 /* Remove the most recently recorded equivalency for VALUE.  */
 
 static void
@@ -339,7 +331,7 @@ remove_equivalence (tree value)
   slot = htab_find_slot (equiv, &equiv_hash_elt, NO_INSERT);
 
   equiv_hash_elt_p = (struct equiv_hash_elt *) *slot;
-  VARRAY_POP (equiv_hash_elt_p->equivalences);
+  VEC_pop (tree, equiv_hash_elt_p->equivalences);
 }
 
 /* Record EQUIVALENCE = VALUE into our hash table.  */
@@ -350,7 +342,7 @@ record_equiv (tree value, tree equivalence)
   struct equiv_hash_elt *equiv_hash_elt;
   void **slot;
 
-  equiv_hash_elt = xmalloc (sizeof (struct equiv_hash_elt));
+  equiv_hash_elt = XNEW (struct equiv_hash_elt);
   equiv_hash_elt->value = value;
   equiv_hash_elt->equivalences = NULL;
 
@@ -362,15 +354,13 @@ record_equiv (tree value, tree equivalence)
      free (equiv_hash_elt);
 
   equiv_hash_elt = (struct equiv_hash_elt *) *slot;
-  
-  if (!equiv_hash_elt->equivalences)
-    VARRAY_TREE_INIT (equiv_hash_elt->equivalences, 10, "value equivs");
-  VARRAY_PUSH_TREE (equiv_hash_elt->equivalences, equivalence);
+
+  VEC_safe_push (tree, heap, equiv_hash_elt->equivalences, equivalence);
 }
 
 /* Main driver for un-cprop.  */
 
-static void
+static unsigned int
 tree_ssa_uncprop (void)
 {
   struct dom_walk_data walk_data;
@@ -379,26 +369,20 @@ tree_ssa_uncprop (void)
   associate_equivalences_with_edges ();
 
   /* Create our global data structures.  */
-  equiv = htab_create (1024, equiv_hash, equiv_eq, free);
-  VARRAY_TREE_INIT (equiv_stack, 2, "Block equiv stack");
+  equiv = htab_create (1024, equiv_hash, equiv_eq, equiv_free);
+  equiv_stack = VEC_alloc (tree, heap, 2);
 
   /* We're going to do a dominator walk, so ensure that we have
      dominance information.  */
   calculate_dominance_info (CDI_DOMINATORS);
 
   /* Setup callbacks for the generic dominator tree walker.  */
-  walk_data.walk_stmts_backward = false;
   walk_data.dom_direction = CDI_DOMINATORS;
   walk_data.initialize_block_local_data = NULL;
-  walk_data.before_dom_children_before_stmts = uncprop_initialize_block;
-  walk_data.before_dom_children_walk_stmts = NULL;
-  walk_data.before_dom_children_after_stmts = uncprop_into_successor_phis;
-  walk_data.after_dom_children_before_stmts = NULL;
-  walk_data.after_dom_children_walk_stmts = NULL;
-  walk_data.after_dom_children_after_stmts = uncprop_finalize_block;
+  walk_data.before_dom_children = uncprop_enter_block;
+  walk_data.after_dom_children = uncprop_leave_block;
   walk_data.global_data = NULL;
   walk_data.block_local_data_size = 0;
-  walk_data.interesting_blocks = NULL;
 
   /* Now initialize the dominator walker.  */
   init_walk_dominator_tree (&walk_data);
@@ -410,10 +394,11 @@ tree_ssa_uncprop (void)
   /* Finalize and clean up.  */
   fini_walk_dominator_tree (&walk_data);
 
-  /* EQUIV_STACK should already be empty at this point, so we just need
-     to empty elements out of the hash table and cleanup the AUX field
-     on the edges.  */
+  /* EQUIV_STACK should already be empty at this point, so we just
+     need to empty elements out of the hash table, free EQUIV_STACK,
+     and cleanup the AUX field on the edges.  */
   htab_delete (equiv);
+  VEC_free (tree, heap, equiv_stack);
   FOR_EACH_BB (bb)
     {
       edge e;
@@ -428,7 +413,7 @@ tree_ssa_uncprop (void)
            }
        }
     }
-
+  return 0;
 }
 
 
@@ -437,13 +422,11 @@ tree_ssa_uncprop (void)
    the dominator tree.  */
 
 static void
-uncprop_finalize_block (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
-                       basic_block bb ATTRIBUTE_UNUSED)
+uncprop_leave_block (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
+                    basic_block bb ATTRIBUTE_UNUSED)
 {
-  tree value = VARRAY_TOP_TREE (equiv_stack);
-
   /* Pop the topmost value off the equiv stack.  */
-  VARRAY_POP (equiv_stack);
+  tree value = VEC_pop (tree, equiv_stack);
 
   /* If that value was non-null, then pop the topmost equivalency off
      its equivalency stack.  */
@@ -454,8 +437,7 @@ uncprop_finalize_block (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
 /* Unpropagate values from PHI nodes in successor blocks of BB.  */
 
 static void
-uncprop_into_successor_phis (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
-                            basic_block bb)
+uncprop_into_successor_phis (basic_block bb)
 {
   edge e;
   edge_iterator ei;
@@ -465,24 +447,25 @@ uncprop_into_successor_phis (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
      destination of the edge.  Then remove the temporary equivalence.  */
   FOR_EACH_EDGE (e, ei, bb->succs)
     {
-      tree phi = phi_nodes (e->dest);
+      gimple_seq phis = phi_nodes (e->dest);
+      gimple_stmt_iterator gsi;
 
       /* If there are no PHI nodes in this destination, then there is
         no sense in recording any equivalences.  */
-      if (!phi)
+      if (gimple_seq_empty_p (phis))
        continue;
 
       /* Record any equivalency associated with E.  */
       if (e->aux)
        {
-         struct edge_equivalency *equiv = e->aux;
+         struct edge_equivalency *equiv = (struct edge_equivalency *) e->aux;
          record_equiv (equiv->rhs, equiv->lhs);
        }
 
       /* Walk over the PHI nodes, unpropagating values.  */
-      for ( ; phi; phi = PHI_CHAIN (phi))
+      for (gsi = gsi_start (phis) ; !gsi_end_p (gsi); gsi_next (&gsi))
        {
-         /* Sigh.  We'll have more efficient access to this one day.  */
+         gimple phi = gsi_stmt (gsi);
          tree arg = PHI_ARG_DEF (phi, e->dest_idx);
          struct equiv_hash_elt equiv_hash_elt;
          void **slot;
@@ -501,17 +484,17 @@ uncprop_into_successor_phis (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
 
          if (slot)
            {
-             struct equiv_hash_elt *elt = *slot;
+             struct equiv_hash_elt *elt = (struct equiv_hash_elt *) *slot;
              int j;
 
              /* Walk every equivalence with the same value.  If we find
                 one with the same underlying variable as the PHI result,
                 then replace the value in the argument with its equivalent
-                SSA_NAME.  Use the most recent equivlance as hopefully
+                SSA_NAME.  Use the most recent equivalence as hopefully
                 that results in shortest lifetimes.  */
-             for (j = VARRAY_ACTIVE_SIZE (elt->equivalences) - 1; j >= 0; j--)
+             for (j = VEC_length (tree, elt->equivalences) - 1; j >= 0; j--)
                {
-                 tree equiv = VARRAY_TREE (elt->equivalences, j);
+                 tree equiv = VEC_index (tree, elt->equivalences, j);
 
                  if (SSA_NAME_VAR (equiv) == SSA_NAME_VAR (PHI_RESULT (phi)))
                    {
@@ -525,7 +508,7 @@ uncprop_into_successor_phis (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
       /* If we had an equivalence associated with this edge, remove it.  */
       if (e->aux)
        {
-         struct edge_equivalency *equiv = e->aux;
+         struct edge_equivalency *equiv = (struct edge_equivalency *) e->aux;
          remove_equivalence (equiv->rhs);
        }
     }
@@ -561,8 +544,8 @@ single_incoming_edge_ignoring_loop_edges (basic_block bb)
 }
 
 static void
-uncprop_initialize_block (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
-                         basic_block bb)
+uncprop_enter_block (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
+                    basic_block bb)
 {
   basic_block parent;
   edge e;
@@ -578,16 +561,18 @@ uncprop_initialize_block (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
 
       if (e && e->src == parent && e->aux)
        {
-         struct edge_equivalency *equiv = e->aux;
+         struct edge_equivalency *equiv = (struct edge_equivalency *) e->aux;
 
          record_equiv (equiv->rhs, equiv->lhs);
-         VARRAY_PUSH_TREE (equiv_stack, equiv->rhs);
+         VEC_safe_push (tree, heap, equiv_stack, equiv->rhs);
          recorded = true;
        }
     }
 
   if (!recorded)
-    VARRAY_PUSH_TREE (equiv_stack, NULL_TREE);
+    VEC_safe_push (tree, heap, equiv_stack, NULL_TREE);
+
+  uncprop_into_successor_phis (bb);
 }
 
 static bool
@@ -596,8 +581,10 @@ gate_uncprop (void)
   return flag_tree_dom != 0;
 }
 
-struct tree_opt_pass pass_uncprop = 
+struct gimple_opt_pass pass_uncprop =
 {
+ {
+  GIMPLE_PASS,
   "uncprop",                           /* name */
   gate_uncprop,                                /* gate */
   tree_ssa_uncprop,                    /* execute */
@@ -609,6 +596,7 @@ struct tree_opt_pass pass_uncprop =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func | TODO_verify_ssa,    /* todo_flags_finish */
-  0                                    /* letter */
+  TODO_dump_func | TODO_verify_ssa     /* todo_flags_finish */
+ }
 };
+