OSDN Git Service

PR target/39139
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-sink.c
index 6dff7ff..82a027d 100644 (file)
@@ -1,12 +1,13 @@
 /* Code sinking for trees
-   Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   Copyright (C) 2001, 2002, 2003, 2004, 2007, 2009
+   Free Software Foundation, Inc.
    Contributed by Daniel Berlin <dan@dberlin.org>
 
 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,
@@ -15,9 +16,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, 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
@@ -29,7 +29,7 @@ Boston, MA 02110-1301, USA.  */
 #include "diagnostic.h"
 #include "tree-inline.h"
 #include "tree-flow.h"
-#include "tree-gimple.h"
+#include "gimple.h"
 #include "tree-dump.h"
 #include "timevar.h"
 #include "fibheap.h"
@@ -83,18 +83,18 @@ static struct
    we return NULL.  */
 
 static basic_block
-find_bb_for_arg (tree phi, tree def)
+find_bb_for_arg (gimple phi, tree def)
 {
-  int i;
+  size_t i;
   bool foundone = false;
   basic_block result = NULL;
-  for (i = 0; i < PHI_NUM_ARGS (phi); i++)
+  for (i = 0; i < gimple_phi_num_args (phi); i++)
     if (PHI_ARG_DEF (phi, i) == def)
       {
        if (foundone)
          return NULL;
        foundone = true;
-       result = PHI_ARG_EDGE (phi, i)->src;
+       result = gimple_phi_arg_edge (phi, i)->src;
       }
   return result;
 }
@@ -108,9 +108,9 @@ find_bb_for_arg (tree phi, tree def)
    used in, so that you only have one place you can sink it to.  */
 
 static bool
