OSDN Git Service

* config/i386/i386.md (R8_REG, R9_REG): New constants.
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-loop-unswitch.c
index 03631b8..b42c70d 100644 (file)
@@ -1,11 +1,11 @@
 /* Loop unswitching.
 /* Loop unswitching.
-   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2005, 2007, 2008 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
    
 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) any
+Free Software Foundation; either version 3, or (at your option) any
 later version.
    
 GCC is distributed in the hope that it will be useful, but WITHOUT
 later version.
    
 GCC is distributed in the hope that it will be useful, but WITHOUT
@@ -14,9 +14,8 @@ 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
 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"
 
 #include "config.h"
 #include "system.h"
@@ -36,6 +35,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "domwalk.h"
 #include "params.h"
 #include "tree-pass.h"
 #include "domwalk.h"
 #include "params.h"
 #include "tree-pass.h"
+#include "tree-inline.h"
 
 /* This file implements the loop unswitching, i.e. transformation of loops like
 
 
 /* This file implements the loop unswitching, i.e. transformation of loops like
 
@@ -73,42 +73,28 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
    tree-ssa-loop-im.c ensures that all the suitable conditions are in this
    shape.  */
 
    tree-ssa-loop-im.c ensures that all the suitable conditions are in this
    shape.  */
 
-static struct loop *tree_unswitch_loop (struct loops *, struct loop *, basic_block,
-                                  tree);
-static bool tree_unswitch_single_loop (struct loops *, struct loop *, int);
+static struct loop *tree_unswitch_loop (struct loop *, basic_block, tree);
+static bool tree_unswitch_single_loop (struct loop *, int);
 static tree tree_may_unswitch_on (basic_block, struct loop *);
 
 static tree tree_may_unswitch_on (basic_block, struct loop *);
 
-/* Main entry point.  Perform loop unswitching on all suitable LOOPS.  */
+/* Main entry point.  Perform loop unswitching on all suitable loops.  */
 
 
-void
-tree_ssa_unswitch_loops (struct loops *loops)
+unsigned int
+tree_ssa_unswitch_loops (void)
 {
 {
-  int i, num;
+  loop_iterator li;
   struct loop *loop;
   bool changed = false;
 
   /* Go through inner loops (only original ones).  */
   struct loop *loop;
   bool changed = false;
 
   /* Go through inner loops (only original ones).  */
-  num = loops->num;
-
-  for (i = 1; i < num; i++)
+  FOR_EACH_LOOP (li, loop, LI_ONLY_INNERMOST)
     {
     {
-      /* Removed loop?  */
-      loop = loops->parray[i];
-      if (!loop)
-       continue;
-
-      if (loop->inner)
-       continue;
-
-      changed |= tree_unswitch_single_loop (loops, loop, 0);
-#ifdef ENABLE_CHECKING
-      verify_dominators (CDI_DOMINATORS);
-      verify_loop_structure (loops);
-#endif
+      changed |= tree_unswitch_single_loop (loop, 0);
     }
 
   if (changed)
     }
 
   if (changed)
-    cleanup_tree_cfg_loop ();
+    return TODO_cleanup_cfg;
+  return 0;
 }
 
 /* Checks whether we can unswitch LOOP on condition at end of BB -- one of its
 }
 
 /* Checks whether we can unswitch LOOP on condition at end of BB -- one of its
@@ -117,29 +103,29 @@ tree_ssa_unswitch_loops (struct loops *loops)
 static tree
 tree_may_unswitch_on (basic_block bb, struct loop *loop)
 {
 static tree
 tree_may_unswitch_on (basic_block bb, struct loop *loop)
 {
-  tree stmt, def, cond;
+  gimple stmt, def;
+  tree cond, use;
   basic_block def_bb;
   basic_block def_bb;
-  use_optype uses;
-  unsigned i;
+  ssa_op_iter iter;
 
   /* BB must end in a simple conditional jump.  */
   stmt = last_stmt (bb);
 
   /* BB must end in a simple conditional jump.  */
   stmt = last_stmt (bb);
-  if (!stmt || TREE_CODE (stmt) != COND_EXPR)
+  if (!stmt || gimple_code (stmt) != GIMPLE_COND)
     return NULL_TREE;
 
   /* Condition must be invariant.  */
     return NULL_TREE;
 
   /* Condition must be invariant.  */
-  get_stmt_operands (stmt);
-  uses = STMT_USE_OPS (stmt);
-  for (i = 0; i < NUM_USES (uses); i++)
+  FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)
     {
     {
-      def = SSA_NAME_DEF_STMT (USE_OP (uses, i));
-      def_bb = bb_for_stmt (def);
+      def = SSA_NAME_DEF_STMT (use);
+      def_bb = gimple_bb (def);
       if (def_bb
          && flow_bb_inside_loop_p (loop, def_bb))
        return NULL_TREE;
     }
 
       if (def_bb
          && flow_bb_inside_loop_p (loop, def_bb))
        return NULL_TREE;
     }
 
