OSDN Git Service

PR target/39139
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-sink.c
index 3242f3f..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))
@@ -131,20 +131,20 @@ all_immediate_uses_same_place (tree stmt)
   return true;
 }
 
-/* Some global stores don't necessarily have V_MAY_DEF's of global variables,
+/* Some global stores don't necessarily have VDEF's of global variables,
    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) == MODIFY_EXPR);
+      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
@@ -156,7 +156,7 @@ is_hidden_global_store (tree stmt)
                  int x;
                  p_1 = (i_2 > 3) ? &x : p;
 
-                 # x_4 = V_MAY_DEF <x_3>
+                 # x_4 = VDEF <x_3>
                  *p_1 = 5;
 
                  return 2;
@@ -168,10 +168,11 @@ is_hidden_global_store (tree stmt)
         variable.
 
         Therefore, we check the base address of the LHS.  If the
-        address is a pointer, we check if its name tag or type tag is
+        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 = TREE_OPERAND (stmt, 0);
+      lhs = gimple_get_lhs (stmt);
+
       if (REFERENCE_CLASS_P (lhs))
        lhs = get_base_address (lhs);
 
@@ -190,30 +191,18 @@ 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 tmt = var_ann (SSA_NAME_VAR (ptr))->type_mem_tag;
-
-         /* If either the name tag or the type tag for PTR is a
-            global variable, then the store is necessary.  */
-         if ((nmt && is_global_var (nmt))
-             || (tmt && is_global_var (tmt)))
-           {
-             return true;
-           }
-       }
+       return may_point_to_global_var (TREE_OPERAND (lhs, 0));
       else
        gcc_unreachable ();
     }
+
   return false;
 }
 
 /* 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;
@@ -229,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.  */
@@ -262,21 +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.
-   Return the basic block to sink it to, or NULL if we should not sink
-   it.  */
+   Returns true if there is such location; in that case, TOGSI points to the
+   statement before that STMT should be moved.  */
 
-static tree
-statement_sink_location (tree stmt, basic_block frombb)
+static bool
+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)
     {
@@ -290,11 +280,10 @@ statement_sink_location (tree stmt, basic_block frombb)
 
   /* Return if there are no immediate uses of this stmt.  */
   if (one_use == NULL_USE_OPERAND_P)
-    return NULL;
+    return false;
 
-  if (TREE_CODE (stmt) != MODIFY_EXPR)
-    return NULL;
-  rhs = TREE_OPERAND (stmt, 1);
+  if (gimple_code (stmt) != GIMPLE_ASSIGN)
+    return false;
 
   /* 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
@@ -313,32 +302,39 @@ statement_sink_location (tree stmt, basic_block frombb)
      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))
-    return NULL;
+      || 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)
     {
       tree def = DEF_FROM_PTR (def_p);
       if (is_global_var (SSA_NAME_VAR (def))
          || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (def))
-       return NULL;
+       return false;
     }
     
   FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_ALL_USES)
     {
       tree use = USE_FROM_PTR (use_p);
       if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (use))
-       return NULL;
+       return false;
     }
   
   /* If all the immediate uses are not in the same place, find the nearest
@@ -350,13 +346,13 @@ statement_sink_location (tree stmt, basic_block frombb)
       basic_block commondom = nearest_common_dominator_of_uses (stmt);
      
       if (commondom == frombb)
-       return NULL;
+       return false;
 
       /* Our common dominator has to be dominated by frombb in order to be a
         trivially safe place to put this statement, since it has multiple
         uses.  */     
       if (!dominated_by_p (CDI_DOMINATORS, commondom, frombb))
-       return NULL;
+       return false;
       
       /* It doesn't make sense to move to a dominator that post-dominates
         frombb, because it means we've just moved it into a path that always
@@ -366,27 +362,30 @@ statement_sink_location (tree stmt, basic_block frombb)
        {
          if (dump_file && (dump_flags & TDF_DETAILS))
            fprintf (dump_file, "Not moving store, common dominator post-dominates from block.\n");
-         return NULL;
+         return false;
        }
 
       if (commondom == frombb || commondom->loop_depth > frombb->loop_depth)
-       return NULL;
+       return false;
       if (dump_file && (dump_flags & TDF_DETAILS))
        {
          fprintf (dump_file, "Common dominator of all uses is %d\n",
                   commondom->index);
        }
-      return first_stmt (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 NULL;      
-      return use;
+       return false;
+
+      *togsi = gsi_for_stmt (use);
+      return true;
     }
 
   /* Note that at this point, all uses must be in the same statement, so it
@@ -394,26 +393,27 @@ statement_sink_location (tree stmt, basic_block frombb)
   FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_ALL_DEFS)
     break;
 
-  
   sinkbb = find_bb_for_arg (use, def);
   if (!sinkbb)
-    return NULL;
+    return false;
 
   /* This will happen when you have
      a_3 = PHI <a_13, a_26>
        
-     a_26 = V_MAY_DEF <a_3> 
+     a_26 = VDEF <a_3> 
 
      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)
-    return NULL;
+  if (gimple_bb (use) == frombb)
+    return false;
   if (sinkbb == frombb || sinkbb->loop_depth > frombb->loop_depth
       || sinkbb->loop_father != frombb->loop_father)
-    return NULL;
+    return false;
 
-  return first_stmt (sinkbb);
+  *togsi = gsi_after_labels (sinkbb);
+
+  return true;
 }
 
 /* Perform code sinking on BB */
@@ -422,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.  */
@@ -436,42 +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;
-      tree sinkstmt;
-      
-      sinkstmt = statement_sink_location (stmt, bb);
-      if (!sinkstmt)
+      gimple stmt = gsi_stmt (gsi);    
+      gimple_stmt_iterator togsi;
+
+      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, bb_for_stmt (sinkstmt)->index);
+                  bb->index, (gsi_bb (togsi))->index);
        }
-      tobsi = bsi_for_stmt (sinkstmt);
-      /* Find the first non-label.  */
-      while (!bsi_end_p (tobsi)
-             && TREE_CODE (bsi_stmt (tobsi)) == LABEL_EXPR)
-        bsi_next (&tobsi);
       
       /* 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, bb_for_stmt (sinkstmt));
+      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:
@@ -522,25 +530,26 @@ sink_code_in_bb (basic_block bb)
 static void
 execute_sink_code (void)
 {
-  struct loops *loops = loop_optimizer_init (LOOPS_NORMAL);
+  loop_optimizer_init (LOOPS_NORMAL);
 
   connect_infinite_loops_to_exit ();
   memset (&sink_stats, 0, sizeof (sink_stats));
-  calculate_dominance_info (CDI_DOMINATORS | CDI_POST_DOMINATORS);
+  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 (loops);
+  loop_optimizer_finalize ();
 }
 
 /* Gate and execute functions for PRE.  */
 
-static void
+static unsigned int
 do_sink (void)
 {
   execute_sink_code ();
+  return 0;
 }
 
 static bool
@@ -549,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 */
@@ -566,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 */
+ }
 };