OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-uncprop.c
index 9f06e38..6f603ff 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;
@@ -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,7 +369,7 @@ tree_ssa_uncprop (void)
   associate_equivalences_with_edges ();
 
   /* Create our global data structures.  */
-  equiv = htab_create (1024, equiv_hash, equiv_eq, free);
+  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
@@ -387,18 +377,12 @@ tree_ssa_uncprop (void)
   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);
@@ -429,7 +413,7 @@ tree_ssa_uncprop (void)
            }
        }
     }
-
+  return 0;
 }
 
 
@@ -438,8 +422,8 @@ 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)
 {
   /* Pop the topmost value off the equiv stack.  */
   tree value = VEC_pop (tree, equiv_stack);
@@ -453,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;
@@ -464,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;
@@ -500,7 +484,7 @@ 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
@@ -508,9 +492,9 @@ uncprop_into_successor_phis (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
                 then replace the value in the argument with its equivalent
                 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)))
                    {
@@ -524,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);
        }
     }
@@ -560,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;
@@ -577,7 +561,7 @@ 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);
          VEC_safe_push (tree, heap, equiv_stack, equiv->rhs);
@@ -587,6 +571,8 @@ uncprop_initialize_block (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
 
   if (!recorded)
     VEC_safe_push (tree, heap, equiv_stack, NULL_TREE);
+
+  uncprop_into_successor_phis (bb);
 }
 
 static bool
@@ -595,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 */
@@ -608,6 +596,6 @@ 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_verify_ssa                      /* todo_flags_finish */
+ }
 };