-all_immediate_uses_same_place (tree stmt)
+all_immediate_uses_same_place (gimple stmt)
 {
-  tree firstuse = NULL_TREE;
+  gimple firstuse = NULL;
   ssa_op_iter op_iter;
   imm_use_iterator imm_iter;
   use_operand_p use_p;
@@ -120,7 +120,7 @@ all_immediate_uses_same_place (tree stmt)
     {
       FOR_EACH_IMM_USE_FAST (use_p, imm_iter, var)
         {
-         if (firstuse == NULL_TREE)
+         if (firstuse == NULL)
            firstuse = USE_STMT (use_p);
          else
            if (firstuse != USE_STMT (use_p))
@@ -135,16 +135,16 @@ all_immediate_uses_same_place (tree stmt)
    but we still must avoid moving them around.  */
 
 bool
-is_hidden_global_store (tree stmt)
+is_hidden_global_store (gimple stmt)
 {
   /* Check virtual definitions.  If we get here, the only virtual
-     definitions we should see are those generated by assignment
+     definitions we should see are those generated by assignment or call
      statements.  */
   if (!ZERO_SSA_OPERANDS (stmt, SSA_OP_VIRTUAL_DEFS))
     {
       tree lhs;
 
-      gcc_assert (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT);
+      gcc_assert (is_gimple_assign (stmt) || is_gimple_call (stmt));
 
       /* Note that we must not check the individual virtual operands
         here.  In particular, if this is an aliased store, we could
@@ -171,7 +171,8 @@ is_hidden_global_store (tree stmt)
         address is a pointer, we check if its name tag or symbol tag is
         a global variable.  Otherwise, we check if the base variable
         is a global.  */
-      lhs = GIMPLE_STMT_OPERAND (stmt, 0);
+      lhs = gimple_get_lhs (stmt);
+
       if (REFERENCE_CLASS_P (lhs))
        lhs = get_base_address (lhs);
 
@@ -190,20 +191,7 @@ is_hidden_global_store (tree stmt)
 
        }
       else if (INDIRECT_REF_P (lhs))
-       {
-         tree ptr = TREE_OPERAND (lhs, 0);
-         struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
-         tree nmt = (pi) ? pi->name_mem_tag : NULL_TREE;
-         tree smt = symbol_mem_tag (SSA_NAME_VAR (ptr));
-
-         /* If either the name tag or the symbol tag for PTR is a
-            global variable, then the store is necessary.  */
-         if ((nmt && is_global_var (nmt))
-             || (smt && is_global_var (smt)))
-           {
-             return true;
-           }
-       }
+       return may_point_to_global_var (TREE_OPERAND (lhs, 0));
       else
        gcc_unreachable ();
     }
@@ -214,7 +202,7 @@ is_hidden_global_store (tree stmt)
 /* Find the nearest common dominator of all of the immediate uses in IMM.  */
 
 static basic_block
-nearest_common_dominator_of_uses (tree stmt)
+nearest_common_dominator_of_uses (gimple stmt)
 {  
   bitmap blocks = BITMAP_ALLOC (NULL);
   basic_block commondom;
@@ -230,18 +218,18 @@ nearest_common_dominator_of_uses (tree stmt)
     {
       FOR_EACH_IMM_USE_FAST (use_p, imm_iter, var)
         {
-         tree usestmt = USE_STMT (use_p);
+         gimple usestmt = USE_STMT (use_p);
          basic_block useblock;
 
-         if (TREE_CODE (usestmt) == PHI_NODE)
+         if (gimple_code (usestmt) == GIMPLE_PHI)
            {
              int idx = PHI_ARG_INDEX_FROM_USE (use_p);
 
-             useblock = PHI_ARG_EDGE (usestmt, idx)->src;
+             useblock = gimple_phi_arg_edge (usestmt, idx)->src;
            }
          else
            {
-             useblock = bb_for_stmt (usestmt);
+             useblock = gimple_bb (usestmt);
            }
 
          /* Short circuit. Nothing dominates the entry block.  */
@@ -263,23 +251,22 @@ nearest_common_dominator_of_uses (tree stmt)
 
 /* Given a statement (STMT) and the basic block it is currently in (FROMBB), 
    determine the location to sink the statement to, if any.
-   Returns true if there is such location; in that case, TOBB is set to the
-   basic block of the location, and TOBSI points to the statement before
-   that STMT should be moved.  */
+   Returns true if there is such location; in that case, TOGSI points to the
+   statement before that STMT should be moved.  */
 
 static bool
-statement_sink_location (tree stmt, basic_block frombb, basic_block *tobb,
-                        block_stmt_iterator *tobsi)
+statement_sink_location (gimple stmt, basic_block frombb,
+                        gimple_stmt_iterator *togsi)
 {
-  tree use, def;
+  gimple use;
+  tree def;
   use_operand_p one_use = NULL_USE_OPERAND_P;
   basic_block sinkbb;
   use_operand_p use_p;
   def_operand_p def_p;
   ssa_op_iter iter;
-  stmt_ann_t ann;
-  tree rhs;
   imm_use_iterator imm_iter;
+  enum tree_code code;
 
   FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_ALL_DEFS)
     {
@@ -295,9 +282,8 @@ statement_sink_location (tree stmt, basic_block frombb, basic_block *tobb,
   if (one_use == NULL_USE_OPERAND_P)
     return false;
 
-  if (TREE_CODE (stmt) != GIMPLE_MODIFY_STMT)
+  if (gimple_code (stmt) != GIMPLE_ASSIGN)
     return false;
-  rhs = GIMPLE_STMT_OPERAND (stmt, 1);
 
   /* There are a few classes of things we can't or don't move, some because we
      don't have code to handle it, some because it's not profitable and some
@@ -316,17 +302,24 @@ statement_sink_location (tree stmt, basic_block frombb, basic_block *tobb,
      We can't sink statements that have volatile operands.  
 
      We don't want to sink dead code, so anything with 0 immediate uses is not
-     sunk.  
+     sunk.
+
+     Don't sink BLKmode assignments if current function has any local explicit
+     register variables, as BLKmode assignments may involve memcpy or memset
+     calls or, on some targets, inline expansion thereof that sometimes need
+     to use specific hard registers.
 
   */
-  ann = stmt_ann (stmt);
+  code = gimple_assign_rhs_code (stmt);
   if (stmt_ends_bb_p (stmt)
-      || TREE_SIDE_EFFECTS (rhs)
-      || TREE_CODE (rhs) == EXC_PTR_EXPR
-      || TREE_CODE (rhs) == FILTER_EXPR
+      || gimple_has_side_effects (stmt)
+      || code == EXC_PTR_EXPR
+      || code == FILTER_EXPR
       || is_hidden_global_store (stmt)
-      || ann->has_volatile_ops
-      || !ZERO_SSA_OPERANDS (stmt, SSA_OP_VUSE))
+      || gimple_has_volatile_ops (stmt)
+      || !ZERO_SSA_OPERANDS (stmt, SSA_OP_VUSE)
+      || (cfun->has_local_explicit_reg_vars
+         && TYPE_MODE (TREE_TYPE (gimple_assign_lhs (stmt))) == BLKmode))
     return false;
   
   FOR_EACH_SSA_DEF_OPERAND (def_p, stmt, iter, SSA_OP_ALL_DEFS)
@@ -379,20 +372,19 @@ statement_sink_location (tree stmt, basic_block frombb, basic_block *tobb,
          fprintf (dump_file, "Common dominator of all uses is %d\n",
                   commondom->index);
        }
-      *tobb = commondom;
-      *tobsi = bsi_after_labels (commondom);
+      *togsi = gsi_after_labels (commondom);
       return true;
     }
 
   use = USE_STMT (one_use);
-  if (TREE_CODE (use) != PHI_NODE)
+  if (gimple_code (use) != GIMPLE_PHI)
     {
-      sinkbb = bb_for_stmt (use);
+      sinkbb = gimple_bb (use);
       if (sinkbb == frombb || sinkbb->loop_depth > frombb->loop_depth
          || sinkbb->loop_father != frombb->loop_father)
        return false;
-      *tobb = sinkbb;
-      *tobsi = bsi_for_stmt (use);
+
+      *togsi = gsi_for_stmt (use);
       return true;
     }
 
@@ -413,14 +405,13 @@ statement_sink_location (tree stmt, basic_block frombb, basic_block *tobb,
      If the use is a phi, and is in the same bb as the def, 
      we can't sink it.  */
 
-  if (bb_for_stmt (use) == frombb)
+  if (gimple_bb (use) == frombb)
     return false;
   if (sinkbb == frombb || sinkbb->loop_depth > frombb->loop_depth
       || sinkbb->loop_father != frombb->loop_father)
     return false;
 
-  *tobb = sinkbb;
-  *tobsi = bsi_after_labels (sinkbb);
+  *togsi = gsi_after_labels (sinkbb);
 
   return true;
 }
@@ -431,9 +422,10 @@ static void
 sink_code_in_bb (basic_block bb)
 {
   basic_block son;
-  block_stmt_iterator bsi;
+  gimple_stmt_iterator gsi;
   edge_iterator ei;
   edge e;
+  bool last = true;
   
   /* If this block doesn't dominate anything, there can't be any place to sink
      the statements to.  */
@@ -445,36 +437,49 @@ sink_code_in_bb (basic_block bb)
     if (e->flags & EDGE_ABNORMAL)
       goto earlyout;
 
-  for (bsi = bsi_last (bb); !bsi_end_p (bsi);)
+  for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi);)
     {
-      tree stmt = bsi_stmt (bsi);      
-      block_stmt_iterator tobsi;
-      basic_block tobb;
+      gimple stmt = gsi_stmt (gsi);    
+      gimple_stmt_iterator togsi;
 
-      if (!statement_sink_location (stmt, bb, &tobb, &tobsi))
+      if (!statement_sink_location (stmt, bb, &togsi))
        {
-         if (!bsi_end_p (bsi))
-           bsi_prev (&bsi);
+         if (!gsi_end_p (gsi))
+           gsi_prev (&gsi);
+         last = false;
          continue;
        }      
       if (dump_file)
        {
          fprintf (dump_file, "Sinking ");
-         print_generic_expr (dump_file, stmt, TDF_VOPS);
+         print_gimple_stmt (dump_file, stmt, 0, TDF_VOPS);
          fprintf (dump_file, " from bb %d to bb %d\n",
-                  bb->index, tobb->index);
+                  bb->index, (gsi_bb (togsi))->index);
        }
       
       /* If this is the end of the basic block, we need to insert at the end
          of the basic block.  */
-      if (bsi_end_p (tobsi))
-       bsi_move_to_bb_end (&bsi, tobb);
+      if (gsi_end_p (togsi))
+       gsi_move_to_bb_end (&gsi, gsi_bb (togsi));
       else
-       bsi_move_before (&bsi, &tobsi);
+       gsi_move_before (&gsi, &togsi);
 
       sink_stats.sunk++;
-      if (!bsi_end_p (bsi))
-       bsi_prev (&bsi);
+
+      /* If we've just removed the last statement of the BB, the
+        gsi_end_p() test below would fail, but gsi_prev() would have
+        succeeded, and we want it to succeed.  So we keep track of
+        whether we're at the last statement and pick up the new last
+        statement.  */
+      if (last)
+       {
+         gsi = gsi_last_bb (bb);
+         continue;
+       }
+
+      last = false;
+      if (!gsi_end_p (gsi))
+       gsi_prev (&gsi);
       
     }
  earlyout:
@@ -532,8 +537,7 @@ execute_sink_code (void)
   calculate_dominance_info (CDI_DOMINATORS);
   calculate_dominance_info (CDI_POST_DOMINATORS);
   sink_code_in_bb (EXIT_BLOCK_PTR); 
-  if (dump_file && (dump_flags & TDF_STATS))
-    fprintf (dump_file, "Sunk statements:%d\n", sink_stats.sunk);
+  statistics_counter_event (cfun, "Sunk statements", sink_stats.sunk);
   free_dominance_info (CDI_POST_DOMINATORS);
   remove_fake_exit_edges ();
   loop_optimizer_finalize ();
@@ -554,8 +558,10 @@ gate_sink (void)
   return flag_tree_sink != 0;
 }
 
-struct tree_opt_pass pass_sink_code =
+struct gimple_opt_pass pass_sink_code =
 {
+ {
+  GIMPLE_PASS,
   "sink",                              /* name */
   gate_sink,                           /* gate */
   do_sink,                             /* execute */
@@ -571,6 +577,6 @@ struct tree_opt_pass pass_sink_code =
   TODO_update_ssa 
     | TODO_dump_func
     | TODO_ggc_collect
-    | TODO_verify_ssa,                 /* todo_flags_finish */
-  0                                    /* letter */
+    | TODO_verify_ssa                  /* todo_flags_finish */
+ }
 };