-  cond = COND_EXPR_COND (stmt);
+  cond = build2 (gimple_cond_code (stmt), boolean_type_node,
+                gimple_cond_lhs (stmt), gimple_cond_rhs (stmt));
+
   /* To keep the things simple, we do not directly remove the conditions,
      but just replace tests with 0/1.  Prevent the infinite loop where we
      would unswitch again on such a condition.  */
   /* To keep the things simple, we do not directly remove the conditions,
      but just replace tests with 0/1.  Prevent the infinite loop where we
      would unswitch again on such a condition.  */
@@ -157,14 +143,18 @@ static tree
 simplify_using_entry_checks (struct loop *loop, tree cond)
 {
   edge e = loop_preheader_edge (loop);
 simplify_using_entry_checks (struct loop *loop, tree cond)
 {
   edge e = loop_preheader_edge (loop);
-  tree stmt;
+  gimple stmt;
 
   while (1)
     {
       stmt = last_stmt (e->src);
       if (stmt
 
   while (1)
     {
       stmt = last_stmt (e->src);
       if (stmt
-         && TREE_CODE (stmt) == COND_EXPR
-         && operand_equal_p (COND_EXPR_COND (stmt), cond, 0))
+         && gimple_code (stmt) == GIMPLE_COND
+         && gimple_cond_code (stmt) == TREE_CODE (cond)
+         && operand_equal_p (gimple_cond_lhs (stmt),
+                             TREE_OPERAND (cond, 0), 0)
+         && operand_equal_p (gimple_cond_rhs (stmt),
+                             TREE_OPERAND (cond, 1), 0))
        return (e->flags & EDGE_TRUE_VALUE
                ? boolean_true_node
                : boolean_false_node);
        return (e->flags & EDGE_TRUE_VALUE
                ? boolean_true_node
                : boolean_false_node);
@@ -183,12 +173,13 @@ simplify_using_entry_checks (struct loop *loop, tree cond)
    grow exponentially.  */
 
 static bool
    grow exponentially.  */
 
 static bool
-tree_unswitch_single_loop (struct loops *loops, struct loop *loop, int num)
+tree_unswitch_single_loop (struct loop *loop, int num)
 {
   basic_block *bbs;
   struct loop *nloop;
   unsigned i;
 {
   basic_block *bbs;
   struct loop *nloop;
   unsigned i;
-  tree cond = NULL_TREE, stmt;
+  tree cond = NULL_TREE;
+  gimple stmt;
   bool changed = false;
 
   /* Do not unswitch too much.  */
   bool changed = false;
 
   /* Do not unswitch too much.  */
@@ -207,8 +198,16 @@ tree_unswitch_single_loop (struct loops *loops, struct loop *loop, int num)
       return false;
     }
 
       return false;
     }
 
+  /* Do not unswitch in cold regions.  */
+  if (optimize_loop_for_size_p (loop))
+    {
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       fprintf (dump_file, ";; Not unswitching cold loops\n");
+      return false;
+    }
+
   /* The loop should not be too large, to limit code growth.  */
   /* The loop should not be too large, to limit code growth.  */
-  if (tree_num_loop_insns (loop)
+  if (tree_num_loop_insns (loop, &eni_size_weights)
       > (unsigned) PARAM_VALUE (PARAM_MAX_UNSWITCH_INSNS))
     {
       if (dump_file && (dump_flags & TDF_DETAILS))
       > (unsigned) PARAM_VALUE (PARAM_MAX_UNSWITCH_INSNS))
     {
       if (dump_file && (dump_flags & TDF_DETAILS))
@@ -237,33 +236,43 @@ tree_unswitch_single_loop (struct loops *loops, struct loop *loop, int num)
       if (integer_nonzerop (cond))
        {
          /* Remove false path.  */
       if (integer_nonzerop (cond))
        {
          /* Remove false path.  */
-         COND_EXPR_COND (stmt) = boolean_true_node;
+         gimple_cond_set_condition_from_tree (stmt, boolean_true_node);
          changed = true;
        }
       else if (integer_zerop (cond))
        {
          /* Remove true path.  */
          changed = true;
        }
       else if (integer_zerop (cond))
        {
          /* Remove true path.  */
-         COND_EXPR_COND (stmt) = boolean_false_node;
+         gimple_cond_set_condition_from_tree (stmt, boolean_false_node);
          changed = true;
        }
       else
        break;
 
          changed = true;
        }
       else
        break;
 
-      modify_stmt (stmt);
+      update_stmt (stmt);
       i++;
     }
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     fprintf (dump_file, ";; Unswitching loop\n");
 
       i++;
     }
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     fprintf (dump_file, ";; Unswitching loop\n");
 
+  initialize_original_copy_tables ();
   /* Unswitch the loop on this condition.  */
   /* Unswitch the loop on this condition.  */
-  nloop = tree_unswitch_loop (loops, loop, bbs[i], cond);
+  nloop = tree_unswitch_loop (loop, bbs[i], cond);
   if (!nloop)
   if (!nloop)
-    return changed;
+    {
+      free_original_copy_tables ();
+      free (bbs);
+      return changed;
+    }
+
+  /* Update the SSA form after unswitching.  */
+  update_ssa (TODO_update_ssa);
+  free_original_copy_tables ();
 
   /* Invoke itself on modified loops.  */
 
   /* Invoke itself on modified loops.  */
-  tree_unswitch_single_loop (loops, nloop, num + 1);
-  tree_unswitch_single_loop (loops, loop, num + 1);
+  tree_unswitch_single_loop (nloop, num + 1);
+  tree_unswitch_single_loop (loop, num + 1);
+  free (bbs);
   return true;
 }
 
   return true;
 }
 
@@ -273,16 +282,20 @@ tree_unswitch_single_loop (struct loops *loops, struct loop *loop, int num)
    if impossible, new loop otherwise.  */
 
 static struct loop *
    if impossible, new loop otherwise.  */
 
 static struct loop *
-tree_unswitch_loop (struct loops *loops, struct loop *loop,
+tree_unswitch_loop (struct loop *loop,
                    basic_block unswitch_on, tree cond)
 {
                    basic_block unswitch_on, tree cond)
 {
-  basic_block condition_bb;
+  unsigned prob_true;
+  edge edge_true, edge_false;
 
   /* Some sanity checking.  */
   gcc_assert (flow_bb_inside_loop_p (loop, unswitch_on));
   gcc_assert (EDGE_COUNT (unswitch_on->succs) == 2);
   gcc_assert (loop->inner == NULL);
 
 
   /* Some sanity checking.  */
   gcc_assert (flow_bb_inside_loop_p (loop, unswitch_on));
   gcc_assert (EDGE_COUNT (unswitch_on->succs) == 2);
   gcc_assert (loop->inner == NULL);
 
-  return loop_version (loops, loop, unshare_expr (cond), 
-                      &condition_bb);
+  extract_true_false_edges_from_block (unswitch_on, &edge_true, &edge_false);
+  prob_true = edge_true->probability;
+  return loop_version (loop, unshare_expr (cond), 
+                      NULL, prob_true, prob_true,
+                      REG_BR_PROB_BASE - prob_true, false);
 }
